summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorMat M <mathew1800@gmail.com>2017-01-31 22:28:42 -0500
committerGitHub <noreply@github.com>2017-01-31 22:28:42 -0500
commit6fd0e96ea3992e62f6750fcebfeec4755d110435 (patch)
tree8399f62d91554c1b8603ddf0f42d29f36e90fe82 /Source/Core
parent84d81a4b7a9622e00c723fa8aec648f7b71e2717 (diff)
parentd2da1897e7943fd6f8551528778219e0d2a5acd8 (diff)
Merge pull request #4785 from lioncash/ios-fs
IOS FS: Move behavior to separate functions
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/IOS/FS/FS.cpp950
-rw-r--r--Source/Core/Core/IOS/FS/FS.h13
2 files changed, 494 insertions, 469 deletions
diff --git a/Source/Core/Core/IOS/FS/FS.cpp b/Source/Core/Core/IOS/FS/FS.cpp
index cebd8dfc5c..912b475f6a 100644
--- a/Source/Core/Core/IOS/FS/FS.cpp
+++ b/Source/Core/Core/IOS/FS/FS.cpp
@@ -37,11 +37,99 @@ FS::FS(u32 device_id, const std::string& device_name) : Device(device_id, device
{
}
-// ~1/1000th of a second is too short and causes hangs in Wii Party
-// Play it safe at 1/500th
-IPCCommandResult FS::GetFSReply(const s32 return_value) const
+void FS::DoState(PointerWrap& p)
{
- return {return_value, true, SystemTimers::GetTicksPerSecond() / 500};
+ DoStateShared(p);
+
+ // handle /tmp
+
+ std::string Path = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/tmp";
+ if (p.GetMode() == PointerWrap::MODE_READ)
+ {
+ File::DeleteDirRecursively(Path);
+ File::CreateDir(Path);
+
+ // now restore from the stream
+ while (1)
+ {
+ char type = 0;
+ p.Do(type);
+ if (!type)
+ break;
+ std::string filename;
+ p.Do(filename);
+ std::string name = Path + DIR_SEP + filename;
+ switch (type)
+ {
+ case 'd':
+ {
+ File::CreateDir(name);
+ break;
+ }
+ case 'f':
+ {
+ u32 size = 0;
+ p.Do(size);
+
+ File::IOFile handle(name, "wb");
+ char buf[65536];
+ u32 count = size;
+ while (count > 65536)
+ {
+ p.DoArray(buf);
+ handle.WriteArray(&buf[0], 65536);
+ count -= 65536;
+ }
+ p.DoArray(&buf[0], count);
+ handle.WriteArray(&buf[0], count);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // recurse through tmp and save dirs and files
+
+ File::FSTEntry parentEntry = File::ScanDirectoryTree(Path, true);
+ std::deque<File::FSTEntry> todo;
+ todo.insert(todo.end(), parentEntry.children.begin(), parentEntry.children.end());
+
+ while (!todo.empty())
+ {
+ File::FSTEntry& entry = todo.front();
+ std::string name = entry.physicalName;
+ name.erase(0, Path.length() + 1);
+ char type = entry.isDirectory ? 'd' : 'f';
+ p.Do(type);
+ p.Do(name);
+ if (entry.isDirectory)
+ {
+ todo.insert(todo.end(), entry.children.begin(), entry.children.end());
+ }
+ else
+ {
+ u32 size = (u32)entry.size;
+ p.Do(size);
+
+ File::IOFile handle(entry.physicalName, "rb");
+ char buf[65536];
+ u32 count = size;
+ while (count > 65536)
+ {
+ handle.ReadArray(&buf[0], 65536);
+ p.DoArray(buf);
+ count -= 65536;
+ }
+ handle.ReadArray(&buf[0], count);
+ p.DoArray(&buf[0], count);
+ }
+ todo.pop_front();
+ }
+
+ char type = 0;
+ p.Do(type);
+ }
}
ReturnCode FS::Open(const OpenRequest& request)
@@ -72,571 +160,497 @@ static u64 ComputeTotalFileSize(const File::FSTEntry& parentEntry)
return sizeOfFiles;
}
+IPCCommandResult FS::IOCtl(const IOCtlRequest& request)
+{
+ Memory::Memset(request.buffer_out, 0, request.buffer_out_size);
+
+ switch (request.request)
+ {
+ case IOCTL_GET_STATS:
+ return GetStats(request);
+ case IOCTL_CREATE_DIR:
+ return CreateDirectory(request);
+ case IOCTL_SET_ATTR:
+ return SetAttribute(request);
+ case IOCTL_GET_ATTR:
+ return GetAttribute(request);
+ case IOCTL_DELETE_FILE:
+ return DeleteFile(request);
+ case IOCTL_RENAME_FILE:
+ return RenameFile(request);
+ case IOCTL_CREATE_FILE:
+ return CreateFile(request);
+ case IOCTL_SHUTDOWN:
+ return Shutdown(request);
+ default:
+ request.DumpUnknown(GetDeviceName(), LogTypes::IOS_FILEIO);
+ break;
+ }
+
+ return GetFSReply(FS_EINVAL);
+}
+
IPCCommandResult FS::IOCtlV(const IOCtlVRequest& request)
{
- s32 return_value = IPC_SUCCESS;
switch (request.request)
{
case IOCTLV_READ_DIR:
- {
- const std::string relative_path =
- Memory::GetString(request.in_vectors[0].address, request.in_vectors[0].size);
+ return ReadDirectory(request);
+ case IOCTLV_GETUSAGE:
+ return GetUsage(request);
+ default:
+ request.DumpUnknown(GetDeviceName(), LogTypes::IOS_FILEIO);
+ break;
+ }
- if (!IsValidWiiPath(relative_path))
- {
- WARN_LOG(IOS_FILEIO, "Not a valid path: %s", relative_path.c_str());
- return_value = FS_EINVAL;
- break;
- }
+ return GetFSReply(IPC_SUCCESS);
+}
- // the Wii uses this function to define the type (dir or file)
- std::string DirName(HLE_IPC_BuildFilename(relative_path));
+// ~1/1000th of a second is too short and causes hangs in Wii Party
+// Play it safe at 1/500th
+IPCCommandResult FS::GetFSReply(const s32 return_value) const
+{
+ return {return_value, true, SystemTimers::GetTicksPerSecond() / 500};
+}
- INFO_LOG(IOS_FILEIO, "FS: IOCTL_READ_DIR %s", DirName.c_str());
+IPCCommandResult FS::GetStats(const IOCtlRequest& request)
+{
+ if (request.buffer_out_size < 0x1c)
+ return GetFSReply(-1017);
- if (!File::Exists(DirName))
- {
- WARN_LOG(IOS_FILEIO, "FS: Search not found: %s", DirName.c_str());
- return_value = FS_ENOENT;
- break;
- }
- else if (!File::IsDirectory(DirName))
- {
- // It's not a directory, so error.
- // Games don't usually seem to care WHICH error they get, as long as it's <
- // Well the system menu CARES!
- WARN_LOG(IOS_FILEIO, "\tNot a directory - return FS_EINVAL");
- return_value = FS_EINVAL;
- break;
- }
+ WARN_LOG(IOS_FILEIO, "FS: GET STATS - returning static values for now");
- File::FSTEntry entry = File::ScanDirectoryTree(DirName, false);
+ // TODO: scrape the real amounts from somewhere...
+ NANDStat fs;
+ fs.BlockSize = 0x4000;
+ fs.FreeUserBlocks = 0x5DEC;
+ fs.UsedUserBlocks = 0x1DD4;
+ fs.FreeSysBlocks = 0x10;
+ fs.UsedSysBlocks = 0x02F0;
+ fs.Free_INodes = 0x146B;
+ fs.Used_Inodes = 0x0394;
- // it is one
- if ((request.in_vectors.size() == 1) && (request.io_vectors.size() == 1))
- {
- size_t numFile = entry.children.size();
- INFO_LOG(IOS_FILEIO, "\t%zu files found", numFile);
+ std::memcpy(Memory::GetPointer(request.buffer_out), &fs, sizeof(NANDStat));
- Memory::Write_U32((u32)numFile, request.io_vectors[0].address);
- }
- else
- {
- for (File::FSTEntry& child : entry.children)
- {
- // Decode escaped invalid file system characters so that games (such as
- // Harry Potter and the Half-Blood Prince) can find what they expect.
- child.virtualName = Common::UnescapeFileName(child.virtualName);
- }
+ return GetFSReply(IPC_SUCCESS);
+}
- std::sort(entry.children.begin(), entry.children.end(),
- [](const File::FSTEntry& one, const File::FSTEntry& two) {
- return one.virtualName < two.virtualName;
- });
+IPCCommandResult FS::CreateDirectory(const IOCtlRequest& request)
+{
+ _dbg_assert_(IOS_FILEIO, request.buffer_out_size == 0);
+ u32 Addr = request.buffer_in;
- u32 MaxEntries = Memory::Read_U32(request.in_vectors[0].address);
+ u32 OwnerID = Memory::Read_U32(Addr);
+ Addr += 4;
+ u16 GroupID = Memory::Read_U16(Addr);
+ Addr += 2;
- memset(Memory::GetPointer(request.io_vectors[0].address), 0, request.io_vectors[0].size);
+ const std::string wii_path = Memory::GetString(Addr, 64);
+ if (!IsValidWiiPath(wii_path))
+ {
+ WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
+ return GetFSReply(FS_EINVAL);
+ }
- size_t numFiles = 0;
- char* pFilename = (char*)Memory::GetPointer((u32)(request.io_vectors[0].address));
+ std::string DirName(HLE_IPC_BuildFilename(wii_path));
+ Addr += 64;
+ Addr += 9; // owner attribs, permission
+ u8 Attribs = Memory::Read_U8(Addr);
- for (size_t i = 0; i < entry.children.size() && i < MaxEntries; i++)
- {
- const std::string& FileName = entry.children[i].virtualName;
+ INFO_LOG(IOS_FILEIO, "FS: CREATE_DIR %s, OwnerID %#x, GroupID %#x, Attributes %#x",
+ DirName.c_str(), OwnerID, GroupID, Attribs);
- strcpy(pFilename, FileName.c_str());
- pFilename += FileName.length();
- *pFilename++ = 0x00; // termination
- numFiles++;
+ DirName += DIR_SEP;
+ File::CreateFullPath(DirName);
+ _dbg_assert_msg_(IOS_FILEIO, File::IsDirectory(DirName), "FS: CREATE_DIR %s failed",
+ DirName.c_str());
- INFO_LOG(IOS_FILEIO, "\tFound: %s", FileName.c_str());
- }
+ return GetFSReply(IPC_SUCCESS);
+}
- Memory::Write_U32((u32)numFiles, request.io_vectors[1].address);
- }
+IPCCommandResult FS::SetAttribute(const IOCtlRequest& request)
+{
+ u32 Addr = request.buffer_in;
- return_value = IPC_SUCCESS;
- }
- break;
+ u32 OwnerID = Memory::Read_U32(Addr);
+ Addr += 4;
+ u16 GroupID = Memory::Read_U16(Addr);
+ Addr += 2;
- case IOCTLV_GETUSAGE:
+ const std::string wii_path = Memory::GetString(Addr, 64);
+ if (!IsValidWiiPath(wii_path))
{
- _dbg_assert_(IOS_FILEIO, request.io_vectors.size() == 2);
- _dbg_assert_(IOS_FILEIO, request.io_vectors[0].size == 4);
- _dbg_assert_(IOS_FILEIO, request.io_vectors[1].size == 4);
+ WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
+ return GetFSReply(FS_EINVAL);
+ }
- // this command sucks because it asks of the number of used
- // fsBlocks and inodes
- // It should be correct, but don't count on it...
- std::string relativepath =
- Memory::GetString(request.in_vectors[0].address, request.in_vectors[0].size);
+ std::string Filename = HLE_IPC_BuildFilename(wii_path);
+ Addr += 64;
+ u8 OwnerPerm = Memory::Read_U8(Addr);
+ Addr += 1;
+ u8 GroupPerm = Memory::Read_U8(Addr);
+ Addr += 1;
+ u8 OtherPerm = Memory::Read_U8(Addr);
+ Addr += 1;
+ u8 Attributes = Memory::Read_U8(Addr);
+ Addr += 1;
+
+ INFO_LOG(IOS_FILEIO, "FS: SetAttrib %s", Filename.c_str());
+ DEBUG_LOG(IOS_FILEIO, " OwnerID: 0x%08x", OwnerID);
+ DEBUG_LOG(IOS_FILEIO, " GroupID: 0x%04x", GroupID);
+ DEBUG_LOG(IOS_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm);
+ DEBUG_LOG(IOS_FILEIO, " GroupPerm: 0x%02x", GroupPerm);
+ DEBUG_LOG(IOS_FILEIO, " OtherPerm: 0x%02x", OtherPerm);
+ DEBUG_LOG(IOS_FILEIO, " Attributes: 0x%02x", Attributes);
+
+ return GetFSReply(IPC_SUCCESS);
+}
- if (!IsValidWiiPath(relativepath))
- {
- WARN_LOG(IOS_FILEIO, "Not a valid path: %s", relativepath.c_str());
- return_value = FS_EINVAL;
- break;
- }
+IPCCommandResult FS::GetAttribute(const IOCtlRequest& request)
+{
+ _dbg_assert_msg_(IOS_FILEIO, request.buffer_out_size == 76,
+ " GET_ATTR needs an 76 bytes large output buffer but it is %i bytes large",
+ request.buffer_out_size);
- std::string path(HLE_IPC_BuildFilename(relativepath));
- u32 fsBlocks = 0;
- u32 iNodes = 0;
+ u32 OwnerID = 0;
+ u16 GroupID = 0x3031; // this is also known as makercd, 01 (0x3031) for nintendo and 08
+ // (0x3038) for MH3 etc
- INFO_LOG(IOS_FILEIO, "IOCTL_GETUSAGE %s", path.c_str());
- if (File::IsDirectory(path))
- {
- // LPFaint99: After I found that setting the number of inodes to the number of children + 1
- // for the directory itself
- // I decided to compare with sneek which has the following 2 special cases which are
- // Copyright (C) 2009-2011 crediar http://code.google.com/p/sneek/
- if ((relativepath.compare(0, 16, "/title/00010001") == 0) ||
- (relativepath.compare(0, 16, "/title/00010005") == 0))
- {
- fsBlocks = 23; // size is size/0x4000
- iNodes = 42; // empty folders return a FileCount of 1
- }
- else
- {
- File::FSTEntry parentDir = File::ScanDirectoryTree(path, true);
- // add one for the folder itself
- iNodes = 1 + (u32)parentDir.size;
-
- u64 totalSize =
- ComputeTotalFileSize(parentDir); // "Real" size, to be converted to nand blocks
+ const std::string wii_path = Memory::GetString(request.buffer_in, 64);
+ if (!IsValidWiiPath(wii_path))
+ {
+ WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
+ return GetFSReply(FS_EINVAL);
+ }
- fsBlocks = (u32)(totalSize / (16 * 1024)); // one bock is 16kb
- }
- return_value = IPC_SUCCESS;
+ std::string Filename = HLE_IPC_BuildFilename(wii_path);
+ u8 OwnerPerm = 0x3; // read/write
+ u8 GroupPerm = 0x3; // read/write
+ u8 OtherPerm = 0x3; // read/write
+ u8 Attributes = 0x00; // no attributes
- INFO_LOG(IOS_FILEIO, "FS: fsBlock: %i, iNodes: %i", fsBlocks, iNodes);
+ if (File::IsDirectory(Filename))
+ {
+ INFO_LOG(IOS_FILEIO, "FS: GET_ATTR Directory %s - all permission flags are set",
+ Filename.c_str());
+ }
+ else
+ {
+ if (File::Exists(Filename))
+ {
+ INFO_LOG(IOS_FILEIO, "FS: GET_ATTR %s - all permission flags are set", Filename.c_str());
}
else
{
- fsBlocks = 0;
- iNodes = 0;
- return_value = IPC_SUCCESS;
- WARN_LOG(IOS_FILEIO, "FS: fsBlock failed, cannot find directory: %s", path.c_str());
+ INFO_LOG(IOS_FILEIO, "FS: GET_ATTR unknown %s", Filename.c_str());
+ return GetFSReply(FS_ENOENT);
}
-
- Memory::Write_U32(fsBlocks, request.io_vectors[0].address);
- Memory::Write_U32(iNodes, request.io_vectors[1].address);
}
- break;
- default:
- request.DumpUnknown(GetDeviceName(), LogTypes::IOS_FILEIO);
- break;
+ // write answer to buffer
+ if (request.buffer_out_size == 76)
+ {
+ u32 Addr = request.buffer_out;
+ Memory::Write_U32(OwnerID, Addr);
+ Addr += 4;
+ Memory::Write_U16(GroupID, Addr);
+ Addr += 2;
+ memcpy(Memory::GetPointer(Addr), Memory::GetPointer(request.buffer_in), 64);
+ Addr += 64;
+ Memory::Write_U8(OwnerPerm, Addr);
+ Addr += 1;
+ Memory::Write_U8(GroupPerm, Addr);
+ Addr += 1;
+ Memory::Write_U8(OtherPerm, Addr);
+ Addr += 1;
+ Memory::Write_U8(Attributes, Addr);
+ Addr += 1;
}
- return GetFSReply(return_value);
+ return GetFSReply(IPC_SUCCESS);
}
-IPCCommandResult FS::IOCtl(const IOCtlRequest& request)
+IPCCommandResult FS::DeleteFile(const IOCtlRequest& request)
{
- Memory::Memset(request.buffer_out, 0, request.buffer_out_size);
- const s32 return_value = ExecuteCommand(request);
- return GetFSReply(return_value);
-}
+ _dbg_assert_(IOS_FILEIO, request.buffer_out_size == 0);
+ int Offset = 0;
-s32 FS::ExecuteCommand(const IOCtlRequest& request)
-{
- switch (request.request)
+ const std::string wii_path = Memory::GetString(request.buffer_in + Offset, 64);
+ if (!IsValidWiiPath(wii_path))
{
- case IOCTL_GET_STATS:
- {
- if (request.buffer_out_size < 0x1c)
- return -1017;
-
- WARN_LOG(IOS_FILEIO, "FS: GET STATS - returning static values for now");
+ WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
+ return GetFSReply(FS_EINVAL);
+ }
- NANDStat fs;
+ std::string Filename = HLE_IPC_BuildFilename(wii_path);
+ Offset += 64;
+ if (File::Delete(Filename))
+ {
+ INFO_LOG(IOS_FILEIO, "FS: DeleteFile %s", Filename.c_str());
+ }
+ else if (File::DeleteDir(Filename))
+ {
+ INFO_LOG(IOS_FILEIO, "FS: DeleteDir %s", Filename.c_str());
+ }
+ else
+ {
+ WARN_LOG(IOS_FILEIO, "FS: DeleteFile %s - failed!!!", Filename.c_str());
+ }
- // TODO: scrape the real amounts from somewhere...
- fs.BlockSize = 0x4000;
- fs.FreeUserBlocks = 0x5DEC;
- fs.UsedUserBlocks = 0x1DD4;
- fs.FreeSysBlocks = 0x10;
- fs.UsedSysBlocks = 0x02F0;
- fs.Free_INodes = 0x146B;
- fs.Used_Inodes = 0x0394;
+ return GetFSReply(IPC_SUCCESS);
+}
- std::memcpy(Memory::GetPointer(request.buffer_out), &fs, sizeof(NANDStat));
+IPCCommandResult FS::RenameFile(const IOCtlRequest& request)
+{
+ _dbg_assert_(IOS_FILEIO, request.buffer_out_size == 0);
+ int Offset = 0;
- return IPC_SUCCESS;
+ const std::string wii_path = Memory::GetString(request.buffer_in + Offset, 64);
+ if (!IsValidWiiPath(wii_path))
+ {
+ WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
+ return GetFSReply(FS_EINVAL);
}
- break;
+ std::string Filename = HLE_IPC_BuildFilename(wii_path);
+ Offset += 64;
- case IOCTL_CREATE_DIR:
+ const std::string wii_path_rename = Memory::GetString(request.buffer_in + Offset, 64);
+ if (!IsValidWiiPath(wii_path_rename))
{
- _dbg_assert_(IOS_FILEIO, request.buffer_out_size == 0);
- u32 Addr = request.buffer_in;
-
- u32 OwnerID = Memory::Read_U32(Addr);
- Addr += 4;
- u16 GroupID = Memory::Read_U16(Addr);
- Addr += 2;
- const std::string wii_path = Memory::GetString(Addr, 64);
- if (!IsValidWiiPath(wii_path))
- {
- WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
- return FS_EINVAL;
- }
- std::string DirName(HLE_IPC_BuildFilename(wii_path));
- Addr += 64;
- Addr += 9; // owner attribs, permission
- u8 Attribs = Memory::Read_U8(Addr);
+ WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path_rename.c_str());
+ return GetFSReply(FS_EINVAL);
+ }
- INFO_LOG(IOS_FILEIO, "FS: CREATE_DIR %s, OwnerID %#x, GroupID %#x, Attributes %#x",
- DirName.c_str(), OwnerID, GroupID, Attribs);
+ std::string FilenameRename = HLE_IPC_BuildFilename(wii_path_rename);
+ Offset += 64;
- DirName += DIR_SEP;
- File::CreateFullPath(DirName);
- _dbg_assert_msg_(IOS_FILEIO, File::IsDirectory(DirName), "FS: CREATE_DIR %s failed",
- DirName.c_str());
+ // try to make the basis directory
+ File::CreateFullPath(FilenameRename);
- return IPC_SUCCESS;
+ // if there is already a file, delete it
+ if (File::Exists(Filename) && File::Exists(FilenameRename))
+ {
+ File::Delete(FilenameRename);
}
- break;
- case IOCTL_SET_ATTR:
+ // finally try to rename the file
+ if (File::Rename(Filename, FilenameRename))
+ {
+ INFO_LOG(IOS_FILEIO, "FS: Rename %s to %s", Filename.c_str(), FilenameRename.c_str());
+ }
+ else
{
- u32 Addr = request.buffer_in;
+ ERROR_LOG(IOS_FILEIO, "FS: Rename %s to %s - failed", Filename.c_str(), FilenameRename.c_str());
+ return GetFSReply(FS_ENOENT);
+ }
- u32 OwnerID = Memory::Read_U32(Addr);
- Addr += 4;
- u16 GroupID = Memory::Read_U16(Addr);
- Addr += 2;
- const std::string wii_path = Memory::GetString(Addr, 64);
- if (!IsValidWiiPath(wii_path))
- {
- WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
- return FS_EINVAL;
- }
- std::string Filename = HLE_IPC_BuildFilename(wii_path);
- Addr += 64;
- u8 OwnerPerm = Memory::Read_U8(Addr);
- Addr += 1;
- u8 GroupPerm = Memory::Read_U8(Addr);
- Addr += 1;
- u8 OtherPerm = Memory::Read_U8(Addr);
- Addr += 1;
- u8 Attributes = Memory::Read_U8(Addr);
- Addr += 1;
+ return GetFSReply(IPC_SUCCESS);
+}
+
+IPCCommandResult FS::CreateFile(const IOCtlRequest& request)
+{
+ _dbg_assert_(IOS_FILEIO, request.buffer_out_size == 0);
- INFO_LOG(IOS_FILEIO, "FS: SetAttrib %s", Filename.c_str());
- DEBUG_LOG(IOS_FILEIO, " OwnerID: 0x%08x", OwnerID);
- DEBUG_LOG(IOS_FILEIO, " GroupID: 0x%04x", GroupID);
- DEBUG_LOG(IOS_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm);
- DEBUG_LOG(IOS_FILEIO, " GroupPerm: 0x%02x", GroupPerm);
- DEBUG_LOG(IOS_FILEIO, " OtherPerm: 0x%02x", OtherPerm);
- DEBUG_LOG(IOS_FILEIO, " Attributes: 0x%02x", Attributes);
+ u32 Addr = request.buffer_in;
+ u32 OwnerID = Memory::Read_U32(Addr);
+ Addr += 4;
+ u16 GroupID = Memory::Read_U16(Addr);
+ Addr += 2;
- return IPC_SUCCESS;
+ const std::string wii_path = Memory::GetString(Addr, 64);
+ if (!IsValidWiiPath(wii_path))
+ {
+ WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
+ return GetFSReply(FS_EINVAL);
}
- break;
- case IOCTL_GET_ATTR:
+ std::string Filename(HLE_IPC_BuildFilename(wii_path));
+ Addr += 64;
+ u8 OwnerPerm = Memory::Read_U8(Addr);
+ Addr++;
+ u8 GroupPerm = Memory::Read_U8(Addr);
+ Addr++;
+ u8 OtherPerm = Memory::Read_U8(Addr);
+ Addr++;
+ u8 Attributes = Memory::Read_U8(Addr);
+ Addr++;
+
+ INFO_LOG(IOS_FILEIO, "FS: CreateFile %s", Filename.c_str());
+ DEBUG_LOG(IOS_FILEIO, " OwnerID: 0x%08x", OwnerID);
+ DEBUG_LOG(IOS_FILEIO, " GroupID: 0x%04x", GroupID);
+ DEBUG_LOG(IOS_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm);
+ DEBUG_LOG(IOS_FILEIO, " GroupPerm: 0x%02x", GroupPerm);
+ DEBUG_LOG(IOS_FILEIO, " OtherPerm: 0x%02x", OtherPerm);
+ DEBUG_LOG(IOS_FILEIO, " Attributes: 0x%02x", Attributes);
+
+ // check if the file already exist
+ if (File::Exists(Filename))
{
- _dbg_assert_msg_(IOS_FILEIO, request.buffer_out_size == 76,
- " GET_ATTR needs an 76 bytes large output buffer but it is %i bytes large",
- request.buffer_out_size);
+ INFO_LOG(IOS_FILEIO, "\tresult = FS_EEXIST");
+ return GetFSReply(FS_EEXIST);
+ }
- u32 OwnerID = 0;
- u16 GroupID = 0x3031; // this is also known as makercd, 01 (0x3031) for nintendo and 08
- // (0x3038) for MH3 etc
- const std::string wii_path = Memory::GetString(request.buffer_in, 64);
- if (!IsValidWiiPath(wii_path))
- {
- WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
- return FS_EINVAL;
- }
- std::string Filename = HLE_IPC_BuildFilename(wii_path);
- u8 OwnerPerm = 0x3; // read/write
- u8 GroupPerm = 0x3; // read/write
- u8 OtherPerm = 0x3; // read/write
- u8 Attributes = 0x00; // no attributes
- if (File::IsDirectory(Filename))
- {
- INFO_LOG(IOS_FILEIO, "FS: GET_ATTR Directory %s - all permission flags are set",
- Filename.c_str());
- }
- else
- {
- if (File::Exists(Filename))
- {
- INFO_LOG(IOS_FILEIO, "FS: GET_ATTR %s - all permission flags are set", Filename.c_str());
- }
- else
- {
- INFO_LOG(IOS_FILEIO, "FS: GET_ATTR unknown %s", Filename.c_str());
- return FS_ENOENT;
- }
- }
+ // create the file
+ File::CreateFullPath(Filename); // just to be sure
+ bool Result = File::CreateEmptyFile(Filename);
+ if (!Result)
+ {
+ ERROR_LOG(IOS_FILEIO, "FS: couldn't create new file");
+ PanicAlert("FS: couldn't create new file");
+ return GetFSReply(FS_EINVAL);
+ }
- // write answer to buffer
- if (request.buffer_out_size == 76)
- {
- u32 Addr = request.buffer_out;
- Memory::Write_U32(OwnerID, Addr);
- Addr += 4;
- Memory::Write_U16(GroupID, Addr);
- Addr += 2;
- memcpy(Memory::GetPointer(Addr), Memory::GetPointer(request.buffer_in), 64);
- Addr += 64;
- Memory::Write_U8(OwnerPerm, Addr);
- Addr += 1;
- Memory::Write_U8(GroupPerm, Addr);
- Addr += 1;
- Memory::Write_U8(OtherPerm, Addr);
- Addr += 1;
- Memory::Write_U8(Attributes, Addr);
- Addr += 1;
- }
+ INFO_LOG(IOS_FILEIO, "\tresult = IPC_SUCCESS");
+ return GetFSReply(IPC_SUCCESS);
+}
- return IPC_SUCCESS;
- }
- break;
+IPCCommandResult FS::Shutdown(const IOCtlRequest& request)
+{
+ // TODO: stop emulation
+ INFO_LOG(IOS_FILEIO, "Wii called Shutdown()");
+ return GetFSReply(IPC_SUCCESS);
+}
- case IOCTL_DELETE_FILE:
+IPCCommandResult FS::ReadDirectory(const IOCtlVRequest& request)
+{
+ const std::string relative_path =
+ Memory::GetString(request.in_vectors[0].address, request.in_vectors[0].size);
+
+ if (!IsValidWiiPath(relative_path))
{
- _dbg_assert_(IOS_FILEIO, request.buffer_out_size == 0);
- int Offset = 0;
+ WARN_LOG(IOS_FILEIO, "Not a valid path: %s", relative_path.c_str());
+ return GetFSReply(FS_EINVAL);
+ }
- const std::string wii_path = Memory::GetString(request.buffer_in + Offset, 64);
- if (!IsValidWiiPath(wii_path))
- {
- WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
- return FS_EINVAL;
- }
- std::string Filename = HLE_IPC_BuildFilename(wii_path);
- Offset += 64;
- if (File::Delete(Filename))
- {
- INFO_LOG(IOS_FILEIO, "FS: DeleteFile %s", Filename.c_str());
- }
- else if (File::DeleteDir(Filename))
- {
- INFO_LOG(IOS_FILEIO, "FS: DeleteDir %s", Filename.c_str());
- }
- else
- {
- WARN_LOG(IOS_FILEIO, "FS: DeleteFile %s - failed!!!", Filename.c_str());
- }
+ // the Wii uses this function to define the type (dir or file)
+ std::string DirName(HLE_IPC_BuildFilename(relative_path));
- return IPC_SUCCESS;
- }
- break;
+ INFO_LOG(IOS_FILEIO, "FS: IOCTL_READ_DIR %s", DirName.c_str());
- case IOCTL_RENAME_FILE:
+ if (!File::Exists(DirName))
{
- _dbg_assert_(IOS_FILEIO, request.buffer_out_size == 0);
- int Offset = 0;
+ WARN_LOG(IOS_FILEIO, "FS: Search not found: %s", DirName.c_str());
+ return GetFSReply(FS_ENOENT);
+ }
- const std::string wii_path = Memory::GetString(request.buffer_in + Offset, 64);
- if (!IsValidWiiPath(wii_path))
- {
- WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
- return FS_EINVAL;
- }
- std::string Filename = HLE_IPC_BuildFilename(wii_path);
- Offset += 64;
+ if (!File::IsDirectory(DirName))
+ {
+ // It's not a directory, so error.
+ // Games don't usually seem to care WHICH error they get, as long as it's <
+ // Well the system menu CARES!
+ WARN_LOG(IOS_FILEIO, "\tNot a directory - return FS_EINVAL");
+ return GetFSReply(FS_EINVAL);
+ }
- const std::string wii_path_rename = Memory::GetString(request.buffer_in + Offset, 64);
- if (!IsValidWiiPath(wii_path_rename))
- {
- WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path_rename.c_str());
- return FS_EINVAL;
- }
- std::string FilenameRename = HLE_IPC_BuildFilename(wii_path_rename);
- Offset += 64;
+ File::FSTEntry entry = File::ScanDirectoryTree(DirName, false);
- // try to make the basis directory
- File::CreateFullPath(FilenameRename);
+ // it is one
+ if ((request.in_vectors.size() == 1) && (request.io_vectors.size() == 1))
+ {
+ size_t numFile = entry.children.size();
+ INFO_LOG(IOS_FILEIO, "\t%zu files found", numFile);
- // if there is already a file, delete it
- if (File::Exists(Filename) && File::Exists(FilenameRename))
+ Memory::Write_U32((u32)numFile, request.io_vectors[0].address);
+ }
+ else
+ {
+ for (File::FSTEntry& child : entry.children)
{
- File::Delete(FilenameRename);
+ // Decode escaped invalid file system characters so that games (such as
+ // Harry Potter and the Half-Blood Prince) can find what they expect.
+ child.virtualName = Common::UnescapeFileName(child.virtualName);
}
- // finally try to rename the file
- if (File::Rename(Filename, FilenameRename))
- {
- INFO_LOG(IOS_FILEIO, "FS: Rename %s to %s", Filename.c_str(), FilenameRename.c_str());
- }
- else
- {
- ERROR_LOG(IOS_FILEIO, "FS: Rename %s to %s - failed", Filename.c_str(),
- FilenameRename.c_str());
- return FS_ENOENT;
- }
+ std::sort(entry.children.begin(), entry.children.end(),
+ [](const File::FSTEntry& one, const File::FSTEntry& two) {
+ return one.virtualName < two.virtualName;
+ });
- return IPC_SUCCESS;
- }
- break;
+ u32 MaxEntries = Memory::Read_U32(request.in_vectors[0].address);
- case IOCTL_CREATE_FILE:
- {
- _dbg_assert_(IOS_FILEIO, request.buffer_out_size == 0);
+ memset(Memory::GetPointer(request.io_vectors[0].address), 0, request.io_vectors[0].size);
- u32 Addr = request.buffer_in;
- u32 OwnerID = Memory::Read_U32(Addr);
- Addr += 4;
- u16 GroupID = Memory::Read_U16(Addr);
- Addr += 2;
- const std::string wii_path = Memory::GetString(Addr, 64);
- if (!IsValidWiiPath(wii_path))
- {
- WARN_LOG(IOS_FILEIO, "Not a valid path: %s", wii_path.c_str());
- return FS_EINVAL;
- }
- std::string Filename(HLE_IPC_BuildFilename(wii_path));
- Addr += 64;
- u8 OwnerPerm = Memory::Read_U8(Addr);
- Addr++;
- u8 GroupPerm = Memory::Read_U8(Addr);
- Addr++;
- u8 OtherPerm = Memory::Read_U8(Addr);
- Addr++;
- u8 Attributes = Memory::Read_U8(Addr);
- Addr++;
-
- INFO_LOG(IOS_FILEIO, "FS: CreateFile %s", Filename.c_str());
- DEBUG_LOG(IOS_FILEIO, " OwnerID: 0x%08x", OwnerID);
- DEBUG_LOG(IOS_FILEIO, " GroupID: 0x%04x", GroupID);
- DEBUG_LOG(IOS_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm);
- DEBUG_LOG(IOS_FILEIO, " GroupPerm: 0x%02x", GroupPerm);
- DEBUG_LOG(IOS_FILEIO, " OtherPerm: 0x%02x", OtherPerm);
- DEBUG_LOG(IOS_FILEIO, " Attributes: 0x%02x", Attributes);
-
- // check if the file already exist
- if (File::Exists(Filename))
- {
- INFO_LOG(IOS_FILEIO, "\tresult = FS_EEXIST");
- return FS_EEXIST;
- }
+ size_t numFiles = 0;
+ char* pFilename = (char*)Memory::GetPointer((u32)(request.io_vectors[0].address));
- // create the file
- File::CreateFullPath(Filename); // just to be sure
- bool Result = File::CreateEmptyFile(Filename);
- if (!Result)
+ for (size_t i = 0; i < entry.children.size() && i < MaxEntries; i++)
{
- ERROR_LOG(IOS_FILEIO, "FS: couldn't create new file");
- PanicAlert("FS: couldn't create new file");
- return FS_EINVAL;
+ const std::string& FileName = entry.children[i].virtualName;
+
+ strcpy(pFilename, FileName.c_str());
+ pFilename += FileName.length();
+ *pFilename++ = 0x00; // termination
+ numFiles++;
+
+ INFO_LOG(IOS_FILEIO, "\tFound: %s", FileName.c_str());
}
- INFO_LOG(IOS_FILEIO, "\tresult = IPC_SUCCESS");
- return IPC_SUCCESS;
- }
- break;
- case IOCTL_SHUTDOWN:
- {
- INFO_LOG(IOS_FILEIO, "Wii called Shutdown()");
- // TODO: stop emulation
- }
- break;
- default:
- request.DumpUnknown(GetDeviceName(), LogTypes::IOS_FILEIO);
+ Memory::Write_U32((u32)numFiles, request.io_vectors[1].address);
}
- return FS_EINVAL;
+ return GetFSReply(IPC_SUCCESS);
}
-void FS::DoState(PointerWrap& p)
+IPCCommandResult FS::GetUsage(const IOCtlVRequest& request)
{
- DoStateShared(p);
+ _dbg_assert_(IOS_FILEIO, request.io_vectors.size() == 2);
+ _dbg_assert_(IOS_FILEIO, request.io_vectors[0].size == 4);
+ _dbg_assert_(IOS_FILEIO, request.io_vectors[1].size == 4);
- // handle /tmp
+ // this command sucks because it asks of the number of used
+ // fsBlocks and inodes
+ // It should be correct, but don't count on it...
+ std::string relativepath =
+ Memory::GetString(request.in_vectors[0].address, request.in_vectors[0].size);
- std::string Path = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/tmp";
- if (p.GetMode() == PointerWrap::MODE_READ)
+ if (!IsValidWiiPath(relativepath))
{
- File::DeleteDirRecursively(Path);
- File::CreateDir(Path);
+ WARN_LOG(IOS_FILEIO, "Not a valid path: %s", relativepath.c_str());
+ return GetFSReply(FS_EINVAL);
+ }
- // now restore from the stream
- while (1)
+ std::string path(HLE_IPC_BuildFilename(relativepath));
+ u32 fsBlocks = 0;
+ u32 iNodes = 0;
+
+ INFO_LOG(IOS_FILEIO, "IOCTL_GETUSAGE %s", path.c_str());
+ if (File::IsDirectory(path))
+ {
+ // LPFaint99: After I found that setting the number of inodes to the number of children + 1
+ // for the directory itself
+ // I decided to compare with sneek which has the following 2 special cases which are
+ // Copyright (C) 2009-2011 crediar http://code.google.com/p/sneek/
+ if ((relativepath.compare(0, 16, "/title/00010001") == 0) ||
+ (relativepath.compare(0, 16, "/title/00010005") == 0))
{
- char type = 0;
- p.Do(type);
- if (!type)
- break;
- std::string filename;
- p.Do(filename);
- std::string name = Path + DIR_SEP + filename;
- switch (type)
- {
- case 'd':
- {
- File::CreateDir(name);
- break;
- }
- case 'f':
- {
- u32 size = 0;
- p.Do(size);
+ fsBlocks = 23; // size is size/0x4000
+ iNodes = 42; // empty folders return a FileCount of 1
+ }
+ else
+ {
+ File::FSTEntry parentDir = File::ScanDirectoryTree(path, true);
+ // add one for the folder itself
+ iNodes = 1 + (u32)parentDir.size;
- File::IOFile handle(name, "wb");
- char buf[65536];
- u32 count = size;
- while (count > 65536)
- {
- p.DoArray(buf);
- handle.WriteArray(&buf[0], 65536);
- count -= 65536;
- }
- p.DoArray(&buf[0], count);
- handle.WriteArray(&buf[0], count);
- break;
- }
- }
+ u64 totalSize =
+ ComputeTotalFileSize(parentDir); // "Real" size, to be converted to nand blocks
+
+ fsBlocks = (u32)(totalSize / (16 * 1024)); // one bock is 16kb
}
+
+ INFO_LOG(IOS_FILEIO, "FS: fsBlock: %i, iNodes: %i", fsBlocks, iNodes);
}
else
{
- // recurse through tmp and save dirs and files
-
- File::FSTEntry parentEntry = File::ScanDirectoryTree(Path, true);
- std::deque<File::FSTEntry> todo;
- todo.insert(todo.end(), parentEntry.children.begin(), parentEntry.children.end());
-
- while (!todo.empty())
- {
- File::FSTEntry& entry = todo.front();
- std::string name = entry.physicalName;
- name.erase(0, Path.length() + 1);
- char type = entry.isDirectory ? 'd' : 'f';
- p.Do(type);
- p.Do(name);
- if (entry.isDirectory)
- {
- todo.insert(todo.end(), entry.children.begin(), entry.children.end());
- }
- else
- {
- u32 size = (u32)entry.size;
- p.Do(size);
+ fsBlocks = 0;
+ iNodes = 0;
+ WARN_LOG(IOS_FILEIO, "FS: fsBlock failed, cannot find directory: %s", path.c_str());
+ }
- File::IOFile handle(entry.physicalName, "rb");
- char buf[65536];
- u32 count = size;
- while (count > 65536)
- {
- handle.ReadArray(&buf[0], 65536);
- p.DoArray(buf);
- count -= 65536;
- }
- handle.ReadArray(&buf[0], count);
- p.DoArray(&buf[0], count);
- }
- todo.pop_front();
- }
+ Memory::Write_U32(fsBlocks, request.io_vectors[0].address);
+ Memory::Write_U32(iNodes, request.io_vectors[1].address);
- char type = 0;
- p.Do(type);
- }
+ return GetFSReply(IPC_SUCCESS);
}
} // namespace Device
} // namespace HLE
diff --git a/Source/Core/Core/IOS/FS/FS.h b/Source/Core/Core/IOS/FS/FS.h
index b40038b391..cec7983df7 100644
--- a/Source/Core/Core/IOS/FS/FS.h
+++ b/Source/Core/Core/IOS/FS/FS.h
@@ -56,7 +56,18 @@ private:
};
IPCCommandResult GetFSReply(s32 return_value) const;
- s32 ExecuteCommand(const IOCtlRequest& request);
+
+ IPCCommandResult GetStats(const IOCtlRequest& request);
+ IPCCommandResult CreateDirectory(const IOCtlRequest& request);
+ IPCCommandResult SetAttribute(const IOCtlRequest& request);
+ IPCCommandResult GetAttribute(const IOCtlRequest& request);
+ IPCCommandResult DeleteFile(const IOCtlRequest& request);
+ IPCCommandResult RenameFile(const IOCtlRequest& request);
+ IPCCommandResult CreateFile(const IOCtlRequest& request);
+ IPCCommandResult Shutdown(const IOCtlRequest& request);
+
+ IPCCommandResult ReadDirectory(const IOCtlVRequest& request);
+ IPCCommandResult GetUsage(const IOCtlVRequest& request);
};
} // namespace Device
} // namespace HLE