From 223b04c0ba9f6d9739629368405dcfa098288f5f Mon Sep 17 00:00:00 2001 From: TurtleP Date: Wed, 20 Mar 2024 00:11:34 -0400 Subject: [PATCH 1/3] add 3ds --- CMakeLists.txt | 1 + src/physfs_platform_ctr.c | 463 ++++++++++++++++++++++++++++++++++++++ src/physfs_platforms.h | 3 + 3 files changed, 467 insertions(+) create mode 100644 src/physfs_platform_ctr.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 59910dbc..446484dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,7 @@ set(PHYSFS_SRCS src/physfs.c src/physfs_byteorder.c src/physfs_unicode.c + src/physfs_platform_ctr.c src/physfs_platform_posix.c src/physfs_platform_unix.c src/physfs_platform_windows.c diff --git a/src/physfs_platform_ctr.c b/src/physfs_platform_ctr.c new file mode 100644 index 00000000..47f5f2d1 --- /dev/null +++ b/src/physfs_platform_ctr.c @@ -0,0 +1,463 @@ +/* + * Nintendo 3DS support routines for PhysicsFS. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_platforms.h" + +#ifdef PHYSFS_PLATFORM_CTR + +#include +#include +#include +#include +#include +#include + +#include + +#include <3ds.h> + +#include "physfs_internal.h" + +static PHYSFS_ErrorCode errcodeFromErrnoError(const int err) +{ + switch (err) + { + case 0: + return PHYSFS_ERR_OK; + case EACCES: + return PHYSFS_ERR_PERMISSION; + case EPERM: + return PHYSFS_ERR_PERMISSION; + case EDQUOT: + return PHYSFS_ERR_NO_SPACE; + case EIO: + return PHYSFS_ERR_IO; + case ELOOP: + return PHYSFS_ERR_SYMLINK_LOOP; + case EMLINK: + return PHYSFS_ERR_NO_SPACE; + case ENAMETOOLONG: + return PHYSFS_ERR_BAD_FILENAME; + case ENOENT: + return PHYSFS_ERR_NOT_FOUND; + case ENOSPC: + return PHYSFS_ERR_NO_SPACE; + case ENOTDIR: + return PHYSFS_ERR_NOT_FOUND; + case EISDIR: + return PHYSFS_ERR_NOT_A_FILE; + case EROFS: + return PHYSFS_ERR_READ_ONLY; + case ETXTBSY: + return PHYSFS_ERR_BUSY; + case EBUSY: + return PHYSFS_ERR_BUSY; + case ENOMEM: + return PHYSFS_ERR_OUT_OF_MEMORY; + case ENOTEMPTY: + return PHYSFS_ERR_DIR_NOT_EMPTY; + default: + return PHYSFS_ERR_OS_ERROR; + } +} + +static inline PHYSFS_ErrorCode errcodeFromErrno(void) +{ + return errcodeFromErrnoError(errno); +} /* errcodeFromErrno */ + +char *__PHYSFS_platformCalcUserDir(void) +{ + /* Use the jail directory (hopefully) found before. */ + return __PHYSFS_strdup(PHYSFS_getBaseDir()); +} + +int __PHYSFS_platformInit(void) +{ + return 1; /* always succeeds. */ +} /* __PHYSFS_platformInit */ + +void __PHYSFS_platformDeinit(void) +{ + /* no-op */ +} /* __PHYSFS_platformDeinit */ + +void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) +{ +} /* __PHYSFS_platformDetectAvailableCDs */ + +char *__PHYSFS_platformCalcBaseDir(const char *argv0) +{ + char *result = NULL; + + /* + ** The user has not provided a path + ** so we will use the current working directory + */ + if (argv0 == NULL) + { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) != NULL) + { + const size_t length = strlen(cwd); + result = (char *)allocator.Malloc(length + 2); + BAIL_IF(!result, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + strncpy(result, cwd, length); + result[length] = '/'; + result[length + 1] = '\0'; + } + } + else + { + /* hbmenu gives us the full path to the application */ + return NULL; + } + + if (!result) + { + result = __PHYSFS_strdup("/3ds/"); + } + + return result; +} + +char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app) +{ + char *result = NULL; + size_t length = 0; + + /* + ** Use the jail directory (hopefully) found before. + ** This way we don't need an application folder since it's exclusive. + */ + const char *userDir = __PHYSFS_getUserDir(); + BAIL_IF_ERRPASS(!userDir, NULL); + + const char *append = ".config/"; + length = strlen(userDir) + strlen(append) + 1; + result = (char *)allocator.Malloc(length); + BAIL_IF(!result, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + snprintf(result, length, "%s%s", userDir, append); + + return result; +} + +int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st, const int follow) +{ + struct stat statbuf; + const int rc = follow ? stat(fname, &statbuf) : lstat(fname, &statbuf); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + + if (S_ISREG(statbuf.st_mode)) + { + st->filetype = PHYSFS_FILETYPE_REGULAR; + st->filesize = statbuf.st_size; + } /* if */ + + else if (S_ISDIR(statbuf.st_mode)) + { + st->filetype = PHYSFS_FILETYPE_DIRECTORY; + st->filesize = 0; + } /* else if */ + + else if (S_ISLNK(statbuf.st_mode)) + { + st->filetype = PHYSFS_FILETYPE_SYMLINK; + st->filesize = 0; + } /* else if */ + + else + { + st->filetype = PHYSFS_FILETYPE_OTHER; + st->filesize = statbuf.st_size; + } /* else */ + + st->modtime = statbuf.st_mtime; + st->createtime = statbuf.st_ctime; + st->accesstime = statbuf.st_atime; + + st->readonly = !(statbuf.st_mode & S_IWRITE); + return 1; +} + +typedef struct +{ + pthread_mutex_t mutex; + pthread_t owner; + PHYSFS_uint32 count; +} PthreadMutex; + +void *__PHYSFS_platformGetThreadID(void) +{ + return ((void *)((size_t)pthread_self())); +} /* __PHYSFS_platformGetThreadID */ + +void *__PHYSFS_platformCreateMutex(void) +{ + int rc; + PthreadMutex *m = (PthreadMutex *)allocator.Malloc(sizeof(PthreadMutex)); + BAIL_IF(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + rc = pthread_mutex_init(&m->mutex, NULL); + if (rc != 0) + { + allocator.Free(m); + BAIL(PHYSFS_ERR_OS_ERROR, NULL); + } /* if */ + + m->count = 0; + m->owner = (pthread_t)0xDEADBEEF; + return ((void *)m); +} /* __PHYSFS_platformCreateMutex */ + +void __PHYSFS_platformDestroyMutex(void *mutex) +{ + PthreadMutex *m = (PthreadMutex *)mutex; + + /* Destroying a locked mutex is a bug, but we'll try to be helpful. */ + if ((m->owner == pthread_self()) && (m->count > 0)) + pthread_mutex_unlock(&m->mutex); + + pthread_mutex_destroy(&m->mutex); + allocator.Free(m); +} /* __PHYSFS_platformDestroyMutex */ + +int __PHYSFS_platformGrabMutex(void *mutex) +{ + PthreadMutex *m = (PthreadMutex *)mutex; + pthread_t tid = pthread_self(); + if (m->owner != tid) + { + if (pthread_mutex_lock(&m->mutex) != 0) + return 0; + m->owner = tid; + } /* if */ + + m->count++; + return 1; +} /* __PHYSFS_platformGrabMutex */ + +void __PHYSFS_platformReleaseMutex(void *mutex) +{ + PthreadMutex *m = (PthreadMutex *)mutex; + assert(m->owner == pthread_self()); /* catch programming errors. */ + assert(m->count > 0); /* catch programming errors. */ + if (m->owner == pthread_self()) + { + if (--m->count == 0) + { + m->owner = (pthread_t)0xDEADBEEF; + pthread_mutex_unlock(&m->mutex); + } /* if */ + } /* if */ +} /* __PHYSFS_platformReleaseMutex */ + +PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname, + PHYSFS_EnumerateCallback callback, + const char *origdir, void *callbackdata) +{ + DIR *dir; + struct dirent *ent; + PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK; + + dir = opendir(dirname); + BAIL_IF(dir == NULL, errcodeFromErrno(), PHYSFS_ENUM_ERROR); + + while ((retval == PHYSFS_ENUM_OK) && ((ent = readdir(dir)) != NULL)) + { + const char *name = ent->d_name; + if (name[0] == '.') /* ignore "." and ".." */ + { + if ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0'))) + continue; + } /* if */ + + retval = callback(callbackdata, origdir, name); + if (retval == PHYSFS_ENUM_ERROR) + PHYSFS_setErrorCode(PHYSFS_ERR_APP_CALLBACK); + } /* while */ + + closedir(dir); + + return retval; +} /* __PHYSFS_platformEnumerate */ + +int __PHYSFS_platformMkDir(const char *path) +{ + const int rc = mkdir(path, S_IRWXU); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformMkDir */ + +#if !defined(O_CLOEXEC) && defined(FD_CLOEXEC) +static inline void set_CLOEXEC(int fildes) +{ + int flags = fcntl(fildes, F_GETFD); + if (flags != -1) + { + fcntl(fildes, F_SETFD, flags | FD_CLOEXEC); + } +} +#endif + +static void *doOpen(const char *filename, int mode) +{ + const int appending = (mode & O_APPEND); + int fd; + int *retval; + + errno = 0; + + /* O_APPEND doesn't actually behave as we'd like. */ + mode &= ~O_APPEND; + +#ifdef O_CLOEXEC + /* Add O_CLOEXEC if defined */ + mode |= O_CLOEXEC; +#endif + + do + { + fd = open(filename, mode, S_IRUSR | S_IWUSR); + } while ((fd < 0) && (errno == EINTR)); + BAIL_IF(fd < 0, errcodeFromErrno(), NULL); + +#if !defined(O_CLOEXEC) && defined(FD_CLOEXEC) + set_CLOEXEC(fd); +#endif + + if (appending) + { + if (lseek(fd, 0, SEEK_END) < 0) + { + const int err = errno; + close(fd); + BAIL(errcodeFromErrnoError(err), NULL); + } /* if */ + } /* if */ + + retval = (int *)allocator.Malloc(sizeof(int)); + if (!retval) + { + close(fd); + BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } /* if */ + + *retval = fd; + return ((void *)retval); +} /* doOpen */ + +void *__PHYSFS_platformOpenRead(const char *filename) +{ + return doOpen(filename, O_RDONLY); +} /* __PHYSFS_platformOpenRead */ + +void *__PHYSFS_platformOpenWrite(const char *filename) +{ + return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC); +} /* __PHYSFS_platformOpenWrite */ + +void *__PHYSFS_platformOpenAppend(const char *filename) +{ + return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND); +} /* __PHYSFS_platformOpenAppend */ + +PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer, + PHYSFS_uint64 len) +{ + const int fd = *((int *)opaque); + ssize_t rc = 0; + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + do + { + rc = read(fd, buffer, (size_t)len); + } while ((rc == -1) && (errno == EINTR)); + BAIL_IF(rc == -1, errcodeFromErrno(), -1); + assert(rc >= 0); + assert(rc <= len); + return (PHYSFS_sint64)rc; +} /* __PHYSFS_platformRead */ + +PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer, + PHYSFS_uint64 len) +{ + const int fd = *((int *)opaque); + ssize_t rc = 0; + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + do + { + rc = write(fd, (void *)buffer, (size_t)len); + } while ((rc == -1) && (errno == EINTR)); + BAIL_IF(rc == -1, errcodeFromErrno(), rc); + assert(rc >= 0); + assert(rc <= len); + return (PHYSFS_sint64)rc; +} /* __PHYSFS_platformWrite */ + +int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos) +{ + const int fd = *((int *)opaque); + const off_t rc = lseek(fd, (off_t)pos, SEEK_SET); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformSeek */ + +PHYSFS_sint64 __PHYSFS_platformTell(void *opaque) +{ + const int fd = *((int *)opaque); + PHYSFS_sint64 retval; + retval = (PHYSFS_sint64)lseek(fd, 0, SEEK_CUR); + BAIL_IF(retval == -1, errcodeFromErrno(), -1); + return retval; +} /* __PHYSFS_platformTell */ + +PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque) +{ + const int fd = *((int *)opaque); + struct stat statbuf; + BAIL_IF(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1); + return ((PHYSFS_sint64)statbuf.st_size); +} /* __PHYSFS_platformFileLength */ + +int __PHYSFS_platformFlush(void *opaque) +{ + const int fd = *((int *)opaque); + int rc = -1; + if ((fcntl(fd, F_GETFL) & O_ACCMODE) != O_RDONLY) + { + do + { + rc = fsync(fd); + } while ((rc == -1) && (errno == EINTR)); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + } + return 1; +} /* __PHYSFS_platformFlush */ + +void __PHYSFS_platformClose(void *opaque) +{ + const int fd = *((int *)opaque); + int rc = -1; + do + { + rc = close(fd); /* we don't check this. You should have used flush! */ + } while ((rc == -1) && (errno == EINTR)); + allocator.Free(opaque); +} /* __PHYSFS_platformClose */ + +int __PHYSFS_platformDelete(const char *path) +{ + BAIL_IF(remove(path) == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformDelete */ + +#endif diff --git a/src/physfs_platforms.h b/src/physfs_platforms.h index 36119b3f..6efadaaf 100644 --- a/src/physfs_platforms.h +++ b/src/physfs_platforms.h @@ -75,6 +75,9 @@ #elif defined(__wii__) || defined(__gamecube__) # define PHYSFS_PLATFORM_OGC 1 # define PHYSFS_NO_CDROM_SUPPORT 1 // TODO +#elif defined(__3DS__) +# define PHYSFS_PLATFORM_CTR 1 +# define PHYSFS_NO_CDROM_SUPPORT 1 #else # error Unknown platform. #endif From 3e4c4e6d16bde88ba23e735be1863342b4ae0874 Mon Sep 17 00:00:00 2001 From: TurtleP Date: Wed, 20 Mar 2024 01:21:23 -0400 Subject: [PATCH 2/3] switch and wii u --- CMakeLists.txt | 2 + src/physfs_platform_cafe.c | 433 ++++++++++++++++++++++++++++++++++ src/physfs_platform_hac.c | 463 +++++++++++++++++++++++++++++++++++++ src/physfs_platforms.h | 6 + 4 files changed, 904 insertions(+) create mode 100644 src/physfs_platform_cafe.c create mode 100644 src/physfs_platform_hac.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 446484dc..3e59543f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,9 @@ set(PHYSFS_SRCS src/physfs.c src/physfs_byteorder.c src/physfs_unicode.c + src/physfs_platform_cafe.c src/physfs_platform_ctr.c + src/physfs_platform_hac.c src/physfs_platform_posix.c src/physfs_platform_unix.c src/physfs_platform_windows.c diff --git a/src/physfs_platform_cafe.c b/src/physfs_platform_cafe.c new file mode 100644 index 00000000..aaabd582 --- /dev/null +++ b/src/physfs_platform_cafe.c @@ -0,0 +1,433 @@ +/* + * Nintendo Switch support routines for PhysicsFS. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_platforms.h" + +#ifdef PHYSFS_PLATFORM_CAFE + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "physfs_internal.h" + +static PHYSFS_ErrorCode errcodeFromErrnoError(const int err) +{ + switch (err) + { + case 0: + return PHYSFS_ERR_OK; + case EACCES: + return PHYSFS_ERR_PERMISSION; + case EPERM: + return PHYSFS_ERR_PERMISSION; + case EDQUOT: + return PHYSFS_ERR_NO_SPACE; + case EIO: + return PHYSFS_ERR_IO; + case ELOOP: + return PHYSFS_ERR_SYMLINK_LOOP; + case EMLINK: + return PHYSFS_ERR_NO_SPACE; + case ENAMETOOLONG: + return PHYSFS_ERR_BAD_FILENAME; + case ENOENT: + return PHYSFS_ERR_NOT_FOUND; + case ENOSPC: + return PHYSFS_ERR_NO_SPACE; + case ENOTDIR: + return PHYSFS_ERR_NOT_FOUND; + case EISDIR: + return PHYSFS_ERR_NOT_A_FILE; + case EROFS: + return PHYSFS_ERR_READ_ONLY; + case ETXTBSY: + return PHYSFS_ERR_BUSY; + case EBUSY: + return PHYSFS_ERR_BUSY; + case ENOMEM: + return PHYSFS_ERR_OUT_OF_MEMORY; + case ENOTEMPTY: + return PHYSFS_ERR_DIR_NOT_EMPTY; + default: + return PHYSFS_ERR_OS_ERROR; + } +} + +static inline PHYSFS_ErrorCode errcodeFromErrno(void) +{ + return errcodeFromErrnoError(errno); +} /* errcodeFromErrno */ + +char *__PHYSFS_platformCalcUserDir(void) +{ + /* Use the jail directory (hopefully) found before. */ + return __PHYSFS_strdup(PHYSFS_getBaseDir()); +} + +int __PHYSFS_platformInit(void) +{ + return 1; /* always succeeds. */ +} /* __PHYSFS_platformInit */ + +void __PHYSFS_platformDeinit(void) +{ + /* no-op */ +} /* __PHYSFS_platformDeinit */ + +void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) +{ +} /* __PHYSFS_platformDetectAvailableCDs */ + +char *__PHYSFS_platformCalcBaseDir(const char *argv0) +{ + char *result = NULL; + + /* + ** The user has not provided a path + ** so we will use the current working directory + */ + if (argv0 == NULL) + { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) != NULL) + { + const size_t length = strlen(cwd); + result = (char *)allocator.Malloc(length + 2); + BAIL_IF(!result, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + strncpy(result, cwd, length); + result[length] = '/'; + result[length + 1] = '\0'; + } + } + else + { + /* hbmenu gives us the full path to the application */ + return NULL; + } + + if (!result) + { + result = __PHYSFS_strdup("/wiiu/"); + } + + return result; +} + +char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app) +{ + char *result = NULL; + size_t length = 0; + + /* + ** Use the jail directory (hopefully) found before. + ** This way we don't need an application folder since it's exclusive. + */ + const char *userDir = __PHYSFS_getUserDir(); + BAIL_IF_ERRPASS(!userDir, NULL); + + const char *append = ".config/"; + length = strlen(userDir) + strlen(append) + 1; + result = (char *)allocator.Malloc(length); + BAIL_IF(!result, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + snprintf(result, length, "%s%s", userDir, append); + + return result; +} + +int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st, const int follow) +{ + struct stat statbuf; + const int rc = follow ? stat(fname, &statbuf) : lstat(fname, &statbuf); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + + if (S_ISREG(statbuf.st_mode)) + { + st->filetype = PHYSFS_FILETYPE_REGULAR; + st->filesize = statbuf.st_size; + } /* if */ + + else if (S_ISDIR(statbuf.st_mode)) + { + st->filetype = PHYSFS_FILETYPE_DIRECTORY; + st->filesize = 0; + } /* else if */ + + else if (S_ISLNK(statbuf.st_mode)) + { + st->filetype = PHYSFS_FILETYPE_SYMLINK; + st->filesize = 0; + } /* else if */ + + else + { + st->filetype = PHYSFS_FILETYPE_OTHER; + st->filesize = statbuf.st_size; + } /* else */ + + st->modtime = statbuf.st_mtime; + st->createtime = statbuf.st_ctime; + st->accesstime = statbuf.st_atime; + + st->readonly = !(statbuf.st_mode & S_IWRITE); + return 1; +} + +typedef struct +{ + pthread_mutex_t mutex; + pthread_t owner; + PHYSFS_uint32 count; +} PthreadMutex; + +void *__PHYSFS_platformGetThreadID(void) +{ + return ((void *)OSGetCurrentThread()); +} /* __PHYSFS_platformGetThreadID */ + +void *__PHYSFS_platformCreateMutex(void) +{ + OSMutex *m = allocator.Malloc(sizeof(OSMutex)); + BAIL_IF(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + OSInitMutex(m); + + return ((void *)m); +} /* __PHYSFS_platformCreateMutex */ + +void __PHYSFS_platformDestroyMutex(void *mutex) +{ + PthreadMutex *m = (PthreadMutex *)mutex; + allocator.Free((OSMutex *)mutex); +} /* __PHYSFS_platformDestroyMutex */ + +int __PHYSFS_platformGrabMutex(void *mutex) +{ + OSLockMutex((OSMutex *)mutex); + return 1; +} /* __PHYSFS_platformGrabMutex */ + +void __PHYSFS_platformReleaseMutex(void *mutex) +{ + PthreadMutex *m = (PthreadMutex *)mutex; + OSUnlockMutex((OSMutex *)mutex); +} /* __PHYSFS_platformReleaseMutex */ + +PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname, + PHYSFS_EnumerateCallback callback, + const char *origdir, void *callbackdata) +{ + DIR *dir; + struct dirent *ent; + PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK; + + dir = opendir(dirname); + BAIL_IF(dir == NULL, errcodeFromErrno(), PHYSFS_ENUM_ERROR); + + while ((retval == PHYSFS_ENUM_OK) && ((ent = readdir(dir)) != NULL)) + { + const char *name = ent->d_name; + if (name[0] == '.') /* ignore "." and ".." */ + { + if ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0'))) + continue; + } /* if */ + + retval = callback(callbackdata, origdir, name); + if (retval == PHYSFS_ENUM_ERROR) + PHYSFS_setErrorCode(PHYSFS_ERR_APP_CALLBACK); + } /* while */ + + closedir(dir); + + return retval; +} /* __PHYSFS_platformEnumerate */ + +int __PHYSFS_platformMkDir(const char *path) +{ + const int rc = mkdir(path, S_IRWXU); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformMkDir */ + +#if !defined(O_CLOEXEC) && defined(FD_CLOEXEC) +static inline void set_CLOEXEC(int fildes) +{ + int flags = fcntl(fildes, F_GETFD); + if (flags != -1) + { + fcntl(fildes, F_SETFD, flags | FD_CLOEXEC); + } +} +#endif + +static void *doOpen(const char *filename, int mode) +{ + const int appending = (mode & O_APPEND); + int fd; + int *retval; + + errno = 0; + + /* O_APPEND doesn't actually behave as we'd like. */ + mode &= ~O_APPEND; + +#ifdef O_CLOEXEC + /* Add O_CLOEXEC if defined */ + mode |= O_CLOEXEC; +#endif + + do + { + fd = open(filename, mode, S_IRUSR | S_IWUSR); + } while ((fd < 0) && (errno == EINTR)); + BAIL_IF(fd < 0, errcodeFromErrno(), NULL); + +#if !defined(O_CLOEXEC) && defined(FD_CLOEXEC) + set_CLOEXEC(fd); +#endif + + if (appending) + { + if (lseek(fd, 0, SEEK_END) < 0) + { + const int err = errno; + close(fd); + BAIL(errcodeFromErrnoError(err), NULL); + } /* if */ + } /* if */ + + retval = (int *)allocator.Malloc(sizeof(int)); + if (!retval) + { + close(fd); + BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } /* if */ + + *retval = fd; + return ((void *)retval); +} /* doOpen */ + +void *__PHYSFS_platformOpenRead(const char *filename) +{ + return doOpen(filename, O_RDONLY); +} /* __PHYSFS_platformOpenRead */ + +void *__PHYSFS_platformOpenWrite(const char *filename) +{ + return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC); +} /* __PHYSFS_platformOpenWrite */ + +void *__PHYSFS_platformOpenAppend(const char *filename) +{ + return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND); +} /* __PHYSFS_platformOpenAppend */ + +PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer, + PHYSFS_uint64 len) +{ + const int fd = *((int *)opaque); + ssize_t rc = 0; + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + do + { + rc = read(fd, buffer, (size_t)len); + } while ((rc == -1) && (errno == EINTR)); + BAIL_IF(rc == -1, errcodeFromErrno(), -1); + assert(rc >= 0); + assert(rc <= len); + return (PHYSFS_sint64)rc; +} /* __PHYSFS_platformRead */ + +PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer, + PHYSFS_uint64 len) +{ + const int fd = *((int *)opaque); + ssize_t rc = 0; + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + do + { + rc = write(fd, (void *)buffer, (size_t)len); + } while ((rc == -1) && (errno == EINTR)); + BAIL_IF(rc == -1, errcodeFromErrno(), rc); + assert(rc >= 0); + assert(rc <= len); + return (PHYSFS_sint64)rc; +} /* __PHYSFS_platformWrite */ + +int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos) +{ + const int fd = *((int *)opaque); + const off_t rc = lseek(fd, (off_t)pos, SEEK_SET); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformSeek */ + +PHYSFS_sint64 __PHYSFS_platformTell(void *opaque) +{ + const int fd = *((int *)opaque); + PHYSFS_sint64 retval; + retval = (PHYSFS_sint64)lseek(fd, 0, SEEK_CUR); + BAIL_IF(retval == -1, errcodeFromErrno(), -1); + return retval; +} /* __PHYSFS_platformTell */ + +PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque) +{ + const int fd = *((int *)opaque); + struct stat statbuf; + BAIL_IF(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1); + return ((PHYSFS_sint64)statbuf.st_size); +} /* __PHYSFS_platformFileLength */ + +int __PHYSFS_platformFlush(void *opaque) +{ + const int fd = *((int *)opaque); + int rc = -1; + if ((fcntl(fd, F_GETFL) & O_ACCMODE) != O_RDONLY) + { + do + { + rc = fsync(fd); + } while ((rc == -1) && (errno == EINTR)); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + } + return 1; +} /* __PHYSFS_platformFlush */ + +void __PHYSFS_platformClose(void *opaque) +{ + const int fd = *((int *)opaque); + int rc = -1; + do + { + rc = close(fd); /* we don't check this. You should have used flush! */ + } while ((rc == -1) && (errno == EINTR)); + allocator.Free(opaque); +} /* __PHYSFS_platformClose */ + +int __PHYSFS_platformDelete(const char *path) +{ + BAIL_IF(remove(path) == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformDelete */ + +#endif diff --git a/src/physfs_platform_hac.c b/src/physfs_platform_hac.c new file mode 100644 index 00000000..f930e25b --- /dev/null +++ b/src/physfs_platform_hac.c @@ -0,0 +1,463 @@ +/* + * Nintendo Switch support routines for PhysicsFS. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_platforms.h" + +#ifdef PHYSFS_PLATFORM_HAC + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "physfs_internal.h" + +static PHYSFS_ErrorCode errcodeFromErrnoError(const int err) +{ + switch (err) + { + case 0: + return PHYSFS_ERR_OK; + case EACCES: + return PHYSFS_ERR_PERMISSION; + case EPERM: + return PHYSFS_ERR_PERMISSION; + case EDQUOT: + return PHYSFS_ERR_NO_SPACE; + case EIO: + return PHYSFS_ERR_IO; + case ELOOP: + return PHYSFS_ERR_SYMLINK_LOOP; + case EMLINK: + return PHYSFS_ERR_NO_SPACE; + case ENAMETOOLONG: + return PHYSFS_ERR_BAD_FILENAME; + case ENOENT: + return PHYSFS_ERR_NOT_FOUND; + case ENOSPC: + return PHYSFS_ERR_NO_SPACE; + case ENOTDIR: + return PHYSFS_ERR_NOT_FOUND; + case EISDIR: + return PHYSFS_ERR_NOT_A_FILE; + case EROFS: + return PHYSFS_ERR_READ_ONLY; + case ETXTBSY: + return PHYSFS_ERR_BUSY; + case EBUSY: + return PHYSFS_ERR_BUSY; + case ENOMEM: + return PHYSFS_ERR_OUT_OF_MEMORY; + case ENOTEMPTY: + return PHYSFS_ERR_DIR_NOT_EMPTY; + default: + return PHYSFS_ERR_OS_ERROR; + } +} + +static inline PHYSFS_ErrorCode errcodeFromErrno(void) +{ + return errcodeFromErrnoError(errno); +} /* errcodeFromErrno */ + +char *__PHYSFS_platformCalcUserDir(void) +{ + /* Use the jail directory (hopefully) found before. */ + return __PHYSFS_strdup(PHYSFS_getBaseDir()); +} + +int __PHYSFS_platformInit(void) +{ + return 1; /* always succeeds. */ +} /* __PHYSFS_platformInit */ + +void __PHYSFS_platformDeinit(void) +{ + /* no-op */ +} /* __PHYSFS_platformDeinit */ + +void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) +{ +} /* __PHYSFS_platformDetectAvailableCDs */ + +char *__PHYSFS_platformCalcBaseDir(const char *argv0) +{ + char *result = NULL; + + /* + ** The user has not provided a path + ** so we will use the current working directory + */ + if (argv0 == NULL) + { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) != NULL) + { + const size_t length = strlen(cwd); + result = (char *)allocator.Malloc(length + 2); + BAIL_IF(!result, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + strncpy(result, cwd, length); + result[length] = '/'; + result[length + 1] = '\0'; + } + } + else + { + /* hbmenu gives us the full path to the application */ + return NULL; + } + + if (!result) + { + result = __PHYSFS_strdup("/switch/"); + } + + return result; +} + +char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app) +{ + char *result = NULL; + size_t length = 0; + + /* + ** Use the jail directory (hopefully) found before. + ** This way we don't need an application folder since it's exclusive. + */ + const char *userDir = __PHYSFS_getUserDir(); + BAIL_IF_ERRPASS(!userDir, NULL); + + const char *append = ".config/"; + length = strlen(userDir) + strlen(append) + 1; + result = (char *)allocator.Malloc(length); + BAIL_IF(!result, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + snprintf(result, length, "%s%s", userDir, append); + + return result; +} + +int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st, const int follow) +{ + struct stat statbuf; + const int rc = follow ? stat(fname, &statbuf) : lstat(fname, &statbuf); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + + if (S_ISREG(statbuf.st_mode)) + { + st->filetype = PHYSFS_FILETYPE_REGULAR; + st->filesize = statbuf.st_size; + } /* if */ + + else if (S_ISDIR(statbuf.st_mode)) + { + st->filetype = PHYSFS_FILETYPE_DIRECTORY; + st->filesize = 0; + } /* else if */ + + else if (S_ISLNK(statbuf.st_mode)) + { + st->filetype = PHYSFS_FILETYPE_SYMLINK; + st->filesize = 0; + } /* else if */ + + else + { + st->filetype = PHYSFS_FILETYPE_OTHER; + st->filesize = statbuf.st_size; + } /* else */ + + st->modtime = statbuf.st_mtime; + st->createtime = statbuf.st_ctime; + st->accesstime = statbuf.st_atime; + + st->readonly = !(statbuf.st_mode & S_IWRITE); + return 1; +} + +typedef struct +{ + pthread_mutex_t mutex; + pthread_t owner; + PHYSFS_uint32 count; +} PthreadMutex; + +void *__PHYSFS_platformGetThreadID(void) +{ + return ((void *)((size_t)pthread_self())); +} /* __PHYSFS_platformGetThreadID */ + +void *__PHYSFS_platformCreateMutex(void) +{ + int rc; + PthreadMutex *m = (PthreadMutex *)allocator.Malloc(sizeof(PthreadMutex)); + BAIL_IF(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + rc = pthread_mutex_init(&m->mutex, NULL); + if (rc != 0) + { + allocator.Free(m); + BAIL(PHYSFS_ERR_OS_ERROR, NULL); + } /* if */ + + m->count = 0; + m->owner = (pthread_t)0xDEADBEEF; + return ((void *)m); +} /* __PHYSFS_platformCreateMutex */ + +void __PHYSFS_platformDestroyMutex(void *mutex) +{ + PthreadMutex *m = (PthreadMutex *)mutex; + + /* Destroying a locked mutex is a bug, but we'll try to be helpful. */ + if ((m->owner == pthread_self()) && (m->count > 0)) + pthread_mutex_unlock(&m->mutex); + + pthread_mutex_destroy(&m->mutex); + allocator.Free(m); +} /* __PHYSFS_platformDestroyMutex */ + +int __PHYSFS_platformGrabMutex(void *mutex) +{ + PthreadMutex *m = (PthreadMutex *)mutex; + pthread_t tid = pthread_self(); + if (m->owner != tid) + { + if (pthread_mutex_lock(&m->mutex) != 0) + return 0; + m->owner = tid; + } /* if */ + + m->count++; + return 1; +} /* __PHYSFS_platformGrabMutex */ + +void __PHYSFS_platformReleaseMutex(void *mutex) +{ + PthreadMutex *m = (PthreadMutex *)mutex; + assert(m->owner == pthread_self()); /* catch programming errors. */ + assert(m->count > 0); /* catch programming errors. */ + if (m->owner == pthread_self()) + { + if (--m->count == 0) + { + m->owner = (pthread_t)0xDEADBEEF; + pthread_mutex_unlock(&m->mutex); + } /* if */ + } /* if */ +} /* __PHYSFS_platformReleaseMutex */ + +PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname, + PHYSFS_EnumerateCallback callback, + const char *origdir, void *callbackdata) +{ + DIR *dir; + struct dirent *ent; + PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK; + + dir = opendir(dirname); + BAIL_IF(dir == NULL, errcodeFromErrno(), PHYSFS_ENUM_ERROR); + + while ((retval == PHYSFS_ENUM_OK) && ((ent = readdir(dir)) != NULL)) + { + const char *name = ent->d_name; + if (name[0] == '.') /* ignore "." and ".." */ + { + if ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0'))) + continue; + } /* if */ + + retval = callback(callbackdata, origdir, name); + if (retval == PHYSFS_ENUM_ERROR) + PHYSFS_setErrorCode(PHYSFS_ERR_APP_CALLBACK); + } /* while */ + + closedir(dir); + + return retval; +} /* __PHYSFS_platformEnumerate */ + +int __PHYSFS_platformMkDir(const char *path) +{ + const int rc = mkdir(path, S_IRWXU); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformMkDir */ + +#if !defined(O_CLOEXEC) && defined(FD_CLOEXEC) +static inline void set_CLOEXEC(int fildes) +{ + int flags = fcntl(fildes, F_GETFD); + if (flags != -1) + { + fcntl(fildes, F_SETFD, flags | FD_CLOEXEC); + } +} +#endif + +static void *doOpen(const char *filename, int mode) +{ + const int appending = (mode & O_APPEND); + int fd; + int *retval; + + errno = 0; + + /* O_APPEND doesn't actually behave as we'd like. */ + mode &= ~O_APPEND; + +#ifdef O_CLOEXEC + /* Add O_CLOEXEC if defined */ + mode |= O_CLOEXEC; +#endif + + do + { + fd = open(filename, mode, S_IRUSR | S_IWUSR); + } while ((fd < 0) && (errno == EINTR)); + BAIL_IF(fd < 0, errcodeFromErrno(), NULL); + +#if !defined(O_CLOEXEC) && defined(FD_CLOEXEC) + set_CLOEXEC(fd); +#endif + + if (appending) + { + if (lseek(fd, 0, SEEK_END) < 0) + { + const int err = errno; + close(fd); + BAIL(errcodeFromErrnoError(err), NULL); + } /* if */ + } /* if */ + + retval = (int *)allocator.Malloc(sizeof(int)); + if (!retval) + { + close(fd); + BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } /* if */ + + *retval = fd; + return ((void *)retval); +} /* doOpen */ + +void *__PHYSFS_platformOpenRead(const char *filename) +{ + return doOpen(filename, O_RDONLY); +} /* __PHYSFS_platformOpenRead */ + +void *__PHYSFS_platformOpenWrite(const char *filename) +{ + return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC); +} /* __PHYSFS_platformOpenWrite */ + +void *__PHYSFS_platformOpenAppend(const char *filename) +{ + return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND); +} /* __PHYSFS_platformOpenAppend */ + +PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer, + PHYSFS_uint64 len) +{ + const int fd = *((int *)opaque); + ssize_t rc = 0; + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + do + { + rc = read(fd, buffer, (size_t)len); + } while ((rc == -1) && (errno == EINTR)); + BAIL_IF(rc == -1, errcodeFromErrno(), -1); + assert(rc >= 0); + assert(rc <= len); + return (PHYSFS_sint64)rc; +} /* __PHYSFS_platformRead */ + +PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer, + PHYSFS_uint64 len) +{ + const int fd = *((int *)opaque); + ssize_t rc = 0; + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + do + { + rc = write(fd, (void *)buffer, (size_t)len); + } while ((rc == -1) && (errno == EINTR)); + BAIL_IF(rc == -1, errcodeFromErrno(), rc); + assert(rc >= 0); + assert(rc <= len); + return (PHYSFS_sint64)rc; +} /* __PHYSFS_platformWrite */ + +int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos) +{ + const int fd = *((int *)opaque); + const off_t rc = lseek(fd, (off_t)pos, SEEK_SET); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformSeek */ + +PHYSFS_sint64 __PHYSFS_platformTell(void *opaque) +{ + const int fd = *((int *)opaque); + PHYSFS_sint64 retval; + retval = (PHYSFS_sint64)lseek(fd, 0, SEEK_CUR); + BAIL_IF(retval == -1, errcodeFromErrno(), -1); + return retval; +} /* __PHYSFS_platformTell */ + +PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque) +{ + const int fd = *((int *)opaque); + struct stat statbuf; + BAIL_IF(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1); + return ((PHYSFS_sint64)statbuf.st_size); +} /* __PHYSFS_platformFileLength */ + +int __PHYSFS_platformFlush(void *opaque) +{ + const int fd = *((int *)opaque); + int rc = -1; + if ((fcntl(fd, F_GETFL) & O_ACCMODE) != O_RDONLY) + { + do + { + rc = fsync(fd); + } while ((rc == -1) && (errno == EINTR)); + BAIL_IF(rc == -1, errcodeFromErrno(), 0); + } + return 1; +} /* __PHYSFS_platformFlush */ + +void __PHYSFS_platformClose(void *opaque) +{ + const int fd = *((int *)opaque); + int rc = -1; + do + { + rc = close(fd); /* we don't check this. You should have used flush! */ + } while ((rc == -1) && (errno == EINTR)); + allocator.Free(opaque); +} /* __PHYSFS_platformClose */ + +int __PHYSFS_platformDelete(const char *path) +{ + BAIL_IF(remove(path) == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformDelete */ + +#endif diff --git a/src/physfs_platforms.h b/src/physfs_platforms.h index 6efadaaf..9e2ef91d 100644 --- a/src/physfs_platforms.h +++ b/src/physfs_platforms.h @@ -78,6 +78,12 @@ #elif defined(__3DS__) # define PHYSFS_PLATFORM_CTR 1 # define PHYSFS_NO_CDROM_SUPPORT 1 +#elif defined(__SWITCH__) +# define PHYSFS_PLATFORM_HAC 1 +# define PHYSFS_NO_CDROM_SUPPORT 1 +#elif defined(__WIIU__) +# define PHYSFS_PLATFORM_CAFE 1 +# define PHYSFS_NO_CDROM_SUPPORT 1 #else # error Unknown platform. #endif From 4c682d947ee293f5bb116a1bd828fa6833787bcf Mon Sep 17 00:00:00 2001 From: TurtleP Date: Wed, 20 Mar 2024 01:23:57 -0400 Subject: [PATCH 3/3] update comments at the top --- src/physfs_platform_cafe.c | 6 +++++- src/physfs_platform_ctr.c | 4 ++++ src/physfs_platform_hac.c | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/physfs_platform_cafe.c b/src/physfs_platform_cafe.c index aaabd582..773f707a 100644 --- a/src/physfs_platform_cafe.c +++ b/src/physfs_platform_cafe.c @@ -1,5 +1,9 @@ /* - * Nintendo Switch support routines for PhysicsFS. + * Nintendo Wii U support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by TurtleP */ #define __PHYSICSFS_INTERNAL__ diff --git a/src/physfs_platform_ctr.c b/src/physfs_platform_ctr.c index 47f5f2d1..169502cf 100644 --- a/src/physfs_platform_ctr.c +++ b/src/physfs_platform_ctr.c @@ -1,5 +1,9 @@ /* * Nintendo 3DS support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by TurtleP */ #define __PHYSICSFS_INTERNAL__ diff --git a/src/physfs_platform_hac.c b/src/physfs_platform_hac.c index f930e25b..f86b79c6 100644 --- a/src/physfs_platform_hac.c +++ b/src/physfs_platform_hac.c @@ -1,5 +1,9 @@ /* * Nintendo Switch support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by TurtleP */ #define __PHYSICSFS_INTERNAL__