author | Alberto Bertogli
<albertito@blitiri.com.ar> 2023-04-03 02:33:11 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2023-04-03 02:33:11 UTC |
parent | 8a455f10e2b12f6d335ff570f809a6ff317b4b7b |
summer.go | +39 | -29 |
test/access.t | +9 | -0 |
test/help.t | +3 | -0 |
diff --git a/summer.go b/summer.go index c31ac59..40545ca 100644 --- a/summer.go +++ b/summer.go @@ -8,6 +8,7 @@ import ( "io/fs" "os" "path/filepath" + "syscall" ) const usage = `# summer 🌞 🏖 @@ -34,7 +35,8 @@ Flags: ` var ( - dbPath = flag.String("db", "", "database to read from/write to") + dbPath = flag.String("db", "", "database to read from/write to") + oneFilesystem = flag.Bool("x", false, "don't cross filesystem boundaries") ) func Usage() { @@ -94,39 +96,53 @@ type ChecksumV1 struct { ModTimeUsec int64 } -func isFileRelevant(path string, d fs.DirEntry, err error) bool { +func openAndInfo(path string, d fs.DirEntry, err error, rootDev uint64) (bool, *os.File, fs.FileInfo, error) { if err != nil { - return false + return false, nil, nil, err } - if d.IsDir() { - return false + if d.IsDir() || !d.Type().IsRegular() { + return false, nil, nil, nil } - return d.Type().IsRegular() -} -func openAndInfo(path string, d fs.DirEntry) (*os.File, fs.FileInfo, error) { info, err := d.Info() if err != nil { - return nil, nil, err + return true, nil, nil, err } + fd, err := os.Open(path) if err != nil { - return nil, nil, err + return true, nil, nil, err + } + + if *oneFilesystem && rootDev != getDevice(info) { + fd.Close() + return false, nil, nil, fs.SkipDir } - return fd, info, nil + return true, fd, info, nil +} + +func getDevice(info fs.FileInfo) uint64 { + return info.Sys().(*syscall.Stat_t).Dev +} + +func getDeviceForPath(path string) uint64 { + fi, err := os.Stat(path) + if err != nil { + // Doesn't matter, because we'll get an error during WalkDir. + return 0 + } + return getDevice(fi) } func generate(db DB, root string) error { + rootDev := getDeviceForPath(root) p := NewProgress() defer p.Stop() - fn := func(path string, d fs.DirEntry, err error) error { - if !isFileRelevant(path, d, err) { - return err - } - fd, info, err := openAndInfo(path, d) - if err != nil { + fn := func(path string, d fs.DirEntry, err error) error { + ok, fd, info, err := openAndInfo(path, d, err, rootDev) + if !ok || err != nil { return err } defer fd.Close() @@ -156,16 +172,13 @@ func generate(db DB, root string) error { } func verify(db DB, root string) error { + rootDev := getDeviceForPath(root) p := NewProgress() defer p.Stop() fn := func(path string, d fs.DirEntry, err error) error { - if !isFileRelevant(path, d, err) { - return err - } - - fd, info, err := openAndInfo(path, d) - if err != nil { + ok, fd, info, err := openAndInfo(path, d, err, rootDev) + if !ok || err != nil { return err } defer fd.Close() @@ -215,16 +228,13 @@ func verify(db DB, root string) error { } func update(db DB, root string) error { + rootDev := getDeviceForPath(root) p := NewProgress() defer p.Stop() fn := func(path string, d fs.DirEntry, err error) error { - if !isFileRelevant(path, d, err) { - return err - } - - fd, info, err := openAndInfo(path, d) - if err != nil { + ok, fd, info, err := openAndInfo(path, d, err, rootDev) + if !ok || err != nil { return err } defer fd.Close() diff --git a/test/access.t b/test/access.t index b0893b9..426ac8f 100644 --- a/test/access.t +++ b/test/access.t @@ -21,3 +21,12 @@ interfere. 0s: 0 matched, 0 modified, 0 new, 0 corrupted open root/empty: permission denied [1] + +Test behaviour when the root does not exist. This exercises some different +code paths, because the root is special. + + $ summer verify doesnotexist + \r (no-eol) (esc) + 0s: 0 matched, 0 modified, 0 new, 0 corrupted + lstat doesnotexist: no such file or directory + [1] diff --git a/test/help.t b/test/help.t index ffb1568..cd660c5 100644 --- a/test/help.t +++ b/test/help.t @@ -30,6 +30,7 @@ No arguments. \tdatabase to read from/write to (esc) -q\tquiet mode (esc) -v\tverbose mode (list each file) (esc) + -x\tdon't cross filesystem boundaries (esc) [1] @@ -61,6 +62,7 @@ Too few arguments. \tdatabase to read from/write to (esc) -q\tquiet mode (esc) -v\tverbose mode (list each file) (esc) + -x\tdon't cross filesystem boundaries (esc) [1] @@ -92,6 +94,7 @@ No valid path (the argument is given, but it is empty). \tdatabase to read from/write to (esc) -q\tquiet mode (esc) -v\tverbose mode (list each file) (esc) + -x\tdon't cross filesystem boundaries (esc) [1]