Attempt to virtually handle truncation properly.

Fixes LittleBigPlanet save problem, at least on US.
This commit is contained in:
Unknown W. Brackets
2014-02-15 10:34:38 -08:00
parent 9293bb17b9
commit cff6ad6428
2 changed files with 49 additions and 5 deletions
+46 -5
View File
@@ -166,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
@@ -188,10 +195,6 @@ 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
int flags = 0;
if (access & FILEACCESS_APPEND) {
@@ -238,6 +241,17 @@ 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
@@ -254,11 +268,25 @@ size_t DirectoryFileHandle::Write(const u8* pointer, s64 size)
#else
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) {
@@ -281,6 +309,14 @@ size_t DirectoryFileHandle::Seek(s32 position, FileMove type)
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);
@@ -674,7 +710,7 @@ std::vector<PSPFileInfo> 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;
@@ -685,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);
@@ -707,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 {
@@ -717,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_);
}
}
}