mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-28 02:30:35 +00:00
Merge pull request #7995 from krzys-h/vfs-v3
VFS v3: stat, mkdir, directory listings
This commit is contained in:
commit
d4b33ac1ad
24
dynamic.c
24
dynamic.c
@ -1927,9 +1927,10 @@ bool rarch_environment_cb(unsigned cmd, void *data)
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_VFS_INTERFACE:
|
||||
{
|
||||
const uint32_t supported_vfs_version = 1;
|
||||
const uint32_t supported_vfs_version = 3;
|
||||
static struct retro_vfs_interface vfs_iface =
|
||||
{
|
||||
{
|
||||
/* VFS API v1 */
|
||||
retro_vfs_file_get_path_impl,
|
||||
retro_vfs_file_open_impl,
|
||||
retro_vfs_file_close_impl,
|
||||
@ -1939,15 +1940,32 @@ bool rarch_environment_cb(unsigned cmd, void *data)
|
||||
retro_vfs_file_read_impl,
|
||||
retro_vfs_file_write_impl,
|
||||
retro_vfs_file_flush_impl,
|
||||
retro_vfs_file_remove_impl
|
||||
retro_vfs_file_remove_impl,
|
||||
retro_vfs_file_rename_impl,
|
||||
/* VFS API v2 */
|
||||
retro_vfs_file_truncate_impl,
|
||||
/* VFS API v3 */
|
||||
retro_vfs_stat_impl,
|
||||
retro_vfs_mkdir_impl,
|
||||
retro_vfs_opendir_impl,
|
||||
retro_vfs_readdir_impl,
|
||||
retro_vfs_dirent_get_name_impl,
|
||||
retro_vfs_dirent_is_dir_impl,
|
||||
retro_vfs_closedir_impl
|
||||
};
|
||||
|
||||
struct retro_vfs_interface_info *vfs_iface_info = (struct retro_vfs_interface_info *) data;
|
||||
if (vfs_iface_info->required_interface_version <= supported_vfs_version)
|
||||
{
|
||||
RARCH_LOG("Core requested VFS version >= v%d, providing v%d\n", vfs_iface_info->required_interface_version, supported_vfs_version);
|
||||
vfs_iface_info->required_interface_version = supported_vfs_version;
|
||||
vfs_iface_info->iface = &vfs_iface;
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_WARN("Core requested VFS version v%d which is higher than what we support (v%d)\n", vfs_iface_info->required_interface_version, supported_vfs_version);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_path.c).
|
||||
@ -32,7 +32,10 @@
|
||||
#include <file/file_path.h>
|
||||
#include <retro_assert.h>
|
||||
#include <string/stdstring.h>
|
||||
#define VFS_FRONTEND
|
||||
#include <vfs/vfs_implementation.h>
|
||||
|
||||
/* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
@ -116,118 +119,39 @@
|
||||
|
||||
#endif
|
||||
|
||||
enum stat_mode
|
||||
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)
|
||||
{
|
||||
IS_DIRECTORY = 0,
|
||||
IS_CHARACTER_SPECIAL,
|
||||
IS_VALID
|
||||
};
|
||||
const struct retro_vfs_interface* vfs_iface;
|
||||
|
||||
static bool path_stat(const char *path, enum stat_mode mode, int32_t *size)
|
||||
path_stat_cb = NULL;
|
||||
path_mkdir_cb = NULL;
|
||||
|
||||
vfs_iface = vfs_info->iface;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int path_stat(const char *path, int32_t *size)
|
||||
{
|
||||
#if defined(ORBIS)
|
||||
return false; /* for now */
|
||||
#endif
|
||||
#if defined(VITA) || defined(PSP)
|
||||
SceIoStat buf;
|
||||
char *tmp = strdup(path);
|
||||
size_t len = strlen(tmp);
|
||||
if (tmp[len-1] == '/')
|
||||
tmp[len-1] = '\0';
|
||||
if (path_stat_cb != NULL)
|
||||
return path_stat_cb(path, NULL);
|
||||
else
|
||||
return retro_vfs_stat_impl(path, NULL);
|
||||
}
|
||||
|
||||
if (sceIoGetstat(tmp, &buf) < 0)
|
||||
{
|
||||
free(tmp);
|
||||
return false;
|
||||
}
|
||||
free(tmp);
|
||||
#elif defined(PS2)
|
||||
iox_stat_t buf;
|
||||
char *tmp = strdup(path);
|
||||
size_t len = strlen(tmp);
|
||||
if (tmp[len-1] == '/')
|
||||
tmp[len-1] = '\0';
|
||||
|
||||
if (fileXioGetStat(tmp, &buf) < 0)
|
||||
{
|
||||
free(tmp);
|
||||
return false;
|
||||
}
|
||||
free(tmp);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
CellFsStat buf;
|
||||
if (cellFsStat(path, &buf) < 0)
|
||||
return false;
|
||||
#elif defined(_WIN32)
|
||||
DWORD file_info;
|
||||
struct _stat buf;
|
||||
char *path_local = NULL;
|
||||
wchar_t *path_wide = NULL;
|
||||
|
||||
if (!path || !*path)
|
||||
return false;
|
||||
|
||||
(void)path_wide;
|
||||
(void)path_local;
|
||||
(void)file_info;
|
||||
|
||||
#if defined(LEGACY_WIN32)
|
||||
path_local = utf8_to_local_string_alloc(path);
|
||||
file_info = GetFileAttributes(path_local);
|
||||
|
||||
_stat(path_local, &buf);
|
||||
|
||||
if (path_local)
|
||||
free(path_local);
|
||||
#else
|
||||
path_wide = utf8_to_utf16_string_alloc(path);
|
||||
file_info = GetFileAttributesW(path_wide);
|
||||
|
||||
_wstat(path_wide, &buf);
|
||||
|
||||
if (path_wide)
|
||||
free(path_wide);
|
||||
#endif
|
||||
|
||||
if (file_info == INVALID_FILE_ATTRIBUTES)
|
||||
return false;
|
||||
#else
|
||||
struct stat buf;
|
||||
if (stat(path, &buf) < 0)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (size)
|
||||
#if defined(PS2)
|
||||
*size = (int32_t)buf.size;
|
||||
#else
|
||||
*size = (int32_t)buf.st_size;
|
||||
#endif
|
||||
switch (mode)
|
||||
{
|
||||
case IS_DIRECTORY:
|
||||
#if defined(VITA) || defined(PSP)
|
||||
return FIO_S_ISDIR(buf.st_mode);
|
||||
#elif defined(PS2)
|
||||
return FIO_S_ISDIR(buf.mode);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
return ((buf.st_mode & S_IFMT) == S_IFDIR);
|
||||
#elif defined(_WIN32)
|
||||
return (file_info & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
return S_ISDIR(buf.st_mode);
|
||||
#endif
|
||||
case IS_CHARACTER_SPECIAL:
|
||||
#if defined(VITA) || defined(PSP) || defined(PS2) || defined(__CELLOS_LV2__) || defined(_WIN32)
|
||||
return false;
|
||||
#else
|
||||
return S_ISCHR(buf.st_mode);
|
||||
#endif
|
||||
case IS_VALID:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
static int path_mkdir_norecurse(const char *dir)
|
||||
{
|
||||
if (path_mkdir_cb != NULL)
|
||||
return path_mkdir_cb(dir);
|
||||
else
|
||||
return retro_vfs_mkdir_impl(dir);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -241,6 +165,7 @@ static bool path_stat(const char *path, enum stat_mode mode, int32_t *size)
|
||||
bool path_is_directory(const char *path)
|
||||
{
|
||||
#ifdef ORBIS
|
||||
/* TODO: This should be moved to the VFS module */
|
||||
int dfd;
|
||||
if (!path)
|
||||
return false;
|
||||
@ -250,40 +175,29 @@ bool path_is_directory(const char *path)
|
||||
orbisDclose(dfd);
|
||||
return true;
|
||||
#else
|
||||
return path_stat(path, IS_DIRECTORY, NULL);
|
||||
return (path_stat(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool path_is_character_special(const char *path)
|
||||
{
|
||||
return path_stat(path, IS_CHARACTER_SPECIAL, NULL);
|
||||
return (path_stat(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
|
||||
}
|
||||
|
||||
bool path_is_valid(const char *path)
|
||||
{
|
||||
return path_stat(path, IS_VALID, NULL);
|
||||
return (path_stat(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;
|
||||
}
|
||||
|
||||
int32_t path_get_size(const char *path)
|
||||
{
|
||||
int32_t filesize = 0;
|
||||
if (path_stat(path, IS_VALID, &filesize))
|
||||
if (path_stat(path, &filesize) != 0)
|
||||
return filesize;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool path_mkdir_error(int ret)
|
||||
{
|
||||
#if defined(VITA)
|
||||
return (ret == SCE_ERROR_ERRNO_EEXIST);
|
||||
#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(ORBIS)
|
||||
return (ret == -1);
|
||||
#else
|
||||
return (ret < 0 && errno == EEXIST);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* path_mkdir:
|
||||
* @dir : directory
|
||||
@ -329,35 +243,10 @@ bool path_mkdir(const char *dir)
|
||||
|
||||
if (norecurse)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
#ifdef LEGACY_WIN32
|
||||
int ret = _mkdir(dir);
|
||||
#else
|
||||
wchar_t *dirW = utf8_to_utf16_string_alloc(dir);
|
||||
int ret = -1;
|
||||
|
||||
if (dirW)
|
||||
{
|
||||
ret = _wmkdir(dirW);
|
||||
free(dirW);
|
||||
}
|
||||
#endif
|
||||
#elif defined(IOS)
|
||||
int ret = mkdir(dir, 0755);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
int ret = sceIoMkdir(dir, 0777);
|
||||
#elif defined(PS2)
|
||||
int ret =fileXioMkdir(dir, 0777);
|
||||
#elif defined(ORBIS)
|
||||
int ret =orbisMkdir(dir, 0755);
|
||||
#elif defined(__QNX__)
|
||||
int ret = mkdir(dir, 0777);
|
||||
#else
|
||||
int ret = mkdir(dir, 0750);
|
||||
#endif
|
||||
int ret = path_mkdir_norecurse(dir);
|
||||
|
||||
/* Don't treat this as an error. */
|
||||
if (path_mkdir_error(ret) && path_is_directory(dir))
|
||||
if (ret == -2 && path_is_directory(dir))
|
||||
ret = 0;
|
||||
|
||||
if (ret < 0)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_dirent.c).
|
||||
@ -28,313 +28,95 @@
|
||||
|
||||
#include <boolean.h>
|
||||
#include <retro_dirent.h>
|
||||
#include <encodings/utf.h>
|
||||
#include <compat/strl.h>
|
||||
#include <string/stdstring.h>
|
||||
#define VFS_FRONTEND
|
||||
#include <vfs/vfs_implementation.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# ifdef _MSC_VER
|
||||
# define setmode _setmode
|
||||
# endif
|
||||
#include <sys/stat.h>
|
||||
# ifdef _XBOX
|
||||
# include <xtl.h>
|
||||
# define INVALID_FILE_ATTRIBUTES -1
|
||||
# else
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
# include <direct.h>
|
||||
# include <windows.h>
|
||||
# endif
|
||||
#elif defined(VITA)
|
||||
# include <psp2/io/fcntl.h>
|
||||
# include <psp2/io/dirent.h>
|
||||
# include <psp2/io/stat.h>
|
||||
#elif defined(ORBIS)
|
||||
# include <orbisFile.h>
|
||||
# include <ps4link.h>
|
||||
# include <sys/dirent.h>
|
||||
# include <sys/fcntl.h>
|
||||
#else
|
||||
# if defined(PSP)
|
||||
# include <pspiofilemgr.h>
|
||||
# endif
|
||||
# if defined(PS2)
|
||||
# include <fileXio_rpc.h>
|
||||
# endif
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <dirent.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
static retro_vfs_opendir_t dirent_opendir_cb = NULL;
|
||||
static retro_vfs_readdir_t dirent_readdir_cb = NULL;
|
||||
static retro_vfs_dirent_get_name_t dirent_dirent_get_name_cb = NULL;
|
||||
static retro_vfs_dirent_is_dir_t dirent_dirent_is_dir_cb = NULL;
|
||||
static retro_vfs_closedir_t dirent_closedir_cb = NULL;
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
#include <cell/cell_fs.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) || defined(PS2)
|
||||
#include <unistd.h> /* stat() is defined here */
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
|
||||
#ifndef LEGACY_WIN32
|
||||
#define LEGACY_WIN32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct RDIR
|
||||
void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
#if defined(LEGACY_WIN32)
|
||||
WIN32_FIND_DATA entry;
|
||||
#else
|
||||
WIN32_FIND_DATAW entry;
|
||||
#endif
|
||||
HANDLE directory;
|
||||
bool next;
|
||||
char path[PATH_MAX_LENGTH];
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
SceUID directory;
|
||||
SceIoDirent entry;
|
||||
#elif defined(PS2)
|
||||
int directory;
|
||||
iox_dirent_t entry;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
CellFsErrno error;
|
||||
int directory;
|
||||
CellFsDirent entry;
|
||||
#elif defined(ORBIS)
|
||||
int directory;
|
||||
struct dirent entry;
|
||||
#else
|
||||
DIR *directory;
|
||||
const struct dirent *entry;
|
||||
#endif
|
||||
};
|
||||
const struct retro_vfs_interface* vfs_iface;
|
||||
|
||||
dirent_opendir_cb = NULL;
|
||||
dirent_readdir_cb = NULL;
|
||||
dirent_dirent_get_name_cb = NULL;
|
||||
dirent_dirent_is_dir_cb = NULL;
|
||||
dirent_closedir_cb = NULL;
|
||||
|
||||
vfs_iface = vfs_info->iface;
|
||||
|
||||
if (vfs_info->required_interface_version < DIRENT_REQUIRED_VFS_VERSION || !vfs_iface)
|
||||
return;
|
||||
|
||||
dirent_opendir_cb = vfs_iface->opendir;
|
||||
dirent_readdir_cb = vfs_iface->readdir;
|
||||
dirent_dirent_get_name_cb = vfs_iface->dirent_get_name;
|
||||
dirent_dirent_is_dir_cb = vfs_iface->dirent_is_dir;
|
||||
dirent_closedir_cb = vfs_iface->closedir;
|
||||
}
|
||||
|
||||
struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden)
|
||||
{
|
||||
if (dirent_opendir_cb != NULL)
|
||||
return (struct RDIR *)dirent_opendir_cb(name, include_hidden);
|
||||
else
|
||||
return (struct RDIR *)retro_vfs_opendir_impl(name, include_hidden);
|
||||
}
|
||||
|
||||
struct RDIR *retro_opendir(const char *name)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
char path_buf[1024];
|
||||
char *path_local = NULL;
|
||||
wchar_t *path_wide = NULL;
|
||||
unsigned path_len;
|
||||
#endif
|
||||
struct RDIR *rdir;
|
||||
|
||||
/*Reject null or empty string paths*/
|
||||
if (!name||(*name==0))
|
||||
return NULL;
|
||||
|
||||
/*Allocate RDIR struct. Tidied later with retro_closedir*/
|
||||
rdir = (struct RDIR*)calloc(1, sizeof(*rdir));
|
||||
if (!rdir)
|
||||
return NULL;
|
||||
|
||||
#if defined(_WIN32)
|
||||
(void)path_wide;
|
||||
(void)path_local;
|
||||
|
||||
path_buf[0] = '\0';
|
||||
path_len = strlen(name);
|
||||
|
||||
/* 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 defined(LEGACY_WIN32)
|
||||
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);
|
||||
|
||||
if (path_wide)
|
||||
free(path_wide);
|
||||
#endif
|
||||
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
rdir->directory = sceIoDopen(name);
|
||||
#elif defined(PS2)
|
||||
rdir->directory = fileXioDopen(name);
|
||||
#elif defined(_3DS)
|
||||
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
|
||||
rdir->entry = NULL;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
rdir->error = cellFsOpendir(name, &rdir->directory);
|
||||
#elif defined(ORBIS)
|
||||
rdir->directory = orbisDopen(name);
|
||||
#else
|
||||
rdir->directory = opendir(name);
|
||||
rdir->entry = NULL;
|
||||
#endif
|
||||
|
||||
if (rdir->directory)
|
||||
return rdir;
|
||||
|
||||
free(rdir);
|
||||
return NULL;
|
||||
return retro_opendir_include_hidden(name, false);
|
||||
}
|
||||
|
||||
bool retro_dirent_error(struct RDIR *rdir)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return (rdir->directory == INVALID_HANDLE_VALUE);
|
||||
#elif defined(VITA) || defined(PSP) || defined(PS2) || defined(ORBIS)
|
||||
return (rdir->directory < 0);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
return (rdir->error != CELL_FS_SUCCEEDED);
|
||||
#else
|
||||
return !(rdir->directory);
|
||||
#endif
|
||||
/* Left for compatibility */
|
||||
return false;
|
||||
}
|
||||
|
||||
int retro_readdir(struct RDIR *rdir)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if(rdir->next)
|
||||
#if defined(LEGACY_WIN32)
|
||||
return (FindNextFile(rdir->directory, &rdir->entry) != 0);
|
||||
#else
|
||||
return (FindNextFileW(rdir->directory, &rdir->entry) != 0);
|
||||
#endif
|
||||
|
||||
rdir->next = true;
|
||||
return (rdir->directory != INVALID_HANDLE_VALUE);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
|
||||
#elif defined(PS2)
|
||||
iox_dirent_t record;
|
||||
int ret = fileXioDread(rdir->directory, &record);
|
||||
rdir->entry = record;
|
||||
return ( ret > 0);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
uint64_t nread;
|
||||
rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread);
|
||||
return (nread != 0);
|
||||
#elif defined(ORBIS)
|
||||
return (orbisDread(rdir->directory, &rdir->entry) > 0);
|
||||
#else
|
||||
return ((rdir->entry = readdir(rdir->directory)) != NULL);
|
||||
#endif
|
||||
if (dirent_readdir_cb != NULL)
|
||||
return dirent_readdir_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
else
|
||||
return retro_vfs_readdir_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
}
|
||||
|
||||
const char *retro_dirent_get_name(struct RDIR *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));
|
||||
|
||||
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));
|
||||
|
||||
if (name)
|
||||
free(name);
|
||||
#endif
|
||||
return (char*)rdir->entry.cFileName;
|
||||
#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) || defined(ORBIS)
|
||||
return rdir->entry.d_name;
|
||||
#elif defined(PS2)
|
||||
return rdir->entry.name;
|
||||
#else
|
||||
|
||||
return rdir->entry->d_name;
|
||||
#endif
|
||||
if (dirent_dirent_get_name_cb != NULL)
|
||||
return dirent_dirent_get_name_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
else
|
||||
return retro_vfs_dirent_get_name_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* retro_dirent_is_dir:
|
||||
* @rdir : pointer to the directory entry.
|
||||
* @path : path to the directory entry.
|
||||
* @unused : deprecated, included for compatibility reasons, pass NULL
|
||||
*
|
||||
* Is the directory listing entry a directory?
|
||||
*
|
||||
* Returns: true if directory listing entry is
|
||||
* a directory, false if not.
|
||||
*/
|
||||
bool retro_dirent_is_dir(struct RDIR *rdir, const char *path)
|
||||
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
|
||||
return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
|
||||
#if defined(PSP)
|
||||
return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
|
||||
#elif defined(VITA)
|
||||
return SCE_S_ISDIR(entry->d_stat.st_mode);
|
||||
#endif
|
||||
#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__)
|
||||
CellFsDirent *entry = (CellFsDirent*)&rdir->entry;
|
||||
return (entry->d_type == CELL_FS_TYPE_DIRECTORY);
|
||||
#elif defined(ORBIS)
|
||||
const struct dirent *entry = &rdir->entry;
|
||||
if (entry->d_type==DT_DIR)
|
||||
return true;
|
||||
if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
|
||||
return false;
|
||||
#else
|
||||
struct stat buf;
|
||||
#if defined(DT_DIR)
|
||||
const struct dirent *entry = (const struct dirent*)rdir->entry;
|
||||
if (entry->d_type == DT_DIR)
|
||||
return true;
|
||||
/* This can happen on certain file systems. */
|
||||
if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
|
||||
return false;
|
||||
#endif
|
||||
/* dirent struct doesn't have d_type, do it the slow way ... */
|
||||
if (stat(path, &buf) < 0)
|
||||
return false;
|
||||
return S_ISDIR(buf.st_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
void retro_dirent_include_hidden(struct RDIR *rdir, bool include_hidden)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (include_hidden)
|
||||
rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
|
||||
if (dirent_dirent_is_dir_cb != NULL)
|
||||
return dirent_dirent_is_dir_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
else
|
||||
rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
|
||||
#endif
|
||||
return retro_vfs_dirent_is_dir_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
}
|
||||
|
||||
void retro_closedir(struct RDIR *rdir)
|
||||
{
|
||||
if (!rdir)
|
||||
return;
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (rdir->directory != INVALID_HANDLE_VALUE)
|
||||
FindClose(rdir->directory);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
sceIoDclose(rdir->directory);
|
||||
#elif defined(PS2)
|
||||
fileXioDclose(rdir->directory);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
rdir->error = cellFsClosedir(rdir->directory);
|
||||
#elif defined(ORBIS)
|
||||
orbisDclose(rdir->directory);
|
||||
#else
|
||||
if (rdir->directory)
|
||||
closedir(rdir->directory);
|
||||
#endif
|
||||
|
||||
free(rdir);
|
||||
if (dirent_closedir_cb != NULL)
|
||||
dirent_closedir_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
else
|
||||
retro_vfs_closedir_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_path.h).
|
||||
@ -28,12 +28,17 @@
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libretro.h>
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#define PATH_REQUIRED_VFS_VERSION 3
|
||||
|
||||
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info);
|
||||
|
||||
/* Order in this enum is equivalent to negative sort order in filelist
|
||||
* (i.e. DIRECTORY is on top of PLAIN_FILE) */
|
||||
enum
|
||||
|
@ -1100,6 +1100,10 @@ enum retro_mod
|
||||
* Introduced in VFS API v1 */
|
||||
struct retro_vfs_file_handle;
|
||||
|
||||
/* Opaque directory handle
|
||||
* Introduced in VFS API v3 */
|
||||
struct retro_vfs_dir_handle;
|
||||
|
||||
/* File open flags
|
||||
* Introduced in VFS API v1 */
|
||||
#define RETRO_VFS_FILE_ACCESS_READ (1 << 0) /* Read only mode */
|
||||
@ -1119,6 +1123,12 @@ struct retro_vfs_file_handle;
|
||||
#define RETRO_VFS_SEEK_POSITION_CURRENT 1
|
||||
#define RETRO_VFS_SEEK_POSITION_END 2
|
||||
|
||||
/* stat() result flags
|
||||
* Introduced in VFS API v3 */
|
||||
#define RETRO_VFS_STAT_IS_VALID (1 << 0)
|
||||
#define RETRO_VFS_STAT_IS_DIRECTORY (1 << 1)
|
||||
#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL (1 << 2)
|
||||
|
||||
/* Get path from opaque handle. Returns the exact same path passed to file_open when getting the handle
|
||||
* Introduced in VFS API v1 */
|
||||
typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream);
|
||||
@ -1128,7 +1138,7 @@ typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file
|
||||
* Introduced in VFS API v1 */
|
||||
typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints);
|
||||
|
||||
/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on succes, -1 on failure.
|
||||
/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on success, -1 on failure.
|
||||
* Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used.
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream);
|
||||
@ -1141,7 +1151,7 @@ typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle
|
||||
* Introduced in VFS API v2 */
|
||||
typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length);
|
||||
|
||||
/* Get the current read / write position for the file. Returns - 1 for error.
|
||||
/* Get the current read / write position for the file. Returns -1 for error.
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);
|
||||
|
||||
@ -1169,6 +1179,39 @@ typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path);
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path);
|
||||
|
||||
/* Stat the specified file. Retruns a bitmask of RETRO_VFS_STAT_* flags, none are set if path was not valid.
|
||||
* Additionally stores file size in given variable, unless NULL is given.
|
||||
* Introduced in VFS API v3 */
|
||||
typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size);
|
||||
|
||||
/* Create the specified directory. Returns 0 on success, -1 on unknown failure, -2 if already exists.
|
||||
* Introduced in VFS API v3 */
|
||||
typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir);
|
||||
|
||||
/* Open the specified directory for listing. Returns the opaque dir handle, or NULL for error.
|
||||
* Support for the include_hidden argument may vary depending on the platform.
|
||||
* Introduced in VFS API v3 */
|
||||
typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden);
|
||||
|
||||
/* Read the directory entry at the current position, and move the read pointer to the next position.
|
||||
* Returns true on success, false if already on the last entry.
|
||||
* Introduced in VFS API v3 */
|
||||
typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream);
|
||||
|
||||
/* Get the name of the last entry read. Returns a string on success, or NULL for error.
|
||||
* The returned string pointer is valid until the next call to readdir or closedir.
|
||||
* Introduced in VFS API v3 */
|
||||
typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream);
|
||||
|
||||
/* Check if the last entry read was a directory. Returns true if it was, false otherwise (or on error).
|
||||
* Introduced in VFS API v3 */
|
||||
typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream);
|
||||
|
||||
/* Close the directory and release its resources. Must be called if opendir returns non-NULL. Returns 0 on success, -1 on failure.
|
||||
* Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used.
|
||||
* Introduced in VFS API v3 */
|
||||
typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream);
|
||||
|
||||
struct retro_vfs_interface
|
||||
{
|
||||
/* VFS API v1 */
|
||||
@ -1185,6 +1228,14 @@ struct retro_vfs_interface
|
||||
retro_vfs_rename_t rename;
|
||||
/* VFS API v2 */
|
||||
retro_vfs_truncate_t truncate;
|
||||
/* VFS API v3 */
|
||||
retro_vfs_stat_t stat;
|
||||
retro_vfs_mkdir_t mkdir;
|
||||
retro_vfs_opendir_t opendir;
|
||||
retro_vfs_readdir_t readdir;
|
||||
retro_vfs_dirent_get_name_t dirent_get_name;
|
||||
retro_vfs_dirent_is_dir_t dirent_is_dir;
|
||||
retro_vfs_closedir_t closedir;
|
||||
};
|
||||
|
||||
struct retro_vfs_interface_info
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_dirent.h).
|
||||
@ -23,6 +23,7 @@
|
||||
#ifndef __RETRO_DIRENT_H
|
||||
#define __RETRO_DIRENT_H
|
||||
|
||||
#include <libretro.h>
|
||||
#include <retro_common_api.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
@ -30,6 +31,10 @@
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#define DIRENT_REQUIRED_VFS_VERSION 3
|
||||
|
||||
void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info);
|
||||
|
||||
typedef struct RDIR RDIR;
|
||||
|
||||
/**
|
||||
@ -44,25 +49,27 @@ typedef struct RDIR RDIR;
|
||||
*/
|
||||
struct RDIR *retro_opendir(const char *name);
|
||||
|
||||
struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden);
|
||||
|
||||
int retro_readdir(struct RDIR *rdir);
|
||||
|
||||
/* Deprecated, returns false, left for compatibility */
|
||||
bool retro_dirent_error(struct RDIR *rdir);
|
||||
|
||||
void retro_dirent_include_hidden(struct RDIR *rdir, bool include_hidden);
|
||||
|
||||
const char *retro_dirent_get_name(struct RDIR *rdir);
|
||||
|
||||
/**
|
||||
*
|
||||
* retro_dirent_is_dir:
|
||||
* @rdir : pointer to the directory entry.
|
||||
* @unused : deprecated, included for compatibility reasons, pass NULL
|
||||
*
|
||||
* Is the directory listing entry a directory?
|
||||
*
|
||||
* Returns: true if directory listing entry is
|
||||
* a directory, false if not.
|
||||
*/
|
||||
bool retro_dirent_is_dir(struct RDIR *rdir, const char *path);
|
||||
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused);
|
||||
|
||||
void retro_closedir(struct RDIR *rdir);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (vfs_implementation.h).
|
||||
@ -38,6 +38,12 @@ typedef struct retro_vfs_file_handle libretro_vfs_implementation_file;
|
||||
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
|
||||
|
||||
libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints);
|
||||
|
||||
int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream);
|
||||
@ -64,4 +70,18 @@ int retro_vfs_file_rename_impl(const char *old_path, const char *new_path);
|
||||
|
||||
const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream);
|
||||
|
||||
int retro_vfs_stat_impl(const char *path, int32_t *size);
|
||||
|
||||
int retro_vfs_mkdir_impl(const char *dir);
|
||||
|
||||
libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *dir, bool include_hidden);
|
||||
|
||||
bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||
|
||||
const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *dirstream);
|
||||
|
||||
bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||
|
||||
int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||
|
||||
#endif
|
||||
|
@ -171,13 +171,11 @@ static int dir_list_read(const char *dir,
|
||||
bool include_dirs, bool include_hidden,
|
||||
bool include_compressed, bool recursive)
|
||||
{
|
||||
struct RDIR *entry = retro_opendir(dir);
|
||||
struct RDIR *entry = retro_opendir_include_hidden(dir, include_hidden);
|
||||
|
||||
if (!entry || retro_dirent_error(entry))
|
||||
goto error;
|
||||
|
||||
retro_dirent_include_hidden(entry, include_hidden);
|
||||
|
||||
while (retro_readdir(entry))
|
||||
{
|
||||
char file_path[PATH_MAX_LENGTH];
|
||||
@ -189,7 +187,7 @@ static int dir_list_read(const char *dir,
|
||||
file_path[0] = '\0';
|
||||
|
||||
fill_pathname_join(file_path, dir, name, sizeof(file_path));
|
||||
is_dir = retro_dirent_is_dir(entry, file_path);
|
||||
is_dir = retro_dirent_is_dir(entry, NULL);
|
||||
|
||||
if(!is_dir)
|
||||
file_ext = path_get_extension(name);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (vfs_implementation.c).
|
||||
@ -34,6 +34,7 @@
|
||||
# ifdef _MSC_VER
|
||||
# define setmode _setmode
|
||||
# endif
|
||||
#include <sys/stat.h>
|
||||
# ifdef _XBOX
|
||||
# include <xtl.h>
|
||||
# define INVALID_FILE_ATTRIBUTES -1
|
||||
@ -73,6 +74,90 @@
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
/* TODO: Some things are duplicated but I'm really afraid of breaking other platforms by touching this */
|
||||
#if defined(VITA)
|
||||
# include <psp2/io/fcntl.h>
|
||||
# include <psp2/io/dirent.h>
|
||||
# include <psp2/io/stat.h>
|
||||
#elif defined(ORBIS)
|
||||
# include <orbisFile.h>
|
||||
# include <ps4link.h>
|
||||
# include <sys/dirent.h>
|
||||
# include <sys/fcntl.h>
|
||||
#elif !defined(_WIN32)
|
||||
# if defined(PSP)
|
||||
# include <pspiofilemgr.h>
|
||||
# endif
|
||||
# if defined(PS2)
|
||||
# include <fileXio_rpc.h>
|
||||
# endif
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <dirent.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) || defined(PS2)
|
||||
#include <unistd.h> /* stat() is defined here */
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
#ifdef __HAIKU__
|
||||
#include <kernel/image.h>
|
||||
#endif
|
||||
#ifndef __MACH__
|
||||
#include <compat/strl.h>
|
||||
#include <compat/posix_string.h>
|
||||
#endif
|
||||
#include <compat/strcasestr.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <encodings/utf.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifndef _XBOX
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(VITA)
|
||||
#define SCE_ERROR_ERRNO_EEXIST 0x80010011
|
||||
#include <psp2/io/fcntl.h>
|
||||
#include <psp2/io/dirent.h>
|
||||
#include <psp2/io/stat.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(ORBIS)
|
||||
#include <orbisFile.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/dirent.h>
|
||||
#endif
|
||||
#if defined(PSP)
|
||||
#include <pspkernel.h>
|
||||
#endif
|
||||
|
||||
#if defined(PS2)
|
||||
#include <fileXio_rpc.h>
|
||||
#include <fileXio.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#include <cell/cell_fs.h>
|
||||
#endif
|
||||
|
||||
#if defined(VITA)
|
||||
#define FIO_S_ISDIR SCE_S_ISDIR
|
||||
#endif
|
||||
|
||||
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
|
||||
#include <unistd.h> /* stat() is defined here */
|
||||
#endif
|
||||
|
||||
/* Assume W-functions do not work below Win2K and Xbox platforms */
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
|
||||
|
||||
@ -99,6 +184,7 @@
|
||||
#include <memmap.h>
|
||||
#include <encodings/utf.h>
|
||||
#include <compat/fopen_utf8.h>
|
||||
#include <file/file_path.h>
|
||||
|
||||
#define RFILE_HINT_UNBUFFERED (1 << 8)
|
||||
|
||||
@ -712,3 +798,408 @@ const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *strea
|
||||
abort();
|
||||
return stream->orig_path;
|
||||
}
|
||||
|
||||
|
||||
int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||
{
|
||||
bool is_dir, is_character_special;
|
||||
#if defined(ORBIS)
|
||||
return 0; /* for now */
|
||||
#endif
|
||||
#if defined(VITA) || defined(PSP)
|
||||
SceIoStat buf;
|
||||
char *tmp = strdup(path);
|
||||
size_t len = strlen(tmp);
|
||||
if (tmp[len-1] == '/')
|
||||
tmp[len-1] = '\0';
|
||||
|
||||
if (sceIoGetstat(tmp, &buf) < 0)
|
||||
{
|
||||
free(tmp);
|
||||
return 0;
|
||||
}
|
||||
free(tmp);
|
||||
#elif defined(PS2)
|
||||
iox_stat_t buf;
|
||||
char *tmp = strdup(path);
|
||||
size_t len = strlen(tmp);
|
||||
if (tmp[len-1] == '/')
|
||||
tmp[len-1] = '\0';
|
||||
|
||||
if (fileXioGetStat(tmp, &buf) < 0)
|
||||
{
|
||||
free(tmp);
|
||||
return 0;
|
||||
}
|
||||
free(tmp);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
CellFsStat buf;
|
||||
if (cellFsStat(path, &buf) < 0)
|
||||
return 0;
|
||||
#elif defined(_WIN32)
|
||||
DWORD file_info;
|
||||
struct _stat buf;
|
||||
char *path_local = NULL;
|
||||
wchar_t *path_wide = NULL;
|
||||
|
||||
if (!path || !*path)
|
||||
return 0;
|
||||
|
||||
(void)path_wide;
|
||||
(void)path_local;
|
||||
(void)file_info;
|
||||
|
||||
#if defined(LEGACY_WIN32)
|
||||
path_local = utf8_to_local_string_alloc(path);
|
||||
file_info = GetFileAttributes(path_local);
|
||||
|
||||
_stat(path_local, &buf);
|
||||
|
||||
if (path_local)
|
||||
free(path_local);
|
||||
#else
|
||||
path_wide = utf8_to_utf16_string_alloc(path);
|
||||
file_info = GetFileAttributesW(path_wide);
|
||||
|
||||
_wstat(path_wide, &buf);
|
||||
|
||||
if (path_wide)
|
||||
free(path_wide);
|
||||
#endif
|
||||
|
||||
if (file_info == INVALID_FILE_ATTRIBUTES)
|
||||
return 0;
|
||||
#else
|
||||
struct stat buf;
|
||||
if (stat(path, &buf) < 0)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (size)
|
||||
#if defined(PS2)
|
||||
*size = (int32_t)buf.size;
|
||||
#else
|
||||
*size = (int32_t)buf.st_size;
|
||||
#endif
|
||||
|
||||
#if defined(VITA) || defined(PSP)
|
||||
is_dir = FIO_S_ISDIR(buf.st_mode);
|
||||
#elif defined(PS2)
|
||||
is_dir = FIO_S_ISDIR(buf.mode);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
is_dir = ((buf.st_mode & S_IFMT) == S_IFDIR);
|
||||
#elif defined(_WIN32)
|
||||
is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
is_dir = S_ISDIR(buf.st_mode);
|
||||
#endif
|
||||
|
||||
#if defined(VITA) || defined(PSP) || defined(PS2) || defined(__CELLOS_LV2__) || defined(_WIN32)
|
||||
is_character_special = false;
|
||||
#else
|
||||
is_character_special = S_ISCHR(buf.st_mode);
|
||||
#endif
|
||||
|
||||
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
|
||||
}
|
||||
|
||||
static bool path_mkdir_error(int ret)
|
||||
{
|
||||
#if defined(VITA)
|
||||
return (ret == SCE_ERROR_ERRNO_EEXIST);
|
||||
#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(ORBIS)
|
||||
return (ret == -1);
|
||||
#else
|
||||
return (ret < 0 && errno == EEXIST);
|
||||
#endif
|
||||
}
|
||||
|
||||
int retro_vfs_mkdir_impl(const char *dir)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
#ifdef LEGACY_WIN32
|
||||
int ret = _mkdir(dir);
|
||||
#else
|
||||
wchar_t *dirW = utf8_to_utf16_string_alloc(dir);
|
||||
int ret = -1;
|
||||
|
||||
if (dirW)
|
||||
{
|
||||
ret = _wmkdir(dirW);
|
||||
free(dirW);
|
||||
}
|
||||
#endif
|
||||
#elif defined(IOS)
|
||||
int ret = mkdir(dir, 0755);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
int ret = sceIoMkdir(dir, 0777);
|
||||
#elif defined(PS2)
|
||||
int ret =fileXioMkdir(dir, 0777);
|
||||
#elif defined(ORBIS)
|
||||
int ret =orbisMkdir(dir, 0755);
|
||||
#elif defined(__QNX__)
|
||||
int ret = mkdir(dir, 0777);
|
||||
#else
|
||||
int ret = mkdir(dir, 0750);
|
||||
#endif
|
||||
|
||||
if (path_mkdir_error(ret))
|
||||
return -2;
|
||||
return ret < 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
#ifdef VFS_FRONTEND
|
||||
struct retro_vfs_dir_handle
|
||||
#else
|
||||
struct libretro_vfs_implementation_dir
|
||||
#endif
|
||||
{
|
||||
char* orig_path;
|
||||
#if defined(_WIN32)
|
||||
#if defined(LEGACY_WIN32)
|
||||
WIN32_FIND_DATA entry;
|
||||
#else
|
||||
WIN32_FIND_DATAW entry;
|
||||
#endif
|
||||
HANDLE directory;
|
||||
bool next;
|
||||
char path[PATH_MAX_LENGTH];
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
SceUID directory;
|
||||
SceIoDirent entry;
|
||||
#elif defined(PS2)
|
||||
int directory;
|
||||
iox_dirent_t entry;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
CellFsErrno error;
|
||||
int directory;
|
||||
CellFsDirent entry;
|
||||
#elif defined(ORBIS)
|
||||
int directory;
|
||||
struct dirent entry;
|
||||
#else
|
||||
DIR *directory;
|
||||
const struct dirent *entry;
|
||||
#endif
|
||||
};
|
||||
|
||||
static bool dirent_check_error(libretro_vfs_implementation_dir *rdir)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return (rdir->directory == INVALID_HANDLE_VALUE);
|
||||
#elif defined(VITA) || defined(PSP) || defined(PS2) || defined(ORBIS)
|
||||
return (rdir->directory < 0);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
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)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
char path_buf[1024];
|
||||
char *path_local = NULL;
|
||||
wchar_t *path_wide = NULL;
|
||||
unsigned path_len;
|
||||
#endif
|
||||
libretro_vfs_implementation_dir *rdir;
|
||||
|
||||
/*Reject null or empty string paths*/
|
||||
if (!name||(*name==0))
|
||||
return NULL;
|
||||
|
||||
/*Allocate RDIR struct. Tidied later with retro_closedir*/
|
||||
rdir = (libretro_vfs_implementation_dir*)calloc(1, sizeof(*rdir));
|
||||
if (!rdir)
|
||||
return NULL;
|
||||
|
||||
rdir->orig_path = strdup(name);
|
||||
|
||||
#if defined(_WIN32)
|
||||
(void)path_wide;
|
||||
(void)path_local;
|
||||
|
||||
path_buf[0] = '\0';
|
||||
path_len = strlen(name);
|
||||
|
||||
/* 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 defined(LEGACY_WIN32)
|
||||
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);
|
||||
|
||||
if (path_wide)
|
||||
free(path_wide);
|
||||
#endif
|
||||
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
rdir->directory = sceIoDopen(name);
|
||||
#elif defined(PS2)
|
||||
rdir->directory = fileXioDopen(name);
|
||||
#elif defined(_3DS)
|
||||
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
|
||||
rdir->entry = NULL;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
rdir->error = cellFsOpendir(name, &rdir->directory);
|
||||
#elif defined(ORBIS)
|
||||
rdir->directory = orbisDopen(name);
|
||||
#else
|
||||
rdir->directory = opendir(name);
|
||||
rdir->entry = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if (include_hidden)
|
||||
rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
|
||||
else
|
||||
rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
|
||||
#endif
|
||||
|
||||
if (rdir->directory && !dirent_check_error(rdir))
|
||||
return rdir;
|
||||
|
||||
free(rdir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if(rdir->next)
|
||||
#if defined(LEGACY_WIN32)
|
||||
return (FindNextFile(rdir->directory, &rdir->entry) != 0);
|
||||
#else
|
||||
return (FindNextFileW(rdir->directory, &rdir->entry) != 0);
|
||||
#endif
|
||||
|
||||
rdir->next = true;
|
||||
return (rdir->directory != INVALID_HANDLE_VALUE);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
|
||||
#elif defined(PS2)
|
||||
iox_dirent_t record;
|
||||
int ret = fileXioDread(rdir->directory, &record);
|
||||
rdir->entry = record;
|
||||
return ( ret > 0);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
uint64_t nread;
|
||||
rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread);
|
||||
return (nread != 0);
|
||||
#elif defined(ORBIS)
|
||||
return (orbisDread(rdir->directory, &rdir->entry) > 0);
|
||||
#else
|
||||
return ((rdir->entry = readdir(rdir->directory)) != NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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));
|
||||
|
||||
if (name)
|
||||
free(name);
|
||||
#endif
|
||||
return (char*)rdir->entry.cFileName;
|
||||
#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) || defined(ORBIS)
|
||||
return rdir->entry.d_name;
|
||||
#elif defined(PS2)
|
||||
return rdir->entry.name;
|
||||
#else
|
||||
|
||||
return rdir->entry->d_name;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
|
||||
return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
|
||||
#if defined(PSP)
|
||||
return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
|
||||
#elif defined(VITA)
|
||||
return SCE_S_ISDIR(entry->d_stat.st_mode);
|
||||
#endif
|
||||
#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__)
|
||||
CellFsDirent *entry = (CellFsDirent*)&rdir->entry;
|
||||
return (entry->d_type == CELL_FS_TYPE_DIRECTORY);
|
||||
#elif defined(ORBIS)
|
||||
const struct dirent *entry = &rdir->entry;
|
||||
if (entry->d_type==DT_DIR)
|
||||
return true;
|
||||
if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
|
||||
return false;
|
||||
#else
|
||||
struct stat buf;
|
||||
#if defined(DT_DIR)
|
||||
const struct dirent *entry = (const struct dirent*)rdir->entry;
|
||||
if (entry->d_type == DT_DIR)
|
||||
return true;
|
||||
/* This can happen on certain file systems. */
|
||||
if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
|
||||
return false;
|
||||
#endif
|
||||
/* dirent struct doesn't have d_type, do it the slow way ... */
|
||||
char path[PATH_MAX_LENGTH];
|
||||
path[0] = '\0';
|
||||
fill_pathname_join(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
|
||||
if (stat(path, &buf) < 0)
|
||||
return false;
|
||||
return S_ISDIR(buf.st_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
{
|
||||
if (!rdir)
|
||||
return -1;
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (rdir->directory != INVALID_HANDLE_VALUE)
|
||||
FindClose(rdir->directory);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
sceIoDclose(rdir->directory);
|
||||
#elif defined(PS2)
|
||||
fileXioDclose(rdir->directory);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
rdir->error = cellFsClosedir(rdir->directory);
|
||||
#elif defined(ORBIS)
|
||||
orbisDclose(rdir->directory);
|
||||
#else
|
||||
if (rdir->directory)
|
||||
closedir(rdir->directory);
|
||||
#endif
|
||||
|
||||
if (rdir->orig_path)
|
||||
free(rdir->orig_path);
|
||||
free(rdir);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user