filesystem_disk.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * Copyright (c) 2012-2024 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "core/containers/vector.inl"
  6. #include "core/filesystem/file.h"
  7. #include "core/filesystem/filesystem_disk.h"
  8. #include "core/filesystem/path.h"
  9. #include "core/guid.h"
  10. #include "core/memory/temp_allocator.inl"
  11. #include "core/os.h"
  12. #include "core/strings/dynamic_string.inl"
  13. #if CROWN_PLATFORM_WINDOWS
  14. #include <tchar.h>
  15. #ifndef WIN32_LEAN_AND_MEAN
  16. #define WIN32_LEAN_AND_MEAN
  17. #endif
  18. #include <windows.h>
  19. #else
  20. #include <stdio.h>
  21. #include <errno.h>
  22. #include <unistd.h> // fsync
  23. #endif
  24. namespace crown
  25. {
  26. struct FileDisk : public File
  27. {
  28. #if CROWN_PLATFORM_WINDOWS
  29. HANDLE _file;
  30. bool _eof;
  31. #else
  32. FILE *_file;
  33. #endif
  34. /// Opens the file located at @a path with the given @a mode.
  35. FileDisk()
  36. #if CROWN_PLATFORM_WINDOWS
  37. : _file(INVALID_HANDLE_VALUE)
  38. , _eof(false)
  39. #else
  40. : _file(NULL)
  41. #endif
  42. {
  43. }
  44. virtual ~FileDisk()
  45. {
  46. close();
  47. }
  48. void open(const char *path, FileOpenMode::Enum mode) override
  49. {
  50. #if CROWN_PLATFORM_WINDOWS
  51. _file = CreateFile(path
  52. , (mode == FileOpenMode::READ) ? GENERIC_READ : GENERIC_WRITE
  53. , 0
  54. , NULL
  55. , (mode == FileOpenMode::READ) ? OPEN_EXISTING : CREATE_ALWAYS
  56. , FILE_ATTRIBUTE_NORMAL
  57. , NULL
  58. );
  59. #else
  60. _file = fopen(path, (mode == FileOpenMode::READ) ? "rb" : "wb");
  61. #endif
  62. }
  63. void close() override
  64. {
  65. if (is_open()) {
  66. #if CROWN_PLATFORM_WINDOWS
  67. CloseHandle(_file);
  68. _file = INVALID_HANDLE_VALUE;
  69. #else
  70. fclose(_file);
  71. _file = NULL;
  72. #endif
  73. }
  74. }
  75. bool is_open() override
  76. {
  77. #if CROWN_PLATFORM_WINDOWS
  78. return _file != INVALID_HANDLE_VALUE;
  79. #else
  80. return _file != NULL;
  81. #endif
  82. }
  83. u32 size() override
  84. {
  85. CE_ASSERT(is_open(), "File is not open");
  86. #if CROWN_PLATFORM_WINDOWS
  87. return GetFileSize(_file, NULL);
  88. #else
  89. Stat st;
  90. os::stat(st, fileno(_file));
  91. return (u32)st.size;
  92. #endif
  93. }
  94. u32 position() override
  95. {
  96. CE_ASSERT(is_open(), "File is not open");
  97. #if CROWN_PLATFORM_WINDOWS
  98. DWORD pos = SetFilePointer(_file, 0, NULL, FILE_CURRENT);
  99. CE_ASSERT(pos != INVALID_SET_FILE_POINTER
  100. , "SetFilePointer: GetLastError = %d"
  101. , GetLastError()
  102. );
  103. return (u32)pos;
  104. #else
  105. long pos = ftell(_file);
  106. CE_ASSERT(pos != -1, "ftell: errno = %d", errno);
  107. return (u32)pos;
  108. #endif
  109. }
  110. bool end_of_file() override
  111. {
  112. CE_ASSERT(is_open(), "File is not open");
  113. #if CROWN_PLATFORM_WINDOWS
  114. return _eof;
  115. #else
  116. return feof(_file) != 0;
  117. #endif
  118. }
  119. void seek(u32 position) override
  120. {
  121. CE_ASSERT(is_open(), "File is not open");
  122. #if CROWN_PLATFORM_WINDOWS
  123. DWORD err = SetFilePointer(_file, position, NULL, FILE_BEGIN);
  124. CE_ASSERT(err != INVALID_SET_FILE_POINTER
  125. , "SetFilePointer: GetLastError = %d"
  126. , GetLastError()
  127. );
  128. #else
  129. int err = fseek(_file, (long)position, SEEK_SET);
  130. CE_ASSERT(err == 0, "fseek: errno = %d", errno);
  131. #endif
  132. CE_UNUSED(err);
  133. }
  134. void seek_to_end() override
  135. {
  136. CE_ASSERT(is_open(), "File is not open");
  137. #if CROWN_PLATFORM_WINDOWS
  138. DWORD err = SetFilePointer(_file, 0, NULL, FILE_END);
  139. CE_ASSERT(err != INVALID_SET_FILE_POINTER
  140. , "SetFilePointer: GetLastError = %d"
  141. , GetLastError()
  142. );
  143. #else
  144. int err = fseek(_file, 0, SEEK_END);
  145. CE_ASSERT(err == 0, "fseek: errno = %d", errno);
  146. #endif
  147. CE_UNUSED(err);
  148. }
  149. void skip(u32 bytes) override
  150. {
  151. CE_ASSERT(is_open(), "File is not open");
  152. #if CROWN_PLATFORM_WINDOWS
  153. DWORD err = SetFilePointer(_file, bytes, NULL, FILE_CURRENT);
  154. CE_ASSERT(err != INVALID_SET_FILE_POINTER
  155. , "SetFilePointer: GetLastError = %d"
  156. , GetLastError()
  157. );
  158. #else
  159. int err = fseek(_file, bytes, SEEK_CUR);
  160. CE_ASSERT(err == 0, "fseek: errno = %d", errno);
  161. #endif
  162. CE_UNUSED(err);
  163. }
  164. u32 read(void *data, u32 size) override
  165. {
  166. CE_ASSERT(is_open(), "File is not open");
  167. CE_ASSERT(data != NULL, "Data must be != NULL");
  168. #if CROWN_PLATFORM_WINDOWS
  169. DWORD bytes_read;
  170. BOOL err = ReadFile(_file, data, size, &bytes_read, NULL);
  171. CE_ASSERT(err == TRUE, "ReadFile: GetLastError = %d", GetLastError());
  172. _eof = err && bytes_read == 0;
  173. return bytes_read;
  174. #else
  175. size_t bytes_read = fread(data, 1, size, _file);
  176. CE_ASSERT(ferror(_file) == 0, "fread error");
  177. return (u32)bytes_read;
  178. #endif
  179. }
  180. u32 write(const void *data, u32 size) override
  181. {
  182. CE_ASSERT(is_open(), "File is not open");
  183. CE_ASSERT(data != NULL, "Data must be != NULL");
  184. #if CROWN_PLATFORM_WINDOWS
  185. DWORD bytes_written;
  186. WriteFile(_file, data, size, &bytes_written, NULL);
  187. CE_ASSERT(size == bytes_written
  188. , "WriteFile: GetLastError = %d"
  189. , GetLastError()
  190. );
  191. return bytes_written;
  192. #else
  193. size_t bytes_written = fwrite(data, 1, size, _file);
  194. CE_ASSERT(ferror(_file) == 0, "fwrite error");
  195. return (u32)bytes_written;
  196. #endif
  197. }
  198. s32 sync() override
  199. {
  200. CE_ASSERT(is_open(), "File is not open");
  201. #if CROWN_PLATFORM_WINDOWS
  202. if (FlushFileBuffers(_file) != 0)
  203. return -1;
  204. #else
  205. if (fflush(_file) != 0)
  206. return -1;
  207. if (fsync(fileno(_file)) == -1)
  208. return -1;
  209. #endif
  210. return 0;
  211. }
  212. };
  213. FilesystemDisk::FilesystemDisk(Allocator &a)
  214. : _allocator(&a)
  215. , _prefix(a)
  216. {
  217. }
  218. void FilesystemDisk::set_prefix(const char *prefix)
  219. {
  220. _prefix.set(prefix, strlen32(prefix));
  221. }
  222. File *FilesystemDisk::open(const char *path, FileOpenMode::Enum mode)
  223. {
  224. CE_ENSURE(NULL != path);
  225. TempAllocator256 ta;
  226. DynamicString abs_path(ta);
  227. absolute_path(abs_path, path);
  228. FileDisk *file = CE_NEW(*_allocator, FileDisk)();
  229. file->open(abs_path.c_str(), mode);
  230. return file;
  231. }
  232. File *FilesystemDisk::open_temporary(DynamicString &absolute_path)
  233. {
  234. TempAllocator256 ta;
  235. DynamicString tmp_basename(ta);
  236. tmp_basename.from_guid(guid::new_guid());
  237. tmp_basename += ".tmp";
  238. this->absolute_path(absolute_path, tmp_basename.c_str());
  239. FileDisk *file = CE_NEW(*_allocator, FileDisk)();
  240. file->open(absolute_path.c_str(), FileOpenMode::WRITE);
  241. return file;
  242. }
  243. void FilesystemDisk::close(File &file)
  244. {
  245. CE_DELETE(*_allocator, &file);
  246. }
  247. Stat FilesystemDisk::stat(const char *path)
  248. {
  249. CE_ENSURE(NULL != path);
  250. TempAllocator256 ta;
  251. DynamicString abs_path(ta);
  252. absolute_path(abs_path, path);
  253. Stat st;
  254. os::stat(st, abs_path.c_str());
  255. return st;
  256. }
  257. bool FilesystemDisk::exists(const char *path)
  258. {
  259. return stat(path).file_type != Stat::NO_ENTRY;
  260. }
  261. bool FilesystemDisk::is_directory(const char *path)
  262. {
  263. return stat(path).file_type == Stat::DIRECTORY;
  264. }
  265. bool FilesystemDisk::is_file(const char *path)
  266. {
  267. return stat(path).file_type == Stat::REGULAR;
  268. }
  269. u64 FilesystemDisk::last_modified_time(const char *path)
  270. {
  271. return stat(path).mtime;
  272. }
  273. CreateResult FilesystemDisk::create_directory(const char *path)
  274. {
  275. CE_ENSURE(NULL != path);
  276. TempAllocator256 ta;
  277. DynamicString abs_path(ta);
  278. absolute_path(abs_path, path);
  279. return os::create_directory(abs_path.c_str());
  280. }
  281. DeleteResult FilesystemDisk::delete_directory(const char *path)
  282. {
  283. CE_ENSURE(NULL != path);
  284. TempAllocator256 ta;
  285. DynamicString abs_path(ta);
  286. absolute_path(abs_path, path);
  287. return os::delete_directory(abs_path.c_str());
  288. }
  289. DeleteResult FilesystemDisk::delete_file(const char *path)
  290. {
  291. CE_ENSURE(NULL != path);
  292. TempAllocator256 ta;
  293. DynamicString abs_path(ta);
  294. absolute_path(abs_path, path);
  295. return os::delete_file(abs_path.c_str());
  296. }
  297. RenameResult FilesystemDisk::rename(const char *old_path, const char *new_path)
  298. {
  299. CE_ENSURE(old_path != NULL);
  300. CE_ENSURE(new_path != NULL);
  301. DynamicString old_abs_path(default_allocator());
  302. DynamicString new_abs_path(default_allocator());
  303. absolute_path(old_abs_path, old_path);
  304. absolute_path(new_abs_path, new_path);
  305. return os::rename(old_abs_path.c_str(), new_abs_path.c_str());
  306. }
  307. void FilesystemDisk::list_files(const char *path, Vector<DynamicString> &files)
  308. {
  309. CE_ENSURE(NULL != path);
  310. TempAllocator256 ta;
  311. DynamicString abs_path(ta);
  312. absolute_path(abs_path, path);
  313. os::list_files(abs_path.c_str(), files);
  314. }
  315. void FilesystemDisk::absolute_path(DynamicString &os_path, const char *path)
  316. {
  317. if (path::is_absolute(path)) {
  318. os_path = path;
  319. return;
  320. }
  321. TempAllocator1024 ta;
  322. DynamicString str(ta);
  323. path::join(str, _prefix.c_str(), path);
  324. path::reduce(os_path, str.c_str());
  325. }
  326. } // namespace crown