FileSystem.h 18 KB

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