Skip to content

Commit 53b06a8

Browse files
authored
inotify: implement WithNoFollow() (#631)
Option to not follow symlinks, but watch the links themselves. Unexported for now, until it's supported everywhere. Updates #227
1 parent 08e056d commit 53b06a8

File tree

6 files changed

+104
-5
lines changed

6 files changed

+104
-5
lines changed

backend_inotify.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,9 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
403403
}
404404

405405
var flags uint32
406+
if with.noFollow {
407+
flags |= unix.IN_DONT_FOLLOW
408+
}
406409
if with.op.Has(Create) {
407410
flags |= unix.IN_CREATE
408411
}

fsnotify.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,9 @@ func (e Event) String() string {
188188
type (
189189
addOpt func(opt *withOpts)
190190
withOpts struct {
191-
bufsize int
192-
op Op
191+
bufsize int
192+
op Op
193+
noFollow bool
193194
}
194195
)
195196

@@ -208,7 +209,9 @@ var defaultOpts = withOpts{
208209
func getOptions(opts ...addOpt) withOpts {
209210
with := defaultOpts
210211
for _, o := range opts {
211-
o(&with)
212+
if o != nil {
213+
o(&with)
214+
}
212215
}
213216
return with
214217
}
@@ -245,6 +248,12 @@ func withOps(op Op) addOpt {
245248
return func(opt *withOpts) { opt.op = op }
246249
}
247250

251+
// WithNoFollow disables following symlinks, so the symlinks themselves are
252+
// watched.
253+
func withNoFollow() addOpt {
254+
return func(opt *withOpts) { opt.noFollow = true }
255+
}
256+
248257
var enableRecurse = false
249258

250259
// Check if this path is recursive (ends with "/..." or "\..."), and return the

helpers_test.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,15 @@ func supportsRename() bool {
669669
}
670670
}
671671

672+
func supportsNofollow(t *testing.T) {
673+
switch runtime.GOOS {
674+
case "linux":
675+
// Run test.
676+
default:
677+
t.Skip("withNoFollow() not yet supported on " + runtime.GOOS)
678+
}
679+
}
680+
672681
func tmppath(tmp, s string) string {
673682
if len(s) == 0 {
674683
return ""
@@ -812,6 +821,8 @@ loop:
812821
supportsRecurse(t)
813822
case "filter":
814823
supportsFilter(t)
824+
case "nofollow":
825+
supportsNofollow(t)
815826
case "windows":
816827
if runtime.GOOS == "windows" {
817828
t.Skip("Skipping on Windows")
@@ -852,6 +863,16 @@ loop:
852863
do = append(do, func() { addWatch(t, w.w, tmppath(tmp, c.args[0])) })
853864
continue
854865
}
866+
867+
var follow addOpt
868+
for i := range c.args {
869+
if c.args[i] == "nofollow" || c.args[i] == "no-follow" {
870+
c.args = append(c.args[:i], c.args[i+1:]...)
871+
follow = withNoFollow()
872+
break
873+
}
874+
}
875+
855876
var op Op
856877
for _, o := range c.args[1:] {
857878
switch strings.ToLower(o) {
@@ -878,11 +899,10 @@ loop:
878899
case "close_read":
879900
op |= xUnportableCloseRead
880901
}
881-
882902
}
883903
do = append(do, func() {
884904
p := tmppath(tmp, c.args[0])
885-
err := w.w.AddWith(p, withOps(op))
905+
err := w.w.AddWith(p, withOps(op), follow)
886906
if err != nil {
887907
t.Fatalf("line %d: addWatch(%q): %s", c.line+1, p, err)
888908
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Create a new symlink to a watched file.
2+
require symlink
3+
require nofollow
4+
5+
touch /file
6+
mkdir /dir
7+
8+
watch / default nofollow
9+
10+
ln -s /dir /link-file
11+
ln -s /dir /link-dir
12+
13+
rm -r /dir
14+
15+
echo asd >>/file
16+
rm /file
17+
18+
rm /link-file
19+
rm /link-dir
20+
21+
Output:
22+
create /link-dir
23+
create /link-file
24+
25+
remove /dir
26+
write /file
27+
remove /file
28+
29+
remove /link-file
30+
remove /link-dir
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Watch a symlink.
2+
require symlink
3+
require nofollow
4+
5+
mkdir /dir
6+
ln -s /dir /link
7+
watch /link default nofollow
8+
9+
touch /dir/file
10+
chmod 777 /dir
11+
12+
rm -r /dir
13+
rm /link
14+
15+
Output:
16+
chmod /link
17+
remove /link
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Watch a symlink.
2+
require symlink
3+
require nofollow
4+
5+
touch /file
6+
ln -s /file /link
7+
8+
watch /link nofollow default
9+
10+
chmod 777 /file
11+
echo asd >>/file
12+
rm /file
13+
14+
rm /link
15+
16+
touch /link
17+
18+
Output:
19+
chmod /link
20+
remove /link

0 commit comments

Comments
 (0)