os.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*
  2. * Copyright (c) 2012-2022 Daniele Bartolini et al.
  3. * License: https://github.com/crownengine/crown/blob/master/LICENSE
  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
  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
  31. #endif
  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. FreeLibrary((HMODULE)library);
  59. #else
  60. dlclose(library);
  61. #endif
  62. }
  63. void *library_symbol(void *library, const char *name)
  64. {
  65. #if CROWN_PLATFORM_WINDOWS
  66. return (void *)GetProcAddress((HMODULE)library, name);
  67. #else
  68. return ::dlsym(library, name);
  69. #endif
  70. }
  71. void log(const char *msg)
  72. {
  73. #if CROWN_PLATFORM_ANDROID
  74. __android_log_write(ANDROID_LOG_DEBUG, "crown", msg);
  75. #else
  76. fputs(msg, stdout);
  77. fflush(stdout);
  78. #endif
  79. #if CROWN_PLATFORM_WINDOWS
  80. OutputDebugStringA(msg);
  81. #endif
  82. }
  83. #if CROWN_PLATFORM_POSIX
  84. void stat(Stat &info, int fd)
  85. {
  86. info.file_type = Stat::NO_ENTRY;
  87. info.size = 0;
  88. info.mtime = 0;
  89. struct stat buf;
  90. memset(&buf, 0, sizeof(buf));
  91. int err = ::fstat(fd, &buf);
  92. if (err != 0)
  93. return;
  94. if (S_ISREG(buf.st_mode) == 1)
  95. info.file_type = Stat::REGULAR;
  96. else if (S_ISDIR(buf.st_mode) == 1)
  97. info.file_type = Stat::DIRECTORY;
  98. info.size = buf.st_size;
  99. info.mtime = buf.st_mtim.tv_sec * s64(1000000000) + buf.st_mtim.tv_nsec;
  100. }
  101. #endif
  102. void stat(Stat &info, const char *path)
  103. {
  104. info.file_type = Stat::NO_ENTRY;
  105. info.size = 0;
  106. info.mtime = 0;
  107. #if CROWN_PLATFORM_WINDOWS
  108. WIN32_FIND_DATAA wfd;
  109. HANDLE fh = FindFirstFileA(path, &wfd);
  110. if (fh == INVALID_HANDLE_VALUE)
  111. return;
  112. FindClose(fh);
  113. if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  114. info.file_type = Stat::DIRECTORY;
  115. else // Assume regular file.
  116. info.file_type = Stat::REGULAR;
  117. ULARGE_INTEGER fs = {};
  118. fs.LowPart = wfd.nFileSizeLow;
  119. fs.HighPart = wfd.nFileSizeHigh;
  120. info.size = fs.QuadPart;
  121. ULARGE_INTEGER lwt = {};
  122. lwt.LowPart = wfd.ftLastWriteTime.dwLowDateTime;
  123. lwt.HighPart = wfd.ftLastWriteTime.dwHighDateTime;
  124. info.mtime = lwt.QuadPart * u64(100); // See https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
  125. #else
  126. struct stat buf;
  127. memset(&buf, 0, sizeof(buf));
  128. int err = ::stat(path, &buf);
  129. if (err != 0)
  130. return;
  131. if (S_ISREG(buf.st_mode) == 1)
  132. info.file_type = Stat::REGULAR;
  133. else if (S_ISDIR(buf.st_mode) == 1)
  134. info.file_type = Stat::DIRECTORY;
  135. info.size = buf.st_size;
  136. info.mtime = buf.st_mtim.tv_sec * s64(1000000000) + buf.st_mtim.tv_nsec;
  137. #endif
  138. }
  139. DeleteResult delete_file(const char *path)
  140. {
  141. DeleteResult dr;
  142. #if CROWN_PLATFORM_WINDOWS
  143. if (DeleteFile(path) != 0)
  144. dr.error = DeleteResult::SUCCESS;
  145. else if (GetLastError() == ERROR_FILE_NOT_FOUND)
  146. dr.error = DeleteResult::NO_ENTRY;
  147. // else if (GetLastError() == ERROR_ACCESS_DENIED)
  148. // dr.error = DeleteResult::NOT_FILE;
  149. else
  150. dr.error = DeleteResult::UNKNOWN;
  151. #else
  152. if (::unlink(path) == 0)
  153. dr.error = DeleteResult::SUCCESS;
  154. else if (errno == ENOENT)
  155. dr.error = DeleteResult::NO_ENTRY;
  156. else
  157. dr.error = DeleteResult::UNKNOWN;
  158. #endif
  159. return dr;
  160. }
  161. CreateResult create_directory(const char *path)
  162. {
  163. CreateResult cr;
  164. #if CROWN_PLATFORM_WINDOWS
  165. if (CreateDirectory(path, NULL) != 0)
  166. cr.error = CreateResult::SUCCESS;
  167. else if (GetLastError() == ERROR_ALREADY_EXISTS)
  168. cr.error = CreateResult::ALREADY_EXISTS;
  169. else
  170. cr.error = CreateResult::UNKNOWN;
  171. #else
  172. if (::mkdir(path, 0755) == 0)
  173. cr.error = CreateResult::SUCCESS;
  174. else if (errno == EEXIST)
  175. cr.error = CreateResult::ALREADY_EXISTS;
  176. else
  177. cr.error = CreateResult::UNKNOWN;
  178. #endif
  179. return cr;
  180. }
  181. DeleteResult delete_directory(const char *path)
  182. {
  183. DeleteResult dr;
  184. #if CROWN_PLATFORM_WINDOWS
  185. if (RemoveDirectory(path) != 0)
  186. dr.error = DeleteResult::SUCCESS;
  187. else if (GetLastError() == ERROR_FILE_NOT_FOUND)
  188. dr.error = DeleteResult::NO_ENTRY;
  189. // else if (GetLastError() == ERROR_DIRECTORY
  190. // dr.error = DeleteResult::NOT_DIRECTORY;
  191. else
  192. dr.error = DeleteResult::UNKNOWN;
  193. #else
  194. if (::rmdir(path) == 0)
  195. dr.error = DeleteResult::SUCCESS;
  196. else if (errno == ENOENT)
  197. dr.error = DeleteResult::NO_ENTRY;
  198. else
  199. dr.error = DeleteResult::UNKNOWN;
  200. #endif
  201. return dr;
  202. }
  203. const char *getcwd(char *buf, u32 size)
  204. {
  205. #if CROWN_PLATFORM_WINDOWS
  206. GetCurrentDirectory(size, buf);
  207. return buf;
  208. #else
  209. return ::getcwd(buf, size);
  210. #endif
  211. }
  212. const char *getenv(const char *name)
  213. {
  214. #if CROWN_PLATFORM_WINDOWS
  215. // GetEnvironmentVariable(name, buf, size);
  216. return NULL;
  217. #else
  218. return ::getenv(name);
  219. #endif
  220. }
  221. void list_files(const char *path, Vector<DynamicString> &files)
  222. {
  223. #if CROWN_PLATFORM_WINDOWS
  224. TempAllocator256 ta_path;
  225. DynamicString cur_path(ta_path);
  226. cur_path += path;
  227. cur_path += "\\*";
  228. WIN32_FIND_DATA ffd;
  229. HANDLE file = FindFirstFile(cur_path.c_str(), &ffd);
  230. if (file != INVALID_HANDLE_VALUE) {
  231. do {
  232. const char *dname = ffd.cFileName;
  233. if (!strcmp(dname, ".") || !strcmp(dname, ".."))
  234. continue;
  235. TempAllocator256 ta;
  236. DynamicString fname(ta);
  237. fname.set(dname, strlen32(dname));
  238. vector::push_back(files, fname);
  239. } while (FindNextFile(file, &ffd) != 0);
  240. FindClose(file);
  241. }
  242. #else
  243. struct dirent *entry;
  244. DIR *dir = opendir(path);
  245. if (dir != NULL) {
  246. while ((entry = readdir(dir))) {
  247. const char *dname = entry->d_name;
  248. if (!strcmp(dname, ".") || !strcmp(dname, ".."))
  249. continue;
  250. TempAllocator256 ta;
  251. DynamicString fname(ta);
  252. fname.set(dname, strlen32(dname));
  253. vector::push_back(files, fname);
  254. }
  255. closedir(dir);
  256. }
  257. #endif
  258. }
  259. ///
  260. s32 access(const char *path, u32 flags)
  261. {
  262. #if CROWN_PLATFORM_WINDOWS
  263. return ::_access(path, flags == AccessFlags::EXECUTE ? AccessFlags::EXISTS : flags);
  264. #else
  265. return ::access(path, flags);
  266. #endif
  267. }
  268. } // namespace os
  269. } // namespace crown