From Andrew Lindesay <apl@xxxxxxxxxxxxxx>:
Andrew Lindesay has uploaded this change for review. (
https://review.haiku-os.org/c/haiku/+/2397 ;)
Change subject: HaikuDepot: Check Working Files Writable
......................................................................
HaikuDepot: Check Working Files Writable
At start time, it is possible that the local disk
system is not able to be written to where the
application is trying to store working files. This
change introduces a check at startup that ensures
working files can be written to and warns the user
if this is not the case.
---
M src/apps/haikudepot/HaikuDepotConstants.h
M src/apps/haikudepot/model/Model.cpp
M src/apps/haikudepot/model/Model.h
M src/apps/haikudepot/ui/App.cpp
M src/apps/haikudepot/ui/App.h
M src/apps/haikudepot/util/StorageUtils.cpp
M src/apps/haikudepot/util/StorageUtils.h
7 files changed, 232 insertions(+), 84 deletions(-)
git pull ssh://git.haiku-os.org:22/haiku refs/changes/97/2397/1
diff --git a/src/apps/haikudepot/HaikuDepotConstants.h
b/src/apps/haikudepot/HaikuDepotConstants.h
index ba01cd0..9cf2f70 100644
--- a/src/apps/haikudepot/HaikuDepotConstants.h
+++ b/src/apps/haikudepot/HaikuDepotConstants.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2019, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
+ * Copyright 2018-2020, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef HAIKU_DEPOT_CONSTANTS_H
@@ -81,4 +81,6 @@
#define ALERT_MSG_LOGS_USER_GUIDE "Information about how to view the logs is "
\
"available in the HaikuDepot section of the user guide."
+#define CACHE_DIRECTORY_APP "HaikuDepot"
+
#endif // HAIKU_DEPOT_CONSTANTS_H
\ No newline at end of file
diff --git a/src/apps/haikudepot/model/Model.cpp
b/src/apps/haikudepot/model/Model.cpp
index 1e25fef..ff8266a 100644
--- a/src/apps/haikudepot/model/Model.cpp
+++ b/src/apps/haikudepot/model/Model.cpp
@@ -1,7 +1,7 @@
/*
* Copyright 2013-2014, Stephan Aßmus <superstippi@xxxxxx>.
* Copyright 2014, Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>.
- * Copyright 2016-2019, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
+ * Copyright 2016-2020, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
@@ -847,36 +847,6 @@
}
-status_t
-Model::_LocalDataPath(const BString leaf, BPath& path) const
-{
- BPath resultPath;
- status_t result = B_OK;
-
- if (result == B_OK)
- result = find_directory(B_USER_CACHE_DIRECTORY, &resultPath);
-
- if (result == B_OK)
- result = resultPath.Append("HaikuDepot");
-
- if (result == B_OK)
- result = create_directory(resultPath.Path(), 0777);
-
- if (result == B_OK)
- result = resultPath.Append(leaf);
-
- if (result == B_OK)
- path.SetTo(resultPath.Path());
- else {
- path.Unset();
- fprintf(stdout, "unable to find the user cache file for "
- "[%s] data; %s\n", leaf.String(), strerror(result));
- }
-
- return result;
-}
-
-
/*! When bulk repository data comes down from the server, it will
arrive as a json.gz payload. This is stored locally as a cache
and this method will provide the on-disk storage location for
@@ -889,7 +859,7 @@
BString leaf;
leaf.SetToFormat("repository-all_%s.json.gz",
LanguageModel().PreferredLanguage().Code());
- return _LocalDataPath(leaf, path);
+ return StorageUtils::LocalWorkingFilesPath(leaf, path);
}
@@ -904,37 +874,14 @@
BString leaf;
leaf.SetToFormat("reference-all_%s.json.gz",
LanguageModel().PreferredLanguage().Code());
- return _LocalDataPath(leaf, path);
+ return StorageUtils::LocalWorkingFilesPath(leaf, path);
}
status_t
Model::IconStoragePath(BPath& path) const
{
- BPath iconStoragePath;
- status_t result = B_OK;
-
- if (result == B_OK)
- result = find_directory(B_USER_CACHE_DIRECTORY,
&iconStoragePath);
-
- if (result == B_OK)
- result = iconStoragePath.Append("HaikuDepot");
-
- if (result == B_OK)
- result = iconStoragePath.Append("__allicons");
-
- if (result == B_OK)
- result = create_directory(iconStoragePath.Path(), 0777);
-
- if (result == B_OK)
- path.SetTo(iconStoragePath.Path());
- else {
- path.Unset();
- fprintf(stdout, "unable to find the user cache directory for "
- "icons; %s\n", strerror(result));
- }
-
- return result;
+ return StorageUtils::LocalWorkingDirectoryPath("__allicons", path);
}
@@ -945,7 +892,7 @@
BString leaf;
leaf.SetToFormat("pkg-all-%s-%s.json.gz", repositorySourceCode.String(),
LanguageModel().PreferredLanguage().Code());
- return _LocalDataPath(leaf, path);
+ return StorageUtils::LocalWorkingFilesPath(leaf, path);
}
@@ -966,15 +913,21 @@
// See if there is a cached screenshot
BFile screenshotFile;
BPath screenshotCachePath;
+
+ status_t result = StorageUtils::LocalWorkingDirectoryPath(
+ "Screenshots", screenshotCachePath);
+
+ if (result != B_OK) {
+ printf("[!] unable to get the screenshot dir - unable to
proceed");
+ return;
+ }
+
bool fileExists = false;
BString screenshotName(info.Code());
screenshotName << "@" << scaledWidth;
screenshotName << ".png";
time_t modifiedTime;
- if (find_directory(B_USER_CACHE_DIRECTORY, &screenshotCachePath) == B_OK
- && screenshotCachePath.Append("HaikuDepot/Screenshots") == B_OK
- && create_directory(screenshotCachePath.Path(), 0777) == B_OK
- && screenshotCachePath.Append(screenshotName) == B_OK) {
+ if (screenshotCachePath.Append(screenshotName) == B_OK) {
// Try opening the file in read-only mode, which will fail if
its
// not a file or does not exist.
fileExists = screenshotFile.SetTo(screenshotCachePath.Path(),
diff --git a/src/apps/haikudepot/model/Model.h
b/src/apps/haikudepot/model/Model.h
index 6925b6a..2bcb475 100644
--- a/src/apps/haikudepot/model/Model.h
+++ b/src/apps/haikudepot/model/Model.h
@@ -1,12 +1,11 @@
/*
* Copyright 2013-2014, Stephan Aßmus <superstippi@xxxxxx>.
- * Copyright 2016-2019, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
+ * Copyright 2016-2020, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef MODEL_H
#define MODEL_H
-#include <FindDirectory.h>
#include <Locker.h>
#include "AbstractProcess.h"
@@ -155,8 +154,6 @@
private:
void _AddCategory(const
CategoryRef& category);
- status_t _LocalDataPath(const
BString leaf,
- BPath&
path) const;
void _MaybeLogJsonRpcError(
const
BMessage &responsePayload,
@@ -174,17 +171,6 @@
const
ScreenshotInfo& info,
int32
scaledWidth, bool fromCacheOnly);
- bool _GetCacheFile(BPath&
path, BFile& file,
-
directory_which directory,
- const
char* relativeLocation,
- const
char* fileName,
- uint32
openMode) const;
- bool _GetCacheFile(BPath&
path, BFile& file,
-
directory_which directory,
- const
char* relativeLocation,
- const
char* fileName,
- bool
ignoreAge, time_t maxAge) const;
-
void
_NotifyAuthorizationChanged();
void
_NotifyCategoryListChanged();
diff --git a/src/apps/haikudepot/ui/App.cpp b/src/apps/haikudepot/ui/App.cpp
index fbc339b..db2da29 100644
--- a/src/apps/haikudepot/ui/App.cpp
+++ b/src/apps/haikudepot/ui/App.cpp
@@ -1,6 +1,6 @@
/*
* Copyright 2013, Stephan Aßmus <superstippi@xxxxxx>.
- * Copyright 2017-2018, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
+ * Copyright 2017-2020, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
@@ -29,6 +29,7 @@
#include "ServerHelper.h"
#include "ServerSettings.h"
#include "ScreenshotWindow.h"
+#include "StorageUtils.h"
#undef B_TRANSLATION_CONTEXT
@@ -42,6 +43,7 @@
fWindowCount(0),
fSettingsRead(false)
{
+ srand((unsigned int) time(NULL));
_CheckPackageDaemonRuns();
}
@@ -83,6 +85,12 @@
BMessage settings;
_LoadSettings(settings);
+ if (!_CheckTestFile())
+ {
+ Quit();
+ return;
+ }
+
fMainWindow = new MainWindow(settings);
_ShowWindow(fMainWindow);
}
@@ -506,3 +514,44 @@
return true;
}
+
+/*! \brief Checks to ensure that a working file is able to be written.
+ \return false if the startup should be stopped and the application should
+ quit.
+*/
+
+bool
+App::_CheckTestFile()
+{
+ BPath testFilePath;
+ BString pathDescription = "???";
+ status_t result = StorageUtils::LocalWorkingFilesPath("testfile.txt",
+ testFilePath, false);
+
+ if (result == B_OK) {
+ pathDescription = testFilePath.Path();
+ result = StorageUtils::CheckCanWriteTo(testFilePath);
+ }
+
+ if (result != B_OK) {
+ BString msg = B_TRANSLATE("This application writes and reads
some"
+ " working files on your computer in order to function.
It appears"
+ " that there are problems writing a test file at
[%TestFilePath%]."
+ " Check that there are no issues with your local disk
or"
+ " permissions that might prevent this application from
writing"
+ " files into that directory location. You may choose to
acknowledge"
+ " this problem and continue, but follow-on issues are
likely to"
+ " arise.");
+ msg.ReplaceAll("%TestFilePath%", pathDescription);
+
+ BAlert* alert = new(std::nothrow) BAlert(
+ B_TRANSLATE("Problem with working files"),
+ msg,
+ B_TRANSLATE("Quit"), B_TRANSLATE("Continue"));
+
+ if (alert->Go() == 0)
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/apps/haikudepot/ui/App.h b/src/apps/haikudepot/ui/App.h
index 2fb02f8..1eb3f00 100644
--- a/src/apps/haikudepot/ui/App.h
+++ b/src/apps/haikudepot/ui/App.h
@@ -1,6 +1,6 @@
/*
* Copyright 2013, Stephan Aßmus <superstippi@xxxxxx>.
- * Copyright 2018, Andrew Lindesay <apl@xxxxxxxxxxxxxx>
+ * Copyright 2018-2020, Andrew Lindesay <apl@xxxxxxxxxxxxxx>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef APP_H
@@ -36,6 +36,8 @@
void
_CheckPackageDaemonRuns();
bool _LaunchPackageDaemon();
+ bool _CheckTestFile();
+
private:
MainWindow* fMainWindow;
int32 fWindowCount;
diff --git a/src/apps/haikudepot/util/StorageUtils.cpp
b/src/apps/haikudepot/util/StorageUtils.cpp
index 0200045..ad183de 100644
--- a/src/apps/haikudepot/util/StorageUtils.cpp
+++ b/src/apps/haikudepot/util/StorageUtils.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2017, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
+ * Copyright 2017-2020, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
@@ -10,9 +10,11 @@
#include <Directory.h>
#include <File.h>
+#include <FindDirectory.h>
#include <Entry.h>
#include <String.h>
+#include "HaikuDepotConstants.h"
#include "Logger.h"
#define FILE_TO_STRING_BUFFER_LEN 64
@@ -90,7 +92,7 @@
*/
status_t
-StorageUtils::ExistsObject(BPath& path,
+StorageUtils::ExistsObject(const BPath& path,
bool* exists,
bool* isDirectory,
off_t* size)
@@ -122,3 +124,148 @@
return B_OK;
}
+
+
+/*! This method will check that it is possible to write to the specified file.
+ This may create the file, write some data to it and then read that data
+ back again to be sure. This can be used as an effective safety measure as
+ the application starts up in order to ensure that the storage systems are
+ in place for the application to startup.
+
+ It is assumed here that the directory containing the test file exists.
+*/
+
+/*static*/ status_t
+StorageUtils::CheckCanWriteTo(const BPath& path)
+{
+ status_t result = B_OK;
+ bool exists = false;
+ uint8 buffer[16];
+
+ // create some random latin letters into the buffer to write.
+ for (int i = 0; i < 16; i++)
+ buffer[i] = 65 + (abs(rand()) % 26);
+
+ if (result == B_OK)
+ result = ExistsObject(path, &exists, NULL, NULL);
+
+ if (result == B_OK && exists) {
+ if (Logger::IsTraceEnabled()) {
+ printf("an object exists at the candidate path "
+ "[%s] - it will be deleted\n", path.Path());
+ }
+
+ if (remove(path.Path()) == 0) {
+ if (Logger::IsTraceEnabled()) {
+ printf("did delete the candidate file [%s]\n",
path.Path());
+ }
+ } else {
+ printf("unable to delete the candidate file [%s]\n",
path.Path());
+ result = B_ERROR;
+ }
+ }
+
+ if (result == B_OK) {
+ BFile file(path.Path(), O_WRONLY | O_CREAT);
+ if (file.Write(buffer, 16) != 16) {
+ printf("unable to write test data to candidate file
[%s]\n",
+ path.Path());
+ result = B_ERROR;
+ }
+ }
+
+ if (result == B_OK) {
+ BFile file(path.Path(), O_RDONLY);
+ uint8 readBuffer[16];
+ if (file.Read(readBuffer, 16) != 16) {
+ printf("unable to read test data from candidate file
[%s]\n",
+ path.Path());
+ result = B_ERROR;
+ }
+
+ for (int i = 0; result == B_OK && i < 16; i++) {
+ if (readBuffer[i] != buffer[i]) {
+ printf("mismatched read..write check on
candidate file [%s]\n",
+ path.Path());
+ result = B_ERROR;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+/*! As the application runs it will need to store some files into the local
+ disk system. This method, given a leafname, will write into the supplied
+ path variable, a final path where this leafname should be stored.
+*/
+
+/*static*/ status_t
+StorageUtils::LocalWorkingFilesPath(const BString leaf, BPath& path,
+ bool failOnCreateDirectory)
+{
+ BPath resultPath;
+ status_t result = B_OK;
+
+ if (result == B_OK)
+ result = find_directory(B_USER_CACHE_DIRECTORY, &resultPath);
+
+ if (result == B_OK)
+ result = resultPath.Append(CACHE_DIRECTORY_APP);
+
+ if (result == B_OK) {
+ if (failOnCreateDirectory)
+ result = create_directory(resultPath.Path(), 0777);
+ else
+ create_directory(resultPath.Path(), 0777);
+ }
+
+ if (result == B_OK)
+ result = resultPath.Append(leaf);
+
+ if (result == B_OK)
+ path.SetTo(resultPath.Path());
+ else {
+ path.Unset();
+ fprintf(stdout, "unable to find the user cache file for "
+ "[%s] data; %s\n", leaf.String(), strerror(result));
+ }
+
+ return result;
+}
+
+
+/*static*/ status_t
+StorageUtils::LocalWorkingDirectoryPath(const BString leaf, BPath& path,
+ bool failOnCreateDirectory)
+{
+ BPath resultPath;
+ status_t result = B_OK;
+
+ if (result == B_OK)
+ result = find_directory(B_USER_CACHE_DIRECTORY, &resultPath);
+
+ if (result == B_OK)
+ result = resultPath.Append(CACHE_DIRECTORY_APP);
+
+ if (result == B_OK)
+ result = resultPath.Append(leaf);
+
+ if (result == B_OK) {
+ if (failOnCreateDirectory)
+ result = create_directory(resultPath.Path(), 0777);
+ else
+ create_directory(resultPath.Path(), 0777);
+ }
+
+ if (result == B_OK)
+ path.SetTo(resultPath.Path());
+ else {
+ path.Unset();
+ fprintf(stdout, "unable to find the user cache directory for "
+ "[%s] data; %s\n", leaf.String(), strerror(result));
+ }
+
+ return result;
+}
diff --git a/src/apps/haikudepot/util/StorageUtils.h
b/src/apps/haikudepot/util/StorageUtils.h
index 45c025f..f138955 100644
--- a/src/apps/haikudepot/util/StorageUtils.h
+++ b/src/apps/haikudepot/util/StorageUtils.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2017, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
+ * Copyright 2017-2020, Andrew Lindesay <apl@xxxxxxxxxxxxxx>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PATH_UTILS_H
@@ -10,9 +10,18 @@
class StorageUtils {
public:
+ static status_t LocalWorkingFilesPath(const BString
leaf,
+ BPath& path,
+ bool
failOnCreateDirectory = true);
+ static status_t LocalWorkingDirectoryPath(const BString
leaf,
+ BPath& path,
+ bool
failOnCreateDirectory = true);
+
+ static status_t CheckCanWriteTo(const BPath& path);
+
static status_t RemoveDirectoryContents(BPath& path);
static status_t AppendToString(BPath& path, BString&
result);
- static status_t ExistsObject(BPath& directory,
+ static status_t ExistsObject(const BPath& path,
bool* exists,
bool*
isDirectory,
off_t* size);
--
To view, visit https://review.haiku-os.org/c/haiku/+/2397
To unsubscribe, or for help writing mail filters, visit
https://review.haiku-os.org/settings
Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: I907bf41a3b4eceb0083119a082fd5e68e4d534c1
Gerrit-Change-Number: 2397
Gerrit-PatchSet: 1
Gerrit-Owner: Andrew Lindesay <apl@xxxxxxxxxxxxxx>
Gerrit-MessageType: newchange