diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index 858acabd5b..ad107c7d03 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -89,6 +89,8 @@ u8* ParamSFOData::GetValueData(std::string key, unsigned int *size) // I'm so sorry Ced but this is highly endian unsafe :( bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size) { + if (size < sizeof(Header)) + return false; const Header *header = (const Header *)paramsfo; if (header->magic != 0x46535000) return false; diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index c3fa8b40b0..84a3e5ecca 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #endif #if HOST_IS_CASE_SENSITIVE @@ -165,6 +166,13 @@ bool DirectoryFileHandle::Open(std::string& basePath, std::string& fileName, Fil std::string fullName = GetLocalPath(basePath,fileName); DEBUG_LOG(FILESYS,"Actually opening %s", fullName.c_str()); + // On the PSP, truncating doesn't lose data. If you seek later, you'll recover it. + // This is abnormal, so we deviate from the PSP's behavior and truncate on write/close. + // This means it's incorrectly not truncated before the write. + if (access & FILEACCESS_TRUNCATE) { + needsTrunc_ = 0; + } + //TODO: tests, should append seek to end of file? seeking in a file opened for append? #ifdef _WIN32 // Convert parameters to Windows permissions and access @@ -187,49 +195,32 @@ bool DirectoryFileHandle::Open(std::string& basePath, std::string& fileName, Fil //Let's do it! hFile = CreateFile(ConvertUTF8ToWString(fullName).c_str(), desired, sharemode, 0, openmode, 0, 0); bool success = hFile != INVALID_HANDLE_VALUE; - if (success && (access & FILEACCESS_TRUNCATE)) { - // We don't use OPEN_TRUNCATE because it would fail if it existed. - SetEndOfFile(hFile); - } #else - // Convert flags in access parameter to fopen access mode - const char *mode = NULL; + int flags = 0; if (access & FILEACCESS_APPEND) { - if (access & FILEACCESS_READ) - mode = "ab+"; // append+read, create if needed - else - mode = "ab"; // append only, create if needed + flags |= O_APPEND; + } + if ((access & FILEACCESS_READ) && (access & FILEACCESS_WRITE)) { + flags |= O_RDWR; + } else if (access & FILEACCESS_READ) { + flags |= O_RDONLY; } else if (access & FILEACCESS_WRITE) { - // TODO: "w" is wrong here. WRITE means write without truncate. - if (access & FILEACCESS_READ) { - // FILEACCESS_CREATE is ignored for read only, write only, and append - // because C++ standard fopen's nonexistant file creation can only be - // customized for files opened read+write - if (access & FILEACCESS_CREATE) - mode = "wb+"; // read+write, create if needed - else - mode = "rb+"; // read+write, but don't create - } else { - mode = "wb"; // write only, create if needed - } - } else { // neither write nor append, so default to read only - mode = "rb"; // read only, don't create + flags |= O_WRONLY; + } + if (access & FILEACCESS_CREATE) { + flags |= O_CREAT; } - hFile = fopen(fullName.c_str(), mode); - bool success = hFile != 0; + hFile = open(fullName.c_str(), flags, 0666); + bool success = hFile != -1; #endif #if HOST_IS_CASE_SENSITIVE - if (!success && - !(access & FILEACCESS_APPEND) && - !(access & FILEACCESS_CREATE) && - !(access & FILEACCESS_WRITE)) - { + if (!success && !(access & FILEACCESS_CREATE)) { if ( ! FixPathCase(basePath,fileName, FPC_PATH_MUST_EXIST) ) return 0; // or go on and attempt (for a better error code than just 0?) fullName = GetLocalPath(basePath,fileName); - const char* fullNameC = fullName.c_str(); + const char *fullNameC = fullName.c_str(); DEBUG_LOG(FILESYS, "Case may have been incorrect, second try opening %s (%s)", fullNameC, fileName.c_str()); @@ -238,8 +229,8 @@ bool DirectoryFileHandle::Open(std::string& basePath, std::string& fileName, Fil hFile = CreateFile(fullNameC, desired, sharemode, 0, openmode, 0, 0); success = hFile != INVALID_HANDLE_VALUE; #else - hFile = fopen(fullNameC, mode); - success = hFile != 0; + hFile = open(fullNameC, flags, 0666); + success = hFile != -1; #endif } #endif @@ -250,10 +241,21 @@ bool DirectoryFileHandle::Open(std::string& basePath, std::string& fileName, Fil size_t DirectoryFileHandle::Read(u8* pointer, s64 size) { size_t bytesRead = 0; + if (needsTrunc_ != -1) { + // If the file was marked to be truncated, pretend there's nothing. + // On a PSP. it actually is truncated, but the data wasn't erased. + off_t off = (off_t)Seek(0, FILEMOVE_CURRENT); + if (needsTrunc_ <= off) { + return 0; + } + if (needsTrunc_ < off + size) { + size = needsTrunc_ - off; + } + } #ifdef _WIN32 ::ReadFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesRead, 0); #else - bytesRead = fread(pointer, 1, size, hFile); + bytesRead = read(hFile, pointer, size); #endif return bytesRead; } @@ -264,13 +266,27 @@ size_t DirectoryFileHandle::Write(const u8* pointer, s64 size) #ifdef _WIN32 ::WriteFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesWritten, 0); #else - bytesWritten = fwrite(pointer, 1, size, hFile); + bytesWritten = write(hFile, pointer, size); #endif + if (needsTrunc_ != -1) { + off_t off = (off_t)Seek(0, FILEMOVE_CURRENT); + if (needsTrunc_ < off) { + needsTrunc_ = off; + } + } return bytesWritten; } size_t DirectoryFileHandle::Seek(s32 position, FileMove type) { + if (needsTrunc_ != -1) { + // If the file is "currently truncated" move to the end based on that position. + // The actual, underlying file hasn't been truncated (yet.) + if (type == FILEMOVE_END) { + type = FILEMOVE_BEGIN; + position = needsTrunc_ + position; + } + } #ifdef _WIN32 DWORD moveMethod = 0; switch (type) { @@ -287,19 +303,26 @@ size_t DirectoryFileHandle::Seek(s32 position, FileMove type) case FILEMOVE_CURRENT: moveMethod = SEEK_CUR; break; case FILEMOVE_END: moveMethod = SEEK_END; break; } - fseek(hFile, position, moveMethod); - return ftell(hFile); + return lseek(hFile, position, moveMethod); #endif } void DirectoryFileHandle::Close() { + if (needsTrunc_ != -1) { +#ifdef _WIN32 + Seek((s32)needsTrunc_, FILEMOVE_BEGIN); + SetEndOfFile(hFile); +#else + ftruncate(hFile, (off_t)needsTrunc_); +#endif + } #ifdef _WIN32 if (hFile != (HANDLE)-1) CloseHandle(hFile); #else - if (hFile != 0) - fclose(hFile); + if (hFile != -1) + close(hFile); #endif } @@ -466,7 +489,7 @@ u32 DirectoryFileSystem::OpenFile(std::string filename, FileAccess access, const #ifdef _WIN32 ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, %i - access = %i", GetLastError(), (int)access); #else - ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, access = %i", (int)access); + ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, %i - access = %i", errno, (int)access); #endif //wwwwaaaaahh!! return 0; @@ -687,7 +710,7 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { } void DirectoryFileSystem::DoState(PointerWrap &p) { - auto s = p.Section("DirectoryFileSystem", 0, 1); + auto s = p.Section("DirectoryFileSystem", 0, 2); if (!s) return; @@ -698,6 +721,7 @@ void DirectoryFileSystem::DoState(PointerWrap &p) { // std::string filename (in guest's terms, untranslated) // enum FileAccess file access mode // u32 seek position + // s64 current truncate position (v2+ only) u32 num = (u32) entries.size(); p.Do(num); @@ -720,6 +744,9 @@ void DirectoryFileSystem::DoState(PointerWrap &p) { ERROR_LOG(FILESYS, "Failed to restore seek position while loading state: %s", entry.guestFilename.c_str()); continue; } + if (s >= 2) { + p.Do(entry.hFile.needsTrunc_); + } entries[key] = entry; } } else { @@ -730,6 +757,7 @@ void DirectoryFileSystem::DoState(PointerWrap &p) { p.Do(iter->second.access); u32 position = (u32)iter->second.hFile.Seek(0, FILEMOVE_CURRENT); p.Do(position); + p.Do(iter->second.hFile.needsTrunc_); } } } diff --git a/Core/FileSystems/DirectoryFileSystem.h b/Core/FileSystems/DirectoryFileSystem.h index 71e43b1800..1f71d7315e 100644 --- a/Core/FileSystems/DirectoryFileSystem.h +++ b/Core/FileSystems/DirectoryFileSystem.h @@ -62,15 +62,18 @@ struct DirectoryFileHandle #ifdef _WIN32 HANDLE hFile; #else - FILE* hFile; + int hFile; #endif + s64 needsTrunc_; + DirectoryFileHandle() { #ifdef _WIN32 hFile = (HANDLE)-1; #else - hFile = 0; + hFile = -1; #endif + needsTrunc_ = -1; } std::string GetLocalPath(std::string& basePath, std::string localpath);