source: branches/samba-3.0/source/smbd/notify_inotify.c@ 403

Last change on this file since 403 was 124, checked in by Paul Smedley, 18 years ago

Update source to 3.0.28a

File size: 10.9 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Copyright (C) Andrew Tridgell 2006
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21/*
22 notify implementation using inotify
23*/
24
25#include "includes.h"
26
27#ifdef HAVE_INOTIFY
28
29#ifdef HAVE_ASM_TYPES_H
30#include <asm/types.h>
31#endif
32
33#ifndef HAVE_INOTIFY_INIT
34
35#include <linux/inotify.h>
36#include <asm/unistd.h>
37
38
39/*
40 glibc doesn't define these functions yet (as of March 2006)
41*/
42static int inotify_init(void)
43{
44 return syscall(__NR_inotify_init);
45}
46
47static int inotify_add_watch(int fd, const char *path, __u32 mask)
48{
49 return syscall(__NR_inotify_add_watch, fd, path, mask);
50}
51
52static int inotify_rm_watch(int fd, int wd)
53{
54 return syscall(__NR_inotify_rm_watch, fd, wd);
55}
56#else
57
58#include <sys/inotify.h>
59
60#endif
61
62
63/* older glibc headers don't have these defines either */
64#ifndef IN_ONLYDIR
65#define IN_ONLYDIR 0x01000000
66#endif
67#ifndef IN_MASK_ADD
68#define IN_MASK_ADD 0x20000000
69#endif
70
71struct inotify_private {
72 struct sys_notify_context *ctx;
73 int fd;
74 struct inotify_watch_context *watches;
75};
76
77struct inotify_watch_context {
78 struct inotify_watch_context *next, *prev;
79 struct inotify_private *in;
80 int wd;
81 void (*callback)(struct sys_notify_context *ctx,
82 void *private_data,
83 struct notify_event *ev);
84 void *private_data;
85 uint32_t mask; /* the inotify mask */
86 uint32_t filter; /* the windows completion filter */
87 const char *path;
88};
89
90
91/*
92 destroy the inotify private context
93*/
94static int inotify_destructor(struct inotify_private *in)
95{
96 close(in->fd);
97 return 0;
98}
99
100
101/*
102 see if a particular event from inotify really does match a requested
103 notify event in SMB
104*/
105static BOOL filter_match(struct inotify_watch_context *w,
106 struct inotify_event *e)
107{
108 DEBUG(10, ("filter_match: e->mask=%x, w->mask=%x, w->filter=%x\n",
109 e->mask, w->mask, w->filter));
110
111 if ((e->mask & w->mask) == 0) {
112 /* this happens because inotify_add_watch() coalesces watches on the same
113 path, oring their masks together */
114 return False;
115 }
116
117 /* SMB separates the filters for files and directories */
118 if (e->mask & IN_ISDIR) {
119 if ((w->filter & FILE_NOTIFY_CHANGE_DIR_NAME) == 0) {
120 return False;
121 }
122 } else {
123 if ((e->mask & IN_ATTRIB) &&
124 (w->filter & (FILE_NOTIFY_CHANGE_ATTRIBUTES|
125 FILE_NOTIFY_CHANGE_LAST_WRITE|
126 FILE_NOTIFY_CHANGE_LAST_ACCESS|
127 FILE_NOTIFY_CHANGE_EA|
128 FILE_NOTIFY_CHANGE_SECURITY))) {
129 return True;
130 }
131 if ((e->mask & IN_MODIFY) &&
132 (w->filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)) {
133 return True;
134 }
135 if ((w->filter & FILE_NOTIFY_CHANGE_FILE_NAME) == 0) {
136 return False;
137 }
138 }
139
140 return True;
141}
142
143
144
145/*
146 dispatch one inotify event
147
148 the cookies are used to correctly handle renames
149*/
150static void inotify_dispatch(struct inotify_private *in,
151 struct inotify_event *e,
152 uint32_t prev_cookie,
153 struct inotify_event *e2)
154{
155 struct inotify_watch_context *w, *next;
156 struct notify_event ne;
157
158 DEBUG(10, ("inotify_dispatch called with mask=%x, name=[%s]\n",
159 e->mask, e->len ? e->name : ""));
160
161 /* ignore extraneous events, such as unmount and IN_IGNORED events */
162 if ((e->mask & (IN_ATTRIB|IN_MODIFY|IN_CREATE|IN_DELETE|
163 IN_MOVED_FROM|IN_MOVED_TO)) == 0) {
164 return;
165 }
166
167 /* map the inotify mask to a action. This gets complicated for
168 renames */
169 if (e->mask & IN_CREATE) {
170 ne.action = NOTIFY_ACTION_ADDED;
171 } else if (e->mask & IN_DELETE) {
172 ne.action = NOTIFY_ACTION_REMOVED;
173 } else if (e->mask & IN_MOVED_FROM) {
174 if (e2 != NULL && e2->cookie == e->cookie) {
175 ne.action = NOTIFY_ACTION_OLD_NAME;
176 } else {
177 ne.action = NOTIFY_ACTION_REMOVED;
178 }
179 } else if (e->mask & IN_MOVED_TO) {
180 if (e->cookie == prev_cookie) {
181 ne.action = NOTIFY_ACTION_NEW_NAME;
182 } else {
183 ne.action = NOTIFY_ACTION_ADDED;
184 }
185 } else {
186 ne.action = NOTIFY_ACTION_MODIFIED;
187 }
188 ne.path = e->name;
189
190 DEBUG(10, ("inotify_dispatch: ne.action = %d, ne.path = %s\n",
191 ne.action, ne.path));
192
193 /* find any watches that have this watch descriptor */
194 for (w=in->watches;w;w=next) {
195 next = w->next;
196 if (w->wd == e->wd && filter_match(w, e)) {
197 w->callback(in->ctx, w->private_data, &ne);