diff --git a/configuration.c b/configuration.c index 2dfa1fd731..b4d25aceb6 100644 --- a/configuration.c +++ b/configuration.c @@ -2772,8 +2772,14 @@ static void video_driver_default_settings(global_t *global) sizeof(tmp_str)); \ if (path_is_valid(playlist_path)) \ { \ - rename(playlist_path, new_file); \ - if (!path_is_valid(new_file)) \ + if (!filestream_copy(playlist_path, new_file)) \ + RARCH_LOG("[Config]: Copied file \"%s\" to \"%s\".\n", playlist_path, new_file); \ + if (path_is_valid(new_file) && !filestream_cmp(playlist_path, new_file)) \ + { \ + if (!filestream_delete(playlist_path)) \ + RARCH_LOG("[Config]: Deleted file \"%s\".\n", playlist_path); \ + } \ + else \ new_file[0] = '\0'; \ } \ if (!string_is_empty(new_file)) \ diff --git a/libretro-common/include/streams/file_stream.h b/libretro-common/include/streams/file_stream.h index c76968acc4..43bfcf4041 100644 --- a/libretro-common/include/streams/file_stream.h +++ b/libretro-common/include/streams/file_stream.h @@ -369,6 +369,26 @@ int filestream_delete(const char *path); */ int filestream_rename(const char *old_path, const char *new_path); +/** + * Copies a file to a new location. + * + * @param src_path Path to the file to rename. + * @param dst_path The target name and location of the file. + * @return 0 if the file was copied successfully, + * or -1 if there was an error. + */ +int filestream_copy(const char *src_path, const char *dst_path); + +/** + * Compares and verifies files. + * + * @param src_path Path to the file. + * @param dst_path Path to the other file. + * @return 0 if the files are equal, + * or -1 if there was an error. + */ +int filestream_cmp(const char *src_path, const char *dst_path); + /** * Get the path that was used to open a file. * diff --git a/libretro-common/streams/file_stream.c b/libretro-common/streams/file_stream.c index ca867d0f12..68979619bf 100644 --- a/libretro-common/streams/file_stream.c +++ b/libretro-common/streams/file_stream.c @@ -34,6 +34,8 @@ #include #endif +#include +#include #include #include #define VFS_FRONTEND @@ -44,7 +46,7 @@ struct RFILE { struct retro_vfs_file_handle *hfile; - bool error_flag; + bool error_flag; }; static retro_vfs_get_path_t filestream_get_path_cb = NULL; @@ -436,6 +438,72 @@ int filestream_rename(const char *old_path, const char *new_path) return retro_vfs_file_rename_impl(old_path, new_path); } +int filestream_copy(const char *src, const char *dst) +{ + char buf[256] = {0}; + int64_t n = 0; + int ret = 0; + char path_dst[PATH_MAX_LENGTH] = {0}; + + RFILE *fp_src = filestream_open(src, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE); + RFILE *fp_dst = filestream_open(dst, RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE); + + if (!fp_src || !fp_dst) + ret = -1; + + if (ret < 0) + goto close; + + snprintf(path_dst, sizeof(path_dst), "%s", dst); + path_basedir(path_dst); + + if (!path_is_directory(path_dst)) + path_mkdir(path_dst); + + while ((n = filestream_read(fp_src, buf, sizeof(buf))) > 0 && ret == 0) + { + if (filestream_write(fp_dst, buf, sizeof(buf)) != n) + ret = -1; + } + +close: + if (fp_src) + filestream_close(fp_src); + if (fp_dst) + filestream_close(fp_dst); + return ret; +} + +int filestream_cmp(const char *src, const char *dst) +{ + char buf_src[256] = {0}; + char buf_dst[256] = {0}; + int64_t n = 0; + int ret = 0; + + RFILE *fp_src = filestream_open(src, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE); + RFILE *fp_dst = filestream_open(dst, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE); + + if (!fp_src || !fp_dst) + ret = -1; + + if (ret < 0) + goto close; + + while ((n = filestream_read(fp_src, buf_src, sizeof(buf_src))) > 0 && ret == 0) + { + filestream_read(fp_dst, buf_dst, sizeof(buf_dst)); + ret = memcmp(buf_src, buf_dst, sizeof(buf_src)); + } + +close: + if (fp_src) + filestream_close(fp_src); + if (fp_dst) + filestream_close(fp_dst); + return ret; +} + const char* filestream_get_path(RFILE *stream) { if (filestream_get_path_cb)