Skip to content

Commit

Permalink
Follow symlinks to directories when scanning
Browse files Browse the repository at this point in the history
  • Loading branch information
deluan committed Apr 24, 2020
1 parent 79c9d8f commit 5a072fb
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 1 deletion.
27 changes: 26 additions & 1 deletion scanner/change_detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ func (s *ChangeDetector) loadDir(dirPath string) (children []string, lastUpdated
return
}
for _, f := range files {
if f.IsDir() {
isDir, err := IsDirOrSymlinkToDir(dirPath, f)
// Skip invalid symlinks
if err != nil {
continue
}
if isDir {
children = append(children, filepath.Join(dirPath, f.Name()))
} else {
if f.ModTime().After(lastUpdated) {
Expand All @@ -72,6 +77,26 @@ func (s *ChangeDetector) loadDir(dirPath string) (children []string, lastUpdated
return
}

// IsDirOrSymlinkToDir returns true if and only if the Dirent represents a file
// system directory, or a symbolic link to a directory. Note that if the Dirent
// is not a directory but is a symbolic link, this method will resolve by
// sending a request to the operating system to follow the symbolic link.
// Copied from github.com/karrick/godirwalk
func IsDirOrSymlinkToDir(baseDir string, info os.FileInfo) (bool, error) {
if info.IsDir() {
return true, nil
}
if info.Mode()&os.ModeSymlink == 0 {
return false, nil
}
// Does this symlink point to a directory?
info, err := os.Stat(filepath.Join(baseDir, info.Name()))
if err != nil {
return false, err
}
return info.IsDir(), nil
}

func (s *ChangeDetector) loadMap(dirMap dirInfoMap, path string, since time.Time, maybe bool) error {
children, lastUpdated, err := s.loadDir(path)
if err != nil {
Expand Down
19 changes: 19 additions & 0 deletions scanner/change_detector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,25 @@ var _ = Describe("ChangeDetector", func() {
Expect(deleted).To(BeEmpty())
Expect(changed).To(ConsistOf(P("a/b")))
})

Describe("IsDirOrSymlinkToDir", func() {
It("returns true for normal dirs", func() {
dir, _ := os.Stat("tests/fixtures")
Expect(IsDirOrSymlinkToDir("tests", dir)).To(BeTrue())
})
It("returns true for symlinks to dirs", func() {
dir, _ := os.Stat("tests/fixtures/symlink2dir")
Expect(IsDirOrSymlinkToDir("tests/fixtures", dir)).To(BeTrue())
})
It("returns false for files", func() {
dir, _ := os.Stat("tests/fixtures/test.mp3")
Expect(IsDirOrSymlinkToDir("tests/fixtures", dir)).To(BeFalse())
})
It("returns false for symlinks to files", func() {
dir, _ := os.Stat("tests/fixtures/symlink")
Expect(IsDirOrSymlinkToDir("tests/fixtures", dir)).To(BeFalse())
})
})
})

// I hate time-based tests....
Expand Down
1 change: 1 addition & 0 deletions tests/fixtures/symlink
1 change: 1 addition & 0 deletions tests/fixtures/symlink2dir
1 change: 1 addition & 0 deletions tests/fixtures/synlink_invalid

0 comments on commit 5a072fb

Please sign in to comment.