[haiku-commits] haiku: hrev54015 - in src/apps/haikudepot: util server model ui

  • From: waddlesplash <waddlesplash@xxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sat, 28 Mar 2020 16:06:13 -0400 (EDT)

hrev54015 adds 1 changeset to branch 'master'
old head: 663c9749e166d8c74c8d2a171af29bca99ff75fc
new head: 32ed76599d59dc3eead9350b86a6fbbb2591abcf
overview: 
https://git.haiku-os.org/haiku/log/?qt=range&q=32ed76599d59+%5E663c9749e166

----------------------------------------------------------------------------

32ed76599d59: 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.
  
  Change-Id: I907bf41a3b4eceb0083119a082fd5e68e4d534c1
  Reviewed-on: https://review.haiku-os.org/c/haiku/+/2397
  Reviewed-by: waddlesplash <waddlesplash@xxxxxxxxx>

                                    [ Andrew Lindesay <apl@xxxxxxxxxxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev54015
Commit:      32ed76599d59dc3eead9350b86a6fbbb2591abcf
URL:         https://git.haiku-os.org/haiku/commit/?id=32ed76599d59
Author:      Andrew Lindesay <apl@xxxxxxxxxxxxxx>
Date:        Sun Mar 22 10:46:30 2020 UTC
Committer:   waddlesplash <waddlesplash@xxxxxxxxx>
Commit-Date: Sat Mar 28 20:06:08 2020 UTC

----------------------------------------------------------------------------

8 files changed, 299 insertions(+), 124 deletions(-)
src/apps/haikudepot/HaikuDepotConstants.h        |   4 +-
src/apps/haikudepot/model/Model.cpp              |  77 ++-------
src/apps/haikudepot/model/Model.h                |  16 +-
.../server/ProcessCoordinatorFactory.cpp         |  85 +++++-----
src/apps/haikudepot/ui/App.cpp                   |  53 +++++-
src/apps/haikudepot/ui/App.h                     |   4 +-
src/apps/haikudepot/util/StorageUtils.cpp        | 168 ++++++++++++++++++-
src/apps/haikudepot/util/StorageUtils.h          |  16 +-

----------------------------------------------------------------------------

diff --git a/src/apps/haikudepot/HaikuDepotConstants.h 
b/src/apps/haikudepot/HaikuDepotConstants.h
index 74cd6d61ac..190f8cb825 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 @@ enum UserUsageConditionsSelectionMode {
 #define ALERT_MSG_LOGS_USER_GUIDE "\nInformation 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 1e25fef781..ff8266aeb8 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 @@ Model::SetAuthorization(const BString& nickname, const 
BString& passwordClear,
 }
 
 
-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 @@ Model::DumpExportRepositoryDataPath(BPath& path) const
        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 @@ Model::DumpExportReferenceDataPath(BPath& path) const
        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 @@ Model::DumpExportPkgDataPath(BPath& path,
        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 @@ Model::_PopulatePackageScreenshot(const PackageInfoRef& 
package,
        // 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 6925b6aef8..2bcb4755b1 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 @@ public:
 
 private:
                        void                            _AddCategory(const 
CategoryRef& category);
-                       status_t                        _LocalDataPath(const 
BString leaf,
-                                                                       BPath& 
path) const;
 
                        void                            _MaybeLogJsonRpcError(
                                                                        const 
BMessage &responsePayload,
@@ -174,17 +171,6 @@ private:
                                                                        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/server/ProcessCoordinatorFactory.cpp 
b/src/apps/haikudepot/server/ProcessCoordinatorFactory.cpp
index c715802978..69ea8ee457 100644
--- a/src/apps/haikudepot/server/ProcessCoordinatorFactory.cpp
+++ b/src/apps/haikudepot/server/ProcessCoordinatorFactory.cpp
@@ -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.
  */
 
@@ -25,6 +25,7 @@
 #include "ServerReferenceDataUpdateProcess.h"
 #include "ServerRepositoryDataUpdateProcess.h"
 #include "ServerSettings.h"
+#include "StorageUtils.h"
 
 
 using namespace BPackageKit;
@@ -36,6 +37,7 @@ ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
        ProcessCoordinatorListener* processCoordinatorListener,
        Model* model, bool forceLocalUpdate)
 {
+       bool areWorkingFilesAvailable = 
StorageUtils::AreWorkingFilesAvailable();
        uint32 serverProcessOptions = _CalculateServerProcessOptions();
        BAutolock locker(model->Lock());
        ProcessCoordinator* processCoordinator = new ProcessCoordinator(
@@ -52,46 +54,49 @@ ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
        localPkgDataLoad->AddPredecessor(localRepositoryUpdate);
        processCoordinator->AddNode(localPkgDataLoad);
 
-       ProcessNode *serverIconExportUpdate =
-               new ProcessNode(new ServerIconExportUpdateProcess(model,
-                       serverProcessOptions));
-       serverIconExportUpdate->AddPredecessor(localPkgDataLoad);
-       processCoordinator->AddNode(serverIconExportUpdate);
-
-       ProcessNode *serverRepositoryDataUpdate =
-               new ProcessNode(new ServerRepositoryDataUpdateProcess(model,
-                       serverProcessOptions));
-       serverRepositoryDataUpdate->AddPredecessor(localPkgDataLoad);
-       processCoordinator->AddNode(serverRepositoryDataUpdate);
-
-       ProcessNode *serverReferenceDataUpdate =
-               new ProcessNode(new ServerReferenceDataUpdateProcess(model,
-                       serverProcessOptions));
-       processCoordinator->AddNode(serverReferenceDataUpdate);
-
-       // create a process for each of the repositories that are configured on 
the
-       // local system.  Later, only those that have a web-app repository 
server
-       // code will be actually processed, but this means that the creation of 
the
-       // 'processes' does not need to be dynamic as the process coordinator 
runs.
-
-       BPackageRoster roster;
-       BStringList repoNames;
-       status_t repoNamesResult = roster.GetRepositoryNames(repoNames);
-
-       if (repoNamesResult == B_OK) {
-               AutoLocker<BLocker> locker(model->Lock());
-
-               for (int32 i = 0; i < repoNames.CountStrings(); i++) {
-                       ProcessNode* processNode = new ProcessNode(
-                               new ServerPkgDataUpdateProcess(
-                                       
model->Language().PreferredLanguage().Code(),
-                                       repoNames.StringAt(i), model, 
serverProcessOptions));
-                       processNode->AddPredecessor(serverRepositoryDataUpdate);
-                       processNode->AddPredecessor(serverReferenceDataUpdate);
-                       processCoordinator->AddNode(processNode);
+       if (areWorkingFilesAvailable) {
+               ProcessNode *serverIconExportUpdate =
+                       new ProcessNode(new ServerIconExportUpdateProcess(model,
+                               serverProcessOptions));
+               serverIconExportUpdate->AddPredecessor(localPkgDataLoad);
+               processCoordinator->AddNode(serverIconExportUpdate);
+
+               ProcessNode *serverRepositoryDataUpdate =
+                       new ProcessNode(new 
ServerRepositoryDataUpdateProcess(model,
+                               serverProcessOptions));
+               serverRepositoryDataUpdate->AddPredecessor(localPkgDataLoad);
+               processCoordinator->AddNode(serverRepositoryDataUpdate);
+
+               ProcessNode *serverReferenceDataUpdate =
+                       new ProcessNode(new 
ServerReferenceDataUpdateProcess(model,
+                               serverProcessOptions));
+               processCoordinator->AddNode(serverReferenceDataUpdate);
+
+               // create a process for each of the repositories that are 
configured on
+               // the local system.  Later, only those that have a web-app 
repository
+               // server code will be actually processed, but this means that 
the
+               // creation of the 'processes' does not need to be dynamic as 
the
+               // process coordinator runs.
+
+               BPackageRoster roster;
+               BStringList repoNames;
+               status_t repoNamesResult = roster.GetRepositoryNames(repoNames);
+
+               if (repoNamesResult == B_OK) {
+                       AutoLocker<BLocker> locker(model->Lock());
+
+                       for (int32 i = 0; i < repoNames.CountStrings(); i++) {
+                               ProcessNode* processNode = new ProcessNode(
+                                       new ServerPkgDataUpdateProcess(
+                                               
model->Language().PreferredLanguage().Code(),
+                                               repoNames.StringAt(i), model, 
serverProcessOptions));
+                               
processNode->AddPredecessor(serverRepositoryDataUpdate);
+                               
processNode->AddPredecessor(serverReferenceDataUpdate);
+                               processCoordinator->AddNode(processNode);
+                       }
+               } else {
+                       printf("a problem has arisen getting the repository 
names.\n");
                }
-       } else {
-               printf("a problem has arisen getting the repository names.\n");
        }
 
        return processCoordinator;
diff --git a/src/apps/haikudepot/ui/App.cpp b/src/apps/haikudepot/ui/App.cpp
index fbc339bc89..e48573cd45 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 @@ App::App()
        fWindowCount(0),
        fSettingsRead(false)
 {
+       srand((unsigned int) time(NULL));
        _CheckPackageDaemonRuns();
 }
 
@@ -83,6 +85,12 @@ App::ReadyToRun()
        BMessage settings;
        _LoadSettings(settings);
 
+       if (!_CheckTestFile())
+       {
+               Quit();
+               return;
+       }
+
        fMainWindow = new MainWindow(settings);
        _ShowWindow(fMainWindow);
 }
@@ -506,3 +514,46 @@ App::_LaunchPackageDaemon()
        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) {
+               StorageUtils::SetWorkingFilesUnavailable();
+
+               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 some functionality may 
be"
+                       " disabled.");
+               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 2fb02f8c08..1eb3f00864 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 @@ private:
                        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 020004577f..9f742ea674 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,14 +10,33 @@
 
 #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
 
 
+static bool sAreWorkingFilesAvailable = true;
+
+
+/*static*/ bool
+StorageUtils::AreWorkingFilesAvailable()
+{
+       return sAreWorkingFilesAvailable;
+}
+
+
+/*static*/ void
+StorageUtils::SetWorkingFilesUnavailable()
+{
+       sAreWorkingFilesAvailable = false;
+}
+
+
 /* This method will append the contents of the file at the supplied path to the
  * string provided.
  */
@@ -90,7 +109,7 @@ StorageUtils::RemoveDirectoryContents(BPath& path)
  */
 
 status_t
-StorageUtils::ExistsObject(BPath& path,
+StorageUtils::ExistsObject(const BPath& path,
        bool* exists,
        bool* isDirectory,
        off_t* size)
@@ -122,3 +141,148 @@ StorageUtils::ExistsObject(BPath& path,
 
        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 45c025f494..cd39ebd1d5 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,21 @@
 class StorageUtils {
 
 public:
+       static bool                             AreWorkingFilesAvailable();
+       static void                             SetWorkingFilesUnavailable();
+
+       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);


Other related posts:

  • » [haiku-commits] haiku: hrev54015 - in src/apps/haikudepot: util server model ui - waddlesplash