Compare commits

..

No commits in common. "47b65d6fe0f97ac4b9cc5935048e34eeb9e1d3bf" and "525ee4d591c6a87dd7e7584044dd5c8210fab859" have entirely different histories.

View file

@ -120,8 +120,7 @@ var splitSelected int32 = 1
var recombine bool var recombine bool
var compress bool var compress bool
var delete bool var delete bool
var autoUnzip bool var unpack bool
var sameLevel bool
var keep bool var keep bool
var kept bool var kept bool
@ -556,19 +555,8 @@ func draw() {
).Build() ).Build()
giu.Row( giu.Row(
giu.Style().SetDisabled(!strings.HasSuffix(inputFile, ".zip.pcv")).To( giu.Checkbox("Unpack .zip", &unpack),
giu.Checkbox("Auto unzip", &autoUnzip).OnChange(func() { giu.Tooltip("Extract the decrypted .zip (overwrite files)"),
if !autoUnzip {
sameLevel = false
}
}),
giu.Tooltip("Extract .zip upon decryption (may overwrite)"),
),
giu.Dummy(-170, 0),
giu.Style().SetDisabled(!autoUnzip).To(
giu.Checkbox("Same level", &sameLevel),
giu.Tooltip("Extract .zip contents to same folder as volume"),
),
).Build() ).Build()
} }
}), }),
@ -2130,21 +2118,29 @@ func work() {
os.Remove(inputFile) os.Remove(inputFile)
} }
if mode == "decrypt" && !kept && autoUnzip { if mode == "decrypt" && !kept && unpack {
showProgress = true showProgress = true // Turn on the progress popup
popupStatus = "Unzipping..." canCancel = true // Allow the user to cancel
progress = 0
progressInfo = ""
popupStatus = "Preparing to unpack..."
giu.Update() giu.Update()
if err := unpackArchive(outputFile); err != nil { err := unpackArchive(outputFile)
mainStatus = "Auto unzipping failed!" if err != nil {
mainStatus = "Extraction failed: " + err.Error()
mainStatusColor = RED mainStatusColor = RED
giu.Update() giu.Update()
return
} }
os.Remove(outputFile) // Turn off the progress UI
showProgress = false
canCancel = false
progress = 0
progressInfo = ""
popupStatus = ""
giu.Update()
} }
// All done, reset the UI // All done, reset the UI
oldKept := kept oldKept := kept
resetUI() resetUI()
@ -2242,8 +2238,7 @@ func resetUI() {
recombine = false recombine = false
compress = false compress = false
delete = false delete = false
autoUnzip = false unpack = false
sameLevel = false
keep = false keep = false
kept = false kept = false
@ -2366,31 +2361,33 @@ func sizeify(size int64) string {
} }
func unpackArchive(zipPath string) error { func unpackArchive(zipPath string) error {
// Open the .zip
reader, err := zip.OpenReader(zipPath) reader, err := zip.OpenReader(zipPath)
if err != nil { if err != nil {
return err return err
} }
defer reader.Close() defer reader.Close()
// Calculate total unpack size by summing each entrys UncompressedSize64
var totalSize int64 var totalSize int64
for _, f := range reader.File { for _, f := range reader.File {
totalSize += int64(f.UncompressedSize64) totalSize += int64(f.UncompressedSize64)
} }
var extractDir string // Directory containing the .zip
if sameLevel { extractDir := filepath.Dir(zipPath)
extractDir = filepath.Dir(zipPath)
} else {
extractDir = filepath.Join(filepath.Dir(zipPath), strings.TrimSuffix(filepath.Base(zipPath), ".zip"))
}
// Setup progress tracking
var done int64 var done int64
startTime := time.Now() startTime := time.Now()
for _, f := range reader.File { // Iterate over each file in the archive
if strings.Contains(f.Name, "..") { for i, f := range reader.File {
return errors.New("potentially malicious zip item path") // If user clicked "Cancel" elsewhere, stop
if !working {
return errors.New("operation canceled by user")
} }
outPath := filepath.Join(extractDir, f.Name) outPath := filepath.Join(extractDir, f.Name)
// Make directory if current entry is a folder // Make directory if current entry is a folder
@ -2398,21 +2395,9 @@ func unpackArchive(zipPath string) error {
if err := os.MkdirAll(outPath, f.Mode()); err != nil { if err := os.MkdirAll(outPath, f.Mode()); err != nil {
return err return err
} }
}
}
for i, f := range reader.File {
if strings.Contains(f.Name, "..") {
return errors.New("potentially malicious zip item path")
}
// Already handled above
if f.FileInfo().IsDir() {
continue continue
} }
outPath := filepath.Join(extractDir, f.Name)
// Otherwise create necessary parent directories // Otherwise create necessary parent directories
if err := os.MkdirAll(filepath.Dir(outPath), 0755); err != nil { if err := os.MkdirAll(filepath.Dir(outPath), 0755); err != nil {
return err return err
@ -2425,14 +2410,20 @@ func unpackArchive(zipPath string) error {
} }
defer fileInArchive.Close() defer fileInArchive.Close()
dstFile, err := os.Create(outPath) // Create/overwrite the destination file
dstFile, err := os.OpenFile(outPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil { if err != nil {
return err return err
} }
// Read from zip in chunks to update progress // Read from zip in chunks to update progress
buffer := make([]byte, MiB) buffer := make([]byte, MiB) // e.g., 1 MiB chunk
for { for {
if !working {
dstFile.Close()
os.Remove(outPath) // remove partial extraction if canceled
return errors.New("operation canceled by user")
}
n, readErr := fileInArchive.Read(buffer) n, readErr := fileInArchive.Read(buffer)
if n > 0 { if n > 0 {
_, writeErr := dstFile.Write(buffer[:n]) _, writeErr := dstFile.Write(buffer[:n])
@ -2441,6 +2432,7 @@ func unpackArchive(zipPath string) error {
return writeErr return writeErr
} }
// Update "done" and recalc progress, speed, eta
done += int64(n) done += int64(n)
progress, speed, eta = statify(done, totalSize, startTime) progress, speed, eta = statify(done, totalSize, startTime)
progressInfo = fmt.Sprintf("%d/%d", i+1, len(reader.File)) progressInfo = fmt.Sprintf("%d/%d", i+1, len(reader.File))