android: move unzip function to FileUtil and use SecurityException

This commit is contained in:
PabloG02 2023-06-03 14:13:20 +02:00
parent 296ccb698d
commit 19674ec78d
2 changed files with 34 additions and 32 deletions

View file

@ -23,17 +23,14 @@ import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.features.DocumentProvider import org.yuzu.yuzu_emu.features.DocumentProvider
import org.yuzu.yuzu_emu.getPublicFilesDir import org.yuzu.yuzu_emu.getPublicFilesDir
import java.io.BufferedInputStream import org.yuzu.yuzu_emu.utils.FileUtil
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.FilenameFilter import java.io.FilenameFilter
import java.io.IOException
import java.io.InputStream
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
class ImportExportSavesFragment : DialogFragment() { class ImportExportSavesFragment : DialogFragment() {
@ -124,33 +121,6 @@ class ImportExportSavesFragment : DialogFragment() {
return true return true
} }
/**
* Extracts the save files located in the given zip file and copies them to the saves folder.
* @exception IOException if the file was being created outside of the target directory
*/
private fun unzip(zipStream: InputStream, destDir: File): Boolean {
val zis = ZipInputStream(BufferedInputStream(zipStream))
var entry: ZipEntry? = zis.nextEntry
while (entry != null) {
val entryName = entry.name
val entryFile = File(destDir, entryName)
if (!entryFile.canonicalPath.startsWith(destDir.canonicalPath + File.separator)) {
zis.close()
throw IOException("Entry is outside of the target dir: " + entryFile.name)
}
if (entry.isDirectory) {
entryFile.mkdirs()
} else {
entryFile.parentFile?.mkdirs()
entryFile.createNewFile()
entryFile.outputStream().use { fos -> zis.copyTo(fos) }
}
entry = zis.nextEntry
}
zis.close()
return true
}
/** /**
* Exports the save file located in the given folder path by creating a zip file and sharing it via intent. * Exports the save file located in the given folder path by creating a zip file and sharing it via intent.
*/ */
@ -204,7 +174,7 @@ class ImportExportSavesFragment : DialogFragment() {
try { try {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
unzip(inputZip, cacheSaveDir) FileUtil.unzip(inputZip, cacheSaveDir)
cacheSaveDir.list(filterTitleId)?.forEach { savePath -> cacheSaveDir.list(filterTitleId)?.forEach { savePath ->
File(savesFolder, savePath).deleteRecursively() File(savesFolder, savePath).deleteRecursively()
File(cacheSaveDir, savePath).copyRecursively(File(savesFolder, savePath), true) File(cacheSaveDir, savePath).copyRecursively(File(savesFolder, savePath), true)

View file

@ -9,10 +9,14 @@ import android.net.Uri
import android.provider.DocumentsContract import android.provider.DocumentsContract
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import org.yuzu.yuzu_emu.model.MinimalDocumentFile import org.yuzu.yuzu_emu.model.MinimalDocumentFile
import java.io.BufferedInputStream
import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.net.URLDecoder import java.net.URLDecoder
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
object FileUtil { object FileUtil {
const val PATH_TREE = "tree" const val PATH_TREE = "tree"
@ -276,6 +280,34 @@ object FileUtil {
return false return false
} }
/**
* Extracts the given zip file into the given directory.
* @exception IOException if the file was being created outside of the target directory
*/
@Throws(SecurityException::class)
fun unzip(zipStream: InputStream, destDir: File): Boolean {
ZipInputStream(BufferedInputStream(zipStream)).use { zis ->
var entry: ZipEntry? = zis.nextEntry
while (entry != null) {
val entryName = entry.name
val entryFile = File(destDir, entryName)
if (!entryFile.canonicalPath.startsWith(destDir.canonicalPath + File.separator)) {
throw SecurityException("Entry is outside of the target dir: " + entryFile.name)
}
if (entry.isDirectory) {
entryFile.mkdirs()
} else {
entryFile.parentFile?.mkdirs()
entryFile.createNewFile()
entryFile.outputStream().use { fos -> zis.copyTo(fos) }
}
entry = zis.nextEntry
}
}
return true
}
fun isRootTreeUri(uri: Uri): Boolean { fun isRootTreeUri(uri: Uri): Boolean {
val paths = uri.pathSegments val paths = uri.pathSegments
return paths.size == 2 && PATH_TREE == paths[0] return paths.size == 2 && PATH_TREE == paths[0]