diff --git a/libretro/libretro-common/file/file_path.c b/libretro/libretro-common/file/file_path.c index bae8127..90320c7 100644 --- a/libretro/libretro-common/file/file_path.c +++ b/libretro/libretro-common/file/file_path.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2019 The RetroArch team +/* Copyright (C) 2010-2020 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (file_path.c). @@ -32,8 +32,6 @@ #include #include #include -#define VFS_FRONTEND -#include /* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */ #ifdef __APPLE__ @@ -87,7 +85,7 @@ #include #endif -#if defined(__CELLOS_LV2__) +#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) #include #endif @@ -114,137 +112,6 @@ #endif -static retro_vfs_stat_t path_stat_cb = NULL; -static retro_vfs_mkdir_t path_mkdir_cb = NULL; - -void path_vfs_init(const struct retro_vfs_interface_info* vfs_info) -{ - const struct retro_vfs_interface* - vfs_iface = vfs_info->iface; - - path_stat_cb = NULL; - path_mkdir_cb = NULL; - - if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface) - return; - - path_stat_cb = vfs_iface->stat; - path_mkdir_cb = vfs_iface->mkdir; -} - -#define path_stat_internal(path, size) ((path_stat_cb != NULL) ? path_stat_cb((path), (size)) : retro_vfs_stat_impl((path), (size))) - -#define path_mkdir_norecurse(dir) ((path_mkdir_cb != NULL) ? path_mkdir_cb((dir)) : retro_vfs_mkdir_impl((dir))) - -int path_stat(const char *path) -{ - return path_stat_internal(path, NULL); -} - -/** - * path_is_directory: - * @path : path - * - * Checks if path is a directory. - * - * Returns: true (1) if path is a directory, otherwise false (0). - */ -bool path_is_directory(const char *path) -{ - return (path_stat_internal(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0; -} - -bool path_is_character_special(const char *path) -{ - return (path_stat_internal(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0; -} - -bool path_is_valid(const char *path) -{ - return (path_stat_internal(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0; -} - -int32_t path_get_size(const char *path) -{ - int32_t filesize = 0; - if (path_stat_internal(path, &filesize) != 0) - return filesize; - - return -1; -} - -/** - * path_mkdir: - * @dir : directory - * - * Create directory on filesystem. - * - * Returns: true (1) if directory could be created, otherwise false (0). - **/ -bool path_mkdir(const char *dir) -{ - bool sret = false; - bool norecurse = false; - char *basedir = NULL; - - if (!(dir && *dir)) - return false; - - /* Use heap. Real chance of stack - * overflow if we recurse too hard. */ - basedir = strdup(dir); - - if (!basedir) - return false; - - path_parent_dir(basedir); - - if (!*basedir || !strcmp(basedir, dir)) - { - free(basedir); - return false; - } - -#if defined(GEKKO) - { - size_t len = strlen(basedir); - - /* path_parent_dir() keeps the trailing slash. - * On Wii, mkdir() fails if the path has a - * trailing slash... - * We must therefore remove it. */ - if (len > 0) - if (basedir[len - 1] == '/') - basedir[len - 1] = '\0'; - } -#endif - - if (path_is_directory(basedir)) - norecurse = true; - else - { - sret = path_mkdir(basedir); - - if (sret) - norecurse = true; - } - - free(basedir); - - if (norecurse) - { - int ret = path_mkdir_norecurse(dir); - - /* Don't treat this as an error. */ - if (ret == -2 && path_is_directory(dir)) - return true; - - return (ret == 0); - } - - return sret; -} - /** * path_get_archive_delim: * @path : path @@ -393,11 +260,11 @@ void fill_pathname(char *out_path, const char *in_path, * present in 'in_path', it will be ignored. * */ -void fill_pathname_noext(char *out_path, const char *in_path, +size_t fill_pathname_noext(char *out_path, const char *in_path, const char *replace, size_t size) { strlcpy(out_path, in_path, size); - strlcat(out_path, replace, size); + return strlcat(out_path, replace, size); } char *find_last_slash(const char *str) @@ -435,12 +302,8 @@ void fill_pathname_slash(char *path, size_t size) /* Try to preserve slash type. */ if (last_slash != (path + path_len - 1)) { - char join_str[2]; - - join_str[0] = '\0'; - - strlcpy(join_str, last_slash, sizeof(join_str)); - strlcat(path, join_str, size); + path[path_len] = last_slash[0]; + path[path_len+1] = '\0'; } } @@ -461,7 +324,7 @@ void fill_pathname_slash(char *path, size_t size) * E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c", * replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm" **/ -void fill_pathname_dir(char *in_dir, const char *in_basename, +size_t fill_pathname_dir(char *in_dir, const char *in_basename, const char *replace, size_t size) { const char *base = NULL; @@ -469,7 +332,7 @@ void fill_pathname_dir(char *in_dir, const char *in_basename, fill_pathname_slash(in_dir, size); base = path_basename(in_basename); strlcat(in_dir, base, size); - strlcat(in_dir, replace, size); + return strlcat(in_dir, replace, size); } /** @@ -480,14 +343,14 @@ void fill_pathname_dir(char *in_dir, const char *in_basename, * * Copies basename of @in_path into @out_path. **/ -void fill_pathname_base(char *out, const char *in_path, size_t size) +size_t fill_pathname_base(char *out, const char *in_path, size_t size) { const char *ptr = path_basename(in_path); if (!ptr) ptr = in_path; - strlcpy(out, ptr, size); + return strlcpy(out, ptr, size); } void fill_pathname_base_noext(char *out, @@ -497,12 +360,12 @@ void fill_pathname_base_noext(char *out, path_remove_extension(out); } -void fill_pathname_base_ext(char *out, +size_t fill_pathname_base_ext(char *out, const char *in_path, const char *ext, size_t size) { fill_pathname_base_noext(out, in_path, size); - strlcat(out, ext, size); + return strlcat(out, ext, size); } /** @@ -597,7 +460,7 @@ void fill_pathname_parent_dir(char *out_dir, * E.g.: * out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}" **/ -void fill_dated_filename(char *out_filename, +size_t fill_dated_filename(char *out_filename, const char *ext, size_t size) { time_t cur_time = time(NULL); @@ -605,7 +468,7 @@ void fill_dated_filename(char *out_filename, strftime(out_filename, size, "RetroArch-%m%d-%H%M%S", tm_); - strlcat(out_filename, ext, size); + return strlcat(out_filename, ext, size); } /** @@ -629,11 +492,20 @@ void fill_str_dated_filename(char *out_filename, const struct tm* tm_ = localtime(&cur_time); format[0] = '\0'; - strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", tm_); - fill_pathname_join_concat_noext(out_filename, - in_str, format, ext, - size); + if (string_is_empty(ext)) + { + strftime(format, sizeof(format), "-%y%m%d-%H%M%S", tm_); + fill_pathname_noext(out_filename, in_str, format, size); + } + else + { + strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", tm_); + + fill_pathname_join_concat_noext(out_filename, + in_str, format, ext, + size); + } } /** @@ -646,6 +518,7 @@ void fill_str_dated_filename(char *out_filename, void path_basedir(char *path) { char *last = NULL; + if (strlen(path) < 2) return; @@ -747,35 +620,131 @@ bool path_is_absolute(const char *path) /** * path_resolve_realpath: - * @buf : buffer for path + * @buf : input and output buffer for path * @size : size of buffer + * @resolve_symlinks : whether to resolve symlinks or not * - * Turns relative paths into absolute paths and - * resolves use of "." and ".." in absolute paths. - * If relative, rebases on current working dir. + * Resolves use of ".", "..", multiple slashes etc in absolute paths. + * + * Relative paths are rebased on the current working dir. + * + * Returns: @buf if successful, NULL otherwise. + * Note: Not implemented on consoles + * Note: Symlinks are only resolved on Unix-likes + * Note: The current working dir might not be what you expect, + * e.g. on Android it is "/" + * Use of fill_pathname_resolve_relative() should be prefered **/ -void path_resolve_realpath(char *buf, size_t size) +char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks) { #if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL) char tmp[PATH_MAX_LENGTH]; - - tmp[0] = '\0'; - - strlcpy(tmp, buf, sizeof(tmp)); - #ifdef _WIN32 + strlcpy(tmp, buf, sizeof(tmp)); if (!_fullpath(buf, tmp, size)) + { strlcpy(buf, tmp, size); + return NULL; + } + return buf; #else + size_t t; + char *p; + const char *next; + const char *buf_end; - /* NOTE: realpath() expects at least PATH_MAX_LENGTH bytes in buf. - * Technically, PATH_MAX_LENGTH needn't be defined, but we rely on it anyways. - * POSIX 2008 can automatically allocate for you, - * but don't rely on that. */ - if (!realpath(tmp, buf)) - strlcpy(buf, tmp, size); + if (resolve_symlinks) + { + strlcpy(tmp, buf, sizeof(tmp)); + + /* NOTE: realpath() expects at least PATH_MAX_LENGTH bytes in buf. + * Technically, PATH_MAX_LENGTH needn't be defined, but we rely on it anyways. + * POSIX 2008 can automatically allocate for you, + * but don't rely on that. */ + if (!realpath(tmp, buf)) + { + strlcpy(buf, tmp, size); + return NULL; + } + + return buf; + } + + t = 0; /* length of output */ + buf_end = buf + strlen(buf); + + if (!path_is_absolute(buf)) + { + size_t len; + /* rebase on working directory */ + if (!getcwd(tmp, PATH_MAX_LENGTH-1)) + return NULL; + + len = strlen(tmp); + t += len; + + if (tmp[len-1] != '/') + tmp[t++] = '/'; + + if (string_is_empty(buf)) + goto end; + + p = buf; + } + else + { + /* UNIX paths can start with multiple '/', copy those */ + for (p = buf; *p == '/'; p++) + tmp[t++] = '/'; + } + + /* p points to just after a slash while 'next' points to the next slash + * if there are no slashes, they point relative to where one would be */ + do + { + next = strchr(p, '/'); + if (!next) + next = buf_end; + + if ((next - p == 2 && p[0] == '.' && p[1] == '.')) + { + p += 3; + + /* fail for illegal /.., //.. etc */ + if (t == 1 || tmp[t-2] == '/') + return NULL; + + /* delete previous segment in tmp by adjusting size t + * tmp[t-1] == '/', find '/' before that */ + t = t-2; + while (tmp[t] != '/') + t--; + t++; + } + else if (next - p == 1 && p[0] == '.') + p += 2; + else if (next - p == 0) + p += 1; + else + { + /* fail when truncating */ + if (t + next-p+1 > PATH_MAX_LENGTH-1) + return NULL; + + while (p <= next) + tmp[t++] = *p++; + } + + } + while (next < buf_end); + +end: + tmp[t] = '\0'; + strlcpy(buf, tmp, size); + return buf; #endif #endif + return NULL; } /** @@ -792,10 +761,10 @@ void path_resolve_realpath(char *buf, size_t size) * * E.g. path /a/b/e/f.cg with base /a/b/c/d/ turns into ../../e/f.cg **/ -void path_relative_to(char *out, +size_t path_relative_to(char *out, const char *path, const char *base, size_t size) { - unsigned i; + size_t i; const char *trimmed_path, *trimmed_base; #ifdef _WIN32 @@ -803,10 +772,7 @@ void path_relative_to(char *out, if (strlen(path) >= 2 && strlen(base) >= 2 && path[1] == ':' && base[1] == ':' && path[0] != base[0]) - { - out[0] = '\0'; - strlcat(out, path, size); - } + return strlcpy(out, path, size); #endif /* Trim common beginning */ @@ -818,9 +784,10 @@ void path_relative_to(char *out, /* Each segment of base turns into ".." */ out[0] = '\0'; for (i = 0; trimmed_base[i]; i++) - if (trimmed_base[i] == '/' || trimmed_base[i] == '\\') - strlcat(out, "../", size); /* Use '/' as universal separator */ - strlcat(out, trimmed_path, size); + if (trimmed_base[i] == path_default_slash_c()) + strlcat(out, ".." path_default_slash(), size); + + return strlcat(out, trimmed_path, size); } /** @@ -846,7 +813,7 @@ void fill_pathname_resolve_relative(char *out_path, fill_pathname_basedir(out_path, in_refpath, size); strlcat(out_path, in_path, size); - path_resolve_realpath(out_path, size); + path_resolve_realpath(out_path, size, false); } /** @@ -860,7 +827,7 @@ void fill_pathname_resolve_relative(char *out_path, * Makes sure not to get two consecutive slashes * between directory and path. **/ -void fill_pathname_join(char *out_path, +size_t fill_pathname_join(char *out_path, const char *dir, const char *path, size_t size) { if (out_path != dir) @@ -869,10 +836,10 @@ void fill_pathname_join(char *out_path, if (*out_path) fill_pathname_slash(out_path, size); - strlcat(out_path, path, size); + return strlcat(out_path, path, size); } -void fill_pathname_join_special_ext(char *out_path, +size_t fill_pathname_join_special_ext(char *out_path, const char *dir, const char *path, const char *last, const char *ext, size_t size) @@ -882,26 +849,25 @@ void fill_pathname_join_special_ext(char *out_path, fill_pathname_slash(out_path, size); strlcat(out_path, last, size); - strlcat(out_path, ext, size); + return strlcat(out_path, ext, size); } -void fill_pathname_join_concat_noext( - char *out_path, +size_t fill_pathname_join_concat_noext(char *out_path, const char *dir, const char *path, const char *concat, size_t size) { fill_pathname_noext(out_path, dir, path, size); - strlcat(out_path, concat, size); + return strlcat(out_path, concat, size); } -void fill_pathname_join_concat(char *out_path, +size_t fill_pathname_join_concat(char *out_path, const char *dir, const char *path, const char *concat, size_t size) { fill_pathname_join(out_path, dir, path, size); - strlcat(out_path, concat, size); + return strlcat(out_path, concat, size); } void fill_pathname_join_noext(char *out_path, @@ -922,7 +888,7 @@ void fill_pathname_join_noext(char *out_path, * Joins a directory (@dir) and path (@path) together * using the given delimiter (@delim). **/ -void fill_pathname_join_delim(char *out_path, const char *dir, +size_t fill_pathname_join_delim(char *out_path, const char *dir, const char *path, const char delim, size_t size) { size_t copied; @@ -936,15 +902,16 @@ void fill_pathname_join_delim(char *out_path, const char *dir, out_path[copied+1] = '\0'; if (path) - strlcat(out_path, path, size); + copied = strlcat(out_path, path, size); + return copied; } -void fill_pathname_join_delim_concat(char *out_path, const char *dir, +size_t fill_pathname_join_delim_concat(char *out_path, const char *dir, const char *path, const char delim, const char *concat, size_t size) { fill_pathname_join_delim(out_path, dir, path, delim, size); - strlcat(out_path, concat, size); + return strlcat(out_path, concat, size); } /** @@ -962,7 +929,7 @@ void fill_pathname_join_delim_concat(char *out_path, const char *dir, * E.g.: "/path/to/game.img" -> game.img * "/path/to/myarchive.7z#folder/to/game.img" -> game.img */ -void fill_short_pathname_representation(char* out_rep, +size_t fill_short_pathname_representation(char* out_rep, const char *in_path, size_t size) { char path_short[PATH_MAX_LENGTH]; @@ -972,7 +939,7 @@ void fill_short_pathname_representation(char* out_rep, fill_pathname(path_short, path_basename(in_path), "", sizeof(path_short)); - strlcpy(out_rep, path_short, size); + return strlcpy(out_rep, path_short, size); } void fill_short_pathname_representation_noext(char* out_rep, @@ -1189,10 +1156,27 @@ void fill_pathname_application_path(char *s, size_t len) CFURLRef bundle_url = CFBundleCopyBundleURL(bundle); CFStringRef bundle_path = CFURLCopyPath(bundle_url); CFStringGetCString(bundle_path, s, len, kCFStringEncodingUTF8); +#ifdef HAVE_COCOATOUCH + { + /* This needs to be done so that the path becomes + * /private/var/... and this + * is used consistently throughout for the iOS bundle path */ + char resolved_bundle_dir_buf[PATH_MAX_LENGTH] = {0}; + if (realpath(s, resolved_bundle_dir_buf)) + { + strlcpy(s, resolved_bundle_dir_buf, len - 1); + strlcat(s, "/", len); + } + } +#endif + CFRelease(bundle_path); CFRelease(bundle_url); - +#ifndef HAVE_COCOATOUCH + /* Not sure what this does but it breaks + * stuff for iOS, so skipping */ retro_assert(strlcat(s, "nobin", len) < len); +#endif return; } #elif defined(__HAIKU__) @@ -1265,8 +1249,8 @@ void fill_pathname_home_dir(char *s, size_t len) bool is_path_accessible_using_standard_io(const char *path) { + bool result = true; #ifdef __WINRT__ - bool result; size_t path_sizeof = PATH_MAX_LENGTH * sizeof(char); char *relative_path_abbrev = (char*)malloc(path_sizeof); fill_pathname_abbreviate_special(relative_path_abbrev, path, path_sizeof); @@ -1274,8 +1258,6 @@ bool is_path_accessible_using_standard_io(const char *path) result = strlen(relative_path_abbrev) >= 2 && (relative_path_abbrev[0] == ':' || relative_path_abbrev[0] == '~') && path_char_is_slash(relative_path_abbrev[1]); free(relative_path_abbrev); - return result; -#else - return true; #endif + return result; } diff --git a/libretro/libretro-common/include/file/file_path.h b/libretro/libretro-common/include/file/file_path.h index 0dcb7c1..fb5afe4 100644 --- a/libretro/libretro-common/include/file/file_path.h +++ b/libretro/libretro-common/include/file/file_path.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2019 The RetroArch team +/* Copyright (C) 2010-2020 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (file_path.h). @@ -147,14 +147,22 @@ void path_parent_dir(char *path); /** * path_resolve_realpath: - * @buf : buffer for path + * @buf : input and output buffer for path * @size : size of buffer + * @resolve_symlinks : whether to resolve symlinks or not * - * Turns relative paths into absolute paths and - * resolves use of "." and ".." in absolute paths. - * If relative, rebases on current working dir. + * Resolves use of ".", "..", multiple slashes etc in absolute paths. + * + * Relative paths are rebased on the current working dir. + * + * Returns: @buf if successful, NULL otherwise. + * Note: Not implemented on consoles + * Note: Symlinks are only resolved on Unix-likes + * Note: The current working dir might not be what you expect, + * e.g. on Android it is "/" + * Use of fill_pathname_resolve_relative() should be prefered **/ -void path_resolve_realpath(char *buf, size_t size); +char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks); /** * path_relative_to: @@ -170,7 +178,7 @@ void path_resolve_realpath(char *buf, size_t size); * * E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp **/ -void path_relative_to(char *out, const char *path, const char *base, size_t size); +size_t path_relative_to(char *out, const char *path, const char *base, size_t size); /** * path_is_absolute: @@ -218,7 +226,7 @@ void fill_pathname(char *out_path, const char *in_path, * E.g.: * out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}" **/ -void fill_dated_filename(char *out_filename, +size_t fill_dated_filename(char *out_filename, const char *ext, size_t size); /** @@ -251,7 +259,7 @@ void fill_str_dated_filename(char *out_filename, * present in 'in_path', it will be ignored. * */ -void fill_pathname_noext(char *out_path, const char *in_path, +size_t fill_pathname_noext(char *out_path, const char *in_path, const char *replace, size_t size); /** @@ -281,7 +289,7 @@ char *find_last_slash(const char *str); * E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c", * replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm" **/ -void fill_pathname_dir(char *in_dir, const char *in_basename, +size_t fill_pathname_dir(char *in_dir, const char *in_basename, const char *replace, size_t size); /** @@ -292,12 +300,12 @@ void fill_pathname_dir(char *in_dir, const char *in_basename, * * Copies basename of @in_path into @out_path. **/ -void fill_pathname_base(char *out_path, const char *in_path, size_t size); +size_t fill_pathname_base(char *out_path, const char *in_path, size_t size); void fill_pathname_base_noext(char *out_dir, const char *in_path, size_t size); -void fill_pathname_base_ext(char *out, +size_t fill_pathname_base_ext(char *out, const char *in_path, const char *ext, size_t size); @@ -368,21 +376,20 @@ void fill_pathname_resolve_relative(char *out_path, const char *in_refpath, * Makes sure not to get two consecutive slashes * between directory and path. **/ -void fill_pathname_join(char *out_path, const char *dir, +size_t fill_pathname_join(char *out_path, const char *dir, const char *path, size_t size); -void fill_pathname_join_special_ext(char *out_path, +size_t fill_pathname_join_special_ext(char *out_path, const char *dir, const char *path, const char *last, const char *ext, size_t size); -void fill_pathname_join_concat_noext( - char *out_path, +size_t fill_pathname_join_concat_noext(char *out_path, const char *dir, const char *path, const char *concat, size_t size); -void fill_pathname_join_concat(char *out_path, +size_t fill_pathname_join_concat(char *out_path, const char *dir, const char *path, const char *concat, size_t size); @@ -401,10 +408,10 @@ void fill_pathname_join_noext(char *out_path, * Joins a directory (@dir) and path (@path) together * using the given delimiter (@delim). **/ -void fill_pathname_join_delim(char *out_path, const char *dir, +size_t fill_pathname_join_delim(char *out_path, const char *dir, const char *path, const char delim, size_t size); -void fill_pathname_join_delim_concat(char *out_path, const char *dir, +size_t fill_pathname_join_delim_concat(char *out_path, const char *dir, const char *path, const char delim, const char *concat, size_t size); @@ -423,7 +430,7 @@ void fill_pathname_join_delim_concat(char *out_path, const char *dir, * E.g.: "/path/to/game.img" -> game.img * "/path/to/myarchive.7z#folder/to/game.img" -> game.img */ -void fill_short_pathname_representation(char* out_rep, +size_t fill_short_pathname_representation(char* out_rep, const char *in_path, size_t size); void fill_short_pathname_representation_noext(char* out_rep, diff --git a/libretro/libretro-common/include/retro_miscellaneous.h b/libretro/libretro-common/include/retro_miscellaneous.h index 629ce12..99d6d84 100644 --- a/libretro/libretro-common/include/retro_miscellaneous.h +++ b/libretro/libretro-common/include/retro_miscellaneous.h @@ -39,7 +39,7 @@ #include #endif -#if defined(__CELLOS_LV2__) +#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) #include #endif @@ -75,7 +75,7 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count) } #ifndef PATH_MAX_LENGTH -#if defined(__CELLOS_LV2__) +#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) #define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH #elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) #define PATH_MAX_LENGTH 512 diff --git a/libretro/libretro-common/include/vfs/vfs_implementation.h b/libretro/libretro-common/include/vfs/vfs_implementation.h index 9f49f26..c7d6bb0 100644 --- a/libretro/libretro-common/include/vfs/vfs_implementation.h +++ b/libretro/libretro-common/include/vfs/vfs_implementation.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2019 The RetroArch team +/* Copyright (C) 2010-2020 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (vfs_implementation.h). @@ -23,30 +23,13 @@ #ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H #define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H +#include #include #include +#include +#include -/* Replace the following symbol with something appropriate - * to signify the file is being compiled for a front end instead of a core. - * This allows the same code to act as reference implementation - * for VFS and as fallbacks for when the front end does not provide VFS functionality. - */ - -#ifdef VFS_FRONTEND -typedef struct retro_vfs_file_handle libretro_vfs_implementation_file; -#else -typedef struct libretro_vfs_implementation_file libretro_vfs_implementation_file; -#endif - -#ifdef VFS_FRONTEND -typedef struct retro_vfs_dir_handle libretro_vfs_implementation_dir; -#else -typedef struct libretro_vfs_implementation_dir libretro_vfs_implementation_dir; -#endif - -#ifdef __cplusplus -extern "C" { -#endif +RETRO_BEGIN_DECLS libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints); @@ -88,8 +71,6 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream); int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream); -#ifdef __cplusplus -} -#endif +RETRO_END_DECLS #endif diff --git a/libretro/libretro-common/vfs/vfs_implementation.c b/libretro/libretro-common/vfs/vfs_implementation.c index 245b3c7..38d844b 100644 --- a/libretro/libretro-common/vfs/vfs_implementation.c +++ b/libretro/libretro-common/vfs/vfs_implementation.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2019 The RetroArch team +/* Copyright (C) 2010-2020 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (vfs_implementation.c). @@ -41,11 +41,12 @@ # include # define INVALID_FILE_ATTRIBUTES -1 # else -# include + # include # include # include # endif +# include #else # if defined(PSP) # include @@ -67,7 +68,7 @@ # endif #endif -#ifdef __CELLOS_LV2__ +#if defined (__CELLOS_LV2__) && !defined(__PSL1GHT__) #include #define O_RDONLY CELL_FS_O_RDONLY #define O_WRONLY CELL_FS_O_WRONLY @@ -150,7 +151,7 @@ #include #endif -#if defined(__CELLOS_LV2__) +#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) #include #endif @@ -171,18 +172,12 @@ #endif -#if defined(_WIN32) && !defined(_XBOX) +#if defined(_WIN32) #if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1400) #define ATLEAST_VC2005 #endif #endif -#ifdef RARCH_INTERNAL -#ifndef VFS_FRONTEND -#define VFS_FRONTEND -#endif -#endif - #include #include #include @@ -190,26 +185,11 @@ #include #include -#define RFILE_HINT_UNBUFFERED (1 << 8) +#ifdef HAVE_CDROM +#include +#endif -#ifdef VFS_FRONTEND -struct retro_vfs_file_handle -#else -struct libretro_vfs_implementation_file -#endif -{ - int fd; - unsigned hints; - int64_t size; - char *buf; - FILE *fp; - char* orig_path; -#if defined(HAVE_MMAP) - uint64_t mappos; - uint64_t mapsize; - uint8_t *mapped; -#endif -}; +#define RFILE_HINT_UNBUFFERED (1 << 8) int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, int64_t offset, int whence) { @@ -218,22 +198,30 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) { +#ifdef HAVE_CDROM + if (stream->scheme == VFS_SCHEME_CDROM) + return retro_vfs_file_seek_cdrom(stream, offset, whence); +#endif /* VC2005 and up have a special 64-bit fseek */ #ifdef ATLEAST_VC2005 return _fseeki64(stream->fp, offset, whence); #elif defined(__CELLOS_LV2__) || defined(_MSC_VER) && _MSC_VER <= 1310 return fseek(stream->fp, (long)offset, whence); #elif defined(PS2) - int64_t ret = fileXioLseek(fileno(stream->fp), (off_t)offset, whence); - /* fileXioLseek could return positive numbers */ - if (ret > 0) - return 0; - return ret; + { + int64_t ret = fileXioLseek(fileno(stream->fp), (off_t)offset, whence); + /* fileXioLseek could return positive numbers */ + if (ret > 0) + return 0; + return ret; + } #elif defined(ORBIS) - int ret = orbisLseek(stream->fd, offset, whence); - if (ret < 0) - return -1; - return 0; + { + int ret = orbisLseek(stream->fd, offset, whence); + if (ret < 0) + return -1; + return 0; + } #else return fseeko(stream->fp, (off_t)offset, whence); #endif @@ -298,12 +286,14 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl( const char *mode_str = NULL; libretro_vfs_implementation_file *stream = (libretro_vfs_implementation_file*) calloc(1, sizeof(*stream)); +#if defined(VFS_FRONTEND) || defined(HAVE_CDROM) + int path_len = (int)strlen(path); +#endif #ifdef VFS_FRONTEND const char *dumb_prefix = "vfsonly://"; size_t dumb_prefix_siz = strlen(dumb_prefix); int dumb_prefix_len = (int)dumb_prefix_siz; - int path_len = (int)strlen(path); if (path_len >= dumb_prefix_len) { @@ -312,6 +302,23 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl( } #endif +#ifdef HAVE_CDROM + { + const char *cdrom_prefix = "cdrom://"; + size_t cdrom_prefix_siz = strlen(cdrom_prefix); + int cdrom_prefix_len = (int)cdrom_prefix_siz; + + if (path_len > cdrom_prefix_len) + { + if (!memcmp(path, cdrom_prefix, cdrom_prefix_len)) + { + path += cdrom_prefix_siz; + stream->scheme = VFS_SCHEME_CDROM; + } + } + } +#endif + if (!stream) return NULL; @@ -398,11 +405,29 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl( } stream->fd = fd; #else - FILE *fp = (FILE*)fopen_utf8(path, mode_str); + FILE *fp; +#ifdef HAVE_CDROM + if (stream->scheme == VFS_SCHEME_CDROM) + { + retro_vfs_file_open_cdrom(stream, path, mode, hints); +#if defined(_WIN32) && !defined(_XBOX) + if (!stream->fh) + goto error; +#else + if (!stream->fp) + goto error; +#endif + } + else +#endif + { + fp = (FILE*)fopen_utf8(path, mode_str); - if (!fp) - goto error; + if (!fp) + goto error; + stream->fp = fp; + } /* Regarding setvbuf: * * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html @@ -413,10 +438,13 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl( * Since C89 does not support specifying a null buffer with a non-zero size, we create and track our own buffer for it. */ /* TODO: this is only useful for a few platforms, find which and add ifdef */ - stream->fp = fp; #if !defined(PS2) && !defined(PSP) - stream->buf = (char*)calloc(1, 0x4000); - setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000); + if (stream->scheme != VFS_SCHEME_CDROM) + { + stream->buf = (char*)calloc(1, 0x4000); + if (stream->fp) + setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000); + } #endif #endif } @@ -465,12 +493,26 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl( stream->size = orbisLseek(stream->fd, 0, SEEK_END); orbisLseek(stream->fd, 0, SEEK_SET); #else - retro_vfs_file_seek_internal(stream, 0, SEEK_SET); - retro_vfs_file_seek_internal(stream, 0, SEEK_END); +#ifdef HAVE_CDROM + if (stream->scheme == VFS_SCHEME_CDROM) + { + retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET); + retro_vfs_file_seek_cdrom(stream, 0, SEEK_END); - stream->size = retro_vfs_file_tell_impl(stream); + stream->size = retro_vfs_file_tell_impl(stream); - retro_vfs_file_seek_internal(stream, 0, SEEK_SET); + retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET); + } + else +#endif + { + retro_vfs_file_seek_internal(stream, 0, SEEK_SET); + retro_vfs_file_seek_internal(stream, 0, SEEK_END); + + stream->size = retro_vfs_file_tell_impl(stream); + + retro_vfs_file_seek_internal(stream, 0, SEEK_SET); + } #endif return stream; @@ -484,10 +526,20 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream) if (!stream) return -1; +#ifdef HAVE_CDROM + if (stream->scheme == VFS_SCHEME_CDROM) + { + retro_vfs_file_close_cdrom(stream); + goto end; + } +#endif + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) { if (stream->fp) + { fclose(stream->fp); + } } else { @@ -506,10 +558,17 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream) close(stream->fd); #endif } +#ifdef HAVE_CDROM +end: + if (stream->cdrom.cue_buf) + free(stream->cdrom.cue_buf); +#endif if (stream->buf) free(stream->buf); + if (stream->orig_path) free(stream->orig_path); + free(stream); return 0; @@ -517,6 +576,10 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream) int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream) { +#ifdef HAVE_CDROM + if (stream->scheme == VFS_SCHEME_CDROM) + return retro_vfs_file_error_cdrom(stream); +#endif #ifdef ORBIS /* TODO/FIXME - implement this? */ return 0; @@ -555,13 +618,19 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream) if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) { +#ifdef HAVE_CDROM + if (stream->scheme == VFS_SCHEME_CDROM) + return retro_vfs_file_tell_cdrom(stream); +#endif #ifdef ORBIS - int64_t ret = orbisLseek(stream->fd, 0, SEEK_CUR); - if (ret < 0) - return -1; - return ret; + { + int64_t ret = orbisLseek(stream->fd, 0, SEEK_CUR); + if (ret < 0) + return -1; + return ret; + } #else -/* VC2005 and up have a special 64-bit ftell */ + /* VC2005 and up have a special 64-bit ftell */ #ifdef ATLEAST_VC2005 return _ftelli64(stream->fp); #else @@ -609,6 +678,10 @@ int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) { +#ifdef HAVE_CDROM + if (stream->scheme == VFS_SCHEME_CDROM) + return retro_vfs_file_read_cdrom(stream, s, len); +#endif #ifdef ORBIS if (orbisRead(stream->fd, s, (size_t)len) < 0) return -1; @@ -867,14 +940,16 @@ int retro_vfs_stat_impl(const char *path, int32_t *size) /* if fileXioGetStat fails */ int dir_ret = fileXioDopen(path); is_dir = dir_ret > 0; - fileXioDclose(dir_ret); + if (is_dir) { + fileXioDclose(dir_ret); + } } else is_dir = FIO_S_ISDIR(buf.mode); return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0); -#elif defined(__CELLOS_LV2__) +#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) /* CellOS Lv2 */ bool is_dir; bool is_character_special = false; @@ -1020,7 +1095,7 @@ struct libretro_vfs_implementation_dir #elif defined(PS2) int directory; iox_dirent_t entry; -#elif defined(__CELLOS_LV2__) +#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) CellFsErrno error; int directory; CellFsDirent entry; @@ -1039,18 +1114,20 @@ static bool dirent_check_error(libretro_vfs_implementation_dir *rdir) return (rdir->directory == INVALID_HANDLE_VALUE); #elif defined(VITA) || defined(PSP) || defined(PS2) || defined(ORBIS) return (rdir->directory < 0); -#elif defined(__CELLOS_LV2__) +#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) return (rdir->error != CELL_FS_SUCCEEDED); #else return !(rdir->directory); #endif } -libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *name, bool include_hidden) +libretro_vfs_implementation_dir *retro_vfs_opendir_impl( + const char *name, bool include_hidden) { #if defined(_WIN32) unsigned path_len; char path_buf[1024]; + size_t copied = 0; #if defined(LEGACY_WIN32) char *path_local = NULL; #else @@ -1074,21 +1151,24 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *name, bool i path_buf[0] = '\0'; path_len = strlen(name); + copied = strlcpy(path_buf, name, sizeof(path_buf)); + /* Non-NT platforms don't like extra slashes in the path */ - if (name[path_len - 1] == '\\') - snprintf(path_buf, sizeof(path_buf), "%s*", name); - else - snprintf(path_buf, sizeof(path_buf), "%s\\*", name); + if (name[path_len - 1] != '\\') + path_buf[copied++] = '\\'; + + path_buf[copied] = '*'; + path_buf[copied+1] = '\0'; #if defined(LEGACY_WIN32) - path_local = utf8_to_local_string_alloc(path_buf); - rdir->directory = FindFirstFile(path_local, &rdir->entry); + path_local = utf8_to_local_string_alloc(path_buf); + rdir->directory = FindFirstFile(path_local, &rdir->entry); if (path_local) free(path_local); #else - path_wide = utf8_to_utf16_string_alloc(path_buf); - rdir->directory = FindFirstFileW(path_wide, &rdir->entry); + path_wide = utf8_to_utf16_string_alloc(path_buf); + rdir->directory = FindFirstFileW(path_wide, &rdir->entry); if (path_wide) free(path_wide); @@ -1101,7 +1181,7 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *name, bool i #elif defined(_3DS) rdir->directory = !string_is_empty(name) ? opendir(name) : NULL; rdir->entry = NULL; -#elif defined(__CELLOS_LV2__) +#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) rdir->error = cellFsOpendir(name, &rdir->directory); #elif defined(ORBIS) rdir->directory = orbisDopen(name); @@ -1143,7 +1223,7 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir) int ret = ps2fileXioDread(rdir->directory, &record); rdir->entry = record; return ( ret > 0); -#elif defined(__CELLOS_LV2__) +#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) uint64_t nread; rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread); return (nread != 0); @@ -1158,27 +1238,32 @@ const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir { #if defined(_WIN32) #if defined(LEGACY_WIN32) - char *name_local = local_to_utf8_string_alloc(rdir->entry.cFileName); - memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName)); - strlcpy(rdir->entry.cFileName, name_local, sizeof(rdir->entry.cFileName)); + { + char *name_local = local_to_utf8_string_alloc(rdir->entry.cFileName); + memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName)); + strlcpy(rdir->entry.cFileName, name_local, sizeof(rdir->entry.cFileName)); - if (name_local) - free(name_local); + if (name_local) + free(name_local); + } #else - char *name = utf16_to_utf8_string_alloc(rdir->entry.cFileName); - memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName)); - strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName)); + { + char *name = utf16_to_utf8_string_alloc(rdir->entry.cFileName); + memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName)); + strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName)); - if (name) - free(name); + if (name) + free(name); + } #endif return (char*)rdir->entry.cFileName; -#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) || defined(ORBIS) +#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) || defined(ORBIS) return rdir->entry.d_name; #elif defined(PS2) return rdir->entry.name; #else - + if (!rdir || !rdir->entry) + return NULL; return rdir->entry->d_name; #endif } @@ -1198,7 +1283,7 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir) #elif defined(PS2) const iox_dirent_t *entry = (const iox_dirent_t*)&rdir->entry; return FIO_S_ISDIR(entry->stat.mode); -#elif defined(__CELLOS_LV2__) +#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) CellFsDirent *entry = (CellFsDirent*)&rdir->entry; return (entry->d_type == CELL_FS_TYPE_DIRECTORY); #elif defined(ORBIS) @@ -1239,7 +1324,7 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir) sceIoDclose(rdir->directory); #elif defined(PS2) ps2fileXioDclose(rdir->directory); -#elif defined(__CELLOS_LV2__) +#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) rdir->error = cellFsClosedir(rdir->directory); #elif defined(ORBIS) orbisDclose(rdir->directory);