| 553 | } |
| 554 | |
| 555 | bool FolderMemoryCard::AddFile(MemoryCardFileEntry* const dirEntry, const std::string& dirPath, const EnumeratedFileEntry& fileEntry, MemoryCardFileMetadataReference* parent) |
| 556 | { |
| 557 | const std::string filePath(Path::Combine(dirPath, fileEntry.m_fileName)); |
| 558 | pxAssertMsg(filePath.starts_with(m_folderName), "Full file path starts with MC folder path"); |
| 559 | const std::string relativeFilePath(filePath.substr(m_folderName.length() + 1)); |
| 560 | |
| 561 | if (auto file = FileSystem::OpenManagedCFile(filePath.c_str(), "rb"); file) |
| 562 | { |
| 563 | // make sure we have enough space on the memcard to hold the data |
| 564 | const u32 clusterSize = m_superBlock.data.pages_per_cluster * m_superBlock.data.page_len; |
| 565 | const u32 filesize = static_cast<u32>(std::clamp<s64>(FileSystem::FSize64(file.get()), 0, std::numeric_limits<u32>::max())); |
| 566 | const u32 countClusters = (filesize % clusterSize) != 0 ? (filesize / clusterSize + 1) : (filesize / clusterSize); |
| 567 | const u32 newNeededClusters = (dirEntry->entry.data.length % 2) == 0 ? countClusters + 1 : countClusters; |
| 568 | if (newNeededClusters > GetAmountFreeDataClusters()) |
| 569 | { |
| 570 | Console.Warning(GetCardFullMessage(relativeFilePath)); |
| 571 | return false; |
| 572 | } |
| 573 | |
| 574 | MemoryCardFileEntry* newFileEntry = AppendFileEntryToDir(dirEntry); |
| 575 | |
| 576 | // set file entry metadata |
| 577 | memset(newFileEntry->entry.raw, 0x00, sizeof(newFileEntry->entry.raw)); |
| 578 | |
| 579 | std::string metaFileName(Path::Combine(Path::Combine(dirPath, "_pcsx2_meta"), fileEntry.m_fileName)); |
| 580 | if (auto metaFile = FileSystem::OpenManagedCFile(metaFileName.c_str(), "rb"); metaFile) |
| 581 | { |
| 582 | size_t bytesRead = std::fread(&newFileEntry->entry.raw, 1, sizeof(newFileEntry->entry.raw), metaFile.get()); |
| 583 | if (bytesRead < 0x60) |
| 584 | { |
| 585 | StringUtil::Strlcpy(reinterpret_cast<char*>(newFileEntry->entry.data.name), fileEntry.m_fileName.c_str(), sizeof(newFileEntry->entry.data.name)); |
| 586 | } |
| 587 | } |
| 588 | else |
| 589 | { |
| 590 | newFileEntry->entry.data.mode = MemoryCardFileEntry::DefaultFileMode; |
| 591 | newFileEntry->entry.data.timeCreated = MemoryCardFileEntryDateTime::FromTime(fileEntry.m_timeCreated); |
| 592 | newFileEntry->entry.data.timeModified = MemoryCardFileEntryDateTime::FromTime(fileEntry.m_timeModified); |
| 593 | StringUtil::Strlcpy(reinterpret_cast<char*>(newFileEntry->entry.data.name), fileEntry.m_fileName.c_str(), sizeof(newFileEntry->entry.data.name)); |
| 594 | } |
| 595 | |
| 596 | newFileEntry->entry.data.length = filesize; |
| 597 | if (filesize != 0) |
| 598 | { |
| 599 | u32 fileDataStartingCluster = GetFreeDataCluster(); |
| 600 | newFileEntry->entry.data.cluster = fileDataStartingCluster; |
| 601 | |
| 602 | // mark the appropriate amount of clusters as used |
| 603 | u32 dataCluster = fileDataStartingCluster; |
| 604 | m_fat.data[0][0][dataCluster] = LastDataCluster | DataClusterInUseMask; |
| 605 | for (unsigned int i = 0; i < countClusters - 1; ++i) |
| 606 | { |
| 607 | u32 newCluster = GetFreeDataCluster(); |
| 608 | m_fat.data[0][0][dataCluster] = newCluster | DataClusterInUseMask; |
| 609 | m_fat.data[0][0][newCluster] = LastDataCluster | DataClusterInUseMask; |
| 610 | dataCluster = newCluster; |
| 611 | } |
| 612 | } |
nothing calls this directly
no test coverage detected