1
0

physfs_platform_cafe.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*
  2. * Nintendo Wii U support routines for PhysicsFS.
  3. *
  4. * Please see the file LICENSE.txt in the source's root directory.
  5. *
  6. * This file written by TurtleP
  7. */
  8. #define __PHYSICSFS_INTERNAL__
  9. #include "physfs_platforms.h"
  10. #ifdef PHYSFS_PLATFORM_CAFE
  11. #include <unistd.h>
  12. #include <limits.h>
  13. #include <errno.h>
  14. #include <fcntl.h>
  15. #include <pthread.h>
  16. #include <dirent.h>
  17. #include <sys/stat.h>
  18. #include <coreinit/thread.h>
  19. #include <coreinit/mutex.h>
  20. #include <coreinit/debug.h>
  21. #include "physfs_internal.h"
  22. static PHYSFS_ErrorCode errcodeFromErrnoError(const int err)
  23. {
  24. switch (err)
  25. {
  26. case 0:
  27. return PHYSFS_ERR_OK;
  28. case EACCES:
  29. return PHYSFS_ERR_PERMISSION;
  30. case EPERM:
  31. return PHYSFS_ERR_PERMISSION;
  32. case EDQUOT:
  33. return PHYSFS_ERR_NO_SPACE;
  34. case EIO:
  35. return PHYSFS_ERR_IO;
  36. case ELOOP:
  37. return PHYSFS_ERR_SYMLINK_LOOP;
  38. case EMLINK:
  39. return PHYSFS_ERR_NO_SPACE;
  40. case ENAMETOOLONG:
  41. return PHYSFS_ERR_BAD_FILENAME;
  42. case ENOENT:
  43. return PHYSFS_ERR_NOT_FOUND;
  44. case ENOSPC:
  45. return PHYSFS_ERR_NO_SPACE;
  46. case ENOTDIR:
  47. return PHYSFS_ERR_NOT_FOUND;
  48. case EISDIR:
  49. return PHYSFS_ERR_NOT_A_FILE;
  50. case EROFS:
  51. return PHYSFS_ERR_READ_ONLY;
  52. case ETXTBSY:
  53. return PHYSFS_ERR_BUSY;
  54. case EBUSY:
  55. return PHYSFS_ERR_BUSY;
  56. case ENOMEM:
  57. return PHYSFS_ERR_OUT_OF_MEMORY;
  58. case ENOTEMPTY:
  59. return PHYSFS_ERR_DIR_NOT_EMPTY;
  60. default:
  61. return PHYSFS_ERR_OS_ERROR;
  62. }
  63. }
  64. static inline PHYSFS_ErrorCode errcodeFromErrno(void)
  65. {
  66. return errcodeFromErrnoError(errno);
  67. } /* errcodeFromErrno */
  68. char *__PHYSFS_platformCalcUserDir(void)
  69. {
  70. /* Use the jail directory (hopefully) found before. */
  71. return __PHYSFS_strdup(PHYSFS_getBaseDir());
  72. }
  73. int __PHYSFS_platformInit(void)
  74. {
  75. return 1; /* always succeeds. */
  76. } /* __PHYSFS_platformInit */
  77. void __PHYSFS_platformDeinit(void)
  78. {
  79. /* no-op */
  80. } /* __PHYSFS_platformDeinit */
  81. void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
  82. {
  83. } /* __PHYSFS_platformDetectAvailableCDs */
  84. char *__PHYSFS_platformCalcBaseDir(const char *argv0)
  85. {
  86. char *result = NULL;
  87. /*
  88. ** The user has not provided a path
  89. ** so we will use the current working directory
  90. */
  91. if (argv0 == NULL)
  92. {
  93. char cwd[PATH_MAX];
  94. if (getcwd(cwd, sizeof(cwd)) != NULL)
  95. {
  96. const size_t length = strlen(cwd);
  97. result = (char *)allocator.Malloc(length + 2);
  98. BAIL_IF(!result, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  99. strncpy(result, cwd, length);
  100. result[length] = '/';
  101. result[length + 1] = '\0';
  102. }
  103. }
  104. else
  105. {
  106. /* hbmenu gives us the full path to the application */
  107. return NULL;
  108. }
  109. if (!result)
  110. {
  111. result = __PHYSFS_strdup("/wiiu/");
  112. }
  113. return result;
  114. }
  115. char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
  116. {
  117. char *result = NULL;
  118. size_t length = 0;
  119. /*
  120. ** Use the jail directory (hopefully) found before.
  121. ** This way we don't need an application folder since it's exclusive.
  122. */
  123. const char *userDir = __PHYSFS_getUserDir();
  124. BAIL_IF_ERRPASS(!userDir, NULL);
  125. const char *append = ".config/";
  126. length = strlen(userDir) + strlen(append) + 1;
  127. result = (char *)allocator.Malloc(length);
  128. BAIL_IF(!result, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  129. snprintf(result, length, "%s%s", userDir, append);
  130. return result;
  131. }
  132. int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st, const int follow)
  133. {
  134. struct stat statbuf;
  135. const int rc = follow ? stat(fname, &statbuf) : lstat(fname, &statbuf);
  136. BAIL_IF(rc == -1, errcodeFromErrno(), 0);
  137. if (S_ISREG(statbuf.st_mode))
  138. {
  139. st->filetype = PHYSFS_FILETYPE_REGULAR;
  140. st->filesize = statbuf.st_size;
  141. } /* if */
  142. else if (S_ISDIR(statbuf.st_mode))
  143. {
  144. st->filetype = PHYSFS_FILETYPE_DIRECTORY;
  145. st->filesize = 0;
  146. } /* else if */
  147. else if (S_ISLNK(statbuf.st_mode))
  148. {
  149. st->filetype = PHYSFS_FILETYPE_SYMLINK;
  150. st->filesize = 0;
  151. } /* else if */
  152. else
  153. {
  154. st->filetype = PHYSFS_FILETYPE_OTHER;
  155. st->filesize = statbuf.st_size;
  156. } /* else */
  157. st->modtime = statbuf.st_mtime;
  158. st->createtime = statbuf.st_ctime;
  159. st->accesstime = statbuf.st_atime;
  160. st->readonly = !(statbuf.st_mode & S_IWRITE);
  161. return 1;
  162. }
  163. typedef struct
  164. {
  165. pthread_mutex_t mutex;
  166. pthread_t owner;
  167. PHYSFS_uint32 count;
  168. } PthreadMutex;
  169. void *__PHYSFS_platformGetThreadID(void)
  170. {
  171. return ((void *)OSGetCurrentThread());
  172. } /* __PHYSFS_platformGetThreadID */
  173. void *__PHYSFS_platformCreateMutex(void)
  174. {
  175. OSMutex *m = allocator.Malloc(sizeof(OSMutex));
  176. BAIL_IF(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  177. OSInitMutex(m);
  178. return ((void *)m);
  179. } /* __PHYSFS_platformCreateMutex */
  180. void __PHYSFS_platformDestroyMutex(void *mutex)
  181. {
  182. PthreadMutex *m = (PthreadMutex *)mutex;
  183. allocator.Free((OSMutex *)mutex);
  184. } /* __PHYSFS_platformDestroyMutex */
  185. int __PHYSFS_platformGrabMutex(void *mutex)
  186. {
  187. OSLockMutex((OSMutex *)mutex);
  188. return 1;
  189. } /* __PHYSFS_platformGrabMutex */
  190. void __PHYSFS_platformReleaseMutex(void *mutex)
  191. {
  192. PthreadMutex *m = (PthreadMutex *)mutex;
  193. OSUnlockMutex((OSMutex *)mutex);
  194. } /* __PHYSFS_platformReleaseMutex */
  195. PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname,
  196. PHYSFS_EnumerateCallback callback,
  197. const char *origdir, void *callbackdata)
  198. {
  199. DIR *dir;
  200. struct dirent *ent;
  201. PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK;
  202. dir = opendir(dirname);
  203. BAIL_IF(dir == NULL, errcodeFromErrno(), PHYSFS_ENUM_ERROR);
  204. while ((retval == PHYSFS_ENUM_OK) && ((ent = readdir(dir)) != NULL))
  205. {
  206. const char *name = ent->d_name;
  207. if (name[0] == '.') /* ignore "." and ".." */
  208. {
  209. if ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0')))
  210. continue;
  211. } /* if */
  212. retval = callback(callbackdata, origdir, name);
  213. if (retval == PHYSFS_ENUM_ERROR)
  214. PHYSFS_setErrorCode(PHYSFS_ERR_APP_CALLBACK);
  215. } /* while */
  216. closedir(dir);
  217. return retval;
  218. } /* __PHYSFS_platformEnumerate */
  219. int __PHYSFS_platformMkDir(const char *path)
  220. {
  221. const int rc = mkdir(path, S_IRWXU);
  222. BAIL_IF(rc == -1, errcodeFromErrno(), 0);
  223. return 1;
  224. } /* __PHYSFS_platformMkDir */
  225. #if !defined(O_CLOEXEC) && defined(FD_CLOEXEC)
  226. static inline void set_CLOEXEC(int fildes)
  227. {
  228. int flags = fcntl(fildes, F_GETFD);
  229. if (flags != -1)
  230. {
  231. fcntl(fildes, F_SETFD, flags | FD_CLOEXEC);
  232. }
  233. }
  234. #endif
  235. static void *doOpen(const char *filename, int mode)
  236. {
  237. const int appending = (mode & O_APPEND);
  238. int fd;
  239. int *retval;
  240. errno = 0;
  241. /* O_APPEND doesn't actually behave as we'd like. */
  242. mode &= ~O_APPEND;
  243. #ifdef O_CLOEXEC
  244. /* Add O_CLOEXEC if defined */
  245. mode |= O_CLOEXEC;
  246. #endif
  247. do
  248. {
  249. fd = open(filename, mode, S_IRUSR | S_IWUSR);
  250. } while ((fd < 0) && (errno == EINTR));
  251. BAIL_IF(fd < 0, errcodeFromErrno(), NULL);
  252. #if !defined(O_CLOEXEC) && defined(FD_CLOEXEC)
  253. set_CLOEXEC(fd);
  254. #endif
  255. if (appending)
  256. {
  257. if (lseek(fd, 0, SEEK_END) < 0)
  258. {
  259. const int err = errno;
  260. close(fd);
  261. BAIL(errcodeFromErrnoError(err), NULL);
  262. } /* if */
  263. } /* if */
  264. retval = (int *)allocator.Malloc(sizeof(int));
  265. if (!retval)
  266. {
  267. close(fd);
  268. BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  269. } /* if */
  270. *retval = fd;
  271. return ((void *)retval);
  272. } /* doOpen */
  273. void *__PHYSFS_platformOpenRead(const char *filename)
  274. {
  275. return doOpen(filename, O_RDONLY);
  276. } /* __PHYSFS_platformOpenRead */
  277. void *__PHYSFS_platformOpenWrite(const char *filename)
  278. {
  279. return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC);
  280. } /* __PHYSFS_platformOpenWrite */
  281. void *__PHYSFS_platformOpenAppend(const char *filename)
  282. {
  283. return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND);
  284. } /* __PHYSFS_platformOpenAppend */
  285. PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
  286. PHYSFS_uint64 len)
  287. {
  288. const int fd = *((int *)opaque);
  289. ssize_t rc = 0;
  290. if (!__PHYSFS_ui64FitsAddressSpace(len))
  291. BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1);
  292. do
  293. {
  294. rc = read(fd, buffer, (size_t)len);
  295. } while ((rc == -1) && (errno == EINTR));
  296. BAIL_IF(rc == -1, errcodeFromErrno(), -1);
  297. assert(rc >= 0);
  298. assert(rc <= len);
  299. return (PHYSFS_sint64)rc;
  300. } /* __PHYSFS_platformRead */
  301. PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
  302. PHYSFS_uint64 len)
  303. {
  304. const int fd = *((int *)opaque);
  305. ssize_t rc = 0;
  306. if (!__PHYSFS_ui64FitsAddressSpace(len))
  307. BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1);
  308. do
  309. {
  310. rc = write(fd, (void *)buffer, (size_t)len);
  311. } while ((rc == -1) && (errno == EINTR));
  312. BAIL_IF(rc == -1, errcodeFromErrno(), rc);
  313. assert(rc >= 0);
  314. assert(rc <= len);
  315. return (PHYSFS_sint64)rc;
  316. } /* __PHYSFS_platformWrite */
  317. int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
  318. {
  319. const int fd = *((int *)opaque);
  320. const off_t rc = lseek(fd, (off_t)pos, SEEK_SET);
  321. BAIL_IF(rc == -1, errcodeFromErrno(), 0);
  322. return 1;
  323. } /* __PHYSFS_platformSeek */
  324. PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
  325. {
  326. const int fd = *((int *)opaque);
  327. PHYSFS_sint64 retval;
  328. retval = (PHYSFS_sint64)lseek(fd, 0, SEEK_CUR);
  329. BAIL_IF(retval == -1, errcodeFromErrno(), -1);
  330. return retval;
  331. } /* __PHYSFS_platformTell */
  332. PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
  333. {
  334. const int fd = *((int *)opaque);
  335. struct stat statbuf;
  336. BAIL_IF(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1);
  337. return ((PHYSFS_sint64)statbuf.st_size);
  338. } /* __PHYSFS_platformFileLength */
  339. int __PHYSFS_platformFlush(void *opaque)
  340. {
  341. const int fd = *((int *)opaque);
  342. int rc = -1;
  343. if ((fcntl(fd, F_GETFL) & O_ACCMODE) != O_RDONLY)
  344. {
  345. do
  346. {
  347. rc = fsync(fd);
  348. } while ((rc == -1) && (errno == EINTR));
  349. BAIL_IF(rc == -1, errcodeFromErrno(), 0);
  350. }
  351. return 1;
  352. } /* __PHYSFS_platformFlush */
  353. void __PHYSFS_platformClose(void *opaque)
  354. {
  355. const int fd = *((int *)opaque);
  356. int rc = -1;
  357. do
  358. {
  359. rc = close(fd); /* we don't check this. You should have used flush! */
  360. } while ((rc == -1) && (errno == EINTR));
  361. allocator.Free(opaque);
  362. } /* __PHYSFS_platformClose */
  363. int __PHYSFS_platformDelete(const char *path)
  364. {
  365. BAIL_IF(remove(path) == -1, errcodeFromErrno(), 0);
  366. return 1;
  367. } /* __PHYSFS_platformDelete */
  368. #endif