diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0445b74431..a508ed2eeb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1622,8 +1622,6 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/ELF/ParamSFO.cpp
Core/ELF/ParamSFO.h
Core/FileSystems/tlzrc.cpp
- Core/FileSystems/AndroidStorageFileSystem.cpp
- Core/FileSystems/AndroidStorageFileSystem.h
Core/FileSystems/BlobFileSystem.cpp
Core/FileSystems/BlobFileSystem.h
Core/FileSystems/BlockDevices.cpp
diff --git a/Common/File/FileUtil.cpp b/Common/File/FileUtil.cpp
index 7c3c990dfe..e236d58a2e 100644
--- a/Common/File/FileUtil.cpp
+++ b/Common/File/FileUtil.cpp
@@ -932,8 +932,7 @@ IOFile::IOFile(const Path &filename, const char openmode[]) {
Open(filename, openmode);
}
-IOFile::~IOFile()
-{
+IOFile::~IOFile() {
Close();
}
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 8e6c9ff709..797daeeeb9 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -529,7 +529,6 @@
-
@@ -1086,7 +1085,6 @@
-
@@ -1400,4 +1398,4 @@
-
\ No newline at end of file
+
diff --git a/Core/FileSystems/AndroidStorageFileSystem.cpp b/Core/FileSystems/AndroidStorageFileSystem.cpp
deleted file mode 100644
index bf3571e603..0000000000
--- a/Core/FileSystems/AndroidStorageFileSystem.cpp
+++ /dev/null
@@ -1,543 +0,0 @@
-// Copyright (c) 2012- PPSSPP Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official git repository and contact information can be found at
-// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
-
-#include "ppsspp_config.h"
-
-#if PPSSPP_PLATFORM(ANDROID)
-#include "android/jni/app-android.h"
-#include "android/jni/AndroidContentURI.h"
-
-#include
-#include
-#include
-
-#include "Common/Data/Text/I18n.h"
-#include "Common/Data/Encoding/Utf8.h"
-#include "Common/Serialize/Serializer.h"
-#include "Common/Serialize/SerializeFuncs.h"
-#include "Common/StringUtils.h"
-#include "Common/File/DirListing.h"
-#include "Core/FileSystems/AndroidStorageFileSystem.h"
-#include "Core/HLE/sceKernel.h"
-#include "Core/HW/MemoryStick.h"
-#include "Core/CoreTiming.h"
-#include "Core/System.h"
-#include "Core/Host.h"
-#include "Core/Replay.h"
-#include "Core/Reporting.h"
-
-AndroidStorageFileSystem::AndroidStorageFileSystem(IHandleAllocator *_hAlloc, std::string _basePath, FileSystemFlags _flags) : basePath(_basePath), flags(_flags) {
- // File::CreateFullPath(basePath);
- hAlloc = _hAlloc;
-}
-
-AndroidStorageFileSystem::~AndroidStorageFileSystem() {
- CloseAll();
-}
-
-bool AndroidDirectoryFileHandle::Open(const std::string &basePath, std::string &fileName, FileAccess access, u32 &error) {
- error = 0;
-
- AndroidStorageContentURI contentUri = AndroidStorageContentURI(basePath).WithFilePath(fileName);
-
- // 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.
- // This means it's incorrectly not truncated before the write.
- if (access & FILEACCESS_TRUNCATE) {
- needsTrunc_ = 0;
- }
-
- // Check for existance and directory, so we can make better decisions below.
- File::FileInfo fileInfo;
- if (!Android_GetFileInfo(contentUri.ToString(), &fileInfo)) {
- ERROR_LOG(FILESYS, "Failed to call Android_GetFileInfo on %s", contentUri.ToString().c_str());
- return false;
- }
-
- if (fileInfo.exists && fileInfo.isDirectory) {
- ERROR_LOG(FILESYS, "AndroidDirectoryFileHandle::Open on directory %s - not allowed", contentUri.ToString().c_str());
- return false;
- }
-
- // Android_OpenContentUriFd only has three modes: READ/READ_WRITE/READ_WRITE_TRUNCATE.
- // For the modes that can create files, we have to explicitly create the file first, instead.
- // My god, what a pain this is. Gonna need some sort of test suite.
-
- Android_OpenContentUriMode mode = Android_OpenContentUriMode::READ;
-
- // TODO: There are probably improvements to be made in this translation.
- if (access & FILEACCESS_WRITE) {
- mode = Android_OpenContentUriMode::READ_WRITE_TRUNCATE;
- // Should this require EXCL too?
- if (access & FILEACCESS_APPEND) {
- mode = Android_OpenContentUriMode::READ_WRITE;
- // Will also need to seek later.
- }
- } else if (access & FILEACCESS_READ) {
- mode = Android_OpenContentUriMode::READ;
- }
-
- bool success = true;
-
- if (access & FILEACCESS_CREATE) {
- AndroidStorageContentURI parentUri(basePath);
-
- // We're gonna have to explicitly create the file here.
- if (!Android_CreateFile(parentUri.ToString(), fileName)) {
- // Something went wrong.
- success = false;
- }
- } else {
- // Requested an existing file, doesn't exist.
- if (!fileInfo.exists) {
- error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND;
- return false;
- }
- }
-
- // Not sure what to do with FILEACCESS_EXCL.
-
- std::string uriString = contentUri.ToString();
-
- INFO_LOG(FILESYS, "AndroidDirectoryFileHandle::Open(%s)", uriString.c_str());
-
- hFile = Android_OpenContentUriFd(uriString, mode);
- if (hFile == -1) {
- ERROR_LOG(FILESYS, "Android_OpenContentUriFd(%s) failed", uriString.c_str());
- success = false;
- }
-
- // TODO: Experiment with fstat to see if we can extract more info.
-
- // Seek to end to simulate append mode, if requested.
- if (access & FILEACCESS_APPEND) {
- Seek(0, FILEMOVE_END);
- }
-
- // Try to detect reads/writes to PSP/GAME to avoid them in replays.
- if (basePath.find("/PSP/GAME/") != std::string::npos) {
- inGameDir_ = true;
- }
- return success;
-}
-
-size_t AndroidDirectoryFileHandle::Read(u8* pointer, s64 size) {
- size_t bytesRead = 0;
- if (needsTrunc_ != -1) {
- // If the file was marked to be truncated, pretend there's nothing.
- // On a PSP. it actually is truncated, but the data wasn't erased.
- off_t off = (off_t)Seek(0, FILEMOVE_CURRENT);
- if (needsTrunc_ <= off) {
- return replay_ ? ReplayApplyDiskRead(pointer, 0, (uint32_t)size, inGameDir_, CoreTiming::GetGlobalTimeUs()) : 0;
- }
- if (needsTrunc_ < off + size) {
- size = needsTrunc_ - off;
- }
- }
- bytesRead = read(hFile, pointer, size);
- return replay_ ? ReplayApplyDiskRead(pointer, (uint32_t)bytesRead, (uint32_t)size, inGameDir_, CoreTiming::GetGlobalTimeUs()) : bytesRead;
-}
-
-size_t AndroidDirectoryFileHandle::Write(const u8* pointer, s64 size)
-{
- size_t bytesWritten = 0;
- bool diskFull = false;
-
- bytesWritten = write(hFile, pointer, size);
- if (bytesWritten == (size_t)-1) {
- diskFull = errno == ENOSPC;
- }
- if (needsTrunc_ != -1) {
- off_t off = (off_t)Seek(0, FILEMOVE_CURRENT);
- if (needsTrunc_ < off) {
- needsTrunc_ = off;
- }
- }
-
- if (replay_) {
- bytesWritten = ReplayApplyDiskWrite(pointer, (uint64_t)bytesWritten, (uint64_t)size, &diskFull, inGameDir_, CoreTiming::GetGlobalTimeUs());
- }
-
- if (diskFull) {
- ERROR_LOG(FILESYS, "Disk full");
- auto err = GetI18NCategory("Error");
- host->NotifyUserMessage(err->T("Disk full while writing data"));
- // We only return an error when the disk is actually full.
- // When writing this would cause the disk to be full, so it wasn't written, we return 0.
- if (MemoryStick_FreeSpace() == 0) {
- // Sign extend on 64-bit.
- return (size_t)(s64)(s32)SCE_KERNEL_ERROR_ERRNO_DEVICE_NO_FREE_SPACE;
- }
- }
-
- return bytesWritten;
-}
-
-size_t AndroidDirectoryFileHandle::Seek(s32 position, FileMove type)
-{
- if (needsTrunc_ != -1) {
- // If the file is "currently truncated" move to the end based on that position.
- // The actual, underlying file hasn't been truncated (yet.)
- if (type == FILEMOVE_END) {
- type = FILEMOVE_BEGIN;
- position = needsTrunc_ + position;
- }
- }
-
- size_t result;
-
- int moveMethod = 0;
- switch (type) {
- case FILEMOVE_BEGIN: moveMethod = SEEK_SET; break;
- case FILEMOVE_CURRENT: moveMethod = SEEK_CUR; break;
- case FILEMOVE_END: moveMethod = SEEK_END; break;
- }
- result = lseek(hFile, position, moveMethod);
-
- return replay_ ? (size_t)ReplayApplyDisk64(ReplayAction::FILE_SEEK, result, CoreTiming::GetGlobalTimeUs()) : result;
-}
-
-void AndroidDirectoryFileHandle::Close()
-{
- if (needsTrunc_ != -1) {
- // Note: it's not great that Switch cannot truncate appropriately...
- if (ftruncate(hFile, (off_t)needsTrunc_) != 0) {
- ERROR_LOG_REPORT(FILESYS, "Failed to truncate file.");
- }
- }
- if (hFile != -1)
- close(hFile);
-}
-
-void AndroidStorageFileSystem::CloseAll() {
- for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
- INFO_LOG(FILESYS, "DirectoryFileSystem::CloseAll(): Force closing %d (%s)", (int)iter->first, iter->second.guestFilename.c_str());
- iter->second.hFile.Close();
- }
- entries.clear();
-}
-
-std::string AndroidStorageFileSystem::GetLocalPath(std::string localpath) {
- if (localpath.empty()) {
- return baseContentUri.ToString();
- }
-
- if (localpath[0] == '/')
- localpath.erase(0, 1);
-
- return baseContentUri.WithFilePath(localpath).ToString();
-}
-
-bool AndroidStorageFileSystem::MkDir(const std::string &dirname) {
- ERROR_LOG(FILESYS, "MkDir operation not yet supported.");
- // TODO: Figure out a way to create directories in Storage...
- // TODO: Use Android_CreateDirectory. Not sure how deep it can go...
- bool result = false;
- // bool result = File::CreateFullPath(GetLocalPath(dirname));
- return ReplayApplyDisk(ReplayAction::MKDIR, result, CoreTiming::GetGlobalTimeUs()) != 0;
-}
-
-bool AndroidStorageFileSystem::RmDir(const std::string &dirname) {
-
- ERROR_LOG(FILESYS, "RmDir operation not yet supported.");
-
- return false; // ReplayApplyDisk(ReplayAction::RMDIR, result, CoreTiming::GetGlobalTimeUs()) != 0;
-}
-
-int AndroidStorageFileSystem::RenameFile(const std::string &from, const std::string &to) {
- std::string fullTo = to;
-
- // Rename ignores the path (even if specified) on to.
- size_t chop_at = to.find_last_of('/');
- if (chop_at != to.npos)
- fullTo = to.substr(chop_at + 1);
-
- // Now put it in the same directory as from.
- size_t dirname_end = from.find_last_of('/');
- if (dirname_end != from.npos)
- fullTo = from.substr(0, dirname_end + 1) + fullTo;
-
- // At this point, we should check if the paths match and give an already exists error.
- if (from == fullTo)
- return ReplayApplyDisk(ReplayAction::FILE_RENAME, SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS, CoreTiming::GetGlobalTimeUs());
-
- std::string fullFrom = GetLocalPath(from);
-
- fullTo = GetLocalPath(fullTo);
- const char * fullToC = fullTo.c_str();
-
- bool retValue = (0 == rename(fullFrom.c_str(), fullToC));
-
- // TODO: Better error codes.
- int result = retValue ? 0 : (int)SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS;
- return ReplayApplyDisk(ReplayAction::FILE_RENAME, result, CoreTiming::GetGlobalTimeUs());
-}
-
-bool AndroidStorageFileSystem::RemoveFile(const std::string &filename) {
- std::string fullName = GetLocalPath(filename);
- bool retValue = (0 == unlink(fullName.c_str()));
- return ReplayApplyDisk(ReplayAction::FILE_REMOVE, retValue, CoreTiming::GetGlobalTimeUs()) != 0;
-}
-
-int AndroidStorageFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) {
- OpenFileEntry entry;
- u32 err = 0;
- bool success = entry.hFile.Open(basePath, filename, access, err);
- if (err == 0 && !success) {
- err = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND;
- }
-
- err = ReplayApplyDisk(ReplayAction::FILE_OPEN, err, CoreTiming::GetGlobalTimeUs());
- if (err != 0) {
- ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, %i - access = %i", errno, (int)access);
- return err;
- } else {
- if (access & FILEACCESS_APPEND)
- entry.hFile.Seek(0, FILEMOVE_END);
-
- u32 newHandle = hAlloc->GetNewHandle();
-
- entry.guestFilename = filename;
- entry.access = access;
-
- entries[newHandle] = entry;
-
- return newHandle;
- }
-}
-
-void AndroidStorageFileSystem::CloseFile(u32 handle) {
- EntryMap::iterator iter = entries.find(handle);
- if (iter != entries.end()) {
- hAlloc->FreeHandle(handle);
- iter->second.hFile.Close();
- entries.erase(iter);
- } else {
- // This shouldn't happen...
- ERROR_LOG(FILESYS, "Cannot close file that hasn't been opened: %08x", handle);
- }
-}
-
-bool AndroidStorageFileSystem::OwnsHandle(u32 handle) {
- EntryMap::iterator iter = entries.find(handle);
- return (iter != entries.end());
-}
-
-int AndroidStorageFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) {
- return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED;
-}
-
-PSPDevType AndroidStorageFileSystem::DevType(u32 handle) {
- return PSPDevType::FILE;
-}
-
-size_t AndroidStorageFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
- int ignored;
- return ReadFile(handle, pointer, size, ignored);
-}
-
-size_t AndroidStorageFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) {
- EntryMap::iterator iter = entries.find(handle);
- if (iter != entries.end()) {
- if (size < 0) {
- ERROR_LOG_REPORT(FILESYS, "Invalid read for %lld bytes from disk %s", size, iter->second.guestFilename.c_str());
- return 0;
- }
-
- size_t bytesRead = iter->second.hFile.Read(pointer, size);
- return bytesRead;
- } else {
- //This shouldn't happen...
- ERROR_LOG(FILESYS, "Cannot read file that hasn't been opened: %08x", handle);
- return 0;
- }
-}
-
-size_t AndroidStorageFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) {
- int ignored;
- return WriteFile(handle, pointer, size, ignored);
-}
-
-size_t AndroidStorageFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) {
- EntryMap::iterator iter = entries.find(handle);
- if (iter != entries.end())
- {
- size_t bytesWritten = iter->second.hFile.Write(pointer, size);
- return bytesWritten;
- } else {
- //This shouldn't happen...
- ERROR_LOG(FILESYS, "Cannot write to file that hasn't been opened: %08x", handle);
- return 0;
- }
-}
-
-size_t AndroidStorageFileSystem::SeekFile(u32 handle, s32 position, FileMove type) {
- EntryMap::iterator iter = entries.find(handle);
- if (iter != entries.end()) {
- return iter->second.hFile.Seek(position, type);
- } else {
- //This shouldn't happen...
- ERROR_LOG(FILESYS, "Cannot seek in file that hasn't been opened: %08x", handle);
- return 0;
- }
-}
-
-PSPFileInfo AndroidStorageFileSystem::GetFileInfo(std::string filename) {
- PSPFileInfo x;
- x.name = filename;
-
- std::string uri = GetLocalPath(filename);
-
- File::FileInfo info;
- if (!Android_GetFileInfo(uri, &info)) {
- return ReplayApplyDiskFileInfo(x, CoreTiming::GetGlobalTimeUs());
- }
-
- x.type = info.isDirectory ? FILETYPE_DIRECTORY : FILETYPE_NORMAL;
- x.exists = true;
-
- if (x.type != FILETYPE_DIRECTORY) {
- x.size = info.size;
- x.access = info.isWritable ? 0777 : 0666;
-
- // The only time value we get from the storage API.
- int64_t lastModified = info.lastModified / 1000;
-
- time_t atime = lastModified;
- time_t ctime = lastModified;
- time_t mtime = lastModified;
-
- localtime_r((time_t*)&atime, &x.atime);
- localtime_r((time_t*)&ctime, &x.ctime);
- localtime_r((time_t*)&mtime, &x.mtime);
- }
-
- return ReplayApplyDiskFileInfo(x, CoreTiming::GetGlobalTimeUs());
-}
-
-// See comment in DirectoryFileSystem.
-extern std::string SimulateVFATBug(std::string filename);
-
-std::vector AndroidStorageFileSystem::GetDirListing(std::string path) {
- std::vector myVector;
- bool listingRoot = path == "/" || path == "\\";
-
- std::string uri = GetLocalPath(path);
-
- std::vector fileInfo = Android_ListContentUri(uri);
-
- bool hideISOFiles = PSP_CoreParameter().compat.flags().HideISOFiles;
- for (auto &info : fileInfo) {
- PSPFileInfo entry;
- if (info.isDirectory) {
- entry.type = FILETYPE_DIRECTORY;
- } else {
- entry.type = FILETYPE_NORMAL;
- }
- entry.access = info.isWritable ? 0777 : 0666;
- entry.name = info.name;
- if (Flags() & FileSystemFlags::SIMULATE_FAT32) {
- entry.name = SimulateVFATBug(entry.name);
- }
- entry.size = info.size;
-
- bool hideFile = false;
- if (hideISOFiles && (endsWithNoCase(entry.name, ".cso") || endsWithNoCase(entry.name, ".iso"))) {
- // Workaround for DJ Max Portable, see compat.ini.
- hideFile = true;
- }
-
- // TODO: Maybe do this conversion in the Android wrapper layer...
- int64_t lastModified = info.lastModified / 1000;
-
- time_t atime = lastModified;
- time_t ctime = lastModified;
- time_t mtime = lastModified;
-
- localtime_r((time_t*)&atime, &entry.atime);
- localtime_r((time_t*)&ctime, &entry.ctime);
- localtime_r((time_t*)&mtime, &entry.mtime);
- if (!hideFile && (!listingRoot || (strcmp(info.name.c_str(), "..") && strcmp(info.name.c_str(), ".")))) {
- myVector.push_back(entry);
- }
- }
-
- return ReplayApplyDiskListing(myVector, CoreTiming::GetGlobalTimeUs());
-}
-
-u64 AndroidStorageFileSystem::FreeSpace(const std::string &path) {
- // Can't get this, I think.
-
- return ReplayApplyDisk64(ReplayAction::FREESPACE, std::numeric_limits::max(), CoreTiming::GetGlobalTimeUs());
-}
-
-// WARNING! This must be kept compatible with DirectoryFileSystem for save state portability.
-void AndroidStorageFileSystem::DoState(PointerWrap &p) {
- auto s = p.Section("DirectoryFileSystem", 0, 2);
- if (!s)
- return;
-
- // Savestate layout:
- // u32: number of entries
- // per-entry:
- // u32: handle number
- // std::string filename (in guest's terms, untranslated)
- // enum FileAccess file access mode
- // u32 seek position
- // s64 current truncate position (v2+ only)
-
- u32 num = (u32)entries.size();
- Do(p, num);
-
- if (p.mode == p.MODE_READ) {
- CloseAll();
- u32 key;
- OpenFileEntry entry;
- for (u32 i = 0; i < num; i++) {
- Do(p, key);
- Do(p, entry.guestFilename);
- Do(p, entry.access);
- u32 err;
- if (!entry.hFile.Open(basePath, entry.guestFilename, entry.access, err)) {
- ERROR_LOG(FILESYS, "Failed to reopen file while loading state: %s", entry.guestFilename.c_str());
- continue;
- }
- u32 position;
- Do(p, position);
- if (position != entry.hFile.Seek(position, FILEMOVE_BEGIN)) {
- ERROR_LOG(FILESYS, "Failed to restore seek position while loading state: %s", entry.guestFilename.c_str());
- continue;
- }
- if (s >= 2) {
- Do(p, entry.hFile.needsTrunc_);
- }
- entries[key] = entry;
- }
- } else {
- for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
- u32 key = iter->first;
- Do(p, key);
- Do(p, iter->second.guestFilename);
- Do(p, iter->second.access);
- u32 position = (u32)iter->second.hFile.Seek(0, FILEMOVE_CURRENT);
- Do(p, position);
- Do(p, iter->second.hFile.needsTrunc_);
- }
- }
-}
-
-#endif // PPSSPP_PLATFORM(ANDROID)
diff --git a/Core/FileSystems/AndroidStorageFileSystem.h b/Core/FileSystems/AndroidStorageFileSystem.h
deleted file mode 100644
index 01af2bb318..0000000000
--- a/Core/FileSystems/AndroidStorageFileSystem.h
+++ /dev/null
@@ -1,104 +0,0 @@
-#pragma once
-
-// Like DirectoryFileSystem, but uses the Android Storage Access Framework
-// to access a folder tree as if it was a PSP file system.
-// Unfortunately we cannot implement all the semantics like this, let's see
-// how good we can get it though.
-
-// Copyright (c) 2012- PPSSPP Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official git repository and contact information can be found at
-// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
-
-#pragma once
-
-#include "ppsspp_config.h"
-
-#include