file_system.h (7607B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR PolyForm-Strict-1.0.0) 3 4 #pragma once 5 6 #include "heap_array.h" 7 #include "types.h" 8 9 #include <cstdio> 10 #include <ctime> 11 #include <memory> 12 #include <optional> 13 #include <string> 14 #include <sys/stat.h> 15 #include <vector> 16 17 class Error; 18 19 #ifdef _WIN32 20 #define FS_OSPATH_SEPARATOR_CHARACTER '\\' 21 #define FS_OSPATH_SEPARATOR_STR "\\" 22 #else 23 #define FS_OSPATH_SEPARATOR_CHARACTER '/' 24 #define FS_OSPATH_SEPARATOR_STR "/" 25 #endif 26 27 enum FILESYSTEM_FILE_ATTRIBUTES 28 { 29 FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY = (1 << 0), 30 FILESYSTEM_FILE_ATTRIBUTE_READ_ONLY = (1 << 1), 31 FILESYSTEM_FILE_ATTRIBUTE_COMPRESSED = (1 << 2), 32 FILESYSTEM_FILE_ATTRIBUTE_LINK = (1 << 3), 33 }; 34 35 enum FILESYSTEM_FIND_FLAGS 36 { 37 FILESYSTEM_FIND_RECURSIVE = (1 << 0), 38 FILESYSTEM_FIND_RELATIVE_PATHS = (1 << 1), 39 FILESYSTEM_FIND_HIDDEN_FILES = (1 << 2), 40 FILESYSTEM_FIND_FOLDERS = (1 << 3), 41 FILESYSTEM_FIND_FILES = (1 << 4), 42 FILESYSTEM_FIND_KEEP_ARRAY = (1 << 5), 43 FILESYSTEM_FIND_SORT_BY_NAME = (1 << 6), 44 }; 45 46 struct FILESYSTEM_STAT_DATA 47 { 48 std::time_t CreationTime; // actually inode change time on linux 49 std::time_t ModificationTime; 50 s64 Size; 51 u32 Attributes; 52 }; 53 54 struct FILESYSTEM_FIND_DATA 55 { 56 std::time_t CreationTime; // actually inode change time on linux 57 std::time_t ModificationTime; 58 std::string FileName; 59 s64 Size; 60 u32 Attributes; 61 }; 62 63 namespace FileSystem { 64 using FindResultsArray = std::vector<FILESYSTEM_FIND_DATA>; 65 66 /// Returns the display name of a filename. Usually this is the same as the path. 67 std::string GetDisplayNameFromPath(std::string_view path); 68 69 /// Returns a list of "root directories" (i.e. root/home directories on Linux, drive letters on Windows). 70 std::vector<std::string> GetRootDirectoryList(); 71 72 /// Search for files 73 bool FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results); 74 75 /// Stat file 76 bool StatFile(const char* path, struct stat* st); 77 bool StatFile(std::FILE* fp, struct stat* st); 78 bool StatFile(const char* path, FILESYSTEM_STAT_DATA* pStatData); 79 bool StatFile(std::FILE* fp, FILESYSTEM_STAT_DATA* pStatData); 80 s64 GetPathFileSize(const char* path); 81 82 /// File exists? 83 bool FileExists(const char* path); 84 85 /// Directory exists? 86 bool DirectoryExists(const char* path); 87 bool IsRealDirectory(const char* path); 88 89 /// Directory does not contain any files? 90 bool IsDirectoryEmpty(const char* path); 91 92 /// Delete file 93 bool DeleteFile(const char* path, Error* error = nullptr); 94 95 /// Rename file 96 bool RenamePath(const char* OldPath, const char* NewPath, Error* error = nullptr); 97 98 /// Deleter functor for managed file pointers 99 struct FileDeleter 100 { 101 ALWAYS_INLINE void operator()(std::FILE* fp) 102 { 103 if (fp) 104 std::fclose(fp); 105 } 106 }; 107 108 /// open files 109 using ManagedCFilePtr = std::unique_ptr<std::FILE, FileDeleter>; 110 ManagedCFilePtr OpenManagedCFile(const char* filename, const char* mode, Error* error = nullptr); 111 std::FILE* OpenCFile(const char* filename, const char* mode, Error* error = nullptr); 112 113 /// Atomically opens a file in read/write mode, and if the file does not exist, creates it. 114 /// On Windows, if retry_ms is positive, this function will retry opening the file for this 115 /// number of milliseconds. NOTE: The file is opened in binary mode. 116 std::FILE* OpenExistingOrCreateCFile(const char* filename, s32 retry_ms = -1, Error* error = nullptr); 117 ManagedCFilePtr OpenExistingOrCreateManagedCFile(const char* filename, s32 retry_ms = -1, Error* error = nullptr); 118 119 int FSeek64(std::FILE* fp, s64 offset, int whence); 120 bool FSeek64(std::FILE* fp, s64 offset, int whence, Error* error); 121 s64 FTell64(std::FILE* fp); 122 s64 FSize64(std::FILE* fp, Error* error = nullptr); 123 bool FTruncate64(std::FILE* fp, s64 size, Error* error = nullptr); 124 125 int OpenFDFile(const char* filename, int flags, int mode, Error* error = nullptr); 126 127 /// Sharing modes for OpenSharedCFile(). 128 enum class FileShareMode 129 { 130 DenyReadWrite, /// Exclusive access. 131 DenyWrite, /// Other processes can read from this file. 132 DenyRead, /// Other processes can write to this file. 133 DenyNone, /// Other processes can read and write to this file. 134 }; 135 136 /// Opens a file in shareable mode (where other processes can access it concurrently). 137 /// Only has an effect on Windows systems. 138 ManagedCFilePtr OpenManagedSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, 139 Error* error = nullptr); 140 std::FILE* OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error = nullptr); 141 142 /// Atomically-updated file creation. 143 class AtomicRenamedFileDeleter 144 { 145 public: 146 AtomicRenamedFileDeleter(std::string temp_filename, std::string final_filename); 147 ~AtomicRenamedFileDeleter(); 148 149 void operator()(std::FILE* fp); 150 void discard(); 151 152 private: 153 std::string m_temp_filename; 154 std::string m_final_filename; 155 }; 156 using AtomicRenamedFile = std::unique_ptr<std::FILE, AtomicRenamedFileDeleter>; 157 AtomicRenamedFile CreateAtomicRenamedFile(std::string filename, const char* mode, Error* error = nullptr); 158 bool WriteAtomicRenamedFile(std::string filename, const void* data, size_t data_length, Error* error = nullptr); 159 void DiscardAtomicRenamedFile(AtomicRenamedFile& file); 160 161 /// Abstracts a POSIX file lock. 162 #ifndef _WIN32 163 class POSIXLock 164 { 165 public: 166 POSIXLock(int fd); 167 POSIXLock(std::FILE* fp); 168 ~POSIXLock(); 169 170 private: 171 int m_fd; 172 }; 173 #endif 174 175 std::optional<DynamicHeapArray<u8>> ReadBinaryFile(const char* filename, Error* error = nullptr); 176 std::optional<DynamicHeapArray<u8>> ReadBinaryFile(std::FILE* fp, Error* error = nullptr); 177 std::optional<std::string> ReadFileToString(const char* filename, Error* error = nullptr); 178 std::optional<std::string> ReadFileToString(std::FILE* fp, Error* error = nullptr); 179 bool WriteBinaryFile(const char* filename, const void* data, size_t data_length, Error* error = nullptr); 180 bool WriteStringToFile(const char* filename, std::string_view sv, Error* error = nullptr); 181 182 /// creates a directory in the local filesystem 183 /// if the directory already exists, the return value will be true. 184 /// if Recursive is specified, all parent directories will be created 185 /// if they do not exist. 186 bool CreateDirectory(const char* path, bool recursive, Error* error = nullptr); 187 188 /// Creates a directory if it doesn't already exist. 189 /// Returns false if it does not exist and creation failed. 190 bool EnsureDirectoryExists(const char* path, bool recursive, Error* error = nullptr); 191 192 /// Removes a directory. 193 bool DeleteDirectory(const char* path); 194 195 /// Recursively removes a directory and all subdirectories/files. 196 bool RecursiveDeleteDirectory(const char* path); 197 198 /// Copies one file to another, optionally replacing it if it already exists. 199 bool CopyFilePath(const char* source, const char* destination, bool replace); 200 201 /// Returns the path to the current executable. 202 std::string GetProgramPath(); 203 204 /// Retrieves the current working directory. 205 std::string GetWorkingDirectory(); 206 207 /// Sets the current working directory. Returns true if successful. 208 bool SetWorkingDirectory(const char* path); 209 210 /// Enables/disables NTFS compression on a file or directory. 211 /// Does not apply the compression flag recursively if called for a directory. 212 /// Does nothing and returns false on non-Windows platforms. 213 bool SetPathCompression(const char* path, bool enable); 214 215 #ifdef _WIN32 216 // Path limit remover, but also converts to a wide string at the same time. 217 bool GetWin32Path(std::wstring* dest, std::string_view str); 218 std::wstring GetWin32Path(std::string_view str); 219 #endif 220 }; // namespace FileSystem