diff --git a/Utilities/rFile.cpp b/Utilities/rFile.cpp index ff41566927..d572b8c63f 100644 --- a/Utilities/rFile.cpp +++ b/Utilities/rFile.cpp @@ -21,12 +21,20 @@ std::wstring ConvertUTF8ToWString(const std::string &source) { } return str; } +#else +#include +#include +#if defined(__APPLE__) || defined(__FreeBSD__) +#include +#else +#include +#endif #endif #ifdef _WIN32 -#define GET_API_ERROR GetLastError() +#define GET_API_ERROR static_cast(GetLastError()) #else -#define GET_API_ERROR errno +#define GET_API_ERROR static_cast(errno) #endif bool getFileInfo(const char *path, FileInfo *fileInfo) { @@ -116,9 +124,10 @@ bool rRmdir(const std::string &dir) if (rmdir(dir.c_str())) #endif { - LOG_ERROR(GENERAL, "Error deleting directory %s: 0x%llx", dir.c_str(), (u64)GET_API_ERROR); + LOG_ERROR(GENERAL, "Error deleting directory %s: 0x%llx", dir.c_str(), GET_API_ERROR); return false; } + return true; } @@ -128,12 +137,64 @@ bool rRename(const std::string &from, const std::string &to) #ifdef _WIN32 if (!MoveFile(ConvertUTF8ToWString(from).c_str(), ConvertUTF8ToWString(to).c_str())) #else - if (int err = rename(from.c_str(), to.c_str())) + if (rename(from.c_str(), to.c_str())) #endif { - LOG_ERROR(GENERAL, "Error renaming '%s' to '%s': 0x%llx", from.c_str(), to.c_str(), (u64)GET_API_ERROR); + LOG_ERROR(GENERAL, "Error renaming '%s' to '%s': 0x%llx", from.c_str(), to.c_str(), GET_API_ERROR); return false; } + + return true; +} + +#ifndef _WIN32 + +int OSCopyFile(const char* source, const char* destination, bool overwrite) +{ + /* This function was taken from http://stackoverflow.com/questions/2180079/how-can-i-copy-a-file-on-unix-using-c */ + + int input, output; + if ((input = open(source, O_RDONLY)) == -1) + { + return -1; + } + if ((output = open(destination, O_RDWR | O_CREAT | (overwrite ? 0 : O_EXCL))) == -1) + { + close(input); + return -1; + } + + //Here we use kernel-space copying for performance reasons +#if defined(__APPLE__) || defined(__FreeBSD__) + //fcopyfile works on FreeBSD and OS X 10.5+ + int result = fcopyfile(input, output, 0, COPYFILE_ALL); +#else + //sendfile will work with non-socket output (i.e. regular file) on Linux 2.6.33+ + off_t bytesCopied = 0; + struct stat fileinfo = { 0 }; + fstat(input, &fileinfo); + int result = sendfile(output, input, &bytesCopied, fileinfo.st_size); +#endif + + close(input); + close(output); + + return result; +} +#endif + +bool rCopy(const std::string& from, const std::string& to, bool overwrite) +{ +#ifdef _WIN32 + if (!CopyFile(ConvertUTF8ToWString(from).c_str(), ConvertUTF8ToWString(to).c_str(), !overwrite)) +#else + if (OSCopyFile(from.c_str(), to.c_str(), overwrite)) +#endif + { + LOG_ERROR(GENERAL, "Error copying '%s' to '%s': 0x%llx", from.c_str(), to.c_str(), GET_API_ERROR); + return false; + } + return true; } @@ -156,7 +217,7 @@ bool rRemoveFile(const std::string &file) if (unlink(file.c_str())) #endif { - LOG_ERROR(GENERAL, "Error deleting file %s: 0x%llx", file.c_str(), (u64)GET_API_ERROR); + LOG_ERROR(GENERAL, "Error deleting file %s: 0x%llx", file.c_str(), GET_API_ERROR); return false; } return true; @@ -411,4 +472,3 @@ bool rFileName::Normalize() { return reinterpret_cast(handle)->Normalize(); } - diff --git a/Utilities/rFile.h b/Utilities/rFile.h index 563b7475be..174ff797e9 100644 --- a/Utilities/rFile.h +++ b/Utilities/rFile.h @@ -14,9 +14,10 @@ bool rIsDir(const std::string& filename); bool rRmdir(const std::string& dir); bool rMkdir(const std::string& dir); bool rMkpath(const std::string& path); -bool rRename(const std::string &from, const std::string &to); -bool rExists(const std::string &path); -bool rRemoveFile(const std::string &path); +bool rRename(const std::string& from, const std::string& to); +bool rCopy(const std::string& from, const std::string& to, bool overwrite); +bool rExists(const std::string& path); +bool rRemoveFile(const std::string& path); enum rSeekMode { diff --git a/rpcs3/Emu/FS/VFS.cpp b/rpcs3/Emu/FS/VFS.cpp index a44003e460..9182271ddd 100644 --- a/rpcs3/Emu/FS/VFS.cpp +++ b/rpcs3/Emu/FS/VFS.cpp @@ -7,6 +7,7 @@ #include "Emu/System.h" #undef CreateFile +#undef CopyFile std::vector simplify_path_blocks(const std::string& path) { @@ -297,6 +298,21 @@ bool VFS::RenameDir(const std::string& ps3_path_from, const std::string& ps3_pat return false; } +bool VFS::CopyFile(const std::string& ps3_path_from, const std::string& ps3_path_to, bool overwrite) const +{ + std::string path_from, path_to; + + if (vfsDevice* dev = GetDevice(ps3_path_from, path_from)) + { + if (vfsDevice* dev_ = GetDevice(ps3_path_to, path_to)) + { + return rCopy(path_from, path_to, overwrite); + } + } + + return false; +} + vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const { auto try_get_device = [this, &path](const std::string& ps3_path) -> vfsDevice* diff --git a/rpcs3/Emu/FS/VFS.h b/rpcs3/Emu/FS/VFS.h index d62ba7c411..4970af6bdb 100644 --- a/rpcs3/Emu/FS/VFS.h +++ b/rpcs3/Emu/FS/VFS.h @@ -86,6 +86,7 @@ struct VFS bool ExistsDir(const std::string& ps3_path) const; bool RenameFile(const std::string& ps3_path_from, const std::string& ps3_path_to) const; bool RenameDir(const std::string& ps3_path_from, const std::string& ps3_path_to) const; + bool CopyFile(const std::string& ps3_path_from, const std::string& ps3_path_to, bool overwrite = true) const; vfsDevice* GetDevice(const std::string& ps3_path, std::string& path) const; vfsDevice* GetDeviceLocal(const std::string& local_path, std::string& path) const; diff --git a/rpcs3/Emu/SysCalls/Modules/cellGame.cpp b/rpcs3/Emu/SysCalls/Modules/cellGame.cpp index eebdcba61b..dc7c3d85aa 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGame.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGame.cpp @@ -418,8 +418,8 @@ s32 cellGameCreateGameData(vm::ptr init, vm::ptr