r21093: Remove the hash and dnotify backends. Disabling FAM for this checkin, I'm
[samba.git] / source3 / smbd / notify_fam.c
1 /*
2  * FAM file notification support.
3  *
4  * Copyright (c) James Peach 2005
5  * Copyright (c) Volker Lendecke 2007
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
20  */
21
22 #include "includes.h"
23
24 #if 0
25
26 #include <fam.h>
27
28 #if !defined(HAVE_FAM_H_FAMCODES_TYPEDEF)
29 /* Gamin provides this typedef which means we can't use 'enum FAMCodes' as per
30  * every other FAM implementation. Phooey.
31  */
32 typedef enum FAMCodes FAMCodes;
33 #endif
34
35 /* NOTE: There are multiple versions of FAM floating around the net, each with
36  * slight differences from the original SGI FAM implementation. In this file,
37  * we rely only on the SGI features and do not assume any extensions. For
38  * example, we do not look at FAMErrno, because it is not set by the original
39  * implementation.
40  *
41  * Random FAM links:
42  *      http://oss.sgi.com/projects/fam/
43  *      http://savannah.nongnu.org/projects/fam/
44  *      http://sourceforge.net/projects/bsdfam/
45  */
46
47 static void *fam_notify_add(TALLOC_CTX *mem_ctx,
48                             struct event_context *event_ctx,
49                             files_struct *fsp, uint32 *filter);
50
51 /* ------------------------------------------------------------------------- */
52
53 struct fam_notify_ctx {
54         struct fam_notify_ctx *prev, *next;
55         FAMConnection *fam_connection;
56         struct FAMRequest fr;
57         files_struct *fsp;
58         char *path;
59         uint32 filter;
60 };
61
62 static struct fam_notify_ctx *fam_notify_list;
63 static FAMConnection fam_connection;
64 static void fam_handler(struct event_context *event_ctx,
65                         struct fd_event *fd_event,
66                         uint16 flags,
67                         void *private_data);
68
69 static NTSTATUS fam_open_connection(FAMConnection *fam_conn,
70                                     struct event_context *event_ctx)
71 {
72         int res;
73         char *name;
74
75         ZERO_STRUCTP(fam_conn);
76         FAMCONNECTION_GETFD(fam_conn) = -1;
77
78         if (asprintf(&name, "smbd (%lu)", (unsigned long)sys_getpid()) == -1) {
79                 DEBUG(0, ("No memory\n"));
80                 return NT_STATUS_NO_MEMORY;
81         }
82
83         res = FAMOpen2(fam_conn, name);
84         SAFE_FREE(name);
85
86         if (res < 0) {
87                 DEBUG(5, ("FAM file change notifications not available\n"));
88                 /*
89                  * No idea how to get NT_STATUS from a FAM result
90                  */
91                 FAMCONNECTION_GETFD(fam_conn) = -1;
92                 return NT_STATUS_UNEXPECTED_IO_ERROR;
93         }
94
95         if (event_add_fd(event_ctx, event_ctx,
96                          FAMCONNECTION_GETFD(fam_conn),
97                          EVENT_FD_READ, fam_handler,
98                          (void *)fam_conn) == NULL) {
99                 DEBUG(0, ("event_add_fd failed\n"));
100                 FAMClose(fam_conn);
101                 FAMCONNECTION_GETFD(fam_conn) = -1;
102                 return NT_STATUS_NO_MEMORY;
103         }
104
105         return NT_STATUS_OK;
106 }
107
108 static void fam_reopen(FAMConnection *fam_conn,
109                        struct event_context *event_ctx,
110                        struct fam_notify_ctx *notify_list)
111 {
112         struct fam_notify_ctx *ctx;
113
114         DEBUG(5, ("Re-opening FAM connection\n"));
115
116         FAMClose(fam_conn);
117
118         if (!NT_STATUS_IS_OK(fam_open_connection(fam_conn, event_ctx))) {
119                 DEBUG(5, ("Re-opening fam connection failed\n"));
120                 return;
121         }
122
123         for (ctx = notify_list; ctx; ctx = ctx->next) {
124                 FAMMonitorDirectory(fam_conn, ctx->path, &ctx->fr, NULL);
125         }
126 }
127
128 static void fam_handler(struct event_context *event_ctx,
129                         struct fd_event *fd_event,
130                         uint16 flags,
131                         void *private_data)
132 {
133         FAMConnection *fam_conn = (FAMConnection *)private_data;
134         FAMEvent fam_event;
135         struct fam_notify_ctx *ctx;
136         char *name;
137
138         if (FAMPending(fam_conn) == 0) {
139                 DEBUG(10, ("fam_handler called but nothing pending\n"));
140                 return;
141         }
142
143         if (FAMNextEvent(fam_conn, &fam_event) != 1) {
144                 DEBUG(10, ("FAMNextEvent returned an error\n"));
145                 TALLOC_FREE(fd_event);
146                 fam_reopen(fam_conn, event_ctx, fam_notify_list);
147                 return;
148         }
149
150         if ((fam_event.code != FAMCreated) && (fam_event.code != FAMDeleted)) {
151                 DEBUG(10, ("Ignoring code FAMCode %d for file %s\n",
152                            (int)fam_event.code, fam_event.filename));
153                 return;
154         }
155
156         for (ctx = fam_notify_list; ctx; ctx = ctx->next) {
157                 if (memcmp(&fam_event.fr, &ctx->fr, sizeof(FAMRequest)) == 0) {
158                         break;
159                 }
160         }
161
162         if (ctx == NULL) {
163                 DEBUG(5, ("Discarding event for file %s\n",
164                           fam_event.filename));
165                 return;
166         }
167
168         if ((name = strrchr_m(fam_event.filename, '\\')) == NULL) {
169                 name = fam_event.filename;
170         }
171
172         notify_fsp(ctx->fsp,
173                    fam_event.code == FAMCreated
174                    ? NOTIFY_ACTION_ADDED : NOTIFY_ACTION_REMOVED,
175                    name);
176 }
177
178 static int fam_notify_ctx_destructor(struct fam_notify_ctx *ctx)
179 {
180         if (FAMCONNECTION_GETFD(ctx->fam_connection) != -1) {
181                 FAMCancelMonitor(&fam_connection, &ctx->fr);
182         }
183         DLIST_REMOVE(fam_notify_list, ctx);
184         return 0;
185 }
186
187 static void *fam_notify_add(TALLOC_CTX *mem_ctx,
188                             struct event_context *event_ctx,
189                             files_struct *fsp, uint32 *filter)
190 {
191         struct fam_notify_ctx *ctx;
192
193         if ((*filter & FILE_NOTIFY_CHANGE_FILE_NAME) == 0) {
194                 DEBUG(10, ("filter = %u, no FILE_NOTIFY_CHANGE_FILE_NAME\n",
195                            *filter));
196                 return NULL;
197         }
198
199         if (!(ctx = TALLOC_P(mem_ctx, struct fam_notify_ctx))) {
200                 return NULL;
201         }
202
203         ctx->fsp = fsp;
204         ctx->fam_connection = &fam_connection;
205
206         /*
207          * The FAM module in this early state will only take care of
208          * FAMCreated and FAMDeleted events
209          */
210
211         ctx->filter = FILE_NOTIFY_CHANGE_FILE_NAME;
212
213         if (!(ctx->path = talloc_asprintf(ctx, "%s/%s", fsp->conn->connectpath,
214                                           fsp->fsp_name))) {
215                 DEBUG(0, ("talloc_asprintf failed\n"));
216                 TALLOC_FREE(ctx);
217                 return NULL;
218         }
219
220         /*
221          * Leave the rest to smbd itself
222          */
223
224         *filter &= ~FILE_NOTIFY_CHANGE_FILE_NAME;
225
226         DLIST_ADD(fam_notify_list, ctx);
227         talloc_set_destructor(ctx, fam_notify_ctx_destructor);
228
229         /*
230          * Only directories monitored so far
231          */
232
233         if (FAMCONNECTION_GETFD(ctx->fam_connection) != -1) {
234                 FAMMonitorDirectory(ctx->fam_connection, ctx->path, &ctx->fr,
235                                     NULL);
236         }
237         else {
238                 /*
239                  * If the re-open is successful, this will establish the
240                  * FAMMonitor from the list
241                  */
242                 fam_reopen(ctx->fam_connection, event_ctx, fam_notify_list);
243         }
244
245         return ctx;
246 }
247
248 static struct cnotify_fns global_fam_notify =
249 {
250     fam_notify_add,
251 };
252
253 struct cnotify_fns *fam_notify_init(struct event_context *event_ctx)
254 {
255
256         ZERO_STRUCT(fam_connection);
257         FAMCONNECTION_GETFD(&fam_connection) = -1;
258
259         if (!NT_STATUS_IS_OK(fam_open_connection(&fam_connection,
260                                                  event_ctx))) {
261                 DEBUG(0, ("FAM file change notifications not available\n"));
262                 return NULL;
263         }
264
265         DEBUG(10, ("enabling FAM change notifications\n"));
266         return &global_fam_notify;
267 }
268
269 #endif /* HAVE_FAM_CHANGE_NOTIFY */