1 /* Copyright (C) 2017 Wildfire Games. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining 4 * a copy of this software and associated documentation files (the 5 * "Software"), to deal in the Software without restriction, including 6 * without limitation the rights to use, copy, modify, merge, publish, 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 * permit persons to whom the Software is furnished to do so, subject to 9 * the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 /* 24 * Virtual File System API - allows transparent access to files in 25 * archives, modding via multiple mount points and hotloading. 26 */ 27 28 #ifndef INCLUDED_VFS 29 #define INCLUDED_VFS 30 31 #include "lib/file/file_system.h" // CFileInfo 32 #include "lib/file/vfs/vfs_path.h" 33 34 namespace ERR 35 { 36 const Status VFS_DIR_NOT_FOUND = -110100; 37 const Status VFS_FILE_NOT_FOUND = -110101; 38 const Status VFS_ALREADY_MOUNTED = -110102; 39 } 40 41 // (recursive mounting and mounting archives are no longer optional since they don't hurt) 42 enum VfsMountFlags 43 { 44 /** 45 * all real directories mounted during this operation will be watched 46 * for changes. this flag is provided to avoid watches in output-only 47 * directories, e.g. screenshots/ (only causes unnecessary overhead). 48 **/ 49 VFS_MOUNT_WATCH = 1, 50 51 /** 52 * anything mounted from here should be included when building archives. 53 **/ 54 VFS_MOUNT_ARCHIVABLE = 2, 55 56 /** 57 * return ERR::VFS_DIR_NOT_FOUND if the given real path doesn't exist. 58 * (the default behavior is to create all real directories in the path) 59 **/ 60 VFS_MOUNT_MUST_EXIST = 4, 61 62 /** 63 * keep the files named "*.DELETED" visible in the VFS directories. 64 * the standard behavior of hiding the file with the same name minus the 65 * ".DELETED" suffix will still apply. 66 * (the default behavior is to hide both the suffixed and unsuffixed files) 67 **/ 68 VFS_MOUNT_KEEP_DELETED = 8, 69 70 /** 71 * mark a directory replaceable, so that when writing a file to this path 72 * new real directories will be created instead of reusing already existing 73 * ones mounted at a subpath of the VFS path. 74 * (the default behaviour is to write to the real directory associated 75 * with the VFS directory that was last mounted to this path (or subpath)) 76 **/ 77 VFS_MOUNT_REPLACEABLE = 16 78 }; 79 80 // (member functions are thread-safe after the instance has been 81 // constructed - each acquires a pthread mutex.) 82 struct IVFS 83 { ~IVFSIVFS84 virtual ~IVFS() {} 85 86 /** 87 * mount a directory into the VFS. 88 * 89 * @param mountPoint (will be created if it does not already exist) 90 * @param path real directory path 91 * @param flags 92 * @param priority 93 * @return Status. 94 * 95 * if files are encountered that already exist in the VFS (sub)directories, 96 * the most recent / highest priority/precedence version is preferred. 97 * 98 * if files with archive extensions are seen, their contents are added 99 * as well. 100 **/ 101 virtual Status Mount(const VfsPath& mountPoint, const OsPath& path, size_t flags = 0, size_t priority = 0) = 0; 102 103 /** 104 * Retrieve information about a file (similar to POSIX stat). 105 * 106 * @param pathname 107 * @param pfileInfo receives information about the file. Passing NULL 108 * suppresses warnings if the file doesn't exist. 109 * 110 * @return Status. 111 **/ 112 virtual Status GetFileInfo(const VfsPath& pathname, CFileInfo* pfileInfo) const = 0; 113 114 /** 115 * Retrieve mount priority for a file. 116 * 117 * @param pathname 118 * @param ppriority receives priority value, if the file can be found. 119 * 120 * @return Status. 121 **/ 122 virtual Status GetFilePriority(const VfsPath& pathname, size_t* ppriority) const = 0; 123 124 /** 125 * Retrieve lists of all files and subdirectories in a directory. 126 * 127 * @return Status. 128 * 129 * Rationale: 130 * - this interface avoids having to lock the directory while an 131 * iterator is extant. 132 * - we cannot efficiently provide routines for returning files and 133 * subdirectories separately due to the underlying POSIX interface. 134 **/ 135 virtual Status GetDirectoryEntries(const VfsPath& path, CFileInfos* fileInfos, DirectoryNames* subdirectoryNames) const = 0; 136 137 /** 138 * Create a file with the given contents. 139 * @param pathname 140 * @param fileContents 141 * @param size [bytes] of the contents, will match that of the file. 142 * @return Status. 143 **/ 144 virtual Status CreateFile(const VfsPath& pathname, const shared_ptr<u8>& fileContents, size_t size) = 0; 145 146 /** 147 * Replace a file with the given contents. 148 * 149 * @see CreateFile 150 * 151 * Used to replace a file if it is already present (even if the file is not 152 * in the attached vfs directory). Calls CreateFile if the file doesn't yet 153 * exist. 154 **/ 155 virtual Status ReplaceFile(const VfsPath& pathname, const shared_ptr<u8>& fileContents, size_t size) = 0; 156 157 /** 158 * Read an entire file into memory. 159 * 160 * @param pathname 161 * @param fileContents receives a smart pointer to the contents. 162 * @param size receives the size [bytes] of the file contents. 163 * @return Status. 164 **/ 165 virtual Status LoadFile(const VfsPath& pathname, shared_ptr<u8>& fileContents, size_t& size) = 0; 166 167 /** 168 * @return a string representation of all files and directories. 169 **/ 170 virtual std::wstring TextRepresentation() const = 0; 171 172 /** 173 * retrieve the real (POSIX) pathname underlying a VFS file. 174 * 175 * this is useful for passing paths to external libraries. 176 **/ 177 virtual Status GetRealPath(const VfsPath& pathname, OsPath& realPathname) = 0; 178 179 /** 180 * retrieve the real (POSIX) pathname underlying a VFS directory. 181 * 182 * this is useful for passing paths to external libraries. 183 **/ 184 virtual Status GetDirectoryRealPath(const VfsPath& pathname, OsPath& realPathname) = 0; 185 186 /** 187 * retrieve the VFS pathname that corresponds to a real file. 188 * 189 * this is useful for reacting to file change notifications. 190 * 191 * the current implementation requires time proportional to the 192 * number of directories; this could be accelerated by only checking 193 * directories below a mount point with a matching real path. 194 **/ 195 virtual Status GetVirtualPath(const OsPath& realPathname, VfsPath& pathname) = 0; 196 197 /** 198 * remove file from the virtual directory listing. 199 **/ 200 virtual Status RemoveFile(const VfsPath& pathname) = 0; 201 202 /** 203 * request the directory be re-populated when it is next accessed. 204 * useful for synchronizing with the underlying filesystem after 205 * files have been created or their metadata changed. 206 **/ 207 virtual Status RepopulateDirectory(const VfsPath& path) = 0; 208 209 /** 210 * empty the contents of the filesystem. 211 * this is typically only necessary when changing the set of 212 * mounted directories, e.g. when switching mods. 213 * NB: open files are not affected. 214 **/ 215 virtual void Clear() = 0; 216 }; 217 218 typedef shared_ptr<IVFS> PIVFS; 219 220 /** 221 * create an instance of a Virtual File System. 222 * 223 * note: there is no limitation to a single instance, it may make sense 224 * to create and destroy VFS instances during each unit test. 225 **/ 226 LIB_API PIVFS CreateVfs(); 227 228 #endif // #ifndef INCLUDED_VFS 229