Skip to content

Commit 7dee998

Browse files
committed
improve efficiency of SameDirSymlinks
1 parent f3da271 commit 7dee998

File tree

1 file changed

+46
-39
lines changed

1 file changed

+46
-39
lines changed

xunix/gpu.go

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -202,57 +202,64 @@ func recursiveSymlinks(afs FS, mountpoint string, path string) ([]string, error)
202202
// point to target, either indirectly or directly. Only symlinks in the same
203203
// directory as `target` are considered.
204204
func SameDirSymlinks(afs FS, target string) ([]string, error) {
205+
// Get the list of files in the directory of the target.
206+
fis, err := afero.ReadDir(afs, filepath.Dir(target))
207+
if err != nil {
208+
return nil, xerrors.Errorf("read dir %q: %w", filepath.Dir(target), err)
209+
}
210+
211+
// Do an initial pass to map all symlinks to their destinations.
212+
allLinks := make(map[string]string)
213+
for _, fi := range fis {
214+
// Ignore non-symlinks.
215+
if fi.Mode()&os.ModeSymlink == 0 {
216+
continue
217+
}
218+
219+
absPath := filepath.Join(filepath.Dir(target), fi.Name())
220+
link, err := afs.Readlink(filepath.Join(filepath.Dir(target), fi.Name()))
221+
if err != nil {
222+
return nil, xerrors.Errorf("readlink %q: %w", fi.Name(), err)
223+
}
224+
225+
if !filepath.IsAbs(link) {
226+
link = filepath.Join(filepath.Dir(target), link)
227+
}
228+
allLinks[absPath] = link
229+
}
230+
231+
// Now we can start checking for symlinks that point to the target.
205232
var (
206-
found = make([]string, 0)
207-
maxIterations = 10 // arbitrary upper limit to prevent infinite loops
233+
found = make([]string, 0)
234+
// Set an arbitrary upper limit to prevent infinite loops.
235+
maxIterations = 10
208236
)
209237
for range maxIterations {
210-
foundThisTime := false
211-
fis, err := afero.ReadDir(afs, filepath.Dir(target))
212-
if err != nil {
213-
return nil, xerrors.Errorf("read dir %q: %w", filepath.Dir(target), err)
214-
}
215-
for _, fi := range fis {
216-
// Ignore the target itself.
217-
if fi.Name() == filepath.Base(target) {
218-
continue
219-
}
220-
// Ignore non-symlinks.
221-
if fi.Mode()&os.ModeSymlink == 0 {
222-
continue
223-
}
224-
// Get the target of the symlink.
225-
link, err := afs.Readlink(filepath.Join(filepath.Dir(target), fi.Name()))
226-
if err != nil {
227-
return nil, xerrors.Errorf("readlink %q: %w", fi.Name(), err)
228-
}
229-
// Make the link absolute.
230-
if !filepath.IsAbs(link) {
231-
link = filepath.Join(filepath.Dir(target), link)
232-
}
238+
var foundThisTime bool
239+
for linkName, linkDest := range allLinks {
233240
// Ignore symlinks that point outside of target's directory.
234-
if filepath.Dir(link) != filepath.Dir(target) {
241+
if filepath.Dir(linkName) != filepath.Dir(target) {
235242
continue
236243
}
237244

238-
// Check if the symlink points to to the target, or if it points
239-
// to one of the symlinks we've already found.
240-
if link != target {
241-
if !slices.Contains(found, link) {
242-
continue
245+
// If the symlink points to the target, add it to the list.
246+
if linkDest == target {
247+
if !slices.Contains(found, linkName) {
248+
found = append(found, linkName)
249+
foundThisTime = true
243250
}
244251
}
245252

246-
// Have we already seen this target?
247-
fullPath := filepath.Join(filepath.Dir(target), fi.Name())
248-
if slices.Contains(found, fullPath) {
249-
continue
253+
// If the symlink points to another symlink that we already determined
254+
// points to the target, add it to the list.
255+
if slices.Contains(found, linkDest) {
256+
if !slices.Contains(found, linkName) {
257+
found = append(found, linkName)
258+
foundThisTime = true
259+
}
250260
}
251-
252-
found = append(found, filepath.Join(filepath.Dir(target), fi.Name()))
253-
foundThisTime = true
254261
}
255-
// If we didn't find any symlinks this time, we're done.
262+
// If we didn't find any new symlinks, we're done.
256263
if !foundThisTime {
257264
break
258265
}

0 commit comments

Comments
 (0)