Files

137 lines
3.4 KiB
Go

package archiver
import (
"fmt"
"os"
"path/filepath"
"zipprine/internal/models"
"github.com/nwaples/rardecode"
)
// extractRar extracts a RAR archive
func extractRar(config *models.ExtractConfig) error {
file, err := os.Open(config.ArchivePath)
if err != nil {
return fmt.Errorf("failed to open RAR file: %w", err)
}
defer file.Close()
reader, err := rardecode.NewReader(file, "")
if err != nil {
return fmt.Errorf("failed to create RAR reader: %w", err)
}
if err := os.MkdirAll(config.DestPath, 0755); err != nil {
return fmt.Errorf("failed to create destination directory: %w", err)
}
for {
header, err := reader.Next()
if err != nil {
if err.Error() == "EOF" {
break
}
return fmt.Errorf("failed to read RAR entry: %w", err)
}
if header.IsDir {
targetPath := filepath.Join(config.DestPath, header.Name)
if err := os.MkdirAll(targetPath, 0755); err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}
continue
}
targetPath := filepath.Join(config.DestPath, header.Name)
if _, err := os.Stat(targetPath); err == nil && !config.OverwriteAll {
fmt.Printf("Skipping existing file: %s\n", header.Name)
continue
}
if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil {
return fmt.Errorf("failed to create parent directory: %w", err)
}
outFile, err := os.Create(targetPath)
if err != nil {
return fmt.Errorf("failed to create file %s: %w", header.Name, err)
}
if _, err := outFile.ReadFrom(reader); err != nil {
outFile.Close()
return fmt.Errorf("failed to write file %s: %w", header.Name, err)
}
outFile.Close()
// Set permissions if requested
if config.PreservePerms {
if err := os.Chmod(targetPath, header.Mode()); err != nil {
fmt.Printf("Warning: failed to set permissions for %s: %v\n", header.Name, err)
}
}
fmt.Printf("Extracted: %s\n", header.Name)
}
return nil
}
// analyzeRar analyzes a RAR archive and returns information about it
func analyzeRar(path string) (*models.ArchiveInfo, error) {
file, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("failed to open RAR file: %w", err)
}
defer file.Close()
fileStat, _ := file.Stat()
reader, err := rardecode.NewReader(file, "")
if err != nil {
return nil, fmt.Errorf("failed to create RAR reader: %w", err)
}
info := &models.ArchiveInfo{
Type: models.RAR,
CompressedSize: fileStat.Size(),
Files: []models.FileInfo{},
}
for {
header, err := reader.Next()
if err != nil {
if err.Error() == "EOF" {
break
}
return nil, fmt.Errorf("failed to read RAR entry: %w", err)
}
if !header.IsDir {
info.FileCount++
info.TotalSize += header.UnPackedSize
info.Files = append(info.Files, models.FileInfo{
Name: header.Name,
Size: header.UnPackedSize,
IsDir: header.IsDir,
ModTime: header.ModificationTime.Format("2006-01-02 15:04:05"),
})
}
}
if info.TotalSize > 0 {
info.CompressionRatio = float64(info.CompressedSize) / float64(info.TotalSize)
}
return info, nil
}
// Note: RAR compression is proprietary and requires a license.
// This implementation only supports extraction using the rardecode library.
// For compression, users should use WinRAR or other licensed tools.
func createRar(config *models.CompressConfig) error {
return fmt.Errorf("RAR compression is not supported due to proprietary format. Please use ZIP, TAR, or TAR.GZ for compression")
}