Skip to content

Commit

Permalink
Merge pull request #19438 from hrydgard/android-folder-move-fixes
Browse files Browse the repository at this point in the history
Android memstick folder move: Minor logging and robustness improvements
  • Loading branch information
hrydgard authored Sep 9, 2024
2 parents 806a3cd + ea1c840 commit 3f32d8e
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 17 deletions.
14 changes: 10 additions & 4 deletions Common/File/AndroidStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,20 +154,26 @@ static bool ParseFileInfo(const std::string &line, File::FileInfo *fileInfo) {
std::vector<std::string> parts;
SplitString(line, '|', parts);
if (parts.size() != 4) {
ERROR_LOG(Log::FileSystem, "Bad format: %s", line.c_str());
ERROR_LOG(Log::FileSystem, "Bad format (1): %s", line.c_str());
return false;
}
fileInfo->name = std::string(parts[2]);
fileInfo->isDirectory = parts[0][0] == 'D';
fileInfo->exists = true;
sscanf(parts[1].c_str(), "%" PRIu64, &fileInfo->size);
if (1 != sscanf(parts[1].c_str(), "%" PRIu64, &fileInfo->size)) {
ERROR_LOG(Log::FileSystem, "Bad format (2): %s", line.c_str());
return false;
}
fileInfo->isWritable = true; // TODO: Should be passed as part of the string.
// TODO: For read-only mappings, reflect that here, similarly as with isWritable.
// Directories are normally executable (0111) which means they're traversable.
fileInfo->access = fileInfo->isDirectory ? 0777 : 0666;

uint64_t lastModifiedMs = 0;
sscanf(parts[3].c_str(), "%" PRIu64, &lastModifiedMs);
if (1 != sscanf(parts[3].c_str(), "%" PRIu64, &lastModifiedMs)) {
ERROR_LOG(Log::FileSystem, "Bad format (3): %s", line.c_str());
return false;
}

// Convert from milliseconds
uint32_t lastModified = lastModifiedMs / 1000;
Expand Down Expand Up @@ -229,7 +235,7 @@ std::vector<File::FileInfo> Android_ListContentUri(const std::string &path, bool
const char *charArray = env->GetStringUTFChars(str, 0);
if (charArray) { // paranoia
std::string line = charArray;
File::FileInfo info;
File::FileInfo info{};
if (line == "X") {
// Indicates an exception thrown, path doesn't exist.
*exists = false;
Expand Down
14 changes: 12 additions & 2 deletions Common/File/FileUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -683,14 +683,15 @@ bool Copy(const Path &srcFilename, const Path &destFilename) {
if (Android_CopyFile(srcFilename.ToString(), destParent.ToString()) == StorageError::SUCCESS) {
return true;
}
INFO_LOG(Log::Common, "Android_CopyFile failed, falling back.");
// Else fall through, and try using file I/O.
}
break;
default:
return false;
}

INFO_LOG(Log::Common, "Copy: %s --> %s", srcFilename.c_str(), destFilename.c_str());
INFO_LOG(Log::Common, "Copy by OpenCFile: %s --> %s", srcFilename.c_str(), destFilename.c_str());
#ifdef _WIN32
#if PPSSPP_PLATFORM(UWP)
if (CopyFileFromAppW(srcFilename.ToWString().c_str(), destFilename.ToWString().c_str(), FALSE))
Expand All @@ -702,7 +703,7 @@ bool Copy(const Path &srcFilename, const Path &destFilename) {
ERROR_LOG(Log::Common, "Copy: failed %s --> %s: %s",
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str());
return false;
#else
#else // Non-Win32

// buffer size
#define BSIZE 16384
Expand All @@ -726,6 +727,8 @@ bool Copy(const Path &srcFilename, const Path &destFilename) {
return false;
}

int bytesWritten = 0;

// copy loop
while (!feof(input)) {
// read input
Expand All @@ -751,7 +754,14 @@ bool Copy(const Path &srcFilename, const Path &destFilename) {
fclose(output);
return false;
}

bytesWritten += wnum;
}

if (bytesWritten == 0) {
WARN_LOG(Log::Common, "Copy: No bytes written (must mean that input was empty)");
}

// close flushes
fclose(input);
fclose(output);
Expand Down
1 change: 0 additions & 1 deletion Core/System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,5 @@ bool CreateSysDirectories() {
File::CreateEmptyFile(path / ".nomedia");
}
}

return true;
}
38 changes: 29 additions & 9 deletions Core/Util/MemStick.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#include <algorithm>
#include <vector>

#include "Common/File/Path.h"
#include "Common/File/FileUtil.h"
#include "Common/File/DirListing.h"
Expand Down Expand Up @@ -178,7 +181,7 @@ MoveResult *MoveDirectoryContentsSafe(Path moveSrc, Path moveDest, MoveProgressR

bool dryRun = false; // Useful for debugging.

size_t failedFiles = 0;
size_t failedFileCount = 0;

// We're not moving huge files like ISOs during this process, unless
// they can be directly moved, without rewriting the file.
Expand Down Expand Up @@ -218,20 +221,27 @@ MoveResult *MoveDirectoryContentsSafe(Path moveSrc, Path moveDest, MoveProgressR
} else {
// Remove the "from" prefix from the path.
// We have to drop down to string operations for this.
if (File::Exists(to)) {
WARN_LOG(Log::System, "Target file '%s' already exists. Will be overwritten", to.c_str());
}

if (!File::Copy(from, to)) {
ERROR_LOG(Log::System, "Failed to copy file '%s' to '%s'", from.c_str(), to.c_str());
failedFiles++;
failedFileCount++;
// Should probably just bail?
} else {
INFO_LOG(Log::System, "Copied file '%s' to '%s'", from.c_str(), to.c_str());
INFO_LOG(Log::System, "Copied file '%s' to '%s' (size: %d)", from.c_str(), to.c_str(), (int)fileSuffix.fileSize);
}
}
}

if (failedFiles) {
return new MoveResult{ false, "", failedFiles };
if (failedFileCount) {
ERROR_LOG(Log::System, "Copy failed (%d files failed)", (int)failedFileCount);
return new MoveResult{ false, "", failedFileCount };
}

INFO_LOG(Log::System, "Done copying. Moving to verification.");

// After the whole move, verify that all the files arrived correctly.
// If there's a single error, we do not delete the source data.
bool ok = true;
Expand All @@ -247,22 +257,32 @@ MoveResult *MoveDirectoryContentsSafe(Path moveSrc, Path moveDest, MoveProgressR
break;
}

if (fileSuffix.fileSize != info.size) {
ERROR_LOG(Log::System, "Mismatched size in target file %s. Verification failed.", fileSuffix.suffix.c_str());
if (!info.exists) {
ERROR_LOG(Log::System, "File '%s' missing at target location '%s'.", fileSuffix.suffix.c_str(), to.c_str());
ok = false;
failedFileCount++;
break;
}

// More lenient handling for .nomedia files.
if (fileSuffix.fileSize != info.size && !endsWithNoCase(fileSuffix.suffix, ".nomedia")) {
ERROR_LOG(Log::System, "Mismatched size in target file %s (expected %d, was %d bytes). Verification failed.", fileSuffix.suffix.c_str(), (int)fileSuffix.fileSize, (int)info.size);
ok = false;
failedFiles++;
failedFileCount++;
break;
}
}

if (!ok) {
return new MoveResult{ false, "", failedFiles };
return new MoveResult{ false, "", failedFileCount };
}

INFO_LOG(Log::System, "Verification complete");

// Delete all the old, now hopefully empty, directories.
// Hopefully DeleteDir actually fails if it contains a file...
// Reverse the order to delete subfolders before parents.
std::reverse(directorySuffixesToCreate.begin(), directorySuffixesToCreate.end());
for (size_t i = 0; i < directorySuffixesToCreate.size(); i++) {
const auto &dirSuffix = directorySuffixesToCreate[i];
Path dir = moveSrc / dirSuffix;
Expand Down
2 changes: 1 addition & 1 deletion UI/MemStickScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ UI::EventReturn MemStickScreen::OnConfirmClick(UI::EventParams &params) {
}

UI::EventReturn MemStickScreen::SetFolderManually(UI::EventParams &params) {
// The old way, from before scoped storage.
// The old way, from before scoped storage. Write in the full path.
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
auto sy = GetI18NCategory(I18NCat::SYSTEM);
System_InputBoxGetString(GetRequesterToken(), sy->T("Memory Stick Folder"), g_Config.memStickDirectory.ToString(), [&](const std::string &value, int) {
Expand Down

0 comments on commit 3f32d8e

Please sign in to comment.