ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

posix-saves.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 
00024 // Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h.
00025 // Also with clock() in sys/time.h in some Mac OS X SDKs.
00026 #define FORBIDDEN_SYMBOL_EXCEPTION_time_h   //On IRIX, sys/stat.h includes sys/time.h
00027 #define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
00028 #define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
00029 #define FORBIDDEN_SYMBOL_EXCEPTION_getenv
00030 #define FORBIDDEN_SYMBOL_EXCEPTION_random
00031 #define FORBIDDEN_SYMBOL_EXCEPTION_srandom
00032 
00033 #include "common/scummsys.h"
00034 
00035 #if defined(POSIX) && !defined(DISABLE_DEFAULT_SAVEFILEMANAGER)
00036 
00037 #include "backends/saves/posix/posix-saves.h"
00038 #include "backends/fs/posix/posix-fs.h"
00039 
00040 #include "common/config-manager.h"
00041 #include "common/savefile.h"
00042 #include "common/textconsole.h"
00043 
00044 #include <stdio.h>
00045 #include <string.h>
00046 #include <errno.h>
00047 #include <sys/stat.h>
00048 
00049 POSIXSaveFileManager::POSIXSaveFileManager() {
00050     // Register default savepath.
00051 #if defined(SAMSUNGTV)
00052     ConfMan.registerDefault("savepath", "/mtd_wiselink/residualvm savegames");
00053 #else
00054     Common::String savePath;
00055 
00056 #if defined(MACOSX)
00057     const char *home = getenv("HOME");
00058     if (home && *home && strlen(home) < MAXPATHLEN) {
00059         savePath = home;
00060         savePath += "/Documents/ResidualVM Savegames";
00061 
00062         ConfMan.registerDefault("savepath", savePath);
00063     }
00064 
00065 #else
00066     const char *envVar;
00067 
00068     // Previously we placed our default savepath in HOME. If the directory
00069     // still exists, we will use it for backwards compatability.
00070     envVar = getenv("HOME");
00071     if (envVar && *envVar) {
00072         savePath = envVar;
00073         savePath += "/.residualvm";
00074 
00075         struct stat sb;
00076         if (stat(savePath.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
00077             savePath.clear();
00078         }
00079     }
00080 
00081     if (savePath.empty()) {
00082         Common::String prefix;
00083 
00084         // On POSIX systems we follow the XDG Base Directory Specification for
00085         // where to store files. The version we based our code upon can be found
00086         // over here: http://standards.freedesktop.org/basedir-spec/basedir-spec-0.8.html
00087         envVar = getenv("XDG_DATA_HOME");
00088         if (!envVar || !*envVar) {
00089             envVar = getenv("HOME");
00090             if (envVar && *envVar) {
00091                 prefix = envVar;
00092                 savePath = ".local/share/";
00093             }
00094         } else {
00095             prefix = envVar;
00096         }
00097 
00098         // Our default save path is '$XDG_DATA_HOME/residualvm/saves'
00099         savePath += "residualvm/saves";
00100 
00101         if (!Posix::assureDirectoryExists(savePath, prefix.c_str())) {
00102             savePath.clear();
00103         } else {
00104             savePath = prefix + '/' + savePath;
00105         }
00106     }
00107 
00108     if (!savePath.empty() && savePath.size() < MAXPATHLEN) {
00109         ConfMan.registerDefault("savepath", savePath);
00110     }
00111 #endif
00112 
00113     // The user can override the savepath with the SCUMMVM_SAVEPATH
00114     // environment variable. This is weaker than a --savepath on the
00115     // command line, but overrides the default savepath.
00116     //
00117     // To ensure that the command line option (if given) has precedence,
00118     // we only set the value in the transient domain if it is not
00119     // yet present there.
00120     if (!ConfMan.hasKey("savepath", Common::ConfigManager::kTransientDomain)) {
00121         const char *dir = getenv("RESIDUALVM_SAVEPATH");
00122         if (dir && *dir && strlen(dir) < MAXPATHLEN) {
00123             Common::FSNode saveDir(dir);
00124             if (!saveDir.exists()) {
00125                 warning("Ignoring non-existent RESIDUALVM_SAVEPATH '%s'", dir);
00126             } else if (!saveDir.isWritable()) {
00127                 warning("Ignoring non-writable RESIDUALVM_SAVEPATH '%s'", dir);
00128             } else {
00129                 ConfMan.set("savepath", dir, Common::ConfigManager::kTransientDomain);
00130             }
00131         }
00132     }
00133 #endif
00134 }
00135 
00136 void POSIXSaveFileManager::checkPath(const Common::FSNode &dir) {
00137     const Common::String path = dir.getPath();
00138     clearError();
00139 
00140     struct stat sb;
00141 
00142     // Check whether the dir exists
00143     if (stat(path.c_str(), &sb) == -1) {
00144         // The dir does not exist, or stat failed for some other reason.
00145         // If the problem was that the path pointed to nothing, try
00146         // to create the dir (ENOENT case).
00147         switch (errno) {
00148         case EACCES:
00149             setError(Common::kWritePermissionDenied, "Search or write permission denied: "+path);
00150             break;
00151         case ELOOP:
00152             setError(Common::kUnknownError, "Too many symbolic links encountered while traversing the path: "+path);
00153             break;
00154         case ENAMETOOLONG:
00155             setError(Common::kUnknownError, "The path name is too long: "+path);
00156             break;
00157         case ENOENT:
00158             if (mkdir(path.c_str(), 0755) != 0) {
00159                 // mkdir could fail for various reasons: The parent dir doesn't exist,
00160                 // or is not writeable, the path could be completly bogus, etc.
00161                 warning("mkdir for '%s' failed", path.c_str());
00162                 perror("mkdir");
00163 
00164                 switch (errno) {
00165                 case EACCES:
00166                     setError(Common::kWritePermissionDenied, "Search or write permission denied: "+path);
00167                     break;
00168                 case EMLINK:
00169                     setError(Common::kUnknownError, "The link count of the parent directory would exceed {LINK_MAX}: "+path);
00170                     break;
00171                 case ELOOP:
00172                     setError(Common::kUnknownError, "Too many symbolic links encountered while traversing the path: "+path);
00173                     break;
00174                 case ENAMETOOLONG:
00175                     setError(Common::kUnknownError, "The path name is too long: "+path);
00176                     break;
00177                 case ENOENT:
00178                     setError(Common::kPathDoesNotExist, "A component of the path does not exist, or the path is an empty string: "+path);
00179                     break;
00180                 case ENOTDIR:
00181                     setError(Common::kPathDoesNotExist, "A component of the path prefix is not a directory: "+path);
00182                     break;
00183                 case EROFS:
00184                     setError(Common::kWritePermissionDenied, "The parent directory resides on a read-only file system:"+path);
00185                     break;
00186                 }
00187             }
00188             break;
00189         case ENOTDIR:
00190             setError(Common::kPathDoesNotExist, "A component of the path prefix is not a directory: "+path);
00191             break;
00192         }
00193     } else {
00194         // So stat() succeeded. But is the path actually pointing to a directory?
00195         if (!S_ISDIR(sb.st_mode)) {
00196             setError(Common::kPathDoesNotExist, "The given savepath is not a directory: "+path);
00197         }
00198     }
00199 }
00200 
00201 #endif


Generated on Sat Mar 16 2019 05:01:50 for ResidualVM by doxygen 1.7.1
curved edge   curved edge