Baselib_FileIO.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. #pragma once
  2. // Baselib FileIO
  3. //
  4. // This is a file reading abstraction api heavily influenced by next-gen async API's like io_uring, windows register I/O, etc.
  5. // This api allows for platform independent async file reading.
  6. #include "Baselib_ErrorState.h"
  7. #include "Baselib_Memory.h"
  8. #include "Internal/Baselib_EnumSizeCheck.h"
  9. #ifdef __cplusplus
  10. BASELIB_C_INTERFACE
  11. {
  12. #endif
  13. // Event queue handle.
  14. typedef struct Baselib_FileIO_EventQueue {void* handle;} Baselib_FileIO_EventQueue;
  15. // Async file handle.
  16. typedef struct Baselib_FileIO_AsyncFile {void* handle;} Baselib_FileIO_AsyncFile;
  17. // Sync file handle.
  18. typedef struct Baselib_FileIO_SyncFile {void* handle;} Baselib_FileIO_SyncFile;
  19. // Event queue handle invalid constant.
  20. static const Baselib_FileIO_EventQueue Baselib_FileIO_EventQueue_Invalid = { NULL };
  21. // Async file handle invalid constant.
  22. static const Baselib_FileIO_AsyncFile Baselib_FileIO_AsyncFile_Invalid = { NULL };
  23. // Sync file handle invalid constant.
  24. static const Baselib_FileIO_SyncFile Baselib_FileIO_SyncFile_Invalid = { (void*)-1 };
  25. typedef enum Baselib_FileIO_OpenFlags_t
  26. {
  27. // Allows read access to the file.
  28. Baselib_FileIO_OpenFlags_Read = 0x01,
  29. // Allows write access to the file.
  30. Baselib_FileIO_OpenFlags_Write = 0x02,
  31. // Opens existing file without changes or creates 0 size file if file doesn't exist.
  32. // On some platforms open will implicitly add write flag if required by native API's.
  33. Baselib_FileIO_OpenFlags_OpenAlways = 0x04,
  34. // Always creates 0 size file.
  35. // On some platforms open will implicitly add write flag if required by native API's.
  36. Baselib_FileIO_OpenFlags_CreateAlways = 0x08,
  37. } Baselib_FileIO_OpenFlags_t;
  38. typedef uint32_t Baselib_FileIO_OpenFlags;
  39. // File IO read request.
  40. typedef struct Baselib_FileIO_ReadRequest
  41. {
  42. // Offset in a file to read from.
  43. // If offset+size is pointing pass EOF, will read up to EOF bytes.
  44. // If offset is pointing pass EOF, will read 0 bytes.
  45. uint64_t offset;
  46. // Buffer to read to, must be available for duration of operation.
  47. void* buffer;
  48. // Size of requested read.
  49. // If 0 is passed will read 0 bytes and raise no error.
  50. uint64_t size;
  51. } Baselib_FileIO_ReadRequest;
  52. // File IO priorities.
  53. // First we process all requests with high priority, then with normal priority.
  54. // There's no round-robin, and high priority can starve normal priority.
  55. typedef enum Baselib_FileIO_Priority
  56. {
  57. Baselib_FileIO_Priority_Normal = 0,
  58. Baselib_FileIO_Priority_High = 1
  59. } Baselib_FileIO_Priority;
  60. BASELIB_ENUM_ENSURE_ABI_COMPATIBILITY(Baselib_FileIO_Priority);
  61. typedef enum Baselib_FileIO_EventQueue_ResultType
  62. {
  63. // Upon receiving this event, please call the provided callback with provided data argument.
  64. Baselib_FileIO_EventQueue_Callback = 1,
  65. // Result of open file operation.
  66. Baselib_FileIO_EventQueue_OpenFile = 2,
  67. // Result of read file operation.
  68. Baselib_FileIO_EventQueue_ReadFile = 3,
  69. // Result of close file operation.
  70. Baselib_FileIO_EventQueue_CloseFile = 4
  71. } Baselib_FileIO_EventQueue_ResultType;
  72. BASELIB_ENUM_ENSURE_ABI_COMPATIBILITY(Baselib_FileIO_EventQueue_ResultType);
  73. typedef void (*EventQueueCallback)(uint64_t userdata);
  74. typedef struct Baselib_FileIO_EventQueue_Result_Callback
  75. {
  76. // Please invoke this callback with userdata from the event.
  77. EventQueueCallback callback;
  78. } Baselib_FileIO_EventQueue_Result_Callback;
  79. typedef struct Baselib_FileIO_EventQueue_Result_OpenFile
  80. {
  81. // Size of the file as seen on during open.
  82. uint64_t fileSize;
  83. } Baselib_FileIO_EventQueue_Result_OpenFile;
  84. typedef struct Baselib_FileIO_EventQueue_Result_ReadFile
  85. {
  86. // Bytes transferred during read.
  87. uint64_t bytesTransferred;
  88. } Baselib_FileIO_EventQueue_Result_ReadFile;
  89. // Event queue result.
  90. typedef struct Baselib_FileIO_EventQueue_Result
  91. {
  92. // Event type.
  93. Baselib_FileIO_EventQueue_ResultType type;
  94. // Userdata as provided to the request.
  95. uint64_t userdata;
  96. // Error state of the operation.
  97. Baselib_ErrorState errorState;
  98. union
  99. {
  100. Baselib_FileIO_EventQueue_Result_Callback callback;
  101. Baselib_FileIO_EventQueue_Result_OpenFile openFile;
  102. Baselib_FileIO_EventQueue_Result_ReadFile readFile;
  103. };
  104. } Baselib_FileIO_EventQueue_Result;
  105. // Creates event queue.
  106. //
  107. // \returns Event queue.
  108. BASELIB_API Baselib_FileIO_EventQueue Baselib_FileIO_EventQueue_Create(void);
  109. // Frees event queue.
  110. //
  111. // \param eq event queue to free.
  112. BASELIB_API void Baselib_FileIO_EventQueue_Free(
  113. Baselib_FileIO_EventQueue eq
  114. );
  115. // Dequeue events from event queue.
  116. //
  117. // \param eq Event queue to dequeue from.
  118. // \param results Results array to dequeue elements into.
  119. // If null will return 0.
  120. // \param count Amount of elements in results array.
  121. // If equals 0 will return 0.
  122. // \param timeoutInMilliseconds If no elements are present in the queue,
  123. // waits for any elements to be appear for specified amount of time.
  124. // If 0 is passed, wait is omitted.
  125. // If elements are present, dequeues up-to-count elements, and wait is omitted.
  126. //
  127. // File operations errors are reported via Baselib_FileIO_EventQueue_Result::errorState
  128. // Possible error codes:
  129. // - InvalidPathname: Requested pathname is invalid (not found, a directory, etc).
  130. // - RequestedAccessIsNotAllowed: Access to requested pathname is not allowed.
  131. // - IOError: IO error occured.
  132. //
  133. // \returns Amount of results filled.
  134. BASELIB_API uint64_t Baselib_FileIO_EventQueue_Dequeue(
  135. Baselib_FileIO_EventQueue eq,
  136. Baselib_FileIO_EventQueue_Result results[],
  137. uint64_t count,
  138. uint32_t timeoutInMilliseconds // 0 will return immediately
  139. );
  140. // Asynchronously opens a file.
  141. //
  142. // \param eq Event queue to associate file with.
  143. // File can only be associated with one event queue,
  144. // but one event queue can be associated with multiple files.
  145. // If invalid event queue is passed, will return invalid file handle.
  146. // \param pathname Platform defined pathname of a file.
  147. // Can be freed after this function returns.
  148. // If null is passed will return invalid file handle.
  149. // \param userdata Userdata to be set in the completion event.
  150. // \param priority Priority for file opening operation.
  151. //
  152. // Please note errors are reported via Baselib_FileIO_EventQueue_Result::errorState
  153. // Possible error codes:
  154. // - InvalidPathname: Requested pathname is invalid (not found, a directory, etc).
  155. // - RequestedAccessIsNotAllowed: Access to requested pathname is not allowed.
  156. // - IOError: IO error occured.
  157. //
  158. // \returns Async file handle, which can be used immediately for scheduling other operations.
  159. // In case if file opening fails, all scheduled operations will fail as well.
  160. // In case if invalid arguments are passed, might return invalid file handle (see args descriptions).
  161. BASELIB_API Baselib_FileIO_AsyncFile Baselib_FileIO_AsyncOpen(
  162. Baselib_FileIO_EventQueue eq,
  163. const char* pathname,
  164. uint64_t userdata,
  165. Baselib_FileIO_Priority priority
  166. );
  167. // Asynchronously reads data from a file.
  168. //
  169. // Note scheduling reads on closed file is undefined.
  170. //
  171. // \param file Async file to read from.
  172. // If invalid file handle is passed, will no-op.
  173. // If file handle was already closed, behavior is undefined.
  174. // \param requests Requests to schedule.
  175. // If more than 1 provided,
  176. // will provide completion event per individual request in the array.
  177. // If null is passed, will no-op.
  178. // \param count Amount of requests in requests array.
  179. // If 0 is passed, will no-op.
  180. // \param userdata Userdata to be set in the completion event(s).
  181. // \param priority Priority for file reading operation(s).
  182. //
  183. // Please note errors are reported via Baselib_FileIO_EventQueue_Result::errorState
  184. // If file is invalid handle, error can not be reported because event queue is not known.
  185. // Possible error codes:
  186. // - IOError: IO error occured.
  187. BASELIB_API void Baselib_FileIO_AsyncRead(
  188. Baselib_FileIO_AsyncFile file,
  189. Baselib_FileIO_ReadRequest requests[],
  190. uint64_t count,
  191. uint64_t userdata,
  192. Baselib_FileIO_Priority priority
  193. );
  194. // Asynchronously closes a file.
  195. //
  196. // Will wait for all pending operations to complete,
  197. // after that will close a file and put a completion event.
  198. //
  199. // \param file Async file to close.
  200. // If invalid file handle is passed, will no-op.
  201. //
  202. // Please note errors are reported via Baselib_FileIO_EventQueue_Result::errorState
  203. // If file is invalid handle, error can not be reported because event queue is not known.
  204. // Possible error codes:
  205. // - IOError: IO error occured.
  206. BASELIB_API void Baselib_FileIO_AsyncClose(
  207. Baselib_FileIO_AsyncFile file
  208. );
  209. // Synchronously opens a file.
  210. //
  211. // Will try use the most open access permissions options that are available for each platform.
  212. // Meaning it might be possible for other process to write to file opened via this API.
  213. // On most platforms file can be simultaneously opened with different open flags.
  214. // If you require more strict options, or platform specific access configuration, please use Baselib_FileIO_SyncFileFromNativeHandle.
  215. //
  216. // \param pathname Platform defined pathname to open.
  217. // \param openFlags Open flags.
  218. // If file is created because one of Create flags is passed, it will have size of 0 bytes.
  219. //
  220. // Possible error codes:
  221. // - InvalidArgument: Invalid argument was passed.
  222. // - RequestedAccessIsNotAllowed: Request access is not allowed.
  223. // - IOError: Generic IO error occured.
  224. //
  225. // \returns SyncFile handle.
  226. BASELIB_API Baselib_FileIO_SyncFile Baselib_FileIO_SyncOpen(
  227. const char* pathname,
  228. Baselib_FileIO_OpenFlags openFlags,
  229. Baselib_ErrorState* errorState
  230. );
  231. // Transfer ownership of native handle to Baselib_FileIO_SyncFile handle.
  232. //
  233. // This function transfers ownership, meaning you don't need to close native handle yourself,
  234. // instead returned SyncFile must closed via Baselib_FileIO_SyncClose.
  235. // Implementations might cache information about the file state,
  236. // so native handle shouldn't be used after transfering ownership.
  237. //
  238. // \param handle Platform defined native handle.
  239. // If invalid native handle is passed, will return Baselib_FileIO_SyncFile_Invalid.
  240. // \param type Platform defined native handle type from Baselib_FileIO_NativeHandleType enum.
  241. // If unsupported type is passed, will return Baselib_FileIO_SyncFile_Invalid.
  242. //
  243. // \returns SyncFile handle.
  244. BASELIB_API Baselib_FileIO_SyncFile Baselib_FileIO_SyncFileFromNativeHandle(
  245. uint64_t handle,
  246. uint32_t type
  247. );
  248. // Synchronously reads data from a file.
  249. //
  250. // \param file File to read from.
  251. // If invalid file handle is passed, will raise InvalidArgument error and return 0.
  252. // \param offset Offset in the file to read data at.
  253. // If offset+size goes past end-of-file (EOF), function will read until EOF.
  254. // If offset points past EOF, will return 0.
  255. // \param buffer Pointer to data to read into.
  256. // \param size Size of data to read.
  257. //
  258. // Possible error codes:
  259. // - InvalidArgument: Invalid argument was passed.
  260. // - IOError: Generic IO error occured.
  261. //
  262. // \returns Amount of bytes read.
  263. BASELIB_API uint64_t Baselib_FileIO_SyncRead(
  264. Baselib_FileIO_SyncFile file,
  265. uint64_t offset,
  266. void* buffer,
  267. uint64_t size,
  268. Baselib_ErrorState* errorState
  269. );
  270. // Synchronously writes data to a file.
  271. //
  272. // \param file File to write to.
  273. // If invalid file handle is passed, will raise InvalidArgument error and return 0.
  274. // \param offset Offset in the file to write data at.
  275. // If offset+size goes past end-of-file (EOF), then file will be resized.
  276. // \param buffer Pointer to data to write.
  277. // \param size Size of data to write.
  278. //
  279. // Possible error codes:
  280. // - InvalidArgument: Invalid argument was passed.
  281. // - IOError: Generic IO error occured.
  282. //
  283. // \returns Amount of bytes written.
  284. BASELIB_API uint64_t Baselib_FileIO_SyncWrite(
  285. Baselib_FileIO_SyncFile file,
  286. uint64_t offset,
  287. const void* buffer,
  288. uint64_t size,
  289. Baselib_ErrorState* errorState
  290. );
  291. // Synchronously flushes file buffers.
  292. //
  293. // Operating system might buffer some write operations.
  294. // Flushing buffers is required to guarantee (best effort) writing data to disk.
  295. //
  296. // \param file File to flush.
  297. // If invalid file handle is passed, will no-op.
  298. //
  299. // Possible error codes:
  300. // - InvalidArgument: Invalid argument was passed.
  301. // - IOError: Generic IO error occured.
  302. BASELIB_API void Baselib_FileIO_SyncFlush(
  303. Baselib_FileIO_SyncFile file,
  304. Baselib_ErrorState* errorState
  305. );
  306. // Synchronously changes file size.
  307. //
  308. // \param file File to get size of.
  309. // If invalid file handle is passed, will raise invalid argument error.
  310. // \param size New file size.
  311. //
  312. // Possible error codes:
  313. // - InvalidArgument: Invalid argument was passed.
  314. // - IOError: Generic IO error occured.
  315. //
  316. // \returns File size.
  317. BASELIB_API void Baselib_FileIO_SyncSetFileSize(
  318. Baselib_FileIO_SyncFile file,
  319. uint64_t size,
  320. Baselib_ErrorState* errorState
  321. );
  322. // Synchronously retrieves file size.
  323. //
  324. // \param file File to get size of.
  325. // If invalid file handle is passed, will return 0.
  326. //
  327. // Possible error codes:
  328. // - InvalidArgument: Invalid argument was passed.
  329. // - IOError: Generic IO error occured.
  330. //
  331. // \returns File size.
  332. BASELIB_API uint64_t Baselib_FileIO_SyncGetFileSize(
  333. Baselib_FileIO_SyncFile file,
  334. Baselib_ErrorState* errorState
  335. );
  336. // Synchronously closes a file.
  337. //
  338. // Close does not guarantee that the data was written to disk,
  339. // Please use Baselib_FileIO_SyncFlush to guarantee (best effort) that data was written to disk.
  340. //
  341. // \param file File to close.
  342. // If invalid file handle is passed, will no-op.
  343. //
  344. // Possible error codes:
  345. // - InvalidArgument: Invalid argument was passed.
  346. // - IOError: Generic IO error occured.
  347. BASELIB_API void Baselib_FileIO_SyncClose(
  348. Baselib_FileIO_SyncFile file,
  349. Baselib_ErrorState* errorState
  350. );
  351. #include <C/Baselib_FileIO.inl.h>
  352. #ifdef __cplusplus
  353. } // BASELIB_C_INTERFACE
  354. #endif