Merge pull request #14642 from hrydgard/more-scoped-storage-work

Merge a few more of the commits from #14619
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2021-07-25 18:23:35 +02:00
commit e29f749d98
18 files changed
+266 -113

No files matched your search

+61 -20
View File
@@ -12,12 +12,14 @@ static jmethodID listContentUriDir;
static jmethodID contentUriCreateFile;
static jmethodID contentUriCreateDirectory;
static jmethodID contentUriCopyFile;
static jmethodID contentUriMoveFile;
static jmethodID contentUriRemoveFile;
static jmethodID contentUriRenameFileTo;
static jmethodID contentUriGetFileInfo;
static jmethodID contentUriFileExists;
static jmethodID contentUriGetFreeStorageSpace;
static jmethodID filePathGetFreeStorageSpace;
static jmethodID isExternalStoragePreservedLegacy;
static jobject g_nativeActivity;
@@ -30,15 +32,17 @@ void Android_RegisterStorageCallbacks(JNIEnv * env, jobject obj) {
_dbg_assert_(openContentUri);
listContentUriDir = env->GetMethodID(env->GetObjectClass(obj), "listContentUriDir", "(Ljava/lang/String;)[Ljava/lang/String;");
_dbg_assert_(listContentUriDir);
contentUriCreateDirectory = env->GetMethodID(env->GetObjectClass(obj), "contentUriCreateDirectory", "(Ljava/lang/String;Ljava/lang/String;)Z");
contentUriCreateDirectory = env->GetMethodID(env->GetObjectClass(obj), "contentUriCreateDirectory", "(Ljava/lang/String;Ljava/lang/String;)I");
_dbg_assert_(contentUriCreateDirectory);
contentUriCreateFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriCreateFile", "(Ljava/lang/String;Ljava/lang/String;)Z");
contentUriCreateFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriCreateFile", "(Ljava/lang/String;Ljava/lang/String;)I");
_dbg_assert_(contentUriCreateFile);
contentUriCopyFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriCopyFile", "(Ljava/lang/String;Ljava/lang/String;)Z");
contentUriCopyFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriCopyFile", "(Ljava/lang/String;Ljava/lang/String;)I");
_dbg_assert_(contentUriCopyFile);
contentUriRemoveFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriRemoveFile", "(Ljava/lang/String;)Z");
contentUriRemoveFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriRemoveFile", "(Ljava/lang/String;)I");
_dbg_assert_(contentUriRemoveFile);
contentUriRenameFileTo = env->GetMethodID(env->GetObjectClass(obj), "contentUriRenameFileTo", "(Ljava/lang/String;Ljava/lang/String;)Z");
contentUriMoveFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriMoveFile", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I");
_dbg_assert_(contentUriMoveFile);
contentUriRenameFileTo = env->GetMethodID(env->GetObjectClass(obj), "contentUriRenameFileTo", "(Ljava/lang/String;Ljava/lang/String;)I");
_dbg_assert_(contentUriRenameFileTo);
contentUriGetFileInfo = env->GetMethodID(env->GetObjectClass(obj), "contentUriGetFileInfo", "(Ljava/lang/String;)Ljava/lang/String;");
_dbg_assert_(contentUriGetFileInfo);
@@ -48,6 +52,8 @@ void Android_RegisterStorageCallbacks(JNIEnv * env, jobject obj) {
_dbg_assert_(contentUriGetFreeStorageSpace);
filePathGetFreeStorageSpace = env->GetMethodID(env->GetObjectClass(obj), "filePathGetFreeStorageSpace", "(Ljava/lang/String;)J");
_dbg_assert_(filePathGetFreeStorageSpace);
isExternalStoragePreservedLegacy = env->GetMethodID(env->GetObjectClass(obj), "isExternalStoragePreservedLegacy", "()Z");
_dbg_assert_(isExternalStoragePreservedLegacy);
}
bool Android_IsContentUri(const std::string &filename) {
@@ -78,53 +84,64 @@ int Android_OpenContentUriFd(const std::string &filename, Android_OpenContentUri
return fd;
}
bool Android_CreateDirectory(const std::string &rootTreeUri, const std::string &dirName) {
StorageError Android_CreateDirectory(const std::string &rootTreeUri, const std::string &dirName) {
if (!g_nativeActivity) {
return false;
return StorageError::UNKNOWN;
}
auto env = getEnv();
jstring paramRoot = env->NewStringUTF(rootTreeUri.c_str());
jstring paramDirName = env->NewStringUTF(dirName.c_str());
return env->CallBooleanMethod(g_nativeActivity, contentUriCreateDirectory, paramRoot, paramDirName);
return StorageErrorFromInt(env->CallIntMethod(g_nativeActivity, contentUriCreateDirectory, paramRoot, paramDirName));
}
bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName) {
StorageError Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName) {
if (!g_nativeActivity) {
return false;
return StorageError::UNKNOWN;
}
auto env = getEnv();
jstring paramRoot = env->NewStringUTF(parentTreeUri.c_str());
jstring paramFileName = env->NewStringUTF(fileName.c_str());
return env->CallBooleanMethod(g_nativeActivity, contentUriCreateFile, paramRoot, paramFileName);
return StorageErrorFromInt(env->CallIntMethod(g_nativeActivity, contentUriCreateFile, paramRoot, paramFileName));
}
bool Android_CopyFile(const std::string &fileUri, const std::string &destParentUri) {
StorageError Android_CopyFile(const std::string &fileUri, const std::string &destParentUri) {
if (!g_nativeActivity) {
return false;
return StorageError::UNKNOWN;
}
auto env = getEnv();
jstring paramFileName = env->NewStringUTF(fileUri.c_str());
jstring paramDestParentUri = env->NewStringUTF(destParentUri.c_str());
return env->CallBooleanMethod(g_nativeActivity, contentUriCopyFile, paramFileName, paramDestParentUri);
return StorageErrorFromInt(env->CallIntMethod(g_nativeActivity, contentUriCopyFile, paramFileName, paramDestParentUri));
}
bool Android_RemoveFile(const std::string &fileUri) {
StorageError Android_MoveFile(const std::string &fileUri, const std::string &srcParentUri, const std::string &destParentUri) {
if (!g_nativeActivity) {
return false;
return StorageError::UNKNOWN;
}
auto env = getEnv();
jstring paramFileName = env->NewStringUTF(fileUri.c_str());
return env->CallBooleanMethod(g_nativeActivity, contentUriRemoveFile, paramFileName);
jstring paramSrcParentUri = env->NewStringUTF(srcParentUri.c_str());
jstring paramDestParentUri = env->NewStringUTF(destParentUri.c_str());
return StorageErrorFromInt(env->CallIntMethod(g_nativeActivity, contentUriMoveFile, paramFileName, paramSrcParentUri, paramDestParentUri));
}
bool Android_RenameFileTo(const std::string &fileUri, const std::string &newName) {
StorageError Android_RemoveFile(const std::string &fileUri) {
if (!g_nativeActivity) {
return false;
return StorageError::UNKNOWN;
}
auto env = getEnv();
jstring paramFileName = env->NewStringUTF(fileUri.c_str());
return StorageErrorFromInt(env->CallIntMethod(g_nativeActivity, contentUriRemoveFile, paramFileName));
}
StorageError Android_RenameFileTo(const std::string &fileUri, const std::string &newName) {
if (!g_nativeActivity) {
return StorageError::UNKNOWN;
}
auto env = getEnv();
jstring paramFileUri = env->NewStringUTF(fileUri.c_str());
jstring paramNewName = env->NewStringUTF(newName.c_str());
return env->CallBooleanMethod(g_nativeActivity, contentUriRenameFileTo, paramFileUri, paramNewName);
return StorageErrorFromInt(env->CallIntMethod(g_nativeActivity, contentUriRenameFileTo, paramFileUri, paramNewName));
}
// NOTE: Does not set fullName - you're supposed to already know it.
@@ -241,4 +258,28 @@ int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) {
return env->CallLongMethod(g_nativeActivity, filePathGetFreeStorageSpace, param);
}
bool Android_IsExternalStoragePreservedLegacy() {
if (!g_nativeActivity) {
return false;
}
auto env = getEnv();
return env->CallBooleanMethod(g_nativeActivity, isExternalStoragePreservedLegacy);
}
const char *Android_ErrorToString(StorageError error) {
switch (error) {
case StorageError::SUCCESS: return "SUCCESS";
case StorageError::UNKNOWN: return "UNKNOWN";
case StorageError::NOT_FOUND: return "NOT_FOUND";
case StorageError::DISK_FULL: return "DISK_FULL";
case StorageError::ALREADY_EXISTS: return "ALREADY_EXISTS";
default: return "(UNKNOWN)";
}
}
#else
// This string should never appear except on Android.
std::string g_extFilesDir = "(IF YOU SEE THIS THERE'S A BUG)";
#endif
+35 -10
View File
@@ -13,6 +13,23 @@ enum class Android_OpenContentUriMode {
READ_WRITE_TRUNCATE = 2, // "rwt"
};
// Matches the constants in PpssppActivity.java.
enum class StorageError {
SUCCESS = 0,
UNKNOWN = -1,
NOT_FOUND = -2,
DISK_FULL = -3,
ALREADY_EXISTS = -4,
};
inline StorageError StorageErrorFromInt(int ival) {
if (ival >= 0) {
return StorageError::SUCCESS;
} else {
return (StorageError)ival;
}
}
#if PPSSPP_PLATFORM(ANDROID) && !defined(__LIBRETRO__)
#include <jni.h>
@@ -23,15 +40,18 @@ void Android_StorageSetNativeActivity(jobject nativeActivity);
bool Android_IsContentUri(const std::string &uri);
int Android_OpenContentUriFd(const std::string &uri, const Android_OpenContentUriMode mode);
bool Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName);
bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName);
bool Android_CopyFile(const std::string &fileUri, const std::string &destParentUri);
bool Android_RemoveFile(const std::string &fileUri);
bool Android_RenameFileTo(const std::string &fileUri, const std::string &newName);
StorageError Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName);
StorageError Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName);
StorageError Android_MoveFile(const std::string &fileUri, const std::string &srcParentUri, const std::string &destParentUri);
StorageError Android_CopyFile(const std::string &fileUri, const std::string &destParentUri);
StorageError Android_RemoveFile(const std::string &fileUri);
StorageError Android_RenameFileTo(const std::string &fileUri, const std::string &newName);
bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info);
bool Android_FileExists(const std::string &fileUri);
int64_t Android_GetFreeSpaceByContentUri(const std::string &uri);
int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath);
bool Android_IsExternalStoragePreservedLegacy();
const char *Android_ErrorToString(StorageError error);
std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri);
@@ -39,19 +59,24 @@ void Android_RegisterStorageCallbacks(JNIEnv * env, jobject obj);
#else
extern std::string g_extFilesDir;
// Stub out the Android Storage wrappers, so that we can avoid ifdefs everywhere.
inline bool Android_IsContentUri(const std::string &uri) { return false; }
inline int Android_OpenContentUriFd(const std::string &uri, const Android_OpenContentUriMode mode) { return -1; }
inline bool Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName) { return false; }
inline bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName) { return false; }
inline bool Android_CopyFile(const std::string &fileUri, const std::string &destParentUri) { return false; }
inline bool Android_RemoveFile(const std::string &fileUri) { return false; }
inline bool Android_RenameFileTo(const std::string &fileUri, const std::string &newName) { return false; }
inline StorageError Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName) { return StorageError::UNKNOWN; }
inline StorageError Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName) { return StorageError::UNKNOWN; }
inline StorageError Android_MoveFile(const std::string &fileUri, const std::string &srcParentUri, const std::string &destParentUri) { return StorageError::UNKNOWN; }
inline StorageError Android_CopyFile(const std::string &fileUri, const std::string &destParentUri) { return StorageError::UNKNOWN; }
inline StorageError Android_RemoveFile(const std::string &fileUri) { return StorageError::UNKNOWN; }
inline StorageError Android_RenameFileTo(const std::string &fileUri, const std::string &newName) { return StorageError::UNKNOWN; }
inline bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info) { return false; }
inline bool Android_FileExists(const std::string &fileUri) { return false; }
inline int64_t Android_GetFreeSpaceByContentUri(const std::string &uri) { return -1; }
inline int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) { return -1; }
inline bool Android_IsExternalStoragePreservedLegacy() { return false; }
inline const char *Android_ErrorToString(StorageError error) { return ""; }
inline std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri) {
return std::vector<File::FileInfo>();
}
+45 -21
View File
@@ -107,7 +107,7 @@ FILE *OpenCFile(const Path &path, const char *mode) {
INFO_LOG(COMMON, "Opening content file for read: '%s'", path.c_str());
// Read, let's support this - easy one.
int descriptor = Android_OpenContentUriFd(path.ToString(), Android_OpenContentUriMode::READ);
if (descriptor == -1) {
if (descriptor < 0) {
return nullptr;
}
return fdopen(descriptor, "rb");
@@ -119,7 +119,7 @@ FILE *OpenCFile(const Path &path, const char *mode) {
std::string name = path.GetFilename();
if (path.CanNavigateUp()) {
Path parent = path.NavigateUp();
if (!Android_CreateFile(parent.ToString(), name)) {
if (Android_CreateFile(parent.ToString(), name) != StorageError::SUCCESS) {
WARN_LOG(COMMON, "Failed to create file '%s' in '%s'", name.c_str(), parent.c_str());
return nullptr;
}
@@ -133,7 +133,7 @@ FILE *OpenCFile(const Path &path, const char *mode) {
// TODO: Support append modes and stuff... For now let's go with the most common one.
int descriptor = Android_OpenContentUriFd(path.ToString(), Android_OpenContentUriMode::READ_WRITE_TRUNCATE);
if (descriptor == -1) {
if (descriptor < 0) {
INFO_LOG(COMMON, "Opening '%s' for write failed", path.ToString().c_str());
return nullptr;
}
@@ -189,7 +189,7 @@ int OpenFD(const Path &path, OpenFlag flags) {
std::string name = path.GetFilename();
if (path.CanNavigateUp()) {
Path parent = path.NavigateUp();
if (!Android_CreateFile(parent.ToString(), name)) {
if (Android_CreateFile(parent.ToString(), name) != StorageError::SUCCESS) {
WARN_LOG(COMMON, "OpenFD: Failed to create file '%s' in '%s'", name.c_str(), parent.c_str());
return -1;
}
@@ -223,6 +223,12 @@ int OpenFD(const Path &path, OpenFlag flags) {
if (descriptor < 0) {
ERROR_LOG(COMMON, "Android_OpenContentUriFd failed: '%s'", path.c_str());
}
if (flags & OPEN_APPEND) {
// Simply seek to the end of the file to simulate append mode.
lseek(descriptor, 0, SEEK_END);
}
return descriptor;
}
@@ -390,7 +396,7 @@ bool Delete(const Path &filename) {
case PathType::NATIVE:
break; // OK
case PathType::CONTENT_URI:
return Android_RemoveFile(filename.ToString());
return Android_RemoveFile(filename.ToString()) == StorageError::SUCCESS;
default:
return false;
}
@@ -433,13 +439,19 @@ bool CreateDir(const Path &path) {
break; // OK
case PathType::CONTENT_URI:
{
// NOTE: The Android storage API will simply create a renamed directory (append a number) if it already exists.
// We want to avoid that, so let's just return true if the directory already is there.
if (File::Exists(path)) {
return true;
}
// Convert it to a "CreateDirIn" call, if possible, since that's
// what we can do with the storage API.
AndroidContentURI uri(path.ToString());
std::string newDirName = uri.GetLastPart();
if (uri.NavigateUp()) {
INFO_LOG(COMMON, "Calling Android_CreateDirectory(%s, %s)", uri.ToString().c_str(), newDirName.c_str());
return Android_CreateDirectory(uri.ToString(), newDirName);
return Android_CreateDirectory(uri.ToString(), newDirName) == StorageError::SUCCESS;
} else {
// Bad path - can't create this directory.
WARN_LOG(COMMON, "CreateDir failed: '%s'", path.c_str());
@@ -526,7 +538,7 @@ bool DeleteDir(const Path &path) {
case PathType::NATIVE:
break; // OK
case PathType::CONTENT_URI:
return Android_RemoveFile(path.ToString());
return Android_RemoveFile(path.ToString()) == StorageError::SUCCESS;
default:
return false;
}
@@ -565,13 +577,14 @@ bool Rename(const Path &srcFilename, const Path &destFilename) {
break;
case PathType::CONTENT_URI:
// Content URI: Can only rename if in the same folder.
// TODO: Fallback to move + rename? Or do we even care about that use case?
if (srcFilename.GetDirectory() != destFilename.GetDirectory()) {
INFO_LOG(COMMON, "Content URI rename: Directories not matching, failing. %s --> %s", srcFilename.c_str(), destFilename.c_str());
return false;
}
INFO_LOG(COMMON, "Content URI rename: %s --> %s", srcFilename.c_str(), destFilename.c_str());
return Android_RenameFileTo(srcFilename.ToString(), destFilename.GetFilename());
return Android_RenameFileTo(srcFilename.ToString(), destFilename.GetFilename()) == StorageError::SUCCESS;
default:
return false;
}
@@ -594,26 +607,23 @@ bool Rename(const Path &srcFilename, const Path &destFilename) {
}
// copies file srcFilename to destFilename, returns true on success
bool Copy(const Path &srcFilename, const Path &destFilename)
{
bool Copy(const Path &srcFilename, const Path &destFilename) {
switch (srcFilename.Type()) {
case PathType::NATIVE:
break; // OK
case PathType::CONTENT_URI:
ERROR_LOG_REPORT_ONCE(copyUriNotSupported, COMMON, "Copying files by Android URI is not yet supported");
if (destFilename.Type() == PathType::CONTENT_URI && destFilename.CanNavigateUp()) {
Path destParent = destFilename.NavigateUp();
// Use native file copy.
if (Android_CopyFile(srcFilename.ToString(), destParent.ToString()) == StorageError::SUCCESS) {
return true;
}
// Else fall through, and try using file I/O.
}
break;
default:
return false;
}
switch (destFilename.Type()) {
case PathType::NATIVE:
break; // OK
case PathType::CONTENT_URI:
ERROR_LOG_REPORT_ONCE(copyUriNotSupported, COMMON, "Copying files by Android URI is not yet supported");
return false;
default:
return false;
}
INFO_LOG(COMMON, "Copy: %s --> %s", srcFilename.c_str(), destFilename.c_str());
#ifdef _WIN32
@@ -631,7 +641,7 @@ bool Copy(const Path &srcFilename, const Path &destFilename)
#else
// buffer size
#define BSIZE 4096
#define BSIZE 16384
char buffer[BSIZE];
@@ -685,7 +695,21 @@ bool Copy(const Path &srcFilename, const Path &destFilename)
#endif
}
// Will overwrite the target.
bool Move(const Path &srcFilename, const Path &destFilename) {
// Try a shortcut in Android Storage scenarios.
if (srcFilename.Type() == PathType::CONTENT_URI && destFilename.Type() == PathType::CONTENT_URI && srcFilename.CanNavigateUp() && destFilename.CanNavigateUp()) {
// We do not handle simultaneous renames here.
if (srcFilename.GetFilename() == destFilename.GetFilename()) {
Path srcParent = srcFilename.NavigateUp();
Path dstParent = destFilename.NavigateUp();
if (Android_MoveFile(srcFilename.ToString(), srcParent.ToString(), dstParent.ToString()) == StorageError::SUCCESS) {
return true;
}
// If failed, fall through and try other ways.
}
}
if (Rename(srcFilename, destFilename)) {
return true;
} else if (Copy(srcFilename, destFilename)) {
+1 -1
View File
@@ -301,7 +301,7 @@ bool Path::IsAbsolute() const {
return false;
}
std::string Path::PathTo(const Path &other) {
std::string Path::PathTo(const Path &other) const {
if (!other.StartsWith(*this)) {
// Can't do this. Should return an error.
return std::string();
+1 -1
View File
@@ -82,7 +82,7 @@ public:
// For Android directory trees, navigates to the root of the tree.
Path GetRootVolume() const;
std::string PathTo(const Path &child);
std::string PathTo(const Path &child) const;
bool operator ==(const Path &other) const {
return path_ == other.path_ && type_ == other.type_;
+2 -1
View File
@@ -143,7 +143,8 @@ public:
if (p.error != p.ERROR_FAILURE) {
return ERROR_NONE;
} else {
*errorString = std::string("Failure at ") + p.GetBadSectionTitle();
std::string badSectionTitle = p.GetBadSectionTitle() ? p.GetBadSectionTitle() : "(unknown bad section)";
*errorString = std::string("Failure at ") + badSectionTitle;
return ERROR_BROKEN_STATE;
}
}
+1 -1
View File
@@ -61,7 +61,7 @@ LocalFileLoader::LocalFileLoader(const Path &filename)
if (filename.Type() == PathType::CONTENT_URI) {
int fd = Android_OpenContentUriFd(filename.ToString(), Android_OpenContentUriMode::READ);
INFO_LOG(SYSTEM, "Fd %d for content URI: '%s'", fd, filename.c_str());
if (fd == -1) {
if (fd < 0) {
ERROR_LOG(FILESYS, "LoadFileLoader failed to open content URI: '%s'", filename.c_str());
return;
}
+25 -12
View File
@@ -177,17 +177,40 @@ DirectoryFileSystem::~DirectoryFileSystem() {
CloseAll();
}
Path DirectoryFileHandle::GetLocalPath(const Path &basePath, std::string localpath)
{
// TODO(scoped): Merge the two below functions somehow.
Path DirectoryFileHandle::GetLocalPath(const Path &basePath, std::string localpath) const {
if (localpath.empty())
return basePath;
if (localpath[0] == '/')
localpath.erase(0, 1);
if (fileSystemFlags_ & FileSystemFlags::STRIP_PSP) {
if (startsWith(localpath, "/PSP")) {
localpath = localpath.substr(4);
}
}
return basePath / localpath;
}
Path DirectoryFileSystem::GetLocalPath(std::string internalPath) const {
if (internalPath.empty())
return basePath;
if (internalPath[0] == '/')
internalPath.erase(0, 1);
if (flags & FileSystemFlags::STRIP_PSP) {
if (startsWith(internalPath, "/PSP")) {
internalPath = internalPath.substr(4);
}
}
return basePath / internalPath;
}
bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, FileAccess access, u32 &error) {
error = 0;
@@ -508,16 +531,6 @@ void DirectoryFileSystem::CloseAll() {
entries.clear();
}
Path DirectoryFileSystem::GetLocalPath(std::string internalPath) {
if (internalPath.empty())
return basePath;
if (internalPath[0] == '/')
internalPath.erase(0, 1);
return basePath / internalPath;
}
bool DirectoryFileSystem::MkDir(const std::string &dirname) {
bool result;
#if HOST_IS_CASE_SENSITIVE
+9 -6
View File
@@ -72,11 +72,14 @@ struct DirectoryFileHandle {
s64 needsTrunc_ = -1;
bool replay_ = true;
bool inGameDir_ = false;
FileSystemFlags fileSystemFlags_ = (FileSystemFlags)0;
DirectoryFileHandle(Flags flags) : replay_(flags != SKIP_REPLAY) {
}
DirectoryFileHandle() {}
Path GetLocalPath(const Path &basePath, std::string localpath);
DirectoryFileHandle(Flags flags, FileSystemFlags fileSystemFlags)
: replay_(flags != SKIP_REPLAY), fileSystemFlags_(fileSystemFlags) {}
Path GetLocalPath(const Path &basePath, std::string localpath) const;
bool Open(const Path &basePath, std::string &fileName, FileAccess access, u32 &err);
size_t Read(u8* pointer, s64 size);
size_t Write(const u8* pointer, s64 size);
@@ -114,7 +117,7 @@ public:
private:
struct OpenFileEntry {
DirectoryFileHandle hFile = DirectoryFileHandle::NORMAL;
DirectoryFileHandle hFile;
std::string guestFilename;
FileAccess access = FILEACCESS_NONE;
};
@@ -124,8 +127,8 @@ private:
Path basePath;
IHandleAllocator *hAlloc;
FileSystemFlags flags;
// In case of Windows: Translate slashes, etc.
Path GetLocalPath(std::string internalPath);
Path GetLocalPath(std::string internalPath) const;
};
// VFSFileSystem: Ability to map in Android APK paths as well! Does not support all features, only meant for fonts.
+1
View File
@@ -63,6 +63,7 @@ enum class FileSystemFlags {
UMD = 2,
CARD = 4,
FLASH = 8,
STRIP_PSP = 16,
};
ENUM_CLASS_BITOPS(FileSystemFlags);
+4 -3
View File
@@ -187,7 +187,7 @@ void VirtualDiscFileSystem::DoState(PointerWrap &p)
for (int i = 0; i < entryCount; i++)
{
u32 fd = 0;
OpenFileEntry of;
OpenFileEntry of(Flags());
Do(p, fd);
Do(p, of.fileIndex);
@@ -214,6 +214,7 @@ void VirtualDiscFileSystem::DoState(PointerWrap &p)
}
}
// TODO: I think we only need to write to the map on load?
entries[fd] = of;
}
} else {
@@ -321,7 +322,7 @@ int VirtualDiscFileSystem::getFileListIndex(u32 accessBlock, u32 accessSize, boo
int VirtualDiscFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename)
{
OpenFileEntry entry;
OpenFileEntry entry(Flags());
entry.curOffset = 0;
entry.size = 0;
entry.startOffset = 0;
@@ -471,7 +472,7 @@ size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &u
return 0;
}
OpenFileEntry temp;
OpenFileEntry temp(Flags());
if (fileList[fileIndex].handler != NULL) {
temp.handler = fileList[fileIndex].handler;
}
+16 -12
View File
@@ -87,17 +87,15 @@ private:
ReadFunc Read;
CloseFunc Close;
bool IsValid() const { return library != NULL; }
bool IsValid() const { return library != nullptr; }
};
struct HandlerFileHandle {
Handler *handler;
HandlerHandle handle;
HandlerFileHandle() : handler(NULL), handle(0) {
}
HandlerFileHandle(Handler *handler_) : handler(handler_), handle(-1) {
}
HandlerFileHandle() : handler(nullptr), handle(0) {}
HandlerFileHandle(Handler *handler_) : handler(handler_), handle(-1) {}
bool Open(const std::string& basePath, const std::string& fileName, FileAccess access) {
// Ignore access, read only.
@@ -115,7 +113,7 @@ private:
}
bool IsValid() {
return handler != NULL && handler->IsValid();
return handler != nullptr && handler->IsValid();
}
HandlerFileHandle &operator =(Handler *_handler) {
@@ -127,13 +125,18 @@ private:
typedef enum { VFILETYPE_NORMAL, VFILETYPE_LBN, VFILETYPE_ISO } VirtualFileType;
struct OpenFileEntry {
DirectoryFileHandle hFile = DirectoryFileHandle::SKIP_REPLAY;
OpenFileEntry() {}
OpenFileEntry(FileSystemFlags fileSystemFlags) {
hFile = DirectoryFileHandle(DirectoryFileHandle::SKIP_REPLAY, fileSystemFlags);
}
DirectoryFileHandle hFile;
HandlerFileHandle handler;
VirtualFileType type;
u32 fileIndex;
u64 curOffset;
u64 startOffset; // only used by lbn files
u64 size; // only used by lbn files
VirtualFileType type = VFILETYPE_NORMAL;
u32 fileIndex = 0;
u64 curOffset = 0;
u64 startOffset = 0; // only used by lbn files
u64 size = 0; // only used by lbn files
bool Open(const Path &basePath, std::string& fileName, FileAccess access) {
// Ignored, we're read only.
@@ -168,6 +171,7 @@ private:
};
typedef std::map<u32, OpenFileEntry> EntryMap;
EntryMap entries;
IHandleAllocator *hAlloc;
Path basePath;
+12 -4
View File
@@ -631,19 +631,28 @@ void __IoInit() {
asyncNotifyEvent = CoreTiming::RegisterEvent("IoAsyncNotify", __IoAsyncNotify);
syncNotifyEvent = CoreTiming::RegisterEvent("IoSyncNotify", __IoSyncNotify);
auto memstickSystem = std::shared_ptr<IFileSystem>(new DirectoryFileSystem(&pspFileSystem, g_Config.memStickDirectory, FileSystemFlags::SIMULATE_FAT32 | FileSystemFlags::CARD));
// TODO(scoped): This won't work if memStickDirectory points at the contents of /PSP...
#if defined(USING_WIN_UI) || defined(APPLE)
auto flash0System = std::shared_ptr<IFileSystem>(new DirectoryFileSystem(&pspFileSystem, g_Config.flash0Directory, FileSystemFlags::FLASH));
#else
auto flash0System = std::shared_ptr<IFileSystem>(new VFSFileSystem(&pspFileSystem, "flash0"));
#endif
FileSystemFlags memstickFlags = FileSystemFlags::SIMULATE_FAT32 | FileSystemFlags::CARD;
Path pspDir = GetSysDirectory(DIRECTORY_PSP);
if (pspDir == g_Config.memStickDirectory) {
// Initially tried to do this with dual mounts, but failed due to save state compatibility issues.
INFO_LOG(SCEIO, "Enabling /PSP compatibility mode");
memstickFlags |= FileSystemFlags::STRIP_PSP;
}
auto memstickSystem = std::shared_ptr<IFileSystem>(new DirectoryFileSystem(&pspFileSystem, g_Config.memStickDirectory, memstickFlags));
// TODO(scoped): This won't work if memStickDirectory points at the contents of /PSP...
// Will fix later with dual mounts (first mount ms0:/PSP/ at memstickSystem), then also mount ms0:/ on it)
pspFileSystem.Mount("ms0:", memstickSystem);
pspFileSystem.Mount("fatms0:", memstickSystem);
pspFileSystem.Mount("fatms:", memstickSystem);
pspFileSystem.Mount("pfat0:", memstickSystem);
pspFileSystem.Mount("flash0:", flash0System);
if (g_RemasterMode) {
@@ -768,7 +777,6 @@ void __IoShutdown() {
pspFileSystem.UnmountAll();
// All the file systems will be removed when we shut down pspFileSystem later.
MemoryStick_Shutdown();
memStickCallbacks.clear();
memStickFatCallbacks.clear();
+2
View File
@@ -592,6 +592,8 @@ Path GetSysDirectory(PSPDirectories directoryType) {
}
switch (directoryType) {
case DIRECTORY_PSP:
return pspDirectory;
case DIRECTORY_CHEATS:
return pspDirectory / "Cheats";
case DIRECTORY_GAME:
+1
View File
@@ -37,6 +37,7 @@ enum GlobalUIState {
// Use these in conjunction with GetSysDirectory.
enum PSPDirectories {
DIRECTORY_PSP,
DIRECTORY_CHEATS,
DIRECTORY_SCREENSHOT,
DIRECTORY_SYSTEM,
+3 -1
View File
@@ -386,6 +386,7 @@
<ClInclude Include="..\..\Common\BitScan.h" />
<ClInclude Include="..\..\Common\BitSet.h" />
<ClInclude Include="..\..\Common\Buffer.h" />
<ClInclude Include="..\..\Common\File\AndroidStorage.h" />
<ClInclude Include="..\..\Common\Net\NetBuffer.h" />
<ClInclude Include="..\..\Common\Data\Collections\ConstMap.h" />
<ClInclude Include="..\..\Common\Data\Collections\FixedSizeQueue.h" />
@@ -518,6 +519,7 @@
<ClCompile Include="..\..\Common\ArmCPUDetect.cpp" />
<ClCompile Include="..\..\Common\ArmEmitter.cpp" />
<ClCompile Include="..\..\Common\Buffer.cpp" />
<ClCompile Include="..\..\Common\File\AndroidStorage.cpp" />
<ClCompile Include="..\..\Common\Net\NetBuffer.cpp" />
<ClCompile Include="..\..\Common\Data\Color\RGBAUtil.cpp" />
<ClCompile Include="..\..\Common\Data\Convert\SmallDataConvert.cpp" />
@@ -640,4 +642,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
+7 -1
View File
@@ -375,6 +375,9 @@
<ClCompile Include="..\..\Common\GPU\ShaderTranslation.cpp">
<Filter>GPU</Filter>
</ClCompile>
<ClCompile Include="..\..\Common\File\AndroidStorage.cpp">
<Filter>File</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="targetver.h" />
@@ -691,6 +694,9 @@
<ClInclude Include="..\..\Common\GPU\ShaderTranslation.h">
<Filter>GPU</Filter>
</ClInclude>
<ClInclude Include="..\..\Common\File\AndroidStorage.h">
<Filter>File</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="..\..\ext\libpng17\CMakeLists.txt">
@@ -705,4 +711,4 @@
<Filter>Math\lin</Filter>
</None>
</ItemGroup>
</Project>
</Project>
@@ -31,6 +31,13 @@ public class PpssppActivity extends NativeActivity {
public static boolean libraryLoaded = false;
// Matches the enum in AndroidStorage.h.
private static final int STORAGE_ERROR_SUCCESS = 0;
private static final int STORAGE_ERROR_UNKNOWN = -1;
private static final int STORAGE_ERROR_NOT_FOUND = -2;
private static final int STORAGE_ERROR_DISK_FULL = -3;
private static final int STORAGE_ERROR_ALREADY_EXISTS = -4;
@SuppressWarnings("deprecation")
public static void CheckABIAndLoadLibrary() {
if (Build.CPU_ABI.equals("armeabi")) {
@@ -206,81 +213,95 @@ public class PpssppActivity extends NativeActivity {
}
}
public boolean contentUriCreateDirectory(String rootTreeUri, String dirName) {
public int contentUriCreateDirectory(String rootTreeUri, String dirName) {
try {
Uri uri = Uri.parse(rootTreeUri);
DocumentFile documentFile = DocumentFile.fromTreeUri(this, uri);
if (documentFile != null) {
DocumentFile createdDir = documentFile.createDirectory(dirName);
return createdDir != null;
return createdDir != null ? STORAGE_ERROR_SUCCESS : STORAGE_ERROR_UNKNOWN;
} else {
Log.e(TAG, "contentUriCreateDirectory: fromTreeUri returned null");
return false;
return STORAGE_ERROR_UNKNOWN;
}
} catch (Exception e) {
Log.e(TAG, "contentUriCreateDirectory exception: " + e.toString());
return false;
return STORAGE_ERROR_UNKNOWN;
}
}
public boolean contentUriCreateFile(String rootTreeUri, String fileName) {
public int contentUriCreateFile(String rootTreeUri, String fileName) {
try {
Uri uri = Uri.parse(rootTreeUri);
DocumentFile documentFile = DocumentFile.fromTreeUri(this, uri);
if (documentFile != null) {
// TODO: Check the file extension and choose MIME type appropriately.
DocumentFile createdFile = documentFile.createFile("application/octet-stream", fileName);
return createdFile != null;
return createdFile != null ? STORAGE_ERROR_SUCCESS : STORAGE_ERROR_UNKNOWN;
} else {
Log.e(TAG, "contentUriCreateFile: fromTreeUri returned null");
return false;
return STORAGE_ERROR_UNKNOWN;
}
} catch (Exception e) {
Log.e(TAG, "contentUriCreateFile exception: " + e.toString());
return false;
return STORAGE_ERROR_UNKNOWN;
}
}
public boolean contentUriRemoveFile(String fileName) {
public int contentUriRemoveFile(String fileName) {
try {
Uri uri = Uri.parse(fileName);
DocumentFile documentFile = DocumentFile.fromSingleUri(this, uri);
if (documentFile != null) {
return documentFile.delete();
return documentFile.delete() ? STORAGE_ERROR_SUCCESS : STORAGE_ERROR_UNKNOWN;
} else {
return false;
return STORAGE_ERROR_UNKNOWN;
}
} catch (Exception e) {
Log.e(TAG, "contentUriRemoveFile exception: " + e.toString());
return false;
return STORAGE_ERROR_UNKNOWN;
}
}
// NOTE: The destination is the parent directory! This means that contentUriCopyFile
// cannot rename things as part of the operation.
public boolean contentUriCopyFile(String srcFileUri, String dstParentDirUri) {
public int contentUriCopyFile(String srcFileUri, String dstParentDirUri) {
try {
Uri srcUri = Uri.parse(srcFileUri);
Uri dstParentUri = Uri.parse(dstParentDirUri);
DocumentsContract.copyDocument(getContentResolver(), srcUri, dstParentUri);
return true;
return DocumentsContract.copyDocument(getContentResolver(), srcUri, dstParentUri) != null ? STORAGE_ERROR_SUCCESS : STORAGE_ERROR_UNKNOWN;
} catch (Exception e) {
Log.e(TAG, "contentUriCopyFile exception: " + e.toString());
return false;
return STORAGE_ERROR_UNKNOWN;
}
}
public boolean contentUriRenameFileTo(String fileUri, String newName) {
// NOTE: The destination is the parent directory! This means that contentUriCopyFile
// cannot rename things as part of the operation.
public int contentUriMoveFile(String srcFileUri, String srcParentDirUri, String dstParentDirUri) {
try {
Uri srcUri = Uri.parse(srcFileUri);
Uri srcParentUri = Uri.parse(srcParentDirUri);
Uri dstParentUri = Uri.parse(dstParentDirUri);
return DocumentsContract.moveDocument(getContentResolver(), srcUri, srcParentUri, dstParentUri) != null ? STORAGE_ERROR_SUCCESS : STORAGE_ERROR_UNKNOWN;
} catch (Exception e) {
Log.e(TAG, "contentUriMoveFile exception: " + e.toString());
return STORAGE_ERROR_UNKNOWN;
}
}
public int contentUriRenameFileTo(String fileUri, String newName) {
try {
Uri uri = Uri.parse(fileUri);
// Due to a design flaw, we can't use DocumentFile.renameTo().
// Instead we use the DocumentsContract API directly.
// See https://stackoverflow.com/questions/37168200/android-5-0-new-sd-card-access-api-documentfile-renameto-unsupportedoperation.
Uri newUri = DocumentsContract.renameDocument(getContentResolver(), uri, newName);
return true;
return STORAGE_ERROR_SUCCESS;
} catch (Exception e) {
// TODO: More detailed exception processing.
Log.e(TAG, "contentUriRenameFile exception: " + e.toString());
return false;
return STORAGE_ERROR_UNKNOWN;
}
}