DroidFS/app/src/main/java/sushi/hardcore/droidfs/GocryptfsVolume.kt

276 lines
9.6 KiB
Kotlin
Raw Normal View History

package sushi.hardcore.droidfs
2020-07-17 16:35:39 +02:00
import android.content.Context
import android.net.Uri
import sushi.hardcore.droidfs.explorers.ExplorerElement
import sushi.hardcore.droidfs.util.PathUtils
2020-10-14 19:04:19 +02:00
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream
2020-07-17 16:35:39 +02:00
2021-11-11 15:05:33 +01:00
class GocryptfsVolume(val applicationContext: Context, var sessionID: Int) {
2020-07-17 16:35:39 +02:00
private external fun native_close(sessionID: Int)
private external fun native_is_closed(sessionID: Int): Boolean
2020-07-17 16:35:39 +02:00
private external fun native_list_dir(sessionID: Int, dir_path: String): MutableList<ExplorerElement>
private external fun native_open_read_mode(sessionID: Int, file_path: String): Int
2021-06-11 16:27:08 +02:00
private external fun native_open_write_mode(sessionID: Int, file_path: String, mode: Int): Int
2020-07-17 16:35:39 +02:00
private external fun native_read_file(sessionID: Int, handleID: Int, offset: Long, buff: ByteArray): Int
private external fun native_write_file(sessionID: Int, handleID: Int, offset: Long, buff: ByteArray, buff_size: Int): Int
2021-06-11 16:27:08 +02:00
private external fun native_truncate(sessionID: Int, handleID: Int, offset: Long): Boolean
2020-07-17 16:35:39 +02:00
private external fun native_path_exists(sessionID: Int, file_path: String): Boolean
private external fun native_get_size(sessionID: Int, file_path: String): Long
private external fun native_close_file(sessionID: Int, handleID: Int)
private external fun native_remove_file(sessionID: Int, file_path: String): Boolean
2021-06-11 16:27:08 +02:00
private external fun native_mkdir(sessionID: Int, dir_path: String, mode: Int): Boolean
2020-07-17 16:35:39 +02:00
private external fun native_rmdir(sessionID: Int, dir_path: String): Boolean
private external fun native_rename(sessionID: Int, old_path: String, new_path: String): Boolean
companion object {
const val KeyLen = 32
const val ScryptDefaultLogN = 16
const val DefaultBS = 4096
2021-10-17 13:46:10 +02:00
external fun createVolume(root_cipher_dir: String, password: CharArray, plainTextNames: Boolean, xchacha: Int, logN: Int, creator: String): Boolean
2020-07-17 16:35:39 +02:00
external fun init(root_cipher_dir: String, password: CharArray?, givenHash: ByteArray?, returnedHash: ByteArray?): Int
2020-08-01 16:43:48 +02:00
external fun changePassword(root_cipher_dir: String, old_password: CharArray?, givenHash: ByteArray?, new_password: CharArray, returnedHash: ByteArray?): Boolean
2020-07-17 16:35:39 +02:00
2020-10-14 19:04:19 +02:00
fun isGocryptfsVolume(path: File): Boolean {
if (path.isDirectory){
return File(path, ConstValues.gocryptfsConfFilename).isFile
}
return false
}
2020-07-17 16:35:39 +02:00
init {
System.loadLibrary("gocryptfs_jni")
}
}
fun close() {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
native_close(sessionID)
}
2020-07-17 16:35:39 +02:00
}
fun isClosed(): Boolean {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
return native_is_closed(sessionID)
}
}
2020-08-01 16:43:48 +02:00
fun listDir(dir_path: String): MutableList<ExplorerElement> {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
return native_list_dir(sessionID, dir_path)
}
2020-07-17 16:35:39 +02:00
}
fun mkdir(dir_path: String): Boolean {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
return native_mkdir(sessionID, dir_path, ConstValues.DIRECTORY_MODE)
}
2020-07-17 16:35:39 +02:00
}
fun rmdir(dir_path: String): Boolean {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
return native_rmdir(sessionID, dir_path)
}
2020-07-17 16:35:39 +02:00
}
2020-08-01 16:43:48 +02:00
fun removeFile(file_path: String): Boolean {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
return native_remove_file(sessionID, file_path)
}
2020-07-17 16:35:39 +02:00
}
2020-08-01 16:43:48 +02:00
fun pathExists(file_path: String): Boolean {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
return native_path_exists(sessionID, file_path)
}
2020-07-17 16:35:39 +02:00
}
2020-08-01 16:43:48 +02:00
fun getSize(file_path: String): Long {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
return native_get_size(sessionID, file_path)
}
2020-07-17 16:35:39 +02:00
}
2020-08-01 16:43:48 +02:00
fun closeFile(handleID: Int) {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
native_close_file(sessionID, handleID)
}
2020-07-17 16:35:39 +02:00
}
2020-08-01 16:43:48 +02:00
fun openReadMode(file_path: String): Int {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
return native_open_read_mode(sessionID, file_path)
}
2020-07-17 16:35:39 +02:00
}
2020-08-01 16:43:48 +02:00
fun openWriteMode(file_path: String): Int {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
return native_open_write_mode(sessionID, file_path, ConstValues.FILE_MODE)
}
2020-07-17 16:35:39 +02:00
}
2020-08-01 16:43:48 +02:00
fun readFile(handleID: Int, offset: Long, buff: ByteArray): Int {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
return native_read_file(sessionID, handleID, offset, buff)
}
2020-07-17 16:35:39 +02:00
}
2020-08-01 16:43:48 +02:00
fun writeFile(handleID: Int, offset: Long, buff: ByteArray, buff_size: Int): Int {
2021-11-11 15:05:33 +01:00
synchronized(applicationContext) {
return native_write_file(sessionID, handleID, offset, buff, buff_size)
}
2020-07-17 16:35:39 +02:00
}
2021-06-11 16:27:08 +02:00
fun truncate(handleID: Int, offset: Long): Boolean {
synchronized(this) {
2021-06-11 16:27:08 +02:00
return native_truncate(sessionID, handleID, offset)
}
2020-07-17 16:35:39 +02:00
}
fun rename(old_path: String, new_path: String): Boolean {
synchronized(this) {
return native_rename(sessionID, old_path, new_path)
}
2020-07-17 16:35:39 +02:00
}
2020-08-01 16:43:48 +02:00
fun exportFile(handleID: Int, os: OutputStream): Boolean {
2020-07-17 16:35:39 +02:00
var offset: Long = 0
val ioBuffer = ByteArray(DefaultBS)
2020-07-17 16:35:39 +02:00
var length: Int
while (readFile(handleID, offset, ioBuffer).also { length = it } > 0){
os.write(ioBuffer, 0, length)
2020-07-17 16:35:39 +02:00
offset += length.toLong()
}
os.close()
return true
}
2020-08-01 16:43:48 +02:00
fun exportFile(src_path: String, os: OutputStream): Boolean {
2020-07-17 16:35:39 +02:00
var success = false
2020-08-01 16:43:48 +02:00
val srcHandleId = openReadMode(src_path)
if (srcHandleId != -1) {
2020-08-01 16:43:48 +02:00
success = exportFile(srcHandleId, os)
closeFile(srcHandleId)
2020-07-17 16:35:39 +02:00
}
return success
}
2020-08-01 16:43:48 +02:00
fun exportFile(src_path: String, dst_path: String): Boolean {
return exportFile(src_path, FileOutputStream(dst_path))
2020-07-17 16:35:39 +02:00
}
2020-08-01 16:43:48 +02:00
fun exportFile(context: Context, src_path: String, output_path: Uri): Boolean {
2020-07-17 16:35:39 +02:00
val os = context.contentResolver.openOutputStream(output_path)
if (os != null){
2020-08-01 16:43:48 +02:00
return exportFile(src_path, os)
2020-07-17 16:35:39 +02:00
}
return false
}
2020-08-01 16:43:48 +02:00
fun importFile(inputStream: InputStream, handleID: Int): Boolean {
2020-07-17 16:35:39 +02:00
var offset: Long = 0
val ioBuffer = ByteArray(DefaultBS)
2020-07-17 16:35:39 +02:00
var length: Int
while (inputStream.read(ioBuffer).also { length = it } > 0) {
val written = writeFile(handleID, offset, ioBuffer, length).toLong()
2020-07-17 16:35:39 +02:00
if (written == length.toLong()) {
offset += written
} else {
2020-07-21 15:05:05 +02:00
inputStream.close()
2020-07-17 16:35:39 +02:00
return false
}
}
closeFile(handleID)
2020-07-21 15:05:05 +02:00
inputStream.close()
2020-07-17 16:35:39 +02:00
return true
}
2020-08-01 16:43:48 +02:00
fun importFile(inputStream: InputStream, dst_path: String): Boolean {
2020-07-17 16:35:39 +02:00
var success = false
2020-08-01 16:43:48 +02:00
val dstHandleId = openWriteMode(dst_path)
if (dstHandleId != -1) {
2020-08-01 16:43:48 +02:00
success = importFile(inputStream, dstHandleId)
closeFile(dstHandleId)
2020-07-17 16:35:39 +02:00
}
return success
}
2020-08-01 16:43:48 +02:00
fun importFile(context: Context, src_uri: Uri, dst_path: String): Boolean {
2020-07-21 15:05:05 +02:00
val inputStream = context.contentResolver.openInputStream(src_uri)
if (inputStream != null){
2020-08-01 16:43:48 +02:00
return importFile(inputStream, dst_path)
2020-07-17 16:35:39 +02:00
}
return false
}
2020-08-01 16:43:48 +02:00
fun recursiveMapFiles(rootPath: String): MutableList<ExplorerElement> {
val result = mutableListOf<ExplorerElement>()
val explorerElements = listDir(rootPath)
result.addAll(explorerElements)
for (e in explorerElements){
if (e.isDirectory){
2020-08-05 14:06:54 +02:00
result.addAll(recursiveMapFiles(e.fullPath))
2020-08-01 16:43:48 +02:00
}
}
return result
}
2020-12-29 17:05:02 +01:00
fun recursiveRemoveDirectory(plain_directory_path: String): String? {
val explorerElements = listDir(plain_directory_path)
for (e in explorerElements) {
val fullPath = PathUtils.pathJoin(plain_directory_path, e.name)
if (e.isDirectory) {
val result = recursiveRemoveDirectory(fullPath)
result?.let { return it }
} else {
if (!removeFile(fullPath)) {
return fullPath
}
}
}
return if (!rmdir(plain_directory_path)) {
plain_directory_path
} else {
null
}
}
2021-11-11 15:05:33 +01:00
2022-02-18 15:53:48 +01:00
fun loadWholeFile(fullPath: String, size: Long? = null, maxSize: Long? = null): Pair<ByteArray?, Int> {
val fileSize = size ?: getSize(fullPath)
2021-11-11 15:05:33 +01:00
return if (fileSize >= 0) {
maxSize?.let {
if (fileSize > it) {
return Pair(null, 0)
}
}
try {
val fileBuff = ByteArray(fileSize.toInt())
val handleID = openReadMode(fullPath)
if (handleID == -1) {
Pair(null, 3)
} else {
var offset: Long = 0
val ioBuffer = ByteArray(DefaultBS)
var length: Int
while (readFile(handleID, offset, ioBuffer).also { length = it } > 0) {
System.arraycopy(ioBuffer, 0, fileBuff, offset.toInt(), length)
offset += length.toLong()
}
closeFile(handleID)
if (offset == fileBuff.size.toLong()) {
Pair(fileBuff, 0)
} else {
Pair(null, 4)
}
}
} catch (e: OutOfMemoryError) {
Pair(null, 2)
}
} else {
Pair(null, 1)
}
}
2020-07-17 16:35:39 +02:00
}