android: move unzip function to FileUtil and use SecurityException
This commit is contained in:
		@@ -23,17 +23,14 @@ import org.yuzu.yuzu_emu.R
 | 
			
		||||
import org.yuzu.yuzu_emu.YuzuApplication
 | 
			
		||||
import org.yuzu.yuzu_emu.features.DocumentProvider
 | 
			
		||||
import org.yuzu.yuzu_emu.getPublicFilesDir
 | 
			
		||||
import java.io.BufferedInputStream
 | 
			
		||||
import org.yuzu.yuzu_emu.utils.FileUtil
 | 
			
		||||
import java.io.BufferedOutputStream
 | 
			
		||||
import java.io.File
 | 
			
		||||
import java.io.FileOutputStream
 | 
			
		||||
import java.io.FilenameFilter
 | 
			
		||||
import java.io.IOException
 | 
			
		||||
import java.io.InputStream
 | 
			
		||||
import java.time.LocalDateTime
 | 
			
		||||
import java.time.format.DateTimeFormatter
 | 
			
		||||
import java.util.zip.ZipEntry
 | 
			
		||||
import java.util.zip.ZipInputStream
 | 
			
		||||
import java.util.zip.ZipOutputStream
 | 
			
		||||
 | 
			
		||||
class ImportExportSavesFragment : DialogFragment() {
 | 
			
		||||
@@ -124,33 +121,6 @@ class ImportExportSavesFragment : DialogFragment() {
 | 
			
		||||
        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.
 | 
			
		||||
     */
 | 
			
		||||
@@ -204,7 +174,7 @@ class ImportExportSavesFragment : DialogFragment() {
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                unzip(inputZip, cacheSaveDir)
 | 
			
		||||
                FileUtil.unzip(inputZip, cacheSaveDir)
 | 
			
		||||
                cacheSaveDir.list(filterTitleId)?.forEach { savePath ->
 | 
			
		||||
                    File(savesFolder, savePath).deleteRecursively()
 | 
			
		||||
                    File(cacheSaveDir, savePath).copyRecursively(File(savesFolder, savePath), true)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,10 +9,14 @@ import android.net.Uri
 | 
			
		||||
import android.provider.DocumentsContract
 | 
			
		||||
import androidx.documentfile.provider.DocumentFile
 | 
			
		||||
import org.yuzu.yuzu_emu.model.MinimalDocumentFile
 | 
			
		||||
import java.io.BufferedInputStream
 | 
			
		||||
import java.io.File
 | 
			
		||||
import java.io.FileOutputStream
 | 
			
		||||
import java.io.IOException
 | 
			
		||||
import java.io.InputStream
 | 
			
		||||
import java.net.URLDecoder
 | 
			
		||||
import java.util.zip.ZipEntry
 | 
			
		||||
import java.util.zip.ZipInputStream
 | 
			
		||||
 | 
			
		||||
object FileUtil {
 | 
			
		||||
    const val PATH_TREE = "tree"
 | 
			
		||||
@@ -276,6 +280,34 @@ object FileUtil {
 | 
			
		||||
        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 {
 | 
			
		||||
        val paths = uri.pathSegments
 | 
			
		||||
        return paths.size == 2 && PATH_TREE == paths[0]
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user