Skip to content

Commit 8fe1c01

Browse files
ForestEckhardtryanmoran
authored andcommitted
Updates symlink sorting function
- The existing function had trouble sorting symlinks to symlinks in the same directory. The new function should sort symlinks that are dependent on symlinks in the same directory properly
1 parent 9c0ee9f commit 8fe1c01

File tree

2 files changed

+89
-18
lines changed

2 files changed

+89
-18
lines changed

vacation/vacation.go

+43-18
Original file line numberDiff line numberDiff line change
@@ -172,28 +172,38 @@ func (ta TarArchive) Decompress(destination string) error {
172172
// created before they are created.
173173
//
174174
// For example:
175-
// b-sym -> a-sym/file
176-
// a-sym -> dir
177-
// c-sym -> a-sym/other-file
175+
// b-sym -> a-sym/x
176+
// a-sym -> z
177+
// c-sym -> d-sym
178+
// d-sym -> z
178179
//
179180
// Will sort to:
180-
// a-sym -> dir
181-
// b-sym -> a-sym/file
182-
// c-sym -> a-sym/other-file
181+
// a-sym -> z
182+
// b-sym -> a-sym/x
183+
// d-sym -> z
184+
// c-sym -> d-sym
183185
sort.Slice(symlinkHeaders, func(i, j int) bool {
184-
return filepath.Clean(symlinkHeaders[i].name) < filepath.Clean(filepath.Join(filepath.Dir(symlinkHeaders[j].name), symlinkHeaders[j].linkname))
186+
if filepath.Clean(symlinkHeaders[i].name) == linknameFullPath(symlinkHeaders[j].name, symlinkHeaders[j].linkname) {
187+
return true
188+
}
189+
190+
if filepath.Clean(symlinkHeaders[j].name) == linknameFullPath(symlinkHeaders[i].name, symlinkHeaders[i].linkname) {
191+
return false
192+
}
193+
194+
return filepath.Clean(symlinkHeaders[i].name) < linknameFullPath(symlinkHeaders[j].name, symlinkHeaders[j].linkname)
185195
})
186196

187197
for _, h := range symlinkHeaders {
188198
// Check to see if the file that will be linked to is valid for symlinking
189-
_, err := filepath.EvalSymlinks(filepath.Join(filepath.Dir(h.path), h.linkname))
199+
_, err := filepath.EvalSymlinks(linknameFullPath(h.path, h.linkname))
190200
if err != nil {
191201
return fmt.Errorf("failed to evaluate symlink %s: %w", h.path, err)
192202
}
193203

194204
// Check that the file being symlinked to is inside the destination
195205
// directory
196-
err = checkExtractPath(filepath.Join(filepath.Dir(h.name), h.linkname), destination)
206+
err = checkExtractPath(linknameFullPath(h.name, h.linkname), destination)
197207
if err != nil {
198208
return err
199209
}
@@ -420,28 +430,38 @@ func (z ZipArchive) Decompress(destination string) error {
420430
// created before they are created.
421431
//
422432
// For example:
423-
// b-sym -> a-sym/file
424-
// a-sym -> dir
425-
// c-sym -> a-sym/other-file
433+
// b-sym -> a-sym/x
434+
// a-sym -> z
435+
// c-sym -> d-sym
436+
// d-sym -> z
426437
//
427438
// Will sort to:
428-
// a-sym -> dir
429-
// b-sym -> a-sym/file
430-
// c-sym -> a-sym/other-file
439+
// a-sym -> z
440+
// b-sym -> a-sym/x
441+
// d-sym -> z
442+
// c-sym -> d-sym
431443
sort.Slice(symlinkHeaders, func(i, j int) bool {
432-
return filepath.Clean(symlinkHeaders[i].name) < filepath.Clean(filepath.Join(filepath.Dir(symlinkHeaders[j].name), symlinkHeaders[j].linkname))
444+
if filepath.Clean(symlinkHeaders[i].name) == linknameFullPath(symlinkHeaders[j].name, symlinkHeaders[j].linkname) {
445+
return true
446+
}
447+
448+
if filepath.Clean(symlinkHeaders[j].name) == linknameFullPath(symlinkHeaders[i].name, symlinkHeaders[i].linkname) {
449+
return false
450+
}
451+
452+
return filepath.Clean(symlinkHeaders[i].name) < linknameFullPath(symlinkHeaders[j].name, symlinkHeaders[j].linkname)
433453
})
434454

435455
for _, h := range symlinkHeaders {
436456
// Check to see if the file that will be linked to is valid for symlinking
437-
_, err := filepath.EvalSymlinks(filepath.Join(filepath.Dir(h.path), h.linkname))
457+
_, err := filepath.EvalSymlinks(linknameFullPath(h.path, h.linkname))
438458
if err != nil {
439459
return fmt.Errorf("failed to evaluate symlink %s: %w", h.path, err)
440460
}
441461

442462
// Check that the file being symlinked to is inside the destination
443463
// directory
444-
err = checkExtractPath(filepath.Join(filepath.Dir(h.name), h.linkname), destination)
464+
err = checkExtractPath(linknameFullPath(h.name, h.linkname), destination)
445465
if err != nil {
446466
return err
447467
}
@@ -464,3 +484,8 @@ func checkExtractPath(filePath string, destination string) error {
464484
}
465485
return nil
466486
}
487+
488+
// Generates the full path for a symlink from the linkname and the symlink path
489+
func linknameFullPath(path, linkname string) string {
490+
return filepath.Clean(filepath.Join(filepath.Dir(path), linkname))
491+
}

vacation/vacation_symlink_sorting_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ func testVacationSymlinkSorting(t *testing.T, context spec.G, it spec.S) {
3838
_, err = tw.Write([]byte{})
3939
Expect(err).NotTo(HaveOccurred())
4040

41+
Expect(tw.WriteHeader(&tar.Header{Name: "c-symlink", Mode: 0755, Size: int64(0), Typeflag: tar.TypeSymlink, Linkname: "d-symlink"})).To(Succeed())
42+
_, err = tw.Write([]byte{})
43+
Expect(err).NotTo(HaveOccurred())
44+
45+
Expect(tw.WriteHeader(&tar.Header{Name: "d-symlink", Mode: 0755, Size: int64(0), Typeflag: tar.TypeSymlink, Linkname: "z"})).To(Succeed())
46+
_, err = tw.Write([]byte{})
47+
Expect(err).NotTo(HaveOccurred())
48+
4149
Expect(tw.WriteHeader(&tar.Header{Name: "a-symlink", Mode: 0755, Size: int64(0), Typeflag: tar.TypeSymlink, Linkname: "z"})).To(Succeed())
4250
_, err = tw.Write([]byte{})
4351
Expect(err).NotTo(HaveOccurred())
@@ -71,6 +79,8 @@ func testVacationSymlinkSorting(t *testing.T, context spec.G, it spec.S) {
7179
filepath.Join(tempDir, "a-symlink"),
7280
filepath.Join(tempDir, "b-symlink"),
7381
filepath.Join(tempDir, "z"),
82+
filepath.Join(tempDir, "d-symlink"),
83+
filepath.Join(tempDir, "c-symlink"),
7484
}))
7585

7686
Expect(filepath.Join(tempDir, "z")).To(BeADirectory())
@@ -80,6 +90,14 @@ func testVacationSymlinkSorting(t *testing.T, context spec.G, it spec.S) {
8090
Expect(err).NotTo(HaveOccurred())
8191
Expect(link).To(Equal("z"))
8292

93+
link, err = os.Readlink(filepath.Join(tempDir, "c-symlink"))
94+
Expect(err).NotTo(HaveOccurred())
95+
Expect(link).To(Equal("d-symlink"))
96+
97+
link, err = os.Readlink(filepath.Join(tempDir, "d-symlink"))
98+
Expect(err).NotTo(HaveOccurred())
99+
Expect(link).To(Equal("z"))
100+
83101
data, err := os.ReadFile(filepath.Join(tempDir, "b-symlink"))
84102
Expect(err).NotTo(HaveOccurred())
85103
Expect(data).To(Equal([]byte(filepath.Join("z", "x"))))
@@ -109,6 +127,24 @@ func testVacationSymlinkSorting(t *testing.T, context spec.G, it spec.S) {
109127
_, err = bSymlink.Write([]byte(filepath.Join("a-symlink", "x")))
110128
Expect(err).NotTo(HaveOccurred())
111129

130+
fileHeader = &zip.FileHeader{Name: "c-symlink"}
131+
fileHeader.SetMode(0755 | os.ModeSymlink)
132+
133+
cSymlink, err := zw.CreateHeader(fileHeader)
134+
Expect(err).NotTo(HaveOccurred())
135+
136+
_, err = cSymlink.Write([]byte(`d-symlink`))
137+
Expect(err).NotTo(HaveOccurred())
138+
139+
fileHeader = &zip.FileHeader{Name: "d-symlink"}
140+
fileHeader.SetMode(0755 | os.ModeSymlink)
141+
142+
dSymlink, err := zw.CreateHeader(fileHeader)
143+
Expect(err).NotTo(HaveOccurred())
144+
145+
_, err = dSymlink.Write([]byte(`z`))
146+
Expect(err).NotTo(HaveOccurred())
147+
112148
fileHeader = &zip.FileHeader{Name: "a-symlink"}
113149
fileHeader.SetMode(0755 | os.ModeSymlink)
114150

@@ -150,6 +186,8 @@ func testVacationSymlinkSorting(t *testing.T, context spec.G, it spec.S) {
150186
filepath.Join(tempDir, "a-symlink"),
151187
filepath.Join(tempDir, "b-symlink"),
152188
filepath.Join(tempDir, "z"),
189+
filepath.Join(tempDir, "d-symlink"),
190+
filepath.Join(tempDir, "c-symlink"),
153191
}))
154192

155193
Expect(filepath.Join(tempDir, "z")).To(BeADirectory())
@@ -159,6 +197,14 @@ func testVacationSymlinkSorting(t *testing.T, context spec.G, it spec.S) {
159197
Expect(err).NotTo(HaveOccurred())
160198
Expect(link).To(Equal("z"))
161199

200+
link, err = os.Readlink(filepath.Join(tempDir, "c-symlink"))
201+
Expect(err).NotTo(HaveOccurred())
202+
Expect(link).To(Equal("d-symlink"))
203+
204+
link, err = os.Readlink(filepath.Join(tempDir, "d-symlink"))
205+
Expect(err).NotTo(HaveOccurred())
206+
Expect(link).To(Equal("z"))
207+
162208
data, err := os.ReadFile(filepath.Join(tempDir, "b-symlink"))
163209
Expect(err).NotTo(HaveOccurred())
164210
Expect(data).To(Equal([]byte(`x file`)))

0 commit comments

Comments
 (0)