carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1//go:build unix
2
3package hostfiles
4
5import (
6 "context"
7 "errors"
8
9 "golang.org/x/sys/unix"
10)
11
12// syncTree walks the tree beneath root by descriptor and calls visit for
13// every entry that is not a directory, with the open directory that holds
14// it, its name there, and its path relative to root. It never follows a
15// symlink and never blocks on a FIFO: a directory is entered only through
16// openDir.
17//
18// The walk is bounded (withinTreeCap): a path past MaxPathBytes refuses
19// the whole walk with ErrTooDeep, never a
20// silent skip, so a tree no restore could recreate is never published as
21// complete, and a chain of directories cannot make the walk's memory grow
22// with the square of its depth. ctx is checked on entering every
23// directory, so a deep tree with no files still stops when cancelled.
24func syncTree(ctx context.Context, root *dirHandle, p *Publisher, skip func(string, bool) bool, visit func(d *dirHandle, name, rel string) error) error {
25 return walkDir(ctx, root, "", skip, visit)
26}
27
28func walkDir(ctx context.Context, d *dirHandle, prefix string, skip func(string, bool) bool, visit func(d *dirHandle, name, rel string) error) error {
29 if err := ctx.Err(); err != nil {
30 return err
31 }
32 names, err := d.names()
33 if err != nil {
34 return err
35 }
36 for _, name := range names {
37 rel := name
38 if prefix != "" {
39 rel = prefix + "/" + name
40 }
41 st, err := d.look(name)
42 if errors.Is(err, unix.ENOENT) {
43 continue
44 }
45 if err != nil {
46 return err
47 }
48 if !isDir(st) {
49 if skipped(skip, rel, false) {
50 continue
51 }
52 if err := withinTreeCap(rel); err != nil {
53 return err
54 }
55 if err := visit(d, name, rel); err != nil {
56 return err
57 }
58 continue
59 }
60 if skipped(skip, rel, true) {
61 continue
62 }
63 if err := withinTreeCap(rel); err != nil {
64 return err
65 }
66 betweenLookAndOpen()
67 sub, err := d.openDir(name)
68 if err != nil {
69 if errors.Is(err, unix.ENOENT) {
70 continue
71 }
72 if notADirectory(err) {
73 // It was a directory a moment ago and is something else
74 // now. Let readStable say what: it will not follow or
75 // block on it either.
76 if err := visit(d, name, rel); err != nil {
77 return err
78 }
79 continue
80 }
81 return err
82 }
83 err = walkDir(ctx, sub, rel, skip, visit)
84 sub.Close()
85 if err != nil {
86 return err
87 }
88 }
89 return nil
90}
91