mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-15 02:18:04 -04:00
#1333 cleanup and extension correction
This commit is contained in:
parent
8ae692cfbe
commit
a2bd77e98e
@ -21,19 +21,27 @@ package eu.mhutti1.utils.storage
|
|||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.StatFs
|
import android.os.StatFs
|
||||||
import android.util.Log
|
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileReader
|
import java.io.FileReader
|
||||||
import java.io.FileWriter
|
import java.io.FileWriter
|
||||||
import java.io.IOException
|
|
||||||
|
const val LOCATION_EXTENSION = "storageLocationMarker"
|
||||||
|
|
||||||
data class StorageDevice(
|
data class StorageDevice(
|
||||||
val file: File,
|
val file: File,
|
||||||
val isInternal: Boolean
|
val isInternal: Boolean
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var isDuplicate = true
|
constructor(path: String, internal: Boolean) : this(File(path), internal)
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (file.exists()) {
|
||||||
|
createLocationCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var isDuplicate = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val name: String
|
val name: String
|
||||||
@ -62,32 +70,19 @@ data class StorageDevice(
|
|||||||
it.blockSize.toLong() * it.blockCount.toLong()
|
it.blockSize.toLong() * it.blockCount.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(path: String, internal: Boolean) : this(File(path), internal)
|
|
||||||
|
|
||||||
init {
|
|
||||||
if (file.exists()) {
|
|
||||||
createLocationCode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create unique file to identify duplicate devices.
|
// Create unique file to identify duplicate devices.
|
||||||
private fun createLocationCode() {
|
private fun createLocationCode() {
|
||||||
if (!getLocationCodeFromFolder(file)) {
|
if (!getLocationCodeFromFolder(file)) {
|
||||||
val locationCode = File(file.path, ".storageLocationMarker")
|
File(file.path, ".$LOCATION_EXTENSION").let { locationCode ->
|
||||||
try {
|
|
||||||
locationCode.createNewFile()
|
locationCode.createNewFile()
|
||||||
val fw = FileWriter(locationCode)
|
FileWriter(locationCode).use { it.write(file.path) }
|
||||||
fw.write(file.path)
|
|
||||||
fw.close()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.d("android-storage-devices", "Unable to create marker file, duplicates may be listed")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there is already a device code in our path
|
// Check if there is already a device code in our path
|
||||||
private fun getLocationCodeFromFolder(folder: File): Boolean {
|
private fun getLocationCodeFromFolder(folder: File): Boolean {
|
||||||
val locationCode = File(folder.path, ".storageLocationMarker")
|
val locationCode = File(folder.path, ".$LOCATION_EXTENSION")
|
||||||
if (locationCode.exists()) {
|
if (locationCode.exists()) {
|
||||||
try {
|
try {
|
||||||
BufferedReader(FileReader(locationCode)).use { br ->
|
BufferedReader(FileReader(locationCode)).use { br ->
|
||||||
@ -102,11 +97,11 @@ data class StorageDevice(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val parentFile = folder.parentFile
|
val parent = folder.parentFile
|
||||||
if (parentFile == null) {
|
if (parent == null) {
|
||||||
isDuplicate = false
|
isDuplicate = false
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return getLocationCodeFromFolder(parentFile)
|
return getLocationCodeFromFolder(parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,20 +25,18 @@ import androidx.core.content.ContextCompat
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileFilter
|
import java.io.FileFilter
|
||||||
import java.io.RandomAccessFile
|
import java.io.RandomAccessFile
|
||||||
import java.nio.channels.FileLock
|
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
object StorageDeviceUtils {
|
object StorageDeviceUtils {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getStorageDevices(context: Context, writable: Boolean): List<StorageDevice> {
|
fun getStorageDevices(context: Context, writable: Boolean): List<StorageDevice> {
|
||||||
val storageDevices = ArrayList<StorageDevice>()
|
val storageDevices = ArrayList<StorageDevice>().apply {
|
||||||
|
add(environmentDevices(writable))
|
||||||
storageDevices.add(environmentDevices(Environment.getExternalStorageDirectory().path, writable))
|
addAll(externalMountPointDevices())
|
||||||
storageDevices.addAll(externalMountPointDevices())
|
addAll(externalFilesDirsDevices(context, writable))
|
||||||
storageDevices.addAll(externalFilesDirsDevices(context, writable))
|
}
|
||||||
|
return validate(storageDevices, writable)
|
||||||
return validate(storageDevices, writable).also(::deleteStorageMarkers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun externalFilesDirsDevices(
|
private fun externalFilesDirsDevices(
|
||||||
@ -48,44 +46,47 @@ object StorageDeviceUtils {
|
|||||||
.filterNotNull()
|
.filterNotNull()
|
||||||
.map { dir -> StorageDevice(generalisePath(dir.path, writable), false) }
|
.map { dir -> StorageDevice(generalisePath(dir.path, writable), false) }
|
||||||
|
|
||||||
private fun externalMountPointDevices(): Collection<StorageDevice> {
|
private fun externalMountPointDevices(): Collection<StorageDevice> =
|
||||||
val storageDevices = ArrayList<StorageDevice>()
|
ExternalPaths.possiblePaths.fold(mutableListOf(), { acc, path ->
|
||||||
for (path in ExternalPaths.possiblePaths) {
|
acc.apply {
|
||||||
if (path.endsWith("*")) {
|
if (path.endsWith("*")) {
|
||||||
val root = File(path.substringBeforeLast("*"))
|
addAll(devicesBeneath(File(path.substringBeforeLast("*"))))
|
||||||
root.listFiles(FileFilter(File::isDirectory))
|
} else {
|
||||||
?.mapTo(storageDevices) { dir -> StorageDevice(dir, false) }
|
add(StorageDevice(path, false))
|
||||||
} else {
|
}
|
||||||
storageDevices.add(StorageDevice(path, false))
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
return storageDevices
|
|
||||||
}
|
private fun devicesBeneath(directory: File) =
|
||||||
|
directory.listFiles(FileFilter(File::isDirectory))
|
||||||
|
?.map { dir -> StorageDevice(dir, false) }
|
||||||
|
.orEmpty()
|
||||||
|
|
||||||
private fun environmentDevices(
|
private fun environmentDevices(
|
||||||
environmentPath: String,
|
|
||||||
writable: Boolean
|
writable: Boolean
|
||||||
) =
|
) =
|
||||||
// This is our internal storage directory
|
StorageDevice(
|
||||||
if (Environment.isExternalStorageEmulated())
|
generalisePath(Environment.getExternalStorageDirectory().path, writable),
|
||||||
StorageDevice(generalisePath(environmentPath, writable), true)
|
Environment.isExternalStorageEmulated()
|
||||||
// This is an external storage directory
|
)
|
||||||
else StorageDevice(generalisePath(environmentPath, writable), false)
|
|
||||||
|
|
||||||
// Remove app specific path from directories so that we can search them from the top
|
// Remove app specific path from directories so that we can search them from the top
|
||||||
private fun generalisePath(path: String, writable: Boolean) =
|
private fun generalisePath(path: String, writable: Boolean) =
|
||||||
if (writable) path
|
if (writable) path
|
||||||
else path.substringBeforeLast("/Android/data/")
|
else path.substringBefore("/Android/data/")
|
||||||
|
|
||||||
// Amazingly file.canWrite() does not always return the correct value
|
// Amazingly file.canWrite() does not always return the correct value
|
||||||
private fun canWrite(file: File) = "$file/test.txt".let {
|
private fun canWrite(file: File): Boolean = "$file/test.txt".let {
|
||||||
try {
|
try {
|
||||||
RandomAccessFile(it, "rw").use { randomAccessFile ->
|
RandomAccessFile(it, "rw").use { randomAccessFile ->
|
||||||
randomAccessFile.channel.use { channel ->
|
randomAccessFile.channel.use { channel ->
|
||||||
channel.lock().also(FileLock::release)
|
channel.lock().use { fileLock ->
|
||||||
true
|
fileLock.release()
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (ignore: Exception) {
|
||||||
false
|
false
|
||||||
} finally {
|
} finally {
|
||||||
File(it).delete()
|
File(it).delete()
|
||||||
@ -95,13 +96,13 @@ object StorageDeviceUtils {
|
|||||||
private fun validate(
|
private fun validate(
|
||||||
storageDevices: ArrayList<StorageDevice>,
|
storageDevices: ArrayList<StorageDevice>,
|
||||||
writable: Boolean
|
writable: Boolean
|
||||||
): List<StorageDevice> {
|
) = storageDevices.asSequence().distinct()
|
||||||
return storageDevices.asSequence().distinct()
|
.filter { it.file.exists() }
|
||||||
.filter { it.file.exists() }
|
.filter { it.file.isDirectory }
|
||||||
.filter { it.file.isDirectory }
|
.filter { canWrite(it.file) || !writable }
|
||||||
.filter { (!writable || canWrite(it.file)) }
|
.filterNot(StorageDevice::isDuplicate)
|
||||||
.filterNot(StorageDevice::isDuplicate).toList()
|
.toList()
|
||||||
}
|
.also(StorageDeviceUtils::deleteStorageMarkers)
|
||||||
|
|
||||||
private fun deleteStorageMarkers(validatedDevices: List<StorageDevice>) {
|
private fun deleteStorageMarkers(validatedDevices: List<StorageDevice>) {
|
||||||
validatedDevices.forEach { recursiveDeleteStorageMarkers(it.file) }
|
validatedDevices.forEach { recursiveDeleteStorageMarkers(it.file) }
|
||||||
@ -109,10 +110,9 @@ object StorageDeviceUtils {
|
|||||||
|
|
||||||
private fun recursiveDeleteStorageMarkers(file: File) {
|
private fun recursiveDeleteStorageMarkers(file: File) {
|
||||||
file.listFiles().forEach {
|
file.listFiles().forEach {
|
||||||
if (it.isDirectory) {
|
when {
|
||||||
recursiveDeleteStorageMarkers(it)
|
it.isDirectory -> recursiveDeleteStorageMarkers(it)
|
||||||
} else if (it.extension == "storageMarker") {
|
it.extension == LOCATION_EXTENSION -> it.delete()
|
||||||
it.delete()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user