FileSystem.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. #pragma once
  2. #include "App.h"
  3. #include <string>
  4. namespace gameplay
  5. {
  6. struct File;
  7. enum class FileMode
  8. {
  9. READ,
  10. WRITE,
  11. READ_WRITE,
  12. APPEND
  13. };
  14. enum class FileWhence
  15. {
  16. BEGIN,
  17. CURRENT,
  18. END
  19. };
  20. enum class FileStreamStatus
  21. {
  22. STREAM_OK,
  23. STREAM_EOF,
  24. STREAM_ERROR
  25. };
  26. enum class DirectoryItemType
  27. {
  28. FILE,
  29. DIRECTORY,
  30. };
  31. struct FileInfo
  32. {
  33. DirectoryItemType type;
  34. time_t createTime;
  35. time_t modTime;
  36. size_t size;
  37. bool symlink;
  38. };
  39. struct DirectoryInfo : public FileInfo
  40. {
  41. const char* path;
  42. };
  43. enum class VisitAction : signed char
  44. {
  45. STOP = -1,
  46. SKIP,
  47. CONTINUE
  48. };
  49. /**
  50. * Defines the file system.
  51. *
  52. * Any operation that takes a path can be specified in absolute
  53. * or relative paths are resolved from the current working directory.
  54. */
  55. class GP_API FileSystem
  56. {
  57. friend class App;
  58. friend class Config;
  59. public:
  60. /**
  61. * Changes events for files and directories on the file system.
  62. */
  63. enum class ChangeEvent
  64. {
  65. CREATED,
  66. MODIFIED,
  67. DELETED,
  68. RENAMED
  69. };
  70. /**
  71. * Gets the application executable file path.
  72. *
  73. * @return The application executable file path.
  74. */
  75. const char* get_app_executable_path() const;
  76. /**
  77. * Gets the application directory path.
  78. *
  79. * @return The application directory path.
  80. */
  81. const char* get_app_directory_path() const;
  82. /**
  83. * Sets the current directory path for the filesystem.
  84. *
  85. * @param path The current directory path for the filesystem.
  86. */
  87. bool set_current_directory_path(const char* path);
  88. /**
  89. * Gets the current directory path for the filesystem.
  90. *
  91. * @return The current directory path for the filesystem.
  92. */
  93. const char* get_current_directory_path();
  94. /**
  95. * Checks if a file or directory path exists on the file system.
  96. *
  97. * @param path The path to check.
  98. * @return true if the path exists, false if not.
  99. */
  100. bool exists(const char* path);
  101. /**
  102. * Checks is a path is a directory.
  103. *
  104. * @param path The path to check.
  105. * @return true if the path is a directory, false if not.
  106. */
  107. bool is_directory(const char* path);
  108. /**
  109. * Checks is a file is a writable.
  110. *
  111. * @param path The path to check.
  112. * @return true if the file is writable, false if not.
  113. */
  114. bool is_writable(const char* path);
  115. /**
  116. * Gets the time the file or directory was created.
  117. *
  118. * @param path The path to use.
  119. * @return The time the file or directory was created.
  120. */
  121. time_t get_create_time(const char* path);
  122. /**
  123. * Gets the last time a file or directory was modified.
  124. *
  125. * @param path The path to use.
  126. * @return The last time a file or directory was modified.
  127. */
  128. time_t get_mod_time(const char* path);
  129. /**
  130. * Gets an operating system specific canonical path relative to the base.
  131. *
  132. * @param path The absolute or relative path. The path must exist.
  133. * @param base The base path to resolve relative path against. Can be nullptr.
  134. * @return The operating system specific canonical path relative to the base.
  135. */
  136. std::string get_canonical_path(const char* path, const char* base = nullptr);
  137. /**
  138. * Makes a temporary directory on the file system.
  139. *
  140. * The directory is created under the system temporary directory area and will have a randomized name.
  141. *
  142. * @return The full path to the created directory or if fails and empty string and also logs an error message.
  143. */
  144. std::string make_temp_directory();
  145. /**
  146. * Makes a directory on the file system.
  147. *
  148. * @param path The path to the directory to create.
  149. * @param createMissingDirectories if true it will create any missing directories to make the
  150. *
  151. * @return true if the creation was successful, fails if fails.
  152. */
  153. bool make_directory(const char* path, bool createMissingDirectories = true);
  154. /**
  155. * Removes (deletes) a directory from the file system.
  156. *
  157. * This will never follow symbolic links. The symbolic link will be removed, but its target will not.
  158. * To remove the currect directory, you must first change to another directory and then remove it.
  159. *
  160. * @param path The path to the directory to remove.
  161. * @return true if the removal was successful, false is not successful.
  162. */
  163. bool remove_directory(const char* path);
  164. /**
  165. * Removes (deletes) a file from the file system.
  166. *
  167. * This can fail by either having the file still open by either the calling process or another process,
  168. * or by not having sufficient permission to delete the file.
  169. *
  170. * @param path The path of the file to be removed.
  171. * @returns true if the file was removed from the file system, false if not successful.
  172. */
  173. bool remove_file(const char* path);
  174. /**
  175. * Moves (renames) a file or directory on the file system.
  176. *
  177. * @param src The source path to a file or directory to rename.
  178. * @param dst The destination path.
  179. * @return true of the move was successful, false is not successful.
  180. */
  181. bool move(const char* src, const char* dst);
  182. /**
  183. * Copy a file on the file system to a new destination.
  184. *
  185. * @param src The source path to a file to copy.
  186. * @param dst The destination filename and path.
  187. * @return true of the copy was successful, false is not successful.
  188. */
  189. bool copy(const char* src, const char* dst);
  190. /**
  191. * Gets file information on a specified file on the file system.
  192. *
  193. * @param path The path to the file.
  194. * @param info The info populated about the file.
  195. * @return true if information was gathered. false if an error occurs.
  196. */
  197. bool get_file_info(const char* path, FileInfo* info);
  198. /**
  199. * Opens a file on the file system for binary mode with the specifed file mode access.
  200. *
  201. * The file opened must closed with close_file() when it is no longer needed.
  202. *
  203. * Any files opened with FileMode::WRITE, FileMode::READ_WRITE or FileMode::APPEND
  204. * that do not exist will be create if the file does not already exist.
  205. *
  206. * Files opened with FileMode::READ, FileMode::WRITE or FileMode::READ_WRITE will be initially positioned
  207. * to the beginning of the file. Files opened with FileMode::APPEND will be initiallly positioned to the
  208. * end of the file.
  209. *
  210. * @param path The path to the file to open.
  211. * @param The file mode for which to access the file.
  212. * @param The handle for the file opened if successful or nullptr if not successful.
  213. */
  214. File* open_file(const char* path, FileMode mode);
  215. /**
  216. * Closes a file on the file system.
  217. *
  218. * @param file The handle to the file to be closed.
  219. */
  220. void close_file(File* file);
  221. /**
  222. * Gets the total size of the file in bytes.
  223. *
  224. * @param file The handle to the file.
  225. * @param The total size of the file in bytes.
  226. */
  227. size_t get_file_size(File* file);
  228. /**
  229. * Gets the time the file was created.
  230. *
  231. * @param file The handle to the file.
  232. * @return The time this file was created.
  233. */
  234. time_t get_file_create_time(File* file);
  235. /**
  236. * Gets the last time the file was modified.
  237. *
  238. * @param file The handle to the file.
  239. * @return The time this file was created.
  240. */
  241. time_t get_file_mod_time(File* file);
  242. /**
  243. * Reads a chunk of binary data from a file.
  244. *
  245. * @param file The handle to the file to read from in binary mode.
  246. * @param chunk Memory to read the binary data to, at least chunkSize bytes large.
  247. * @param chunkSize Number of bytes to read from file into 'chunk' memory area.
  248. * @return The number of bytes read. This can be less than requested 'chunkSize' when reading the last bytes of
  249. * data. This will return 0 when all data has been read from the file.
  250. */
  251. size_t read_file_chunk(File* file, void* chunk, size_t chunkSize);
  252. /**
  253. * Writes a chunk of binary data to a file.
  254. *
  255. * @param file An handle to the file to write to in binary mode.
  256. * @param chunk The memory buffer to write to the file.
  257. * @param chunkSize Number of bytes from 'chunk' to write to the file.
  258. * @returns The number of bytes successfully written to the file. This can be less than the
  259. * requested chunkSize if an error occurs such as disk full.
  260. * @returns 0 bytes if no data could be written to the file.
  261. */
  262. size_t write_file_chunk(File* file, void* chunk, size_t chunkSize);
  263. /**
  264. * Reads a line of character data from a text file.
  265. *
  266. * A read line will not include any line termination characters.
  267. *
  268. * @param file The handle of the file to read.
  269. * @param line The string that will receive the read line.
  270. * @param maxLineSize The maximum number of characters that can be read into 'line', including null termination.
  271. * If the buffer is exhausted before end-of-line is reached the buffer will be null terminated and thus still a
  272. * proper string but won't necessarily contain the full line from the file.
  273. * @return The read string, 'line', on each successful read but nullptr when end of file is reached.
  274. */
  275. char* read_file_line(File* file, char* line, size_t maxLineSize);
  276. /**
  277. * Writes a line of characters to a text file.
  278. *
  279. * A newline will always be appended to the string in the file if it is successfully written.
  280. *
  281. * @param file The handle of the file to read.
  282. * @param line The null-terminated string to write.
  283. * @returns true if the full line is successfully written to the file, false if the full string could not be written to the file.
  284. */
  285. bool write_file_line(File* file, const char* line);
  286. /**
  287. * Flushes any unwritten data to the file.
  288. *
  289. * When a file is closed, either by calling close_file or during program termination,
  290. * all the associated buffers are automatically flushed.
  291. *
  292. * @param The handle of the file opened for writing or appending.
  293. */
  294. void flush_file(File* file);
  295. /**
  296. * Gets the current file cursor position for an open file.
  297. *
  298. * The file may have been opened for read, write or append. Files that were opened for
  299. * append will always write at the end of the file regardless of the current file position.
  300. * The file current position is typically unused or undefined in the append case.
  301. *
  302. * This retrieves the current location of the file in a file that has been
  303. * opened for read, write, or append. The offset is always returned in bytes.
  304. * The current file position may be beyond the end of the file if the file pointer was
  305. * recently placed beyond the end of the file. However, this does not actually reflect the size of the file
  306. * until at least one byte is written into it at the new position beyond the file's end.
  307. *
  308. * @param file The handle of the file to retrieve the current position for.
  309. * @return The current position in the file in bytes relative to the beginning or -1
  310. * if the position could not be retrieved.
  311. */
  312. int64_t get_file_pos(File* file);
  313. /**
  314. * Sets the new file cursor position for an open file.
  315. *
  316. * The file may have been opened for read, write or append. Files that were opened for
  317. * append will always write at the end of the file regardless of the current file position.
  318. * The file current position is typically unused or undefined in the append case.
  319. *
  320. * This attempts to reposition the file cursor in an open file. The new absolute position may
  321. * not be negative once combined with whence. If the new absolute position is beyond the current
  322. * end of the file, the file will not be extended until at least one byte is written into the
  323. * file at that new position or the file is truncated at the current position with truncate_file_at_current_pos().
  324. * When it is written to or truncated with a larger size than previous, the new space will be filled with zeros.
  325. * However, that if the file pointer is set beyond the end of the file, the get_file_pos() call will return that
  326. * same position even though it is larger than the file currently is.
  327. *
  328. * @param The handle of the file to set the current position for.
  329. * @param offsetFromWhence The new position for the file cursor relative to the location specified in whence.
  330. * This value may be negative only if whence is not FileWhence::BEGIN. This may specify an index beyond the
  331. * current end of the file when combined with whence.
  332. * @return true if the file position was successfully set,
  333. * false if the file position could not be set or was invalid.
  334. */
  335. bool set_file_pos(File* file, int64_t offsetFromWhence, FileWhence whence);
  336. /**
  337. * Sets the file position to the beginning of the open file.
  338. *
  339. * Equivalent to: set_file_pos(file, 0, FileWhence::BEGIN);
  340. *
  341. * @param file The handle of the file.
  342. * @return true if the file position was successfully set,
  343. * false if the file position could not be set or was invalid.
  344. */
  345. bool set_file_pos_begin(File* file);
  346. /**
  347. * Sets the file position to the end of the open file.
  348. *
  349. * Equivalent to: set_file_pos(file, 0, FileWhence::END);
  350. *
  351. * @param file The handle of the file.
  352. * @return true if the file position was successfully set,
  353. * false if the file position could not be set or was invalid.
  354. */
  355. bool set_file_pos_end(File* file);
  356. /**
  357. * Truncates a file at the current file position.
  358. *
  359. * The file must have been opened for write or append.
  360. *
  361. * This truncates a file at the current file pointer position. This can be used
  362. * to extend a file without needing to write anything to it by opening the file,
  363. * setting the file position to the desired size with set_file_pos(), then calling
  364. * this function to set the new end of the file. The new area of the file will be
  365. * filled with zeros if it was extended. If the file is being shortened, all data
  366. * in the file beyond the current file pointer will be removed.
  367. *
  368. * @param file The handle to the file to be truncated.
  369. * @return true if the file was successfully truncated,
  370. * false if the file could not be truncated for any reason.
  371. */
  372. bool truncate_file_at_current_pos(File* file);
  373. /**
  374. * Gets the current file status of a stream.
  375. *
  376. * FileStreamStatus::STREAM_OK Is the file stream is still in a valid state and more read or
  377. * write operation may potentially succeed.
  378. * FileStatus::STREAM_ERROR Is if the file stream has encountered an error of any kind.
  379. * This may include a partial write due to a full disk or a disk quota being reached.
  380. * FileStreamStatus::STREAM_OEF Is if a file stream opened for read has already read the last
  381. * bytes in the file. A future call to read_file_*() will simply return 0 or nullptr
  382. * from the same file position.
  383. *
  384. * This retrieves the current status of a file stream object. The status allows
  385. * the caller to differentiate an error from an end-of-file condition for the
  386. * last file operation. The error condition on the file will be reset after
  387. * each operation after being stored for later retrieval. The file stream status
  388. * value will remain valid until the next operation is performed on the file.
  389. *
  390. * As with all other file operations, retrieving this status is not thread safe
  391. * and could change if another thread performs an unprotected operation on the
  392. * same stream. It is the caller's responsibility to ensure operations on the
  393. * file stream are appropriately protected.
  394. *
  395. * The file status will not be modified by calls to get_file_size(), get_file_mod_time(),
  396. * flush_file(), or get_file_pos().
  397. *
  398. * @param file The handle of an open file to check the status of.
  399. */
  400. FileStreamStatus get_file_stream_status(File* file);
  401. /**
  402. * Callback function that is called for each file or directory visited when calling
  403. * the function for_each_directory_item(..).
  404. *
  405. * @param info The directory information for the item visited.
  406. * @param The user pointer specified by the call to for_each_directory_item()
  407. * @return The action to perform after the visited item is completed.
  408. */
  409. typedef VisitAction (*OnVisitDirectoryItemFn)(const DirectoryInfo* info, void* userPtr);
  410. /**
  411. * Iterate through each item in the directory from the specified directory path.
  412. *
  413. * @param path The path to the directory
  414. * @param fn The visitor function to be called for each directory item encountered.
  415. * @param userPtr The user pointer data passed to the callback function for each item.
  416. * @param recursive true to recursively traverse through each sub-directory too,
  417. * false for only the specified path and not sub-directories.
  418. */
  419. void for_each_directory_item(const char* path, OnVisitDirectoryItemFn fn, void* userPtr, bool recursive = false);
  420. /**
  421. * Callback function to use when listening to changes on file system.
  422. *
  423. * @param path The path for file system change.
  424. * @param evt The change event that occurred.
  425. * @param userPtr The user pointer associated with the subscription to the change event.
  426. * @param newPath The path for the new name of the file. Used only for RENAMED event, otherwise it's nullptr
  427. */
  428. typedef void (*OnChangeEventFn)(const char* path, ChangeEvent evt, void* userPtr, const char* newPath);
  429. /**
  430. * Subscribes to listen on change events on a path.
  431. *
  432. * @param path The path on which to subscribe to change events.
  433. * @param onChangeEvent The callback function to be called when the events are fired.
  434. * @param userData The user pointer passed to the callback function for each item.
  435. * @return The subscription id if the path was successfully subscribed to or nullptr otherwise.
  436. */
  437. uint32_t subscribe_to_change_events(const char* path, OnChangeEventFn fn, void* userPtr);
  438. /**
  439. * Unsubscribes from listening to change events based on subscription path.
  440. *
  441. * @param id The subscription id to unsubscribe from.
  442. */
  443. void unsubscribe_to_change_events(uint32_t id);
  444. private:
  445. FileSystem();
  446. ~FileSystem();
  447. void set_app_executable_path(const char* path);
  448. struct Impl;
  449. Impl* _impl;
  450. };
  451. }