diff options
-rw-r--r-- | zip/zip.go | 52 | ||||
-rw-r--r-- | zip/zip_test.go | 27 |
2 files changed, 74 insertions, 5 deletions
diff --git a/zip/zip.go b/zip/zip.go index ae379f52e..955fe68d0 100644 --- a/zip/zip.go +++ b/zip/zip.go @@ -201,6 +201,16 @@ func (x IncorrectRelativeRootError) Error() string { return fmt.Sprintf("path %q is outside relative root %q", x.Path, x.RelativeRoot) } +type ConflictingFileError struct { + Dest string + Prev string + Src string +} + +func (x ConflictingFileError) Error() string { + return fmt.Sprintf("destination %q has two files %q and %q", x.Dest, x.Prev, x.Src) +} + type ZipWriter struct { time time.Time createdFiles map[string]string @@ -605,13 +615,24 @@ func (z *ZipWriter) addFile(dest, src string, method uint16, emulateJar, srcJar if prev, exists := z.createdDirs[dest]; exists { return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src) } + + return nil + } + + checkDuplicateFiles := func(dest, src string) (bool, error) { if prev, exists := z.createdFiles[dest]; exists { - return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src) + if prev != src { + return true, ConflictingFileError{ + Dest: dest, + Prev: prev, + Src: src, + } + } + return true, nil } z.createdFiles[dest] = src - - return nil + return false, nil } if s.IsDir() { @@ -625,6 +646,14 @@ func (z *ZipWriter) addFile(dest, src string, method uint16, emulateJar, srcJar return err } + duplicate, err := checkDuplicateFiles(dest, src) + if err != nil { + return err + } + if duplicate { + return nil + } + return z.writeSymlink(dest, src) } else if s.Mode().IsRegular() { r, err := z.fs.Open(src) @@ -667,6 +696,14 @@ func (z *ZipWriter) addFile(dest, src string, method uint16, emulateJar, srcJar return err } + duplicate, err := checkDuplicateFiles(dest, src) + if err != nil { + return err + } + if duplicate { + return nil + } + return z.writeFileContents(header, r) } else { return fmt.Errorf("%s is not a file, directory, or symlink", src) @@ -678,7 +715,14 @@ func (z *ZipWriter) addManifest(dest string, src string, _ uint16) error { return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src) } if prev, exists := z.createdFiles[dest]; exists { - return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src) + if prev != src { + return ConflictingFileError{ + Dest: dest, + Prev: prev, + Src: src, + } + } + return nil } if err := z.writeDirectory(filepath.Dir(dest), src, true); err != nil { diff --git a/zip/zip_test.go b/zip/zip_test.go index 79cc0b4b7..c4832dc9a 100644 --- a/zip/zip_test.go +++ b/zip/zip_test.go @@ -46,6 +46,7 @@ var mockFs = pathtools.MockFs(map[string][]byte{ "dangling -> missing": nil, "a/a/d -> b": nil, "c": fileC, + "d/a/a": nil, "l_nl": []byte("a/a/a\na/a/b\nc\n\\[\n"), "l_sp": []byte("a/a/a a/a/b c \\["), "l2": []byte("missing\n"), @@ -400,6 +401,17 @@ func TestZip(t *testing.T) { fh("a/a/b", fileB, zip.Deflate), }, }, + { + name: "duplicate sources", + args: fileArgsBuilder(). + File("a/a/a"). + File("a/a/a"), + compressionLevel: 9, + + files: []zip.FileHeader{ + fh("a/a/a", fileA, zip.Deflate), + }, + }, // errors { @@ -427,6 +439,15 @@ func TestZip(t *testing.T) { File("a/a/a"), err: IncorrectRelativeRootError{}, }, + { + name: "error conflicting file", + args: fileArgsBuilder(). + SourcePrefixToStrip("a"). + File("a/a/a"). + SourcePrefixToStrip("d"). + File("d/a/a"), + err: ConflictingFileError{}, + }, } for _, test := range testCases { @@ -454,13 +475,17 @@ func TestZip(t *testing.T) { t.Fatalf("want error %v, got %v", test.err, err) } else if test.err != nil { if os.IsNotExist(test.err) { - if !os.IsNotExist(test.err) { + if !os.IsNotExist(err) { t.Fatalf("want error %v, got %v", test.err, err) } } else if _, wantRelativeRootErr := test.err.(IncorrectRelativeRootError); wantRelativeRootErr { if _, gotRelativeRootErr := err.(IncorrectRelativeRootError); !gotRelativeRootErr { t.Fatalf("want error %v, got %v", test.err, err) } + } else if _, wantConflictingFileError := test.err.(ConflictingFileError); wantConflictingFileError { + if _, gotConflictingFileError := err.(ConflictingFileError); !gotConflictingFileError { + t.Fatalf("want error %v, got %v", test.err, err) + } } else { t.Fatalf("want error %v, got %v", test.err, err) } |