Fixes some file handling in IPC_HLE

* change File::GetSize to fetch the size directly from the open file instead
  of stat'ing it when challed with a FILE*
* use changed File::GetSize(FILE *f) instead of calling with file name in two
  places
* remove "seek_pos % file_size" hack for ZTP, so one can seek to the end of
  file again. Please check Zelda: Twilight Princess for regressions
* return error codes when reading or writing from/to a file

A lot of those changes are from j4ck.fr0st, so kudos to him.

I did not change the file open mode for ISFS_OPEN_WRITE to "wb". While that
would probably be more correct, it says in the comment that it might affect
Mario Kart Wii. I would prefer somebody with that game try that change
locally first.

Please check your games for regressions (or even improvement). Some games that
may be affected are Zelda - Twilight Princess and Metroid Prime 3.

Fixes issue 1749



git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6634 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
blubberdiblub 2010-12-21 18:03:44 +00:00
parent 6cb78515c6
commit 38e80fe094
2 changed files with 24 additions and 25 deletions

View File

@ -362,7 +362,19 @@ u64 GetSize(const int fd)
// Overloaded GetSize, accepts FILE* // Overloaded GetSize, accepts FILE*
u64 GetSize(FILE *f) u64 GetSize(FILE *f)
{ {
return GetSize(fileno(f)); off_t pos = ftello(f);
if (fseeko(f, 0, SEEK_END) != 0) {
ERROR_LOG(COMMON, "GetSize: seek failed %p: %s",
f, GetLastErrorMsg());
return 0;
}
off_t size = ftello(f);
if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) {
ERROR_LOG(COMMON, "GetSize: seek failed %p: %s",
f, GetLastErrorMsg());
return 0;
}
return size;
} }
// creates an empty file filename, returns true on success // creates an empty file filename, returns true on success

View File

@ -138,8 +138,8 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
m_Filename = std::string(HLE_IPC_BuildFilename(m_Name.c_str(), 64)); m_Filename = std::string(HLE_IPC_BuildFilename(m_Name.c_str(), 64));
// AyuanX: I think file must exist before we can open it // The file must exist before we can open it
// otherwise it should be created by FS, not here // It should be created by ISFS_CreateFile, not here
if(File::Exists(m_Filename.c_str())) if(File::Exists(m_Filename.c_str()))
{ {
INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s)", m_Name.c_str(), Modes[_Mode]); INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s)", m_Name.c_str(), Modes[_Mode]);
@ -161,7 +161,7 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
if (m_pFileHandle != NULL) if (m_pFileHandle != NULL)
{ {
m_FileLength = (u32)File::GetSize(m_Filename.c_str()); m_FileLength = (u32)File::GetSize(m_pFileHandle);
ReturnValue = m_DeviceID; ReturnValue = m_DeviceID;
} }
else if (ReturnValue == 0) else if (ReturnValue == 0)
@ -178,35 +178,21 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
{ {
u32 ReturnValue = 0; u32 ReturnValue = FS_INVALID_ARGUMENT;
s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC); s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
s32 Mode = Memory::Read_U32(_CommandAddress + 0x10); s32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
INFO_LOG(WII_IPC_FILEIO, "FileIO: Old Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08x)", SeekPosition, Mode, m_Name.c_str(), m_FileLength); INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08x)", SeekPosition, Mode, m_Name.c_str(), m_FileLength);
// TODO : The following hack smells bad /* TODO: Check if the new changes and the removed hack
/* Zelda - TP Fix: It doesn't make much sense but it works in Zelda - TP and "magically" fixes Zelda - Twilight Princess as well */
it's probably better than trying to read outside the file (it seeks to 0x6000 instead
of the correct 0x2000 for the second half of the file). Could this be right
or has it misunderstood the filesize somehow? My guess is that the filesize is
hardcoded in to the game, and it never checks the filesize, so I don't know.
Maybe it's wrong to return the seekposition when it's zero? Perhaps it wants
the filesize then? - No, that didn't work either, it seeks to 0x6000 even if I return
0x4000 from the first seek. */
s32 NewSeekPosition = SeekPosition;
if (m_FileLength > 0 && SeekPosition > (s32)m_FileLength && Mode == 0)
{
NewSeekPosition = SeekPosition % m_FileLength;
}
INFO_LOG(WII_IPC_FILEIO, "FileIO: New Seek Pos: 0x%08x, Mode: %i (%s)", NewSeekPosition, Mode, m_Name.c_str());
// Set seek mode // Set seek mode
int seek_mode[3] = {SEEK_SET, SEEK_CUR, SEEK_END}; int seek_mode[3] = {SEEK_SET, SEEK_CUR, SEEK_END};
if (Mode >= 0 && Mode <= 2) if (Mode >= 0 && Mode <= 2)
{ {
if (fseeko(m_pFileHandle, NewSeekPosition, seek_mode[Mode]) == 0) if (fseeko(m_pFileHandle, SeekPosition, seek_mode[Mode]) == 0)
{ {
ReturnValue = (u32)ftello(m_pFileHandle); ReturnValue = (u32)ftello(m_pFileHandle);
} }
@ -235,6 +221,7 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
{ {
INFO_LOG(WII_IPC_FILEIO, "FileIO: Read 0x%x bytes to 0x%08x from %s", Size, Address, m_Name.c_str()); INFO_LOG(WII_IPC_FILEIO, "FileIO: Read 0x%x bytes to 0x%08x from %s", Size, Address, m_Name.c_str());
ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, m_pFileHandle); ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, m_pFileHandle);
if ((ReturnValue != Size) && ferror(m_pFileHandle)) ReturnValue = FS_EACCESS;
} }
else else
{ {
@ -261,7 +248,7 @@ bool CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
#else #else
(void)Result; (void)Result;
#endif #endif
ReturnValue = Size; ReturnValue = (Result == 1) ? Size : FS_EACCESS;
} }
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
@ -285,7 +272,7 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
{ {
case ISFS_IOCTL_GETFILESTATS: case ISFS_IOCTL_GETFILESTATS:
{ {
m_FileLength = (u32)File::GetSize(m_Filename.c_str()); m_FileLength = File::GetSize(m_pFileHandle);
u32 Position = (u32)ftello(m_pFileHandle); u32 Position = (u32)ftello(m_pFileHandle);
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);