os.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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/error/error.h"
  7. #include "core/memory/temp_allocator.inl"
  8. #include "core/os.h"
  9. #include "core/platform.h"
  10. #include "core/strings/dynamic_string.inl"
  11. #include "core/strings/string_stream.h"
  12. #include <string.h> // strcmp
  13. #include <sys/stat.h> // stat, mkdir
  14. #if CROWN_PLATFORM_WINDOWS
  15. #include <io.h> // _access
  16. #include <stdio.h>
  17. #ifndef WIN32_LEAN_AND_MEAN
  18. #define WIN32_LEAN_AND_MEAN
  19. #endif
  20. #include <windows.h>
  21. #else
  22. #include <dirent.h> // opendir, readdir
  23. #include <dlfcn.h> // dlopen, dlclose, dlsym
  24. #include <errno.h>
  25. #include <stdio.h> // fputs, rename
  26. #include <stdlib.h> // getenv
  27. #include <string.h> // memset
  28. #include <sys/wait.h> // wait
  29. #include <time.h> // clock_gettime
  30. #include <unistd.h> // unlink, rmdir, getcwd, access, chdir
  31. #endif // if CROWN_PLATFORM_WINDOWS
  32. #if CROWN_PLATFORM_ANDROID
  33. #include <android/log.h>
  34. #endif
  35. namespace crown
  36. {
  37. namespace os
  38. {
  39. void sleep(u32 ms)
  40. {
  41. #if CROWN_PLATFORM_WINDOWS
  42. Sleep(ms);
  43. #else
  44. usleep(ms * 1000);
  45. #endif
  46. }
  47. void *library_open(const char *path)
  48. {
  49. #if CROWN_PLATFORM_WINDOWS
  50. return (void *)LoadLibraryA(path);
  51. #else
  52. return ::dlopen(path, RTLD_LAZY);
  53. #endif
  54. }
  55. void library_close(void *library)
  56. {
  57. #if CROWN_PLATFORM_WINDOWS
  58. BOOL err = FreeLibrary((HMODULE)library);
  59. CE_ASSERT(err != 0, "FreeLibrary: error: %s", GetLastError());
  60. #else
  61. int err = dlclose(library);
  62. CE_ASSERT(err == 0, "dlclose: error: %s", dlerror());
  63. #endif
  64. CE_UNUSED(err);
  65. }
  66. void *library_symbol(void *library, const char *name)
  67. {
  68. #if CROWN_PLATFORM_WINDOWS
  69. return (void *)GetProcAddress((HMODULE)library, name);
  70. #else
  71. return ::dlsym(library, name);
  72. #endif
  73. }
  74. void log(const char *msg)
  75. {
  76. #if CROWN_PLATFORM_ANDROID
  77. __android_log_write(ANDROID_LOG_DEBUG, "crown", msg);
  78. #else
  79. fputs(msg, stdout);
  80. fflush(stdout);
  81. #endif
  82. #if CROWN_PLATFORM_WINDOWS
  83. OutputDebugStringA(msg);
  84. #endif
  85. }
  86. #if CROWN_PLATFORM_POSIX
  87. void stat(Stat &st, int fd)
  88. {
  89. st.file_type = Stat::NO_ENTRY;
  90. st.size = 0;
  91. st.mtime = 0;
  92. struct stat buf;
  93. memset(&buf, 0, sizeof(buf));
  94. int err = ::fstat(fd, &buf);
  95. if (err != 0)
  96. return;
  97. if (S_ISREG(buf.st_mode) == 1)
  98. st.file_type = Stat::REGULAR;
  99. else if (S_ISDIR(buf.st_mode) == 1)
  100. st.file_type = Stat::DIRECTORY;
  101. st.size = buf.st_size;
  102. st.mtime = buf.st_mtim.tv_sec * s64(1000000000) + buf.st_mtim.tv_nsec;
  103. }
  104. #endif // if CROWN_PLATFORM_POSIX
  105. void stat(Stat &st, const char *path)
  106. {
  107. st.file_type = Stat::NO_ENTRY;
  108. st.size = 0;
  109. st.mtime = 0;
  110. #if CROWN_PLATFORM_WINDOWS
  111. WIN32_FIND_DATAA wfd;
  112. HANDLE fh = FindFirstFileA(path, &wfd);
  113. if (fh == INVALID_HANDLE_VALUE)
  114. return;
  115. FindClose(fh);
  116. if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  117. st.file_type = Stat::DIRECTORY;
  118. else // Assume regular file.
  119. st.file_type = Stat::REGULAR;
  120. ULARGE_INTEGER fs = {};
  121. fs.LowPart = wfd.nFileSizeLow;
  122. fs.HighPart = wfd.nFileSizeHigh;
  123. st.size = fs.QuadPart;
  124. ULARGE_INTEGER lwt = {};
  125. lwt.LowPart = wfd.ftLastWriteTime.dwLowDateTime;
  126. lwt.HighPart = wfd.ftLastWriteTime.dwHighDateTime;
  127. // Convert mtime to ns and subtract Unix epoch to Windows epoch
  128. // difference in ns (i.e. 1970-01-01, 12AM - 1601-01-01, 12AM).
  129. // See: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
  130. st.mtime = lwt.QuadPart * u64(100) - u64(11644473600) * u64(1000000000);
  131. #else
  132. struct stat buf;
  133. memset(&buf, 0, sizeof(buf));
  134. int err = ::stat(path, &buf);
  135. if (err != 0)
  136. return;
  137. if (S_ISREG(buf.st_mode) == 1)
  138. st.file_type = Stat::REGULAR;
  139. else if (S_ISDIR(buf.st_mode) == 1)
  140. st.file_type = Stat::DIRECTORY;
  141. st.size = buf.st_size;
  142. st.mtime = buf.st_mtim.tv_sec * s64(1000000000) + buf.st_mtim.tv_nsec;
  143. #endif // if CROWN_PLATFORM_WINDOWS
  144. }
  145. DeleteResult delete_file(const char *path)
  146. {
  147. DeleteResult dr;
  148. #if CROWN_PLATFORM_WINDOWS
  149. if (DeleteFile(path) != 0)
  150. dr.error = DeleteResult::SUCCESS;
  151. else if (GetLastError() == ERROR_FILE_NOT_FOUND)
  152. dr.error = DeleteResult::NO_ENTRY;
  153. // else if (GetLastError() == ERROR_ACCESS_DENIED)
  154. // dr.error = DeleteResult::NOT_FILE;
  155. else
  156. dr.error = DeleteResult::UNKNOWN;
  157. #else
  158. if (::unlink(path) == 0)
  159. dr.error = DeleteResult::SUCCESS;
  160. else if (errno == ENOENT)
  161. dr.error = DeleteResult::NO_ENTRY;
  162. else
  163. dr.error = DeleteResult::UNKNOWN;
  164. #endif
  165. return dr;
  166. }
  167. CreateResult create_directory(const char *path)
  168. {
  169. CreateResult cr;
  170. #if CROWN_PLATFORM_WINDOWS
  171. if (CreateDirectory(path, NULL) != 0)
  172. cr.error = CreateResult::SUCCESS;
  173. else if (GetLastError() == ERROR_ALREADY_EXISTS)
  174. cr.error = CreateResult::ALREADY_EXISTS;
  175. else
  176. cr.error = CreateResult::UNKNOWN;
  177. #else
  178. if (::mkdir(path, 0755) == 0)
  179. cr.error = CreateResult::SUCCESS;
  180. else if (errno == EEXIST)
  181. cr.error = CreateResult::ALREADY_EXISTS;
  182. else
  183. cr.error = CreateResult::UNKNOWN;
  184. #endif
  185. return cr;
  186. }
  187. DeleteResult delete_directory(const char *path)
  188. {
  189. DeleteResult dr;
  190. #if CROWN_PLATFORM_WINDOWS
  191. if (RemoveDirectory(path) != 0)
  192. dr.error = DeleteResult::SUCCESS;
  193. else if (GetLastError() == ERROR_FILE_NOT_FOUND)
  194. dr.error = DeleteResult::NO_ENTRY;
  195. // else if (GetLastError() == ERROR_DIRECTORY
  196. // dr.error = DeleteResult::NOT_DIRECTORY;
  197. else
  198. dr.error = DeleteResult::UNKNOWN;
  199. #else
  200. if (::rmdir(path) == 0)
  201. dr.error = DeleteResult::SUCCESS;
  202. else if (errno == ENOENT)
  203. dr.error = DeleteResult::NO_ENTRY;
  204. else
  205. dr.error = DeleteResult::UNKNOWN;
  206. #endif
  207. return dr;
  208. }
  209. const char *getcwd(char *buf, u32 size)
  210. {
  211. #if CROWN_PLATFORM_WINDOWS
  212. GetCurrentDirectory(size, buf);
  213. return buf;
  214. #else
  215. return ::getcwd(buf, size);
  216. #endif
  217. }
  218. void setcwd(const char *cwd)
  219. {
  220. #if CROWN_PLATFORM_WINDOWS
  221. BOOL ret = SetCurrentDirectory(cwd);
  222. CE_UNUSED(ret);
  223. #else
  224. int ret = chdir(cwd);
  225. CE_UNUSED(ret);
  226. #endif
  227. }
  228. const char *getenv(const char *name)
  229. {
  230. #if CROWN_PLATFORM_WINDOWS
  231. // GetEnvironmentVariable(name, buf, size);
  232. return NULL;
  233. #else
  234. return ::getenv(name);
  235. #endif
  236. }
  237. void list_files(const char *path, Vector<DynamicString> &files)
  238. {
  239. #if CROWN_PLATFORM_WINDOWS
  240. TempAllocator256 ta_path;
  241. DynamicString cur_path(ta_path);
  242. cur_path += path;
  243. cur_path += "\\*";
  244. WIN32_FIND_DATA ffd;
  245. HANDLE file = FindFirstFile(cur_path.c_str(), &ffd);
  246. if (file != INVALID_HANDLE_VALUE) {
  247. do {
  248. const char *dname = ffd.cFileName;
  249. if (!strcmp(dname, ".") || !strcmp(dname, ".."))
  250. continue;
  251. TempAllocator256 ta;
  252. DynamicString fname(ta);
  253. fname.set(dname, strlen32(dname));
  254. vector::push_back(files, fname);
  255. } while (FindNextFile(file, &ffd) != 0);
  256. FindClose(file);
  257. }
  258. #else
  259. struct dirent *entry;
  260. DIR *dir = opendir(path);
  261. if (dir != NULL) {
  262. while ((entry = readdir(dir))) {
  263. const char *dname = entry->d_name;
  264. if (!strcmp(dname, ".") || !strcmp(dname, ".."))
  265. continue;
  266. TempAllocator256 ta;
  267. DynamicString fname(ta);
  268. fname.set(dname, strlen32(dname));
  269. vector::push_back(files, fname);
  270. }
  271. closedir(dir);
  272. }
  273. #endif // if CROWN_PLATFORM_WINDOWS
  274. }
  275. ///
  276. s32 access(const char *path, u32 flags)
  277. {
  278. #if CROWN_PLATFORM_WINDOWS
  279. return ::_access(path, flags == AccessFlags::EXECUTE ? AccessFlags::EXISTS : flags);
  280. #else
  281. return ::access(path, flags);
  282. #endif
  283. }
  284. RenameResult rename(const char *old_name, const char *new_name)
  285. {
  286. RenameResult rr;
  287. #if CROWN_PLATFORM_WINDOWS
  288. if (MoveFileEx(old_name, new_name, MOVEFILE_REPLACE_EXISTING) != 0)
  289. rr.error = RenameResult::SUCCESS;
  290. else
  291. rr.error = RenameResult::UNKNOWN;
  292. #else
  293. if (::rename(old_name, new_name) == 0)
  294. rr.error = RenameResult::SUCCESS;
  295. else
  296. rr.error = RenameResult::UNKNOWN;
  297. #endif
  298. return rr;
  299. }
  300. } // namespace os
  301. } // namespace crown