From f2276bb70ca04e368f47e944e7a173290f053f8f Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 18 Apr 2015 16:38:42 +0300 Subject: [PATCH] VFS::TruncateFile() implemented --- Utilities/rFile.cpp | 64 +++++++++++++++++--- Utilities/rFile.h | 5 +- rpcs3/Emu/FS/VFS.cpp | 12 ++++ rpcs3/Emu/FS/VFS.h | 1 + rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp | 65 ++++++++++++--------- rpcs3/Emu/SysCalls/lv2/sys_fs.cpp | 22 ++----- rpcs3/Loader/PSF.h | 2 + 7 files changed, 117 insertions(+), 54 deletions(-) diff --git a/Utilities/rFile.cpp b/Utilities/rFile.cpp index bf018601ab..5229474d97 100644 --- a/Utilities/rFile.cpp +++ b/Utilities/rFile.cpp @@ -21,7 +21,7 @@ std::unique_ptr ConvertUTF8ToWChar(const std::string& source) if (!MultiByteToWideChar(CP_UTF8, 0, source.c_str(), size, buffer.get(), size)) { - LOG_ERROR(GENERAL, "ConvertUTF8ToWChar(source='%s') failed: 0x%llx", source.c_str(), GET_API_ERROR); + LOG_ERROR(GENERAL, "ConvertUTF8ToWChar(source='%s') failed: 0x%llx", source, GET_API_ERROR); } return buffer; @@ -36,6 +36,33 @@ time_t to_time_t(const FILETIME& ft) return v.QuadPart / 10000000ULL - 11644473600ULL; } +bool truncate_file(const std::string& file, uint64_t length) +{ + const auto handle = CreateFileW(ConvertUTF8ToWChar(file).get(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle == INVALID_HANDLE_VALUE) + { + return false; + } + + LARGE_INTEGER distance; + distance.QuadPart = length; + + if (!SetFilePointerEx(handle, distance, NULL, FILE_BEGIN)) + { + CloseHandle(handle); + return false; + } + + if (!SetEndOfFile(handle)) + { + CloseHandle(handle); + return false; + } + + return CloseHandle(handle); +} + #else #include #include @@ -119,10 +146,16 @@ bool rIsDir(const std::string& dir) bool rMkdir(const std::string& dir) { #ifdef _WIN32 - return !_mkdir(dir.c_str()); + if (!CreateDirectoryW(ConvertUTF8ToWChar(dir).get(), NULL)) #else - return !mkdir(dir.c_str(), 0777); + if (mkdir(dir.c_str(), 0777)) #endif + { + LOG_ERROR(GENERAL, "Error creating directory '%s': 0x%llx", dir, GET_API_ERROR); + return false; + } + + return true; } bool rMkpath(const std::string& path) @@ -160,7 +193,7 @@ bool rRmdir(const std::string& dir) if (rmdir(dir.c_str())) #endif { - LOG_ERROR(GENERAL, "Error deleting directory %s: 0x%llx", dir.c_str(), GET_API_ERROR); + LOG_ERROR(GENERAL, "Error deleting directory '%s': 0x%llx", dir, GET_API_ERROR); return false; } @@ -176,7 +209,7 @@ bool rRename(const std::string& from, const std::string& to) 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(), GET_API_ERROR); + LOG_ERROR(GENERAL, "Error renaming '%s' to '%s': 0x%llx", from, to, GET_API_ERROR); return false; } @@ -227,7 +260,7 @@ bool rCopy(const std::string& from, const std::string& to, bool overwrite) 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); + LOG_ERROR(GENERAL, "Error copying '%s' to '%s': 0x%llx", from, to, GET_API_ERROR); return false; } @@ -252,9 +285,25 @@ bool rRemoveFile(const std::string& file) if (unlink(file.c_str())) #endif { - LOG_ERROR(GENERAL, "Error deleting file %s: 0x%llx", file.c_str(), GET_API_ERROR); + LOG_ERROR(GENERAL, "Error deleting file '%s': 0x%llx", file, GET_API_ERROR); return false; } + + return true; +} + +bool rTruncate(const std::string& file, uint64_t length) +{ +#ifdef _WIN32 + if (!truncate_file(file, length)) +#else + if (truncate64(file.c_str()), length) +#endif + { + LOG_ERROR(GENERAL, "Error resizing file '%s' to 0x%llx: 0x%llx", file, length, GET_API_ERROR); + return false; + } + return true; } @@ -350,7 +399,6 @@ rFile::rFile() rFile::rFile(const std::string& filename, rFile::OpenMode open) { - handle = reinterpret_cast(new wxFile(fmt::FromUTF8(filename), convertOpenMode(open))); } diff --git a/Utilities/rFile.h b/Utilities/rFile.h index d94e0d63fb..d7e9f6fa12 100644 --- a/Utilities/rFile.h +++ b/Utilities/rFile.h @@ -20,8 +20,9 @@ bool rMkdir(const std::string& dir); bool rMkpath(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); +bool rExists(const std::string& file); +bool rRemoveFile(const std::string& file); +bool rTruncate(const std::string& file, uint64_t length); enum rSeekMode { diff --git a/rpcs3/Emu/FS/VFS.cpp b/rpcs3/Emu/FS/VFS.cpp index a44ea7f203..c228797978 100644 --- a/rpcs3/Emu/FS/VFS.cpp +++ b/rpcs3/Emu/FS/VFS.cpp @@ -315,6 +315,18 @@ bool VFS::CopyFile(const std::string& ps3_path_from, const std::string& ps3_path return false; } +bool VFS::TruncateFile(const std::string& ps3_path, u64 length) const +{ + std::string path; + + if (vfsDevice* dev = GetDevice(ps3_path, path)) + { + return rTruncate(path, length); + } + + 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 99ea1825e9..274b2a32c3 100644 --- a/rpcs3/Emu/FS/VFS.h +++ b/rpcs3/Emu/FS/VFS.h @@ -90,6 +90,7 @@ struct VFS 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; + bool TruncateFile(const std::string& ps3_path, u64 length) 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/cellSaveData.cpp b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp index a52f450692..119564a2ad 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp @@ -346,18 +346,22 @@ __noinline s32 savedata_op( save_entry.dirName = dirName.get_ptr(); } - // get save stats std::string dir_path = base_dir + save_entry.dirName + "/"; std::string sfo_path = dir_path + "PARAM.SFO"; + PSFLoader psf; + + // Load PARAM.SFO + { + vfsFile f(sfo_path); + psf.Load(f); + } + + // Get save stats { vm::stackvar statGet(CPU); vm::stackvar statSet(CPU); - vfsFile f(sfo_path); - PSFLoader psf(f); - f.Close(); - std::string dir_local_path; Emu.GetVFS().GetDevice(dir_path, dir_local_path); @@ -416,9 +420,13 @@ __noinline s32 savedata_op( { file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0; } + else if (psf.GetInteger("*" + entry->name)) // let's put the list of protected files in PARAM.SFO (int param = 1 if protected) + { + file.fileType = CELL_SAVEDATA_FILETYPE_SECUREFILE; + } else { - file.fileType = CELL_SAVEDATA_FILETYPE_NORMALFILE; // protected files are not supported + file.fileType = CELL_SAVEDATA_FILETYPE_NORMALFILE; } file.size = entry->size; @@ -481,22 +489,12 @@ __noinline s32 savedata_op( return CELL_SAVEDATA_ERROR_PARAM; } } + } - // Create save directory if necessary - if (save_entry.isNew && !Emu.GetVFS().CreateDir(dir_path)) - { - // error - } - - // Write PARAM.SFO - if (psf) - { - Emu.GetVFS().CreateFile(sfo_path, true); - - f.Open(sfo_path, vfsWrite); - psf.Save(f); - f.Close(); - } + // Create save directory if necessary + if (save_entry.isNew && !Emu.GetVFS().CreateDir(dir_path)) + { + // Let's ignore this error for now } // Enter the loop where the save files are read/created/deleted @@ -520,38 +518,38 @@ __noinline s32 savedata_op( break; } - std::string filepath = dir_path; + std::string filepath; switch (const u32 type = fileSet->fileType) { case CELL_SAVEDATA_FILETYPE_SECUREFILE: case CELL_SAVEDATA_FILETYPE_NORMALFILE: { - filepath += fileSet->fileName.get_ptr(); + filepath = fileSet->fileName.get_ptr(); break; } case CELL_SAVEDATA_FILETYPE_CONTENT_ICON0: { - filepath += "ICON0.PNG"; + filepath = "ICON0.PNG"; break; } case CELL_SAVEDATA_FILETYPE_CONTENT_ICON1: { - filepath += "ICON1.PAM"; + filepath = "ICON1.PAM"; break; } case CELL_SAVEDATA_FILETYPE_CONTENT_PIC1: { - filepath += "PIC1.PNG"; + filepath = "PIC1.PNG"; break; } case CELL_SAVEDATA_FILETYPE_CONTENT_SND0: { - filepath += "SND0.AT3"; + filepath = "SND0.AT3"; break; } @@ -562,6 +560,10 @@ __noinline s32 savedata_op( } } + psf.SetInteger("*" + filepath, fileSet->fileType.data() == se32(CELL_SAVEDATA_FILETYPE_SECUREFILE)); + + filepath = dir_path + filepath; + std::unique_ptr file; switch (const u32 op = fileSet->fileOperation) @@ -608,6 +610,15 @@ __noinline s32 savedata_op( } } + // Write PARAM.SFO + if (psf) + { + Emu.GetVFS().CreateFile(sfo_path, true); + + vfsFile f(sfo_path, vfsWrite); + psf.Save(f); + } + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp b/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp index 6637fae6d0..4279d9fbf5 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp @@ -527,28 +527,16 @@ s32 sys_fs_truncate(vm::ptr path, u64 size) sys_fs.Warning("sys_fs_truncate(path=*0x%x, size=0x%llx)", path, size); sys_fs.Warning("*** path = '%s'", path.get_ptr()); - vfsFile f(path.get_ptr(), vfsReadWrite); - if (!f.IsOpened()) + const std::string filename = path.get_ptr(); + + if (!Emu.GetVFS().ExistsFile(filename)) { - sys_fs.Warning("sys_fs_truncate(): '%s' not found", path.get_ptr()); return CELL_FS_ENOENT; } - u64 initialSize = f.GetSize(); - - if (initialSize < size) + if (!Emu.GetVFS().TruncateFile(filename, size)) { - u64 last_pos = f.Tell(); - f.Seek(0, vfsSeekEnd); - static const char nullbyte = 0; - f.Seek(size - initialSize - 1, vfsSeekCur); - f.Write(&nullbyte, sizeof(char)); - f.Seek(last_pos, vfsSeekSet); - } - - if (initialSize > size) - { - // (TODO) + return CELL_FS_EIO; // ??? } return CELL_OK; diff --git a/rpcs3/Loader/PSF.h b/rpcs3/Loader/PSF.h index dfc8853ffd..7b5532dd7f 100644 --- a/rpcs3/Loader/PSF.h +++ b/rpcs3/Loader/PSF.h @@ -41,6 +41,8 @@ class PSFLoader std::vector m_entries; public: + PSFLoader() = default; + PSFLoader(vfsStream& stream) { Load(stream);