// This is used by several of the FileIO and /dev/fs functions std::string HLE_IPC_BuildFilename(std::string path_wii, int _size) { std::string path_full = File::GetUserPath(D_WIIROOT_IDX); // Replaces chars that FAT32 can't support with strings defined in /sys/replace for (auto i = replacements.begin(); i != replacements.end(); ++i) { for (size_t j = 0; (j = path_wii.find(i->first, j)) != path_wii.npos; ++j) path_wii.replace(j, 1, i->second); } path_full += path_wii; return path_full; }
// This is used by several of the FileIO and /dev/fs functions std::string HLE_IPC_BuildFilename(std::string path_wii, int _size) { std::string path_full = File::GetUserPath(D_WIIROOT_IDX); if ((path_wii.length() > 0) && (path_wii[1] == '0')) path_full += std::string("/title"); // this looks and feel like a hack... // Replaces chars that FAT32 can't support with strings defined in /sys/replace for (auto i = replacements.begin(); i != replacements.end(); ++i) { for (size_t j = 0; (j = path_wii.find(i->first, j)) != path_wii.npos; ++j) path_wii.replace(j, 1, i->second); } path_full += path_wii; return path_full; }
void CWiiSaveCrypted::ExportWiiSaveFiles() { if (!b_valid) return; u8 *__ENCdata, *__data; for(u32 i = 0; i < _numberOfFiles; i++) { FileHDR tmpFileHDR; std::string __name, __ext; memset(&tmpFileHDR, 0, FILE_HDR_SZ); _fileSize = File::GetSize(FilesList[i]); _roundedfileSize = ROUND_UP(_fileSize, BLOCK_SZ); tmpFileHDR.magic = Common::swap32(FILE_HDR_MAGIC); tmpFileHDR.size = Common::swap32(_fileSize); tmpFileHDR.Permissions = 0x35; tmpFileHDR.type = File::IsDirectory(FilesList[i]) ? 2 : 1; SplitPath(FilesList[i], NULL, &__name, &__ext); __name += __ext; for (Common::replace_v::const_iterator iter = replacements.begin(); iter != replacements.end(); ++iter) { for (size_t j = 0; (j = __name.find(iter->second, j)) != __name.npos; ++j) { __name.replace(j, iter->second.length(), 1, iter->first); } } if (__name.length() > 0x44) { PanicAlertT("%s is too long for the filename, max chars is 45", __name.c_str()); b_valid = false; return; } strncpy((char *)tmpFileHDR.name, __name.c_str(), __name.length()); { File::IOFile fpData_bin(pathData_bin, "ab"); fpData_bin.WriteBytes(&tmpFileHDR, FILE_HDR_SZ); } if (tmpFileHDR.type == 1) { if (_fileSize == 0) { PanicAlertT("%s is a 0 byte file", FilesList[i].c_str()); b_valid = false; return; } File::IOFile fpRawSaveFile(FilesList[i], "rb"); if (!fpRawSaveFile) { PanicAlertT("%s failed to open", FilesList[i].c_str()); b_valid = false; } __data = new u8[_roundedfileSize]; __ENCdata = new u8[_roundedfileSize]; memset(__data, 0, _roundedfileSize); if (!fpRawSaveFile.ReadBytes(__data, _fileSize)) { PanicAlertT("Failed to read data from file: %s", FilesList[i].c_str()); b_valid = false; } AES_cbc_encrypt((const u8*)__data, __ENCdata, _roundedfileSize, &m_AES_KEY, tmpFileHDR.IV, AES_ENCRYPT); File::IOFile fpData_bin(pathData_bin, "ab"); fpData_bin.WriteBytes(__ENCdata, _roundedfileSize); delete [] __data; delete [] __ENCdata; } } }
void CWiiSaveCrypted::ImportWiiSaveFiles() { if (!b_valid) return; File::IOFile fpData_bin(pathData_bin, "rb"); if (!fpData_bin) { PanicAlertT("Cannot open %s", pathData_bin); b_valid = false; return; } fpData_bin.Seek(HEADER_SZ + BK_SZ, SEEK_SET); FileHDR _tmpFileHDR; for(u32 i = 0; i < _numberOfFiles; i++) { memset(&_tmpFileHDR, 0, FILE_HDR_SZ); memset(IV, 0, 0x10); _fileSize = 0; if (!fpData_bin.ReadBytes(&_tmpFileHDR, FILE_HDR_SZ)) { PanicAlertT("Failed to write header for file %d", i); b_valid = false; } if (Common::swap32(_tmpFileHDR.magic) != FILE_HDR_MAGIC) { PanicAlertT("Bad File Header"); break; } else { std::string fileName ((char*)_tmpFileHDR.name); for (Common::replace_v::const_iterator iter = replacements.begin(); iter != replacements.end(); ++iter) { for (size_t j = 0; (j = fileName.find(iter->first, j)) != fileName.npos; ++j) fileName.replace(j, 1, iter->second); } std::string fullFilePath = WiiTitlePath + fileName; File::CreateFullPath(fullFilePath); if (_tmpFileHDR.type == 1) { _fileSize = Common::swap32(_tmpFileHDR.size); u32 RoundedFileSize = ROUND_UP(_fileSize, BLOCK_SZ); _encryptedData = new u8[RoundedFileSize]; _data = new u8[RoundedFileSize]; if (!fpData_bin.ReadBytes(_encryptedData, RoundedFileSize)) { PanicAlertT("Failed to read data from file %d", i); b_valid = false; break; } memcpy(IV, _tmpFileHDR.IV, 0x10); AES_cbc_encrypt((const unsigned char *)_encryptedData, _data, RoundedFileSize, &m_AES_KEY, IV, AES_DECRYPT); delete []_encryptedData; if (!File::Exists(fullFilePath) || AskYesNoT("%s already exists, overwrite?", fullFilePath.c_str())) { INFO_LOG(CONSOLE, "Creating file %s", fullFilePath.c_str()); File::IOFile fpRawSaveFile(fullFilePath, "wb"); fpRawSaveFile.WriteBytes(_data, _fileSize); } delete []_data; } } } }
bool CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress) { u32 ReturnValue = FS_RESULT_OK; SIOCtlVBuffer CommandBuffer(_CommandAddress); // Prepare the out buffer(s) with zeros as a safety precaution // to avoid returning bad values for(u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; i++) { Memory::Memset(CommandBuffer.PayloadBuffer[i].m_Address, 0, CommandBuffer.PayloadBuffer[i].m_Size); } switch(CommandBuffer.Parameter) { case IOCTLV_READ_DIR: { // the wii uses this function to define the type (dir or file) std::string DirName(HLE_IPC_BuildFilename((const char*)Memory::GetPointer( CommandBuffer.InBuffer[0].m_Address), CommandBuffer.InBuffer[0].m_Size)); INFO_LOG(WII_IPC_FILEIO, "FS: IOCTL_READ_DIR %s", DirName.c_str()); if (!File::Exists(DirName)) { WARN_LOG(WII_IPC_FILEIO, "FS: Search not found: %s", DirName.c_str()); ReturnValue = FS_FILE_NOT_EXIST; 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(WII_IPC_FILEIO, "\tNot a directory - return FS_RESULT_FATAL"); ReturnValue = FS_RESULT_FATAL; break; } // make a file search CFileSearch::XStringVector Directories; Directories.push_back(DirName); CFileSearch::XStringVector Extensions; Extensions.push_back("*.*"); CFileSearch FileSearch(Extensions, Directories); // it is one if ((CommandBuffer.InBuffer.size() == 1) && (CommandBuffer.PayloadBuffer.size() == 1)) { size_t numFile = FileSearch.GetFileNames().size(); INFO_LOG(WII_IPC_FILEIO, "\t%lu Files found", (unsigned long)numFile); Memory::Write_U32((u32)numFile, CommandBuffer.PayloadBuffer[0].m_Address); } else { u32 MaxEntries = Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address); memset(Memory::GetPointer(CommandBuffer.PayloadBuffer[0].m_Address), 0, CommandBuffer.PayloadBuffer[0].m_Size); size_t numFiles = 0; char* pFilename = (char*)Memory::GetPointer((u32)(CommandBuffer.PayloadBuffer[0].m_Address)); for (size_t i=0; i<FileSearch.GetFileNames().size(); i++) { if (i >= MaxEntries) break; std::string name, ext; SplitPath(FileSearch.GetFileNames()[i], NULL, &name, &ext); std::string FileName = name + ext; // Decode entities of invalid file system characters so that // games (such as HP:HBP) will be able to find what they expect. for (Common::replace_v::const_iterator it = replacements.begin(); it != replacements.end(); ++it) { for (size_t j = 0; (j = FileName.find(it->second, j)) != FileName.npos; ++j) FileName.replace(j, it->second.length(), 1, it->first); } strcpy(pFilename, FileName.c_str()); pFilename += FileName.length(); *pFilename++ = 0x00; // termination numFiles++; INFO_LOG(WII_IPC_FILEIO, "\tFound: %s", FileName.c_str()); } Memory::Write_U32((u32)numFiles, CommandBuffer.PayloadBuffer[1].m_Address); } ReturnValue = FS_RESULT_OK; } break; case IOCTLV_GETUSAGE: { _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer.size() == 2); _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[0].m_Size == 4); _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[1].m_Size == 4); // this command sucks because it asks of the number of used // fsBlocks and inodes // It should be correct, but don't count on it... const char *relativepath = (const char*)Memory::GetPointer(CommandBuffer.InBuffer[0].m_Address); std::string path(HLE_IPC_BuildFilename(relativepath, CommandBuffer.InBuffer[0].m_Size)); u32 fsBlocks = 0; u32 iNodes = 0; INFO_LOG(WII_IPC_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 ((memcmp(relativepath, "/title/00010001", 16 ) == 0 ) || (memcmp(relativepath, "/title/00010005", 16) == 0 )) { fsBlocks = 23; // size is size/0x4000 iNodes = 42; // empty folders return a FileCount of 1 } else { File::FSTEntry parentDir; // add one for the folder itself, allows some games to create their save files // R8XE52 (Jurassic: The Hunted), STEETR (Tetris Party Deluxe) now create their saves with this change iNodes = 1 + File::ScanDirectoryTree(path, parentDir); u64 totalSize = ComputeTotalFileSize(parentDir); // "Real" size, to be converted to nand blocks fsBlocks = (u32)(totalSize / (16 * 1024)); // one bock is 16kb } ReturnValue = FS_RESULT_OK; INFO_LOG(WII_IPC_FILEIO, "FS: fsBlock: %i, iNodes: %i", fsBlocks, iNodes); } else { fsBlocks = 0; iNodes = 0; ReturnValue = FS_RESULT_OK; WARN_LOG(WII_IPC_FILEIO, "FS: fsBlock failed, cannot find directoy: %s", path.c_str()); } Memory::Write_U32(fsBlocks, CommandBuffer.PayloadBuffer[0].m_Address); Memory::Write_U32(iNodes, CommandBuffer.PayloadBuffer[1].m_Address); } break; default: PanicAlert("CWII_IPC_HLE_Device_fs::IOCtlV: %i", CommandBuffer.Parameter); break; } Memory::Write_U32(ReturnValue, _CommandAddress+4); return true; }