From 9365e96a13bd0ddb9b89e101686bfde9e5fe2b1e Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 3 Dec 2023 23:23:55 +0100 Subject: [PATCH] Fix relative paths --- ee/libcglue/Makefile | 11 +- ee/libcglue/src/cwd.c | 202 ++++++++++++++++++++++++++++++++ ee/libcglue/src/glue.c | 259 +++++++++++++++-------------------------- ee/libcglue/src/init.c | 24 +--- 4 files changed, 310 insertions(+), 186 deletions(-) create mode 100644 ee/libcglue/src/cwd.c diff --git a/ee/libcglue/Makefile b/ee/libcglue/Makefile index c9dab09fe0a..78a6e67d795 100644 --- a/ee/libcglue/Makefile +++ b/ee/libcglue/Makefile @@ -19,20 +19,22 @@ SLEEP_OBJS = nanosleep.o SJIS_OBJS = isSpecialSJIS.o isSpecialASCII.o strcpy_ascii.o strcpy_sjis.o +CWD_OBJS = __cwd.o __get_drive.o getcwd.o __path_absolute.o __init_cwd.o + PS2SDKAPI_OBJS = _ps2sdk_close.o _ps2sdk_open.o _ps2sdk_read.o _ps2sdk_lseek.o _ps2sdk_lseek64.o _ps2sdk_write.o _ps2sdk_ioctl.o \ _ps2sdk_remove.o _ps2sdk_rename.o _ps2sdk_mkdir.o _ps2sdk_rmdir.o _ps2sdk_stat.o _ps2sdk_readlink.o _ps2sdk_symlink.o \ _ps2sdk_dopen.o _ps2sdk_dread.o _ps2sdk_dclose.o -GLUE_OBJS = __direct_pwd.o __dummy_passwd.o __transform_errno.o __transform64_errno.o compile_time_check.o __normalized_path.o _open.o _close.o _read.o _write.o \ +GLUE_OBJS = __dummy_passwd.o __transform_errno.o __transform64_errno.o compile_time_check.o __normalized_path.o _open.o _close.o _read.o _write.o \ _stat.o lstat.o _fstat.o access.o _fcntl.o getdents.o _lseek.o lseek64.o chdir.o mkdir.o \ - rmdir.o _link.o _unlink.o _rename.o getcwd.o _getpid.o _kill.o _fork.o _wait.o _sbrk.o _gettimeofday.o _times.o ftime.o clock_getres.o clock_gettime.o clock_settime.o \ + rmdir.o _link.o _unlink.o _rename.o _getpid.o _kill.o _fork.o _wait.o _sbrk.o _gettimeofday.o _times.o ftime.o clock_getres.o clock_gettime.o clock_settime.o \ truncate.o symlink.o readlink.o utime.o fchown.o getrandom.o getentropy.o _isatty.o chmod.o fchmod.o fchmodat.o pathconf.o \ fsync.o getuid.o geteuid.o getpwuid.o getpwnam.o LOCK_OBJS = __retarget_lock_init.o __retarget_lock_acquire.o __retarget_lock_release.o __retarget_lock_try_acquire.o __retarget_lock_close.o \ __retarget_lock_init_recursive.o __retarget_lock_acquire_recursive.o __retarget_lock_release_recursive.o __retarget_lock_try_acquire_recursive.o __retarget_lock_close_recursive.o -EE_OBJS = $(CORE_OBJS) $(SJIS_OBJS) $(TIME_OBJS) $(FDMAN_OBJS) $(INIT_OBJS) $(SLEEP_OBJS) $(TERMINATE_OBJS) $(PS2SDKAPI_OBJS) $(GLUE_OBJS) $(LOCK_OBJS) +EE_OBJS = $(CORE_OBJS) $(SJIS_OBJS) $(TIME_OBJS) $(FDMAN_OBJS) $(INIT_OBJS) $(SLEEP_OBJS) $(TERMINATE_OBJS) $(CWD_OBJS) $(PS2SDKAPI_OBJS) $(GLUE_OBJS) $(LOCK_OBJS) include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/ee/Rules.lib.make @@ -48,6 +50,9 @@ $(SLEEP_OBJS:%=$(EE_OBJS_DIR)%): $(EE_SRC_DIR)sleep.c $(GLUE_OBJS:%=$(EE_OBJS_DIR)%): $(EE_SRC_DIR)glue.c $(EE_C_COMPILE) -DF_$(*:$(EE_OBJS_DIR)%=%) $< -c -o $@ +$(CWD_OBJS:%=$(EE_OBJS_DIR)%): $(EE_SRC_DIR)cwd.c + $(EE_C_COMPILE) -DF_$(*:$(EE_OBJS_DIR)%=%) $< -c -o $@ + $(PS2SDKAPI_OBJS:%=$(EE_OBJS_DIR)%): $(EE_SRC_DIR)ps2sdkapi.c $(EE_C_COMPILE) -DF_$(*:$(EE_OBJS_DIR)%=%) $< -c -o $@ diff --git a/ee/libcglue/src/cwd.c b/ee/libcglue/src/cwd.c new file mode 100644 index 00000000000..654fdc22fb2 --- /dev/null +++ b/ee/libcglue/src/cwd.c @@ -0,0 +1,202 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include +#include +#include +#include +#include +#include + +#ifdef F___cwd +/* the present working directory variable. */ +char __cwd[MAXNAMLEN + 1] = { 0 }; +#else +extern char __cwd[MAXNAMLEN + 1]; +#endif + +#ifdef F___get_drive +/* Return the number of bytes taken up by the "drive:" prefix, + or -1 if it's not found */ +int __get_drive(const char *d) +{ + int i; + for(i=0; d[i]; i++) { + if(! ((d[i] >= 'a' && d[i] <= 'z') || + (d[i] >= '0' && d[i] <= '9') )) + break; + } + if(d[i] == ':') return i+1; + return -1; +} +#else +int __get_drive(const char *d); +#endif + +#ifdef F_getcwd +char *getcwd(char *buf, size_t size) +{ + if(!buf) { + errno = EINVAL; + return NULL; + } + + if(strlen(__cwd) >= size) { + errno = ERANGE; + return NULL; + } + + strcpy(buf, __cwd); + return buf; +} +#endif + +#ifdef F___path_absolute +/* Like strcpy, but returns 0 if the string doesn't fit */ +static int __safe_strcpy(char *out, const char *in, int maxlen) +{ + for( ; maxlen > 0 && *in ; maxlen-- ) + *(out++) = *(in++); + if(maxlen < 1) return 0; + *out = 0; + return 1; +} + +/* Like strcat, but returns 0 if the string doesn't fit */ +static int __safe_strcat(char *out, const char *in, int maxlen) +{ + for( ; *out ; out++,maxlen-- ) + continue; + return __safe_strcpy(out, in, maxlen); +} + +/* Normalize a pathname (without leading "drive:") by removing + . and .. components, duplicated /, etc. */ +static int __path_normalize(char *out, int len) +{ + int i, j; + int first, next; + + /* First append "/" to make the rest easier */ + if(!__safe_strcat(out,"/",len)) return -10; + + /* Convert "//" to "/" */ + for(i=0; out[i+1]; i++) { + if(out[i]=='/' && out[i+1]=='/') { + for(j=i+1; out[j]; j++) + out[j] = out[j+1]; + i--; + } + } + + /* Convert "/./" to "/" */ + for(i=0; out[i] && out[i+1] && out[i+2]; i++) { + if(out[i]=='/' && out[i+1]=='.' && out[i+2]=='/') { + for(j=i+1; out[j]; j++) + out[j] = out[j+2]; + i--; + } + } + + /* Convert "/asdf/../" to "/" until we can't anymore. Also + * convert leading "/../" to "/" */ + first = next = 0; + while(1) { + /* If a "../" follows, remove it and the parent */ + if(out[next+1] && out[next+1]=='.' && + out[next+2] && out[next+2]=='.' && + out[next+3] && out[next+3]=='/') { + for(j=0; out[first+j+1]; j++) + out[first+j+1] = out[next+j+4]; + first = next = 0; + continue; + } + + /* Find next slash */ + first = next; + for(next=first+1; out[next] && out[next] != '/'; next++) + continue; + if(!out[next]) break; + } + + /* Remove trailing "/" */ + for(i=1; out[i]; i++) + continue; + if(i >= 1 && out[i-1] == '/') + out[i-1] = 0; + + return 0; +} + +/* Convert relative path to absolute path. */ +int __path_absolute(const char *in, char *out, int len) +{ + int dr; + + /* See what the relative URL starts with */ + dr = __get_drive(in); + if(dr > 0 && in[dr] == '/') { + /* It starts with "drive:/", so it's already absolute */ + if(!__safe_strcpy(out, in, len)) + return -1; + } else if(in[0] == '/') { + /* It's absolute, but missing the drive, so use cwd's drive */ + if(strlen(__cwd) >= len) + return -2; + strcpy(out, __cwd); + dr = __get_drive(out); + out[dr] = 0; + if(!__safe_strcat(out, in, len)) + return -3; + } else { + /* It's not absolute, so append it to the current cwd */ + if(strlen(__cwd) >= len) + return -4; + strcpy(out, __cwd); + if(!__safe_strcat(out, "/", len)) + return -6; + if(!__safe_strcat(out, in, len)) + return -7; + } + + /* Now normalize the pathname portion */ + dr = __get_drive(out); + if(dr < 0) dr = 0; + return __path_normalize(out + dr, len - dr); +} +#endif + +#ifdef F___init_cwd +/* Set the current working directory (CWD) to the path where the module was launched. */ +void __init_cwd(int argc, char ** argv) +{ + if (argc == 0) // naplink! + { + chdir("host:"); + } else { + char * p, * s = 0; + // let's find the last slash, or at worst, the : + for (p = argv[0]; *p; p++) { + if ((*p == '/') || (*p == '\\') || (*p == ':')) { + s = p; + } + } + // Nothing?! strange, let's use host. + if (!s) { + chdir("host:"); + } else { + char backup = *(++s); + *s = 0; + chdir(argv[0]); + *s = backup; + } + } +} +#endif \ No newline at end of file diff --git a/ee/libcglue/src/glue.c b/ee/libcglue/src/glue.c index bdf9b513771..cf49dfcbcf4 100644 --- a/ee/libcglue/src/glue.c +++ b/ee/libcglue/src/glue.c @@ -43,16 +43,12 @@ #include "timer_alarm.h" #include "fdman.h" +/* Functions from cwd.c */ +extern char __cwd[MAXNAMLEN + 1]; +int __path_absolute(const char *in, char *out, int len); extern void * _end; -#ifdef F___direct_pwd -/* the present working directory variable. */ -char __direct_pwd[256] = ""; -#else -extern char __direct_pwd[256]; -#endif - #ifdef F___dummy_passwd /* the present working directory variable. */ struct passwd __dummy_passwd = { "ps2_user", "xxx", 1000, 1000, "", "", "/", "" }; @@ -134,132 +130,17 @@ void compile_time_check() { } #endif -#ifdef F___normalized_path -/* Sanitize a pathname by removing . and .. components, duplicated /, etc. */ -static char* sanitize_path(const char *path_name) -{ - int i, j; - int first, next; - static char out[255]; - - /* First copy the path into our temp buffer */ - strcpy(out, path_name); - /* Then append "/" to make the rest easier */ - strcat(out,"/"); - - /* Convert "//" to "/" */ - for(i=0; out[i+1]; i++) { - if(out[i]=='/' && out[i+1]=='/') { - for(j=i+1; out[j]; j++) - out[j] = out[j+1]; - i--; - ;} - } - - /* Convert "/./" to "/" */ - for(i=0; out[i] && out[i+1] && out[i+2]; i++) { - if(out[i]=='/' && out[i+1]=='.' && out[i+2]=='/') { - for(j=i+1; out[j]; j++) - out[j] = out[j+2]; - i--; - } - } - - /* Convert "/path/../" to "/" until we can't anymore. Also convert leading - * "/../" to "/" */ - first = next = 0; - while(1) { - /* If a "../" follows, remove it and the parent */ - if(out[next+1] && out[next+1]=='.' && - out[next+2] && out[next+2]=='.' && - out[next+3] && out[next+3]=='/') { - for(j=0; out[first+j+1]; j++) - out[first+j+1] = out[next+j+4]; - first = next = 0; - continue; - } - - /* Find next slash */ - first = next; - for(next=first+1; out[next] && out[next] != '/'; next++) - continue; - if(!out[next]) break; - } - - /* Remove trailing "/" */ - for(i=1; out[i]; i++) - continue; - if(i >= 1 && out[i-1] == '/') - out[i-1] = 0; - - return (char*)out; -} - -static int isCdromPath(const char *path) -{ - return !strncmp(path, "cdrom0:", 7) || !strncmp(path, "cdrom:", 6); -} - -char *__normalized_path(const char *originalPath) -{ - const char *buf = sanitize_path(originalPath); - static char b_fname[FILENAME_MAX]; - - if (!strchr(buf, ':')) { // filename doesn't contain device - if (buf[0] == '/' || buf[0] == '\\') { // does it contain root ? - char *device_end = strchr(__direct_pwd, ':'); - if (device_end) { // yes, let's strip pwd a bit to keep device only - strncpy(b_fname, __direct_pwd, device_end - __direct_pwd); - strcpy(b_fname + (device_end - __direct_pwd), buf); - } else { // but pwd doesn't contain any device, let's default to host - strcpy(b_fname, "host:"); - strcpy(b_fname + 5, buf); - } - } else { // otherwise, it's relative directory, let's copy pwd straight - int b_fname_len = strlen(__direct_pwd); - if (!strchr(__direct_pwd, ':')) { // check if pwd contains device name - strcpy(b_fname, "host:"); - strcpy(b_fname + 5, __direct_pwd); - if (!(__direct_pwd[b_fname_len - 1] == '/' || __direct_pwd[b_fname_len - 1] == '\\')) { // does it has trailing slash ? - if(isCdromPath(b_fname)) { - b_fname[b_fname_len + 5] = '\\'; - b_fname_len++; - } else { - b_fname[b_fname_len + 5] = '/'; - b_fname_len++; - } - } - b_fname_len += 5; - strcpy(b_fname + b_fname_len, buf); - } else { // device name is here - if (b_fname_len) { - strcpy(b_fname, __direct_pwd); - if (!(b_fname[b_fname_len - 1] == '/' || b_fname[b_fname_len - 1] == '\\')) { - if(isCdromPath(b_fname)) { - b_fname[b_fname_len] = '\\'; - b_fname_len++; - } else { - b_fname[b_fname_len] = '/'; - b_fname_len++; - } - } - strcpy(b_fname + b_fname_len, buf); - } - } - } - } - - return (char *)b_fname; -} -#else -extern char *__normalized_path(const char *path_name); -#endif - #ifdef F__open int _open(const char *buf, int flags, ...) { int iop_flags = 0; int is_dir = 0; int iop_fd, fd; + char t_fname[MAXNAMLEN + 1]; + + if(__path_absolute(buf, t_fname, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } // newlib frags differ from iop flags if ((flags & 3) == O_RDONLY) iop_flags |= IOP_O_RDONLY; @@ -276,7 +157,6 @@ int _open(const char *buf, int flags, ...) { is_dir = 1; } - char *t_fname = __normalized_path(buf); iop_fd = is_dir ? _ps2sdk_dopen(t_fname) : _ps2sdk_open(t_fname, iop_flags); if (iop_fd >= 0) { fd = __fdman_get_new_descriptor(); @@ -394,15 +274,27 @@ int _write(int fd, const void *buf, size_t nbytes) { #ifdef F__stat int _stat(const char *path, struct stat *buf) { - const char *normalized = __normalized_path(path); - return __transform_errno(_ps2sdk_stat(normalized, buf)); + char dest[MAXNAMLEN + 1]; + + if(__path_absolute(path, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __transform_errno(_ps2sdk_stat(dest, buf)); } #endif #ifdef F_lstat int lstat(const char *path, struct stat *buf) { - const char *normalized = __normalized_path(path); - return __transform_errno(stat(normalized, buf)); + char dest[MAXNAMLEN + 1]; + + if(__path_absolute(path, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __transform_errno(stat(dest, buf)); } #endif @@ -518,9 +410,9 @@ int getdents(int fd, void *dd_buf, int count) rv = _ps2sdk_dread(__descriptormap[fd]->descriptor, dirp); if (rv < 0) { - return __transform_errno(rv); + return __transform_errno(rv); } else if (rv == 0) { - return read; + return read; } read += sizeof(struct dirent); @@ -585,58 +477,85 @@ off_t _lseek(int fd, off_t offset, int whence) #ifdef F_lseek64 off64_t lseek64(int fd, off64_t offset, int whence) { - return __transform64_errno(_ps2sdk_lseek64(fd, offset, whence)); + return __transform64_errno(_ps2sdk_lseek64(fd, offset, whence)); } #endif #ifdef F_chdir int chdir(const char *path) { - const char *normalized = __normalized_path(path); - strcpy(__direct_pwd, normalized); - return 0; + char dest[MAXNAMLEN + 1]; + + if(__path_absolute(path, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + strcpy(__cwd, dest); + return 0; } #endif #ifdef F_mkdir int mkdir(const char *path, mode_t mode) { - const char *normalized = __normalized_path(path); - return __transform_errno(_ps2sdk_mkdir(normalized, mode)); + char dest[MAXNAMLEN + 1]; + + if(__path_absolute(path, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __transform_errno(_ps2sdk_mkdir(dest, mode)); } #endif #ifdef F_rmdir int rmdir(const char *path) { - const char *normalized = __normalized_path(path); - return __transform_errno(_ps2sdk_rmdir(normalized)); + char dest[MAXNAMLEN + 1]; + + if(__path_absolute(path, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __transform_errno(_ps2sdk_rmdir(dest)); } #endif #ifdef F__link int _link(const char *old, const char *new) { - errno = ENOSYS; + errno = ENOSYS; return -1; /* not supported */ } #endif #ifdef F__unlink int _unlink(const char *path) { - const char *normalized = __normalized_path(path); - return __transform_errno(_ps2sdk_remove(normalized)); + char dest[MAXNAMLEN + 1]; + if(__path_absolute(path, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __transform_errno(_ps2sdk_remove(dest)); } #endif #ifdef F__rename int _rename(const char *old, const char *new) { - const char *normalized_old = __normalized_path(old); - const char *normalized_new = __normalized_path(new); - return __transform_errno(_ps2sdk_rename(normalized_old, normalized_new)); -} -#endif + char oldname[MAXNAMLEN + 1]; + char newname[MAXNAMLEN + 1]; + + if(__path_absolute(old, oldname, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } -#ifdef F_getcwd -char *getcwd(char *buf, size_t len) { - strncpy(buf, __direct_pwd, len); - return buf; + if(__path_absolute(new, newname, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __transform_errno(_ps2sdk_rename(oldname, newname)); } #endif @@ -800,8 +719,8 @@ int clock_settime(clockid_t clk_id, const struct timespec *tp) { int truncate(const char *path, off_t length) { ssize_t bytes_read; - int fd, res; - char buff[length]; + int fd, res; + char buff[length]; fd = open(path, O_RDONLY); if (fd < 0) { @@ -831,17 +750,33 @@ int truncate(const char *path, off_t length) #ifdef F_symlink int symlink(const char *target, const char *linkpath) { - const char *normalized_target = __normalized_path(target); - const char *normalized_linkpath = __normalized_path(linkpath); - return __transform_errno(_ps2sdk_symlink(normalized_target, normalized_linkpath)); + char dest_target[MAXNAMLEN + 1]; + char dest_linkpath[MAXNAMLEN + 1]; + + if(__path_absolute(target, dest_target, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + if(__path_absolute(linkpath, dest_linkpath, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __transform_errno(_ps2sdk_symlink(dest_target, dest_linkpath)); } #endif #ifdef F_readlink ssize_t readlink(const char *path, char *buf, size_t bufsiz) { - const char *normalized = __normalized_path(path); - return __transform_errno(_ps2sdk_readlink(normalized, buf, bufsiz)); + char dest[MAXNAMLEN + 1]; + + if(__path_absolute(path, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + return __transform_errno(_ps2sdk_readlink(dest, buf, bufsiz)); } #endif diff --git a/ee/libcglue/src/init.c b/ee/libcglue/src/init.c index 90cbe29c266..37b150e31af 100644 --- a/ee/libcglue/src/init.c +++ b/ee/libcglue/src/init.c @@ -13,6 +13,7 @@ * The global init/deinit code for our crt0. */ +void __init_cwd(int argc, char ** argv); void _libcglue_timezone_update(); void _libcglue_rtc_update(); void __fdman_init(); @@ -76,27 +77,8 @@ void _libcglue_deinit() __attribute__((weak)) void _libcglue_args_parse(int argc, char ** argv) { - if (argc == 0) // naplink! - { - chdir("host:"); - } else { - char * p, * s = 0; - // let's find the last slash, or at worst, the : - for (p = argv[0]; *p; p++) { - if ((*p == '/') || (*p == '\\') || (*p == ':')) { - s = p; - } - } - // Nothing?! strange, let's use host. - if (!s) { - chdir("host:"); - } else { - char backup = *(++s); - *s = 0; - chdir(argv[0]); - *s = backup; - } - } + /* Initialize cwd from this program's path */ + __init_cwd(argc, argv); } #endif