Skip to content

Add progress updates. #91

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ linters:
- exhaustruct
- depguard
- nonamedreturns
- forbidigo
exclusions:
rules:
- linters:
Expand All @@ -20,6 +21,7 @@ linters:
gosec:
excludes:
- G304
- G115
gocritic:
enable-all: true
disabled-checks:
Expand All @@ -30,8 +32,8 @@ linters:
checkExported: true
errcheck:
check-type-assertions: true
check-blank: true
disable-default-exclusions: true
check-blank: false
disable-default-exclusions: false
exclude-functions:
- (*os.File).Close
- os.RemoveAll
Expand Down
49 changes: 25 additions & 24 deletions 7z.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

// Extract7z extracts a 7zip archive.
// Volumes: https://github.com/bodgit/sevenzip/issues/54
func Extract7z(xFile *XFile) (size int64, filesList, archiveList []string, err error) {
func Extract7z(xFile *XFile) (size uint64, filesList, archiveList []string, err error) {
if len(xFile.Passwords) == 0 && xFile.Password == "" {
return extract7z(xFile)
}
Expand Down Expand Up @@ -41,50 +41,51 @@ func Extract7z(xFile *XFile) (size int64, filesList, archiveList []string, err e
return 0, nil, nil, nil
}

func extract7z(xFile *XFile) (int64, []string, []string, error) {
var (
sevenZip *sevenzip.ReadCloser
err error
)

if xFile.Password != "" {
sevenZip, err = sevenzip.OpenReaderWithPassword(xFile.FilePath, xFile.Password)
} else {
sevenZip, err = sevenzip.OpenReader(xFile.FilePath)
func extract7z(xFile *XFile) (uint64, []string, []string, error) {
sevenZip, err := sevenzip.OpenReaderWithPassword(xFile.FilePath, xFile.Password)
if err != nil {
return 0, nil, nil, fmt.Errorf("%s: os.Open: %w", xFile.FilePath, err)
}

defer xFile.newProgress(getUncompressed7zSize(sevenZip)).done() // this closes sevenZip

sevenZip, err = sevenzip.OpenReaderWithPassword(xFile.FilePath, xFile.Password)
if err != nil {
return 0, nil, nil, fmt.Errorf("%s: os.Open: %w", xFile.FilePath, err)
}

defer sevenZip.Close()

files := []string{}
size := int64(0)

for _, zipFile := range sevenZip.File {
fSize, wfile, err := xFile.un7zip(zipFile)
if err != nil {
lastFile := xFile.FilePath
/* // https://github.com/bodgit/sevenzip/issues/54
// We can probably never get the file with the error.
if volumes := sevenZip.Volumes(); len(volumes) > 0 {
lastFile = volumes[len(volumes)-1]
} */
return size, files, sevenZip.Volumes(), fmt.Errorf("%s: %w", lastFile, err)
return xFile.prog.Wrote, files, []string{xFile.FilePath}, fmt.Errorf("%s: %w", xFile.FilePath, err)
}

files = append(files, filepath.Join(xFile.OutputDir, zipFile.Name))
size += fSize
xFile.Debugf("Wrote archived file: %s (%d bytes), total: %d files and %d bytes", wfile, fSize, len(files), size)
xFile.Debugf("Wrote archived file: %s (%d bytes), total: %d files and %d bytes",
wfile, fSize, xFile.prog.Files, xFile.prog.Wrote)
}

files, err = xFile.cleanup(files)

return size, files, sevenZip.Volumes(), err
return xFile.prog.Wrote, files, []string{xFile.FilePath}, err
}

func getUncompressed7zSize(reader *sevenzip.ReadCloser) (total, compressed uint64, count int) {
defer reader.Close()

for _, zipFile := range reader.File {
total += zipFile.UncompressedSize
// compressed += uint64(zipFile.FileInfo().Size())
count++
}

return total, 0, count
}

func (x *XFile) un7zip(zipFile *sevenzip.File) (int64, string, error) {
func (x *XFile) un7zip(zipFile *sevenzip.File) (uint64, string, error) {
zFile, err := zipFile.Open()
if err != nil {
return 0, zipFile.Name, fmt.Errorf("zipFile.Open: %w", err)
Expand Down
50 changes: 39 additions & 11 deletions ar.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,28 @@ import (
)

// ExtractAr extracts a raw ar archive. Used by debian (.deb) packages.
func ExtractAr(xFile *XFile) (size int64, filesList []string, err error) {
func ExtractAr(xFile *XFile) (size uint64, filesList []string, err error) {
arFile, err := os.Open(xFile.FilePath)
if err != nil {
return 0, nil, fmt.Errorf("rardecode.OpenReader: %w", err)
}

defer xFile.newProgress(getUncompressedArSize(arFile)).done() // this closes arFile

if arFile, err = os.Open(xFile.FilePath); err != nil {
return 0, nil, fmt.Errorf("os.Open: %w", err)
}

defer arFile.Close()

return xFile.unAr(arFile)
files, err := xFile.unAr(xFile.prog.reader(arFile))

return xFile.prog.Wrote, files, err
}

func (x *XFile) unAr(reader io.Reader) (int64, []string, error) {
func (x *XFile) unAr(reader io.Reader) ([]string, error) {
arReader := ar.NewReader(reader)
files := []string{}
size := int64(0)

for {
header, err := arReader.Next()
Expand All @@ -33,34 +41,54 @@ func (x *XFile) unAr(reader io.Reader) (int64, []string, error) {
break
}

return size, files, fmt.Errorf("%s: arReader.Next: %w", x.FilePath, err)
return files, fmt.Errorf("%s: arReader.Next: %w", x.FilePath, err)
}

file := &file{
Path: x.clean(header.Name),
Data: arReader,
FileMode: os.FileMode(header.Mode), //nolint:gosec // what else ya gonna do with this?
FileMode: os.FileMode(header.Mode),
DirMode: x.DirMode,
Mtime: header.ModTime,
}

if !strings.HasPrefix(file.Path, x.OutputDir) {
// The file being written is trying to write outside of our base path. Malicious archive?
return size, files, fmt.Errorf("%s: %w: %s (from: %s)", x.FilePath, ErrInvalidPath, file.Path, header.Name)
return files, fmt.Errorf("%s: %w: %s (from: %s)", x.FilePath, ErrInvalidPath, file.Path, header.Name)
}

// ar format does not store directory paths. Flat list of files.

fSize, err := x.write(file)
if err != nil {
return size, files, err
return files, err
}

files = append(files, file.Path)
size += fSize
x.Debugf("Wrote archived file: %s (%d bytes), total: %d files and %d bytes",
file.Path, fSize, x.prog.Files, x.prog.Wrote)
}

files, err := x.cleanup(files)
return x.cleanup(files)
}

// ar files are not compressed.
func getUncompressedArSize(arFile io.ReadCloser) (total, compressed uint64, count int) {
defer arFile.Close()

arReader := ar.NewReader(arFile)

return size, files, err
for {
header, err := arReader.Next()
if err != nil {
if errors.Is(err, io.EOF) {
return total, 0, count
}

return total, 0, count
}

total += uint64(header.Size)
count++
}
}
40 changes: 24 additions & 16 deletions cpio.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,57 +13,65 @@ import (
)

// ExtractCPIOGzip extracts a gzip-compressed cpio archive (cpgz).
func ExtractCPIOGzip(xFile *XFile) (size int64, filesList []string, err error) {
compressedFile, err := os.Open(xFile.FilePath)
func ExtractCPIOGzip(xFile *XFile) (size uint64, filesList []string, err error) {
compressedFile, stat, err := openStatFile(xFile.FilePath)
if err != nil {
return 0, nil, fmt.Errorf("os.Open: %w", err)
return 0, nil, err
}
defer compressedFile.Close()

zipStream, err := gzip.NewReader(compressedFile)
defer xFile.newProgress(0, uint64(stat.Size()), 0).done()

zipStream, err := gzip.NewReader(xFile.prog.reader(compressedFile))
if err != nil {
return 0, nil, fmt.Errorf("gzip.NewReader: %w", err)
}
defer zipStream.Close()

return xFile.uncpio(zipStream)
files, err := xFile.uncpio(zipStream)

return xFile.prog.Wrote, files, err
}

// ExtractCPIO extracts a .cpio file.
func ExtractCPIO(xFile *XFile) (size int64, filesList []string, err error) {
fileReader, err := os.Open(xFile.FilePath)
func ExtractCPIO(xFile *XFile) (size uint64, filesList []string, err error) {
fileReader, stat, err := openStatFile(xFile.FilePath)
if err != nil {
return 0, nil, fmt.Errorf("os.Open: %w", err)
return 0, nil, err
}
defer fileReader.Close()

return xFile.uncpio(fileReader)
defer xFile.newProgress(uint64(stat.Size()), uint64(stat.Size()), 0).done()

files, err := xFile.uncpio(xFile.prog.reader(fileReader))

return xFile.prog.Wrote, files, err
}

func (x *XFile) uncpio(reader io.Reader) (int64, []string, error) {
func (x *XFile) uncpio(reader io.Reader) ([]string, error) {
zipReader := cpio.NewReader(reader)
files := []string{}
size := int64(0)

for {
zipFile, err := zipReader.Next()
if errors.Is(err, io.EOF) {
return size, files, nil
return files, nil
} else if err != nil {
return 0, nil, fmt.Errorf("cpio Next() failed: %w", err)
return nil, fmt.Errorf("cpio Next() failed: %w", err)
}

fSize, err := x.uncpioFile(zipFile, zipReader)
if err != nil {
return size, files, fmt.Errorf("%s: %w", x.FilePath, err)
return files, fmt.Errorf("%s: %w", x.FilePath, err)
}

files = append(files, filepath.Join(x.OutputDir, zipFile.Name))
size += fSize
x.Debugf("Wrote archived file: %s (%d bytes), total: %d files and %d bytes",
zipFile.Name, fSize, x.prog.Files, x.prog.Wrote)
}
}

func (x *XFile) uncpioFile(cpioFile *cpio.Header, cpioReader *cpio.Reader) (int64, error) {
func (x *XFile) uncpioFile(cpioFile *cpio.Header, cpioReader *cpio.Reader) (uint64, error) {
file := &file{
Path: x.clean(cpioFile.Name),
Data: cpioReader,
Expand Down
Loading
Loading