diff --git a/Common/File/FileUtil.cpp b/Common/File/FileUtil.cpp index 88db815f7f..5468386096 100644 --- a/Common/File/FileUtil.cpp +++ b/Common/File/FileUtil.cpp @@ -155,32 +155,74 @@ FILE *OpenCFile(const Path &path, const char *mode) { #endif } +static std::string OpenFlagToString(OpenFlag flags) { + std::string s; + if (flags & OPEN_READ) + s += "READ|"; + if (flags & OPEN_WRITE) + s += "WRITE|"; + if (flags & OPEN_APPEND) + s += "APPEND|"; + if (flags & OPEN_CREATE) + s += "CREATE|"; + if (flags & OPEN_TRUNCATE) + s += "TRUNCATE|"; + if (!s.empty()) { + s.pop_back(); // Remove trailing separator. + } + return s; +} + int OpenFD(const Path &path, OpenFlag flags) { switch (path.Type()) { case PathType::CONTENT_URI: break; default: - // Not yet supported. + ERROR_LOG(COMMON, "OpenFD: Only supports Content URI paths. Not '%s' (%s)!", path.c_str(), OpenFlagToString(flags).c_str()); + // Not yet supported - use other paths. return -1; } + if (flags & OPEN_CREATE) { + if (!File::Exists(path)) { + INFO_LOG(COMMON, "OpenFD(%s): Creating file.", path.c_str()); + std::string name = path.GetFilename(); + if (path.CanNavigateUp()) { + Path parent = path.NavigateUp(); + if (!Android_CreateFile(parent.ToString(), name)) { + WARN_LOG(COMMON, "OpenFD: Failed to create file '%s' in '%s'", name.c_str(), parent.c_str()); + return -1; + } + } else { + INFO_LOG(COMMON, "Failed to navigate up to create file: %s", path.c_str()); + return -1; + } + } else { + INFO_LOG(COMMON, "OpenCFile(%s): Opening existing content file ('%s')", path.c_str(), OpenFlagToString(flags).c_str()); + } + } + Android_OpenContentUriMode mode; if (flags == OPEN_READ) { mode = Android_OpenContentUriMode::READ; } else if (flags & OPEN_WRITE) { if (flags & OPEN_TRUNCATE) { - mode = Android_OpenContentUriMode::READ_WRITE; - } else { mode = Android_OpenContentUriMode::READ_WRITE_TRUNCATE; + } else { + mode = Android_OpenContentUriMode::READ_WRITE; } // TODO: Maybe better checking of additional flags here. } else { // TODO: Add support for more modes if possible. - ERROR_LOG_REPORT_ONCE(openFlagNotSupported, COMMON, "OpenFlag 0x%x not yet supported", flags); + ERROR_LOG_REPORT_ONCE(openFlagNotSupported, COMMON, "OpenFlag %s not yet supported", OpenFlagToString(flags).c_str()); return -1; } + INFO_LOG(COMMON, "Android_OpenContentUriFd: %s (%s)", path.c_str(), OpenFlagToString(flags).c_str()); int descriptor = Android_OpenContentUriFd(path.ToString(), mode); + if (descriptor < 0) { + ERROR_LOG(COMMON, "Android_OpenContentUriFd failed: '%s'", path.c_str()); + } return descriptor; } diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 3da8a05947..1e26486e2c 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -208,12 +208,12 @@ void SavedataParam::Init() pspFileSystem.MkDir(savePath); } // Create a nomedia file to hide save icons form Android image viewer -#ifdef __ANDROID__ +#if PPSSPP_PLATFORM(ANDROID) int handle = pspFileSystem.OpenFile(savePath + ".nomedia", (FileAccess)(FILEACCESS_CREATE | FILEACCESS_WRITE), 0); if (handle >= 0) { pspFileSystem.CloseFile(handle); } else { - ERROR_LOG(IO, "Failed to create .nomedia file"); + INFO_LOG(IO, "Failed to create .nomedia file (might be ok if it already exists)"); } #endif } diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index c9d2c22add..6e14d903e0 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -67,8 +67,7 @@ #endif #if HOST_IS_CASE_SENSITIVE -static bool FixFilenameCase(const std::string &path, std::string &filename) -{ +static bool FixFilenameCase(const std::string &path, std::string &filename) { // Are we lucky? if (File::Exists(Path(path + filename))) return true; @@ -112,8 +111,14 @@ static bool FixFilenameCase(const std::string &path, std::string &filename) return retValue; } -bool FixPathCase(const std::string &basePath, std::string &path, FixPathCaseBehavior behavior) -{ +bool FixPathCase(const Path &realBasePath, std::string &path, FixPathCaseBehavior behavior) { + if (realBasePath.Type() == PathType::CONTENT_URI) { + // Nothing to do. These are already case insensitive, I think. + return true; + } + + std::string basePath = realBasePath.ToString(); + size_t len = path.size(); if (len == 0) @@ -189,7 +194,7 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File #if HOST_IS_CASE_SENSITIVE if (access & (FILEACCESS_APPEND | FILEACCESS_CREATE | FILEACCESS_WRITE)) { DEBUG_LOG(FILESYS, "Checking case for path %s", fileName.c_str()); - if (!FixPathCase(basePath.ToString(), fileName, FPC_PATH_MUST_EXIST)) { + if (!FixPathCase(basePath, fileName, FPC_PATH_MUST_EXIST)) { error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; return false; // or go on and attempt (for a better error code than just 0?) } @@ -198,7 +203,7 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File #endif Path fullName = GetLocalPath(basePath, fileName); - VERBOSE_LOG(FILESYS, "Actually opening %s", fullName.c_str()); + INFO_LOG(FILESYS, "Actually opening %s", fullName.c_str()); // On the PSP, truncating doesn't lose data. If you seek later, you'll recover it. // This is abnormal, so we deviate from the PSP's behavior and truncate on write/close. @@ -289,6 +294,7 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File // Success return true; } else { + ERROR_LOG(FILESYS, "File::OpenFD returned an error"); // TODO: Need better error codes from OpenFD so we can distinguish // disk full. Just set not found for now. error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; @@ -296,6 +302,8 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File } } + INFO_LOG(FILESYS, "Opening '%s' straight", fullName.c_str()); + int flags = 0; if (access & FILEACCESS_APPEND) { flags |= O_APPEND; @@ -320,7 +328,7 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File #if HOST_IS_CASE_SENSITIVE if (!success && !(access & FILEACCESS_CREATE)) { - if (!FixPathCase(basePath.ToString(), fileName, FPC_PATH_MUST_EXIST)) { + if (!FixPathCase(basePath, fileName, FPC_PATH_MUST_EXIST)) { error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; return false; } @@ -520,7 +528,7 @@ bool DirectoryFileSystem::MkDir(const std::string &dirname) { // duplicate (different case) directories std::string fixedCase = dirname; - if (!FixPathCase(basePath.ToString(), fixedCase, FPC_PARTIAL_ALLOWED)) + if (!FixPathCase(basePath, fixedCase, FPC_PARTIAL_ALLOWED)) result = false; else result = File::CreateFullPath(GetLocalPath(fixedCase)); @@ -540,7 +548,7 @@ bool DirectoryFileSystem::RmDir(const std::string &dirname) { // Nope, fix case and try again. Should we try again? std::string fullPath = dirname; - if (!FixPathCase(basePath.ToString(), fullPath, FPC_FILE_MUST_EXIST)) + if (!FixPathCase(basePath, fullPath, FPC_FILE_MUST_EXIST)) return (bool)ReplayApplyDisk(ReplayAction::RMDIR, false, CoreTiming::GetGlobalTimeUs()); fullName = GetLocalPath(fullPath); @@ -571,7 +579,7 @@ int DirectoryFileSystem::RenameFile(const std::string &from, const std::string & #if HOST_IS_CASE_SENSITIVE // In case TO should overwrite a file with different case. Check error code? - if (!FixPathCase(basePath.ToString(), fullTo, FPC_PATH_MUST_EXIST)) + if (!FixPathCase(basePath, fullTo, FPC_PATH_MUST_EXIST)) return ReplayApplyDisk(ReplayAction::FILE_RENAME, -1, CoreTiming::GetGlobalTimeUs()); #endif @@ -584,7 +592,7 @@ int DirectoryFileSystem::RenameFile(const std::string &from, const std::string & { // May have failed due to case sensitivity on FROM, so try again. Check error code? std::string fullFromPath = from; - if (!FixPathCase(basePath.ToString(), fullFromPath, FPC_FILE_MUST_EXIST)) + if (!FixPathCase(basePath, fullFromPath, FPC_FILE_MUST_EXIST)) return ReplayApplyDisk(ReplayAction::FILE_RENAME, -1, CoreTiming::GetGlobalTimeUs()); fullFrom = GetLocalPath(fullFromPath); @@ -607,7 +615,7 @@ bool DirectoryFileSystem::RemoveFile(const std::string &filename) { { // May have failed due to case sensitivity, so try again. Try even if it fails? std::string fullNamePath = filename; - if (!FixPathCase(basePath.ToString(), fullNamePath, FPC_FILE_MUST_EXIST)) + if (!FixPathCase(basePath, fullNamePath, FPC_FILE_MUST_EXIST)) return (bool)ReplayApplyDisk(ReplayAction::FILE_REMOVE, false, CoreTiming::GetGlobalTimeUs()); localPath = GetLocalPath(fullNamePath); @@ -739,7 +747,7 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) { Path fullName = GetLocalPath(filename); if (!File::Exists(fullName)) { #if HOST_IS_CASE_SENSITIVE - if (! FixPathCase(basePath.ToString(), filename, FPC_FILE_MUST_EXIST)) + if (! FixPathCase(basePath, filename, FPC_FILE_MUST_EXIST)) return ReplayApplyDiskFileInfo(x, CoreTiming::GetGlobalTimeUs()); fullName = GetLocalPath(filename); @@ -852,13 +860,14 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { std::vector myVector; std::vector files; - if (!File::GetFilesInDir(GetLocalPath(path), &files, nullptr, 0)) { + Path localPath = GetLocalPath(path); + if (!File::GetFilesInDir(localPath, &files, nullptr, 0)) { // TODO: Case sensitivity should be checked on a file system basis, right? #if HOST_IS_CASE_SENSITIVE - if (FixPathCase(basePath.ToString(), path, FPC_FILE_MUST_EXIST)) { + if (FixPathCase(basePath, path, FPC_FILE_MUST_EXIST)) { // May have failed due to case sensitivity, try again localPath = GetLocalPath(path); - if (!File::GetFilesInDir(GetLocalPath(path), &files, nullptr, 0)) { + if (!File::GetFilesInDir(localPath, &files, nullptr, 0)) { return ReplayApplyDiskListing(myVector, CoreTiming::GetGlobalTimeUs()); } } @@ -911,9 +920,9 @@ u64 DirectoryFileSystem::FreeSpace(const std::string &path) { #if HOST_IS_CASE_SENSITIVE std::string fixedCase = path; - if (FixPathCase(basePath.ToString(), fixedCase, FPC_FILE_MUST_EXIST)) { + if (FixPathCase(basePath, fixedCase, FPC_FILE_MUST_EXIST)) { // May have failed due to case sensitivity, try again. - if (free_disk_space(GetLocalPath(fixedCase).ToString(), result)) { + if (free_disk_space(GetLocalPath(fixedCase), result)) { return ReplayApplyDisk64(ReplayAction::FREESPACE, result, CoreTiming::GetGlobalTimeUs()); } } @@ -1022,7 +1031,7 @@ int VFSFileSystem::OpenFile(std::string filename, FileAccess access, const char std::string fullName = GetLocalPath(filename); const char *fullNameC = fullName.c_str(); - VERBOSE_LOG(FILESYS,"VFSFileSystem actually opening %s (%s)", fullNameC, filename.c_str()); + VERBOSE_LOG(FILESYS, "VFSFileSystem actually opening %s (%s)", fullNameC, filename.c_str()); size_t size; u8 *data = VFSReadFile(fullNameC, &size); diff --git a/Core/FileSystems/DirectoryFileSystem.h b/Core/FileSystems/DirectoryFileSystem.h index 0bcd3f8bfc..b7b71c7c34 100644 --- a/Core/FileSystems/DirectoryFileSystem.h +++ b/Core/FileSystems/DirectoryFileSystem.h @@ -55,7 +55,7 @@ enum FixPathCaseBehavior { FPC_PARTIAL_ALLOWED, // don't care how many exist (mkdir recursive) }; -bool FixPathCase(const std::string &basePath, std::string &path, FixPathCaseBehavior behavior); +bool FixPathCase(const Path &basePath, std::string &path, FixPathCaseBehavior behavior); #endif struct DirectoryFileHandle { diff --git a/Core/FileSystems/VirtualDiscFileSystem.cpp b/Core/FileSystems/VirtualDiscFileSystem.cpp index 6cc202e229..276a89f1be 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.cpp +++ b/Core/FileSystems/VirtualDiscFileSystem.cpp @@ -274,7 +274,7 @@ int VirtualDiscFileSystem::getFileListIndex(std::string &fileName) Path fullName = GetLocalPath(fileName); if (! File::Exists(fullName)) { #if HOST_IS_CASE_SENSITIVE - if (! FixPathCase(basePath.ToString(), fileName, FPC_FILE_MUST_EXIST)) + if (! FixPathCase(basePath, fileName, FPC_FILE_MUST_EXIST)) return -1; fullName = GetLocalPath(fileName); @@ -602,7 +602,7 @@ PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) { Path fullName = GetLocalPath(filename); if (!File::Exists(fullName)) { #if HOST_IS_CASE_SENSITIVE - if (! FixPathCase(basePath.ToString(), filename, FPC_FILE_MUST_EXIST)) + if (! FixPathCase(basePath, filename, FPC_FILE_MUST_EXIST)) return x; fullName = GetLocalPath(filename); @@ -661,6 +661,9 @@ static void tmFromFiletime(tm &dest, FILETIME &src) std::vector VirtualDiscFileSystem::GetDirListing(std::string path) { std::vector myVector; + + // TODO(scoped): Switch this over to GetFilesInDir! + #ifdef _WIN32 WIN32_FIND_DATA findData; HANDLE hFind; @@ -708,7 +711,7 @@ std::vector VirtualDiscFileSystem::GetDirListing(std::string path) DIR *dp = opendir(localPath.c_str()); #if HOST_IS_CASE_SENSITIVE - if(dp == NULL && FixPathCase(basePath.ToString(), path, FPC_FILE_MUST_EXIST)) { + if(dp == NULL && FixPathCase(basePath, path, FPC_FILE_MUST_EXIST)) { // May have failed due to case sensitivity, try again localPath = GetLocalPath(path); dp = opendir(localPath.c_str());