int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
{
   char *old_path_local    = NULL;
   char *new_path_local    = NULL;
   wchar_t *old_path_wide  = NULL;
   wchar_t *new_path_wide  = NULL;

   if (!old_path || !*old_path || !new_path || !*new_path)
      return -1;

   (void)old_path_local;
   (void)new_path_local;
   (void)old_path_wide;
   (void)new_path_wide;

#if defined(_WIN32) && !defined(_XBOX)
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
   old_path_local = utf8_to_local_string_alloc(old_path);
   new_path_local = utf8_to_local_string_alloc(new_path);

   if (old_path_local)
   {
      if (new_path_local)
      {
         int ret = rename(old_path_local, new_path_local);
         free(old_path_local);
         free(new_path_local);
         return ret==0 ? 0 : -1;
      }

      free(old_path_local);
   }

   if (new_path_local)
      free(new_path_local);
#else
   old_path_wide = utf8_to_utf16_string_alloc(old_path);
   new_path_wide = utf8_to_utf16_string_alloc(new_path);

   if (old_path_wide)
   {
      if (new_path_wide)
      {
         int ret = _wrename(old_path_wide, new_path_wide);
         free(old_path_wide);
         free(new_path_wide);
         return ret==0 ? 0 : -1;
      }

      free(old_path_wide);
   }

   if (new_path_wide)
      free(new_path_wide);
#endif
   return -1;
#else
   return rename(old_path, new_path)==0 ? 0 : -1;
#endif
}
int retro_vfs_file_remove_impl(const char *path)
{
   char *path_local    = NULL;
   wchar_t *path_wide  = NULL;

   if (!path || !*path)
      return -1;

   (void)path_local;
   (void)path_wide;

#if defined(_WIN32) && !defined(_XBOX)
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
   path_local = utf8_to_local_string_alloc(path);

   if (path_local)
   {
      int ret = remove(path_local);
      free(path_local);

      if (ret == 0)
         return 0;
   }
#else
   path_wide = utf8_to_utf16_string_alloc(path);

   if (path_wide)
   {
      int ret = _wremove(path_wide);
      free(path_wide);

      if (ret == 0)
         return 0;
   }
#endif
#else
   if (remove(path) == 0)
      return 0;
#endif
   return -1;
}
libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints)
{
   int                                flags = 0;
   const char                     *mode_str = NULL;
   libretro_vfs_implementation_file *stream = (libretro_vfs_implementation_file*)calloc(1, sizeof(*stream));

#ifdef VFS_FRONTEND
   const char                 *dumb_prefix  = "vfsonly://";
   int                      dumb_prefix_len = (int)strlen(dumb_prefix);
   int                             path_len = (int)strlen(path);

   if (path_len >= dumb_prefix_len)
      if (!memcmp(path, dumb_prefix, dumb_prefix_len))
         path += strlen(dumb_prefix);
#endif

   if (!stream)
      return NULL;

   (void)flags;

   stream->hints           = hints;
   stream->orig_path       = strdup(path);

#ifdef HAVE_MMAP
   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS && mode == RETRO_VFS_FILE_ACCESS_READ)
      stream->hints |= RFILE_HINT_UNBUFFERED;
   else
#endif
      stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;

   switch (mode)
   {
      case RETRO_VFS_FILE_ACCESS_READ:
         mode_str = "rb";

         flags    = O_RDONLY;
#ifdef _WIN32
         flags   |= O_BINARY;
#endif
         break;

      case RETRO_VFS_FILE_ACCESS_WRITE:
         mode_str = "wb";

         flags    = O_WRONLY | O_CREAT | O_TRUNC;
#if defined(PS2)
         flags   |= FIO_S_IRUSR | FIO_S_IWUSR;
#elif !defined(_WIN32)
         flags   |= S_IRUSR | S_IWUSR;
#else
         flags   |= O_BINARY;
#endif
         break;

      case RETRO_VFS_FILE_ACCESS_READ_WRITE:
         mode_str = "w+b";

         flags    = O_RDWR | O_CREAT | O_TRUNC;
#if defined(PS2)
         flags   |= FIO_S_IRUSR | FIO_S_IWUSR;
#elif !defined(_WIN32)
         flags   |= S_IRUSR | S_IWUSR;
#else
         flags   |= O_BINARY;
#endif
         break;

      case RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
      case RETRO_VFS_FILE_ACCESS_READ_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
         mode_str = "r+b";

         flags    = O_RDWR;
#if defined(PS2)
         flags   |= FIO_S_IRUSR | FIO_S_IWUSR;
#elif !defined(_WIN32)
         flags   |= S_IRUSR | S_IWUSR;
#else
         flags   |= O_BINARY;
#endif
         break;
         
      default:
         goto error;
   }

   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
   {
      FILE   *fp = (FILE*)fopen_utf8(path, mode_str);

      if (!fp)
         goto error;

      /* Regarding setvbuf:
       *
       * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
       *
       * If the size argument is not zero but buf is NULL, a buffer of the given size will be allocated immediately, and
       * released on close. This is an extension to ANSI C.
       *
       * 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;
      stream->buf = (char*)calloc(1, 0x4000);
      setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
   }
   else
   {
#if defined(_WIN32) && !defined(_XBOX)
#if defined(LEGACY_WIN32)
      char *path_local    = utf8_to_local_string_alloc(path);
      stream->fd          = open(path_local, flags, 0);
      if (path_local)
         free(path_local);
#else
      wchar_t * path_wide = utf8_to_utf16_string_alloc(path);
      stream->fd          = _wopen(path_wide, flags, 0);
      if (path_wide)
         free(path_wide);
#endif
#else
      stream->fd = open(path, flags, 0);
#endif

      if (stream->fd == -1)
         goto error;

#ifdef HAVE_MMAP
      if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
      {
         stream->mappos  = 0;
         stream->mapped  = NULL;
         stream->mapsize = retro_vfs_file_seek_internal(stream, 0, SEEK_END);

         if (stream->mapsize == (uint64_t)-1)
            goto error;

         retro_vfs_file_seek_internal(stream, 0, SEEK_SET);

         stream->mapped = (uint8_t*)mmap((void*)0,
               stream->mapsize, PROT_READ,  MAP_SHARED, stream->fd, 0);

         if (stream->mapped == MAP_FAILED)
            stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
      }
#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);

   return stream;

error:
   retro_vfs_file_close_impl(stream);
   return NULL;
}
Exemplo n.º 4
0
static bool path_stat(const char *path, enum stat_mode mode, int32_t *size)
{
#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 false;
   }
   free(tmp);

#elif defined(__CELLOS_LV2__)
    CellFsStat buf;
    if (cellFsStat(path, &buf) < 0)
       return false;
#elif defined(_WIN32)
   struct _stat buf;
   char *path_local;
   wchar_t *path_wide;
   DWORD file_info;

   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)
      *size = (int32_t)buf.st_size;

   switch (mode)
   {
      case IS_DIRECTORY:
#if defined(VITA) || defined(PSP)
         return FIO_S_ISDIR(buf.st_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(__CELLOS_LV2__) || defined(_WIN32)
         return false;
#else
         return S_ISCHR(buf.st_mode);
#endif
      case IS_VALID:
         return true;
   }

   return false;
}