You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-06 12:20:30 +00:00
Address remaining scoped storage regressions
- Accelerate common path used to check the storage scope for a given path - Update the logic for the `get_as_text()` method - previous logic loads the content of a text file one byte at a time
This commit is contained in:
@@ -54,11 +54,19 @@ internal enum class StorageScope {
|
||||
*/
|
||||
UNKNOWN;
|
||||
|
||||
companion object {
|
||||
class Identifier(context: Context) {
|
||||
|
||||
private val internalAppDir: String? = context.filesDir.canonicalPath
|
||||
private val internalCacheDir: String? = context.cacheDir.canonicalPath
|
||||
private val externalAppDir: String? = context.getExternalFilesDir(null)?.canonicalPath
|
||||
private val sharedDir : String? = Environment.getExternalStorageDirectory().canonicalPath
|
||||
private val downloadsSharedDir: String? = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).canonicalPath
|
||||
private val documentsSharedDir: String? = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).canonicalPath
|
||||
|
||||
/**
|
||||
* Determines which [StorageScope] the given path falls under.
|
||||
*/
|
||||
fun getStorageScope(context: Context, path: String?): StorageScope {
|
||||
fun identifyStorageScope(path: String?): StorageScope {
|
||||
if (path == null) {
|
||||
return UNKNOWN
|
||||
}
|
||||
@@ -70,23 +78,19 @@ internal enum class StorageScope {
|
||||
|
||||
val canonicalPathFile = pathFile.canonicalPath
|
||||
|
||||
val internalAppDir = context.filesDir.canonicalPath ?: return UNKNOWN
|
||||
if (canonicalPathFile.startsWith(internalAppDir)) {
|
||||
if (internalAppDir != null && canonicalPathFile.startsWith(internalAppDir)) {
|
||||
return APP
|
||||
}
|
||||
|
||||
val internalCacheDir = context.cacheDir.canonicalPath ?: return UNKNOWN
|
||||
if (canonicalPathFile.startsWith(internalCacheDir)) {
|
||||
if (internalCacheDir != null && canonicalPathFile.startsWith(internalCacheDir)) {
|
||||
return APP
|
||||
}
|
||||
|
||||
val externalAppDir = context.getExternalFilesDir(null)?.canonicalPath ?: return UNKNOWN
|
||||
if (canonicalPathFile.startsWith(externalAppDir)) {
|
||||
if (externalAppDir != null && canonicalPathFile.startsWith(externalAppDir)) {
|
||||
return APP
|
||||
}
|
||||
|
||||
val sharedDir = Environment.getExternalStorageDirectory().canonicalPath ?: return UNKNOWN
|
||||
if (canonicalPathFile.startsWith(sharedDir)) {
|
||||
if (sharedDir != null && canonicalPathFile.startsWith(sharedDir)) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
// Before R, apps had access to shared storage so long as they have the right
|
||||
// permissions (and flag on Q).
|
||||
@@ -95,13 +99,8 @@ internal enum class StorageScope {
|
||||
|
||||
// Post R, access is limited based on the target destination
|
||||
// 'Downloads' and 'Documents' are still accessible
|
||||
val downloadsSharedDir =
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).canonicalPath
|
||||
?: return SHARED
|
||||
val documentsSharedDir =
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).canonicalPath
|
||||
?: return SHARED
|
||||
if (canonicalPathFile.startsWith(downloadsSharedDir) || canonicalPathFile.startsWith(documentsSharedDir)) {
|
||||
if ((downloadsSharedDir != null && canonicalPathFile.startsWith(downloadsSharedDir))
|
||||
|| (documentsSharedDir != null && canonicalPathFile.startsWith(documentsSharedDir))) {
|
||||
return APP
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ internal class FilesystemDirectoryAccess(private val context: Context):
|
||||
|
||||
private data class DirData(val dirFile: File, val files: Array<File>, var current: Int = 0)
|
||||
|
||||
private val storageScopeIdentifier = StorageScope.Identifier(context)
|
||||
private val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
|
||||
private var lastDirId = STARTING_DIR_ID
|
||||
private val dirs = SparseArray<DirData>()
|
||||
@@ -62,7 +63,7 @@ internal class FilesystemDirectoryAccess(private val context: Context):
|
||||
// Directory access is available for shared storage on Android 11+
|
||||
// On Android 10, access is also available as long as the `requestLegacyExternalStorage`
|
||||
// tag is available.
|
||||
return StorageScope.getStorageScope(context, path) != StorageScope.UNKNOWN
|
||||
return storageScopeIdentifier.identifyStorageScope(path) != StorageScope.UNKNOWN
|
||||
}
|
||||
|
||||
override fun hasDirId(dirId: Int) = dirs.indexOfKey(dirId) >= 0
|
||||
@@ -102,7 +103,7 @@ internal class FilesystemDirectoryAccess(private val context: Context):
|
||||
}
|
||||
}
|
||||
|
||||
override fun fileExists(path: String) = FileAccessHandler.fileExists(context, path)
|
||||
override fun fileExists(path: String) = FileAccessHandler.fileExists(context, storageScopeIdentifier, path)
|
||||
|
||||
override fun dirNext(dirId: Int): String {
|
||||
val dirData = dirs[dirId]
|
||||
@@ -199,7 +200,7 @@ internal class FilesystemDirectoryAccess(private val context: Context):
|
||||
if (fromFile.isDirectory) {
|
||||
fromFile.renameTo(File(to))
|
||||
} else {
|
||||
FileAccessHandler.renameFile(context, from, to)
|
||||
FileAccessHandler.renameFile(context, storageScopeIdentifier, from, to)
|
||||
}
|
||||
} catch (e: SecurityException) {
|
||||
false
|
||||
@@ -218,7 +219,7 @@ internal class FilesystemDirectoryAccess(private val context: Context):
|
||||
if (deleteFile.isDirectory) {
|
||||
deleteFile.delete()
|
||||
} else {
|
||||
FileAccessHandler.removeFile(context, filename)
|
||||
FileAccessHandler.removeFile(context, storageScopeIdentifier, filename)
|
||||
}
|
||||
} else {
|
||||
true
|
||||
|
||||
@@ -161,8 +161,9 @@ internal abstract class DataAccess(private val filePath: String) {
|
||||
fun read(buffer: ByteBuffer): Int {
|
||||
return try {
|
||||
val readBytes = fileChannel.read(buffer)
|
||||
endOfFile = readBytes == -1
|
||||
|| (fileChannel.position() >= fileChannel.size() && fileChannel.size() > 0)
|
||||
if (readBytes == -1) {
|
||||
endOfFile = true
|
||||
0
|
||||
} else {
|
||||
readBytes
|
||||
|
||||
@@ -49,8 +49,8 @@ class FileAccessHandler(val context: Context) {
|
||||
private const val INVALID_FILE_ID = 0
|
||||
private const val STARTING_FILE_ID = 1
|
||||
|
||||
fun fileExists(context: Context, path: String?): Boolean {
|
||||
val storageScope = StorageScope.getStorageScope(context, path)
|
||||
internal fun fileExists(context: Context, storageScopeIdentifier: StorageScope.Identifier, path: String?): Boolean {
|
||||
val storageScope = storageScopeIdentifier.identifyStorageScope(path)
|
||||
if (storageScope == StorageScope.UNKNOWN) {
|
||||
return false
|
||||
}
|
||||
@@ -62,8 +62,8 @@ class FileAccessHandler(val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun removeFile(context: Context, path: String?): Boolean {
|
||||
val storageScope = StorageScope.getStorageScope(context, path)
|
||||
internal fun removeFile(context: Context, storageScopeIdentifier: StorageScope.Identifier, path: String?): Boolean {
|
||||
val storageScope = storageScopeIdentifier.identifyStorageScope(path)
|
||||
if (storageScope == StorageScope.UNKNOWN) {
|
||||
return false
|
||||
}
|
||||
@@ -75,8 +75,8 @@ class FileAccessHandler(val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun renameFile(context: Context, from: String?, to: String?): Boolean {
|
||||
val storageScope = StorageScope.getStorageScope(context, from)
|
||||
internal fun renameFile(context: Context, storageScopeIdentifier: StorageScope.Identifier, from: String?, to: String?): Boolean {
|
||||
val storageScope = storageScopeIdentifier.identifyStorageScope(from)
|
||||
if (storageScope == StorageScope.UNKNOWN) {
|
||||
return false
|
||||
}
|
||||
@@ -89,13 +89,14 @@ class FileAccessHandler(val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
private val storageScopeIdentifier = StorageScope.Identifier(context)
|
||||
private val files = SparseArray<DataAccess>()
|
||||
private var lastFileId = STARTING_FILE_ID
|
||||
|
||||
private fun hasFileId(fileId: Int) = files.indexOfKey(fileId) >= 0
|
||||
|
||||
fun fileOpen(path: String?, modeFlags: Int): Int {
|
||||
val storageScope = StorageScope.getStorageScope(context, path)
|
||||
val storageScope = storageScopeIdentifier.identifyStorageScope(path)
|
||||
if (storageScope == StorageScope.UNKNOWN) {
|
||||
return INVALID_FILE_ID
|
||||
}
|
||||
@@ -162,10 +163,10 @@ class FileAccessHandler(val context: Context) {
|
||||
files[fileId].flush()
|
||||
}
|
||||
|
||||
fun fileExists(path: String?) = Companion.fileExists(context, path)
|
||||
fun fileExists(path: String?) = Companion.fileExists(context, storageScopeIdentifier, path)
|
||||
|
||||
fun fileLastModified(filepath: String?): Long {
|
||||
val storageScope = StorageScope.getStorageScope(context, filepath)
|
||||
val storageScope = storageScopeIdentifier.identifyStorageScope(filepath)
|
||||
if (storageScope == StorageScope.UNKNOWN) {
|
||||
return 0L
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user