Skip to content

Commit

Permalink
Merge pull request #524 from sahinfalcon/fix-file-extract
Browse files Browse the repository at this point in the history
Fix file extraction
  • Loading branch information
yorukot authored Dec 25, 2024
2 parents a24093b + a99e468 commit c7fce5c
Showing 1 changed file with 81 additions and 26 deletions.
107 changes: 81 additions & 26 deletions src/internal/file_operations_extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,30 @@ import (
"io"
"os"
"path/filepath"
"runtime"
"strings"
"time"

"github.com/charmbracelet/bubbles/progress"
"github.com/lithammer/shortuuid"
"github.com/yorukot/superfile/src/config/icon"
"golift.io/xtractr"
)

func getDefaultFileMode() os.FileMode {
if runtime.GOOS == "windows" {
return 0666
}
return 0644
}

func shouldSkipFile(name string) bool {
// Skip system files across platforms
return strings.HasPrefix(name, "__MACOSX/") ||
strings.EqualFold(name, "Thumbs.db") ||
strings.EqualFold(name, "desktop.ini")
}

func extractCompressFile(src, dest string) error {
id := shortuuid.New()

Expand All @@ -26,14 +42,17 @@ func extractCompressFile(src, dest string) error {
state: inOperation,
total: 1,
done: 0,
doneTime: time.Time{},
}
message := channelMessage{
messageId: id,
messageType: sendProcess,
processNewState: p,
}

if len(channel) < 5 {
channel <- message
}

x := &xtractr.XFile{
FilePath: src,
Expand All @@ -43,18 +62,24 @@ func extractCompressFile(src, dest string) error {
_, _, _, err := xtractr.ExtractFile(x)

if err != nil {
p.state = successful
p.state = failure
p.doneTime = time.Now()
message.processNewState = p
if len(channel) < 5 {
channel <- message
}
outPutLog(fmt.Sprintf("Error extracting %s: %v", src, err))
return err
}

p.state = successful
p.done = 1

p.doneTime = time.Now()
message.processNewState = p
if len(channel) < 5 {
channel <- message

}

return nil
}

Expand All @@ -63,13 +88,14 @@ func unzip(src, dest string) error {
id := shortuuid.New()
r, err := zip.OpenReader(src)
if err != nil {
return err
return fmt.Errorf("failed to open zip: %w", err)
}
defer func() {
if err := r.Close(); err != nil {
panic(err)
outPutLog(fmt.Sprintf("Error closing zip reader: %v", err))
}
}()

totalFiles := len(r.File)
// progressbar
prog := progress.New(generateGradientColor())
Expand All @@ -81,6 +107,7 @@ func unzip(src, dest string) error {
state: inOperation,
total: totalFiles,
done: 0,
doneTime: time.Time{},
}

message := channelMessage{
Expand All @@ -94,68 +121,96 @@ func unzip(src, dest string) error {

rc, err := f.Open()
if err != nil {
return err
return fmt.Errorf("failed to open file in zip: %w", err)
}
defer func() {
if err := rc.Close(); err != nil {
panic(err)
outPutLog(fmt.Sprintf("Error closing file reader: %v", err))
}
}()

path := filepath.Join(dest, f.Name)

// Check for ZipSlip (Directory traversal)
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
// Cross-platform path security check
if !strings.HasPrefix(filepath.Clean(path), filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("illegal file path: %s", path)
}

fileMode := f.Mode()
if f.FileInfo().IsDir() {
os.MkdirAll(path, f.Mode())
} else {
os.MkdirAll(filepath.Dir(path), f.Mode())
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
err := os.MkdirAll(path, fileMode)
if err != nil {
return fmt.Errorf("error open file: %s", err)
return fmt.Errorf("failed to create directory: %w", err)
}
defer func() {
if err := f.Close(); err != nil {
panic(err)
}
}()
return nil
}

_, err = io.Copy(f, rc)
// Create directory structure
if err := os.MkdirAll(filepath.Dir(path), fileMode); err != nil {
return fmt.Errorf("failed to create parent directory: %w", err)
}

// Try default permissions first
outFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, getDefaultFileMode())
if err != nil {
// Fall back to original file permissions
outFile, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fileMode)
if err != nil {
return fmt.Errorf("error copy file: %s", err)
return fmt.Errorf("failed to create file: %w", err)
}
}
defer func() {
if err := outFile.Close(); err != nil {
outPutLog(fmt.Sprintf("Error closing output file %s: %v", path, err))
}
}()

if _, err := io.Copy(outFile, rc); err != nil {
return fmt.Errorf("failed to write file content: %w", err)
}

return nil
}

for _, f := range r.File {
p.name = icon.ExtractFile + icon.Space + f.Name
if len(channel) < 3 {
if len(channel) < 5 {
message.processNewState = p
channel <- message
}

if shouldSkipFile(f.Name) {
p.done++
continue
}

err := extractAndWriteFile(f)
if err != nil {
p.state = failure
message.processNewState = p
channel <- message
return err
outPutLog(fmt.Sprintf("Error extracting %s: %v", f.Name, err))
p.done++
continue
}
p.done++
if len(channel) < 3 {
if len(channel) < 5 {
message.processNewState = p
channel <- message
channel <- message
}
}

p.total = totalFiles
p.state = successful
p.doneTime = time.Now()
if p.done == totalFiles {
p.state = successful
} else {
p.state = failure
}
message.processNewState = p
if len(channel) < 5 {
channel <- message
}

return nil
}

0 comments on commit c7fce5c

Please sign in to comment.