Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

Commit

Permalink
Fixes #22; check if file exists at destination before writing (#89)
Browse files Browse the repository at this point in the history
Thanks to initial work by @schollz (#89)
  • Loading branch information
johnarok authored and mholt committed Nov 7, 2018
1 parent 7cd3d2c commit 5846562
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 0 deletions.
14 changes: 14 additions & 0 deletions archiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ func MatchingFormat(fpath string) Archiver {
}

func writeNewFile(fpath string, in io.Reader, fm os.FileMode) error {
if fileExists(fpath) {
return fmt.Errorf("%s: skipping because there exists a file with the same name", fpath)
}

err := os.MkdirAll(filepath.Dir(fpath), 0755)
if err != nil {
return fmt.Errorf("%s: making directory for file: %v", fpath, err)
Expand Down Expand Up @@ -117,3 +121,13 @@ func sanitizeExtractPath(filePath string, destination string) error {
}
return nil
}

// fileExists returns true only if we can successfuly get the file attributes or if the reason
// for failure is the absence of the file.
func fileExists(fpath string) bool {
_, err := os.Stat(fpath)
if err == nil {
return true
}
return !os.IsNotExist(err)
}
61 changes: 61 additions & 0 deletions archiver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
)

Expand All @@ -27,6 +28,7 @@ func TestArchiver(t *testing.T) {
testWriteRead(t, name, ar)
testMakeOpen(t, name, ar)
testMakeOpenWithDestinationEndingInSlash(t, name, ar)
testMakeOpenNotOverwriteAtDestination(t, name, ar)
}
})
}
Expand Down Expand Up @@ -189,6 +191,65 @@ func testMakeOpenWithDestinationEndingInSlash(t *testing.T, name string, ar Arch
symmetricTest(t, name, dest)
}

// testMakeOpenNotOverwriteAtDestination performs a test to ensure we do not overwrite existing files
// when extracting at a destination that has existing files named as those in the archive.
func testMakeOpenNotOverwriteAtDestination(t *testing.T, name string, ar Archiver) {
tmp, err := ioutil.TempDir("", "archiver")
if err != nil {
t.Fatalf("[%s] %v", name, err)
}
defer os.RemoveAll(tmp)

mockOverWriteDirectory := filepath.Join(tmp, "testdatamock")
mockOverWriteFile := filepath.Join(tmp, "testdatamock", "shouldnotoverwrite.txt")

// Prepare a mock directory with files for testing
if err := os.Mkdir(mockOverWriteDirectory, 0774); err != nil {
t.Fatalf("[%s] preping mock directory: didn't expect an error, but got: %v", mockOverWriteDirectory, err)
}
if err := ioutil.WriteFile(filepath.Join(mockOverWriteDirectory, "fileatsourceonly.txt"), []byte("File-From-Source"), 0644); err != nil {
t.Fatalf("[%s] prep file in source: didn't expect an error, but got: %v", name, err)
}
defer os.RemoveAll(mockOverWriteDirectory)
if err := ioutil.WriteFile(mockOverWriteFile, []byte("File-From-Source"), 0644); err != nil {
t.Fatalf("[%s] prep file in source: didn't expect an error, but got: %v", name, err)
}

// Test creating archive
outfile := filepath.Join(tmp, "test-"+name)
err = ar.Make(outfile, []string{mockOverWriteDirectory})
if err != nil {
t.Fatalf("[%s] making archive: didn't expect an error, but got: %v", name, err)
}

if !ar.Match(outfile) {
t.Fatalf("[%s] identifying format should be 'true', but got 'false'", name)
}

// Introduce a change to the mock file, to track if it would be overwritten by unarchiving.
if err := ioutil.WriteFile(mockOverWriteFile, []byte("File-At-Destination"), 0644); err != nil {
t.Fatalf("[%s] change file in destination: didn't expect an error, but got: %v", name, err)
}

// Test extracting archive with destination same as original folder
dest := tmp
if err := ar.Open(outfile, dest); err != nil {
if !strings.Contains(err.Error(), "skipping because there exists a file with the same name") {
t.Fatalf("[%s] extracting archive [%s -> %s]: Unexpected error got: %v", name, outfile, dest, err)
}
}

// Validate if the mock file was changed by the un-archiving process
content, err := ioutil.ReadFile(mockOverWriteFile)
if err != nil {
t.Fatalf("[%s] extracting archive [%s -> %s]: Unable to read file : %v", name, outfile, dest, err)
}
if string(content) != "File-At-Destination" {
t.Fatalf("[%s] extracting archive [%s -> %s]: Unexpected Overwrite of File at Destination %s, %s got %s", name, outfile, dest, mockOverWriteFile, "File-At-Destination", string(content))

}
}

// symmetricTest compares the contents of a destination directory to the contents
// of the test corpus and tests that they are equal.
func symmetricTest(t *testing.T, name, dest string) {
Expand Down

0 comments on commit 5846562

Please sign in to comment.