summaryrefslogtreecommitdiff
path: root/source3/smbd/notify_kernel.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd/notify_kernel.c')
-rw-r--r--source3/smbd/notify_kernel.c51
1 files changed, 43 insertions, 8 deletions
diff --git a/source3/smbd/notify_kernel.c b/source3/smbd/notify_kernel.c
index 7732bc646f..f78198f207 100644
--- a/source3/smbd/notify_kernel.c
+++ b/source3/smbd/notify_kernel.c
@@ -43,6 +43,14 @@ static unsigned signals_processed;
#define RT_SIGNAL_NOTIFY 34
#endif
+#ifndef F_SETSIG
+#define F_SETSIG 10
+#endif
+
+#ifndef F_NOTIFY
+#define F_NOTIFY 1026
+#endif
+
/****************************************************************************
This is the structure to keep the information needed to
determine if a directory has changed.
@@ -73,6 +81,8 @@ static BOOL kernel_check_notify(connection_struct *conn, uint16 vuid, char *path
if (data->directory_handle != fd_pending) return False;
+ DEBUG(3,("kernel change notify on %s fd=%d\n", path, fd_pending));
+
close(fd_pending);
data->directory_handle = fd_pending = -1;
signals_processed++;
@@ -86,15 +96,17 @@ remove a change notify data structure
static void kernel_remove_notify(void *datap)
{
struct change_data *data = (struct change_data *)datap;
- if (data->directory_handle != -1) {
- if (data->directory_handle == fd_pending) {
- data->directory_handle = fd_pending = -1;
+ int fd = data->directory_handle;
+ if (fd != -1) {
+ if (fd == fd_pending) {
+ fd_pending = -1;
signals_processed++;
BlockSignals(False, RT_SIGNAL_NOTIFY);
}
- close(data->directory_handle);
+ close(fd);
}
free(data);
+ DEBUG(3,("removed kernel change notify fd=%d\n", fd));
}
@@ -107,10 +119,10 @@ static void *kernel_register_notify(connection_struct *conn, char *path, uint32
int fd;
unsigned long kernel_flags;
- fd = dos_open(fsp->fsp_name, O_RDONLY, 0);
+ fd = dos_open(path, O_RDONLY, 0);
if (fd == -1) {
- DEBUG(3,("Failed to open directory %s for change notify\n", fsp->fsp_name));
+ DEBUG(3,("Failed to open directory %s for change notify\n", path));
return NULL;
}
@@ -120,8 +132,8 @@ static void *kernel_register_notify(connection_struct *conn, char *path, uint32
}
kernel_flags = 0;
- if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags |= DN_RENAME;
- if (flags & FILE_NOTIFY_CHANGE_DIR_NAME) kernel_flags |= DN_RENAME;
+ if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags |= DN_RENAME|DN_DELETE;
+ if (flags & FILE_NOTIFY_CHANGE_DIR_NAME) kernel_flags |= DN_RENAME|DN_DELETE;
if (flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) kernel_flags |= DN_MODIFY;
if (flags & FILE_NOTIFY_CHANGE_SIZE) kernel_flags |= DN_MODIFY;
if (flags & FILE_NOTIFY_CHANGE_LAST_WRITE) kernel_flags |= DN_MODIFY;
@@ -133,11 +145,32 @@ static void *kernel_register_notify(connection_struct *conn, char *path, uint32
return NULL;
}
+ if (fcntl(fd, F_SETOWN, sys_getpid()) == -1) {
+ DEBUG(3,("Failed to set owner for change notify\n"));
+ return NULL;
+ }
+
data.directory_handle = fd;
+ DEBUG(3,("kernel change notify on %s (flags=0x%x) fd=%d\n",
+ path, (int)kernel_flags, fd));
+
return (void *)memdup(&data, sizeof(data));
}
+/****************************************************************************
+see if the kernel supports change notify
+****************************************************************************/
+static BOOL kernel_notify_available(void)
+{
+ int fd, ret;
+ fd = open("/tmp", O_RDONLY);
+ if (fd == -1) return False; /* uggh! */
+ ret = fcntl(fd, F_NOTIFY, 0);
+ close(fd);
+ return ret == 0 || errno != EINVAL;
+}
+
/****************************************************************************
setup kernel based change notify
@@ -147,6 +180,8 @@ struct cnotify_fns *kernel_notify_init(void)
static struct cnotify_fns cnotify;
struct sigaction act;
+ if (!kernel_notify_available()) return NULL;
+
act.sa_handler = NULL;
act.sa_sigaction = signal_handler;
act.sa_flags = SA_SIGINFO;