mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
r21093: Remove the hash and dnotify backends. Disabling FAM for this checkin, I'm
working on that right now.
Volker
(This used to be commit 01c9fb1728
)
This commit is contained in:
parent
2852ecc67e
commit
9974656d3b
@ -408,8 +408,8 @@ PROFILES_OBJ = utils/profiles.o \
|
||||
|
||||
OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o
|
||||
|
||||
NOTIFY_OBJ = smbd/notify.o smbd/notify_hash.o smbd/notify_kernel.o \
|
||||
smbd/notify_fam.o smbd/notify_inotify.o smbd/notify_internal.o
|
||||
NOTIFY_OBJ = smbd/notify.o smbd/notify_fam.o smbd/notify_inotify.o \
|
||||
smbd/notify_internal.o
|
||||
|
||||
VFS_DEFAULT_OBJ = modules/vfs_default.o
|
||||
VFS_AUDIT_OBJ = modules/vfs_audit.o
|
||||
|
@ -1685,15 +1685,6 @@ struct kernel_oplocks {
|
||||
int notification_fd;
|
||||
};
|
||||
|
||||
|
||||
/* this structure defines the functions for doing change notify in
|
||||
various implementations */
|
||||
struct cnotify_fns {
|
||||
void *(*notify_add)(TALLOC_CTX *mem_ctx,
|
||||
struct event_context *event_ctx,
|
||||
files_struct *fsp, uint32 *filter);
|
||||
};
|
||||
|
||||
#include "smb_macros.h"
|
||||
|
||||
#define MAX_NETBIOSNAME_LEN 16
|
||||
|
@ -22,7 +22,6 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
static struct cnotify_fns *cnotify;
|
||||
static struct notify_mid_map *notify_changes_by_mid;
|
||||
|
||||
/*
|
||||
@ -262,157 +261,6 @@ void remove_pending_change_notify_requests_by_fid(files_struct *fsp,
|
||||
}
|
||||
}
|
||||
|
||||
/* notify message definition
|
||||
|
||||
Offset Data length.
|
||||
0 SMB_DEV_T dev 8
|
||||
8 SMB_INO_T inode 8
|
||||
16 uint32 filter 4
|
||||
20 uint32 action 4
|
||||
24.. name
|
||||
*/
|
||||
|
||||
#define MSG_NOTIFY_MESSAGE_SIZE 25 /* Includes at least the '\0' terminator */
|
||||
|
||||
struct notify_message {
|
||||
SMB_DEV_T dev;
|
||||
SMB_INO_T inode;
|
||||
uint32 filter;
|
||||
uint32 action;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static DATA_BLOB notify_message_to_buf(const struct notify_message *msg)
|
||||
{
|
||||
DATA_BLOB result;
|
||||
size_t len;
|
||||
|
||||
len = strlen(msg->name);
|
||||
|
||||
result = data_blob(NULL, MSG_NOTIFY_MESSAGE_SIZE + len);
|
||||
if (!result.data) {
|
||||
return result;
|
||||
}
|
||||
|
||||
SDEV_T_VAL(result.data, 0, msg->dev);
|
||||
SINO_T_VAL(result.data, 8, msg->inode);
|
||||
SIVAL(result.data, 16, msg->filter);
|
||||
SIVAL(result.data, 20, msg->action);
|
||||
memcpy(result.data+24, msg->name, len+1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL buf_to_notify_message(void *buf, size_t len,
|
||||
struct notify_message *msg)
|
||||
{
|
||||
if (len < MSG_NOTIFY_MESSAGE_SIZE) {
|
||||
DEBUG(0, ("Got invalid notify message of len %d\n",
|
||||
(int)len));
|
||||
return False;
|
||||
}
|
||||
|
||||
msg->dev = DEV_T_VAL(buf, 0);
|
||||
msg->inode = INO_T_VAL(buf, 8);
|
||||
msg->filter = IVAL(buf, 16);
|
||||
msg->action = IVAL(buf, 20);
|
||||
msg->name = ((char *)buf)+24;
|
||||
return True;
|
||||
}
|
||||
|
||||
void notify_action(connection_struct *conn, const char *parent,
|
||||
const char *name, uint32 filter, uint32_t action)
|
||||
{
|
||||
struct share_mode_lock *lck;
|
||||
SMB_STRUCT_STAT sbuf;
|
||||
int i;
|
||||
struct notify_message msg;
|
||||
DATA_BLOB blob;
|
||||
|
||||
struct process_id *pids;
|
||||
int num_pids;
|
||||
|
||||
DEBUG(10, ("notify_action: parent=%s, name=%s, action=%u\n",
|
||||
parent, name, (unsigned)action));
|
||||
|
||||
if (SMB_VFS_STAT(conn, parent, &sbuf) != 0) {
|
||||
/*
|
||||
* Not 100% critical, ignore failure
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
char *fullpath;
|
||||
|
||||
if (asprintf(&fullpath, "%s/%s/%s", conn->connectpath,
|
||||
parent, name) != -1) {
|
||||
notify_trigger(conn->notify_ctx, action, filter,
|
||||
fullpath);
|
||||
SAFE_FREE(fullpath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(lck = get_share_mode_lock(NULL, sbuf.st_dev, sbuf.st_ino,
|
||||
NULL, NULL))) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg.dev = sbuf.st_dev;
|
||||
msg.inode = sbuf.st_ino;
|
||||
msg.filter = filter;
|
||||
msg.action = action;
|
||||
msg.name = CONST_DISCARD(char *, name);
|
||||
|
||||
blob = notify_message_to_buf(&msg);
|
||||
if (blob.data == NULL) {
|
||||
DEBUG(0, ("notify_message_to_buf failed\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
pids = NULL;
|
||||
num_pids = 0;
|
||||
|
||||
become_root_uid_only();
|
||||
|
||||
for (i=0; i<lck->num_share_modes; i++) {
|
||||
struct share_mode_entry *e = &lck->share_modes[i];
|
||||
int j;
|
||||
struct process_id *tmp;
|
||||
|
||||
for (j=0; j<num_pids; j++) {
|
||||
if (procid_equal(&e->pid, &pids[j])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j < num_pids) {
|
||||
/*
|
||||
* Already sent to that process, skip it
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
message_send_pid(lck->share_modes[i].pid, MSG_SMB_NOTIFY,
|
||||
blob.data, blob.length, True);
|
||||
|
||||
if (!(tmp = TALLOC_REALLOC_ARRAY(lck, pids, struct process_id,
|
||||
num_pids+1))) {
|
||||
DEBUG(0, ("realloc failed\n"));
|
||||
break;
|
||||
}
|
||||
pids = tmp;
|
||||
pids[num_pids] = e->pid;
|
||||
num_pids += 1;
|
||||
}
|
||||
|
||||
unbecome_root_uid_only();
|
||||
|
||||
data_blob_free(&blob);
|
||||
TALLOC_FREE(lck);
|
||||
}
|
||||
|
||||
void notify_fname(connection_struct *conn, uint32 action, uint32 filter,
|
||||
const char *path)
|
||||
{
|
||||
@ -514,30 +362,6 @@ void notify_fsp(files_struct *fsp, uint32 action, const char *name)
|
||||
fsp->notify->num_changes = 0;
|
||||
}
|
||||
|
||||
static void notify_message_callback(int msgtype, struct process_id pid,
|
||||
void *buf, size_t len,
|
||||
void *private_data)
|
||||
{
|
||||
struct notify_message msg;
|
||||
files_struct *fsp;
|
||||
|
||||
if (!buf_to_notify_message(buf, len, &msg)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(10, ("Received notify_message for 0x%x/%.0f: %d\n",
|
||||
(unsigned)msg.dev, (double)msg.inode, msg.action));
|
||||
|
||||
for(fsp = fsp_find_di_first(msg.dev, msg.inode); fsp;
|
||||
fsp = fsp_find_di_next(fsp)) {
|
||||
if ((fsp->notify != NULL)
|
||||
&& (fsp->notify->requests != NULL)
|
||||
&& (fsp->notify->requests->filter & msg.filter)) {
|
||||
notify_fsp(fsp, msg.action, msg.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter)
|
||||
{
|
||||
char *result = NULL;
|
||||
@ -576,34 +400,6 @@ char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter)
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Initialise the change notify subsystem.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL init_change_notify(void)
|
||||
{
|
||||
cnotify = NULL;
|
||||
|
||||
#if HAVE_KERNEL_CHANGE_NOTIFY
|
||||
if (cnotify == NULL && lp_kernel_change_notify())
|
||||
cnotify = kernel_notify_init(smbd_event_context());
|
||||
#endif
|
||||
#if HAVE_FAM_CHANGE_NOTIFY
|
||||
if (cnotify == NULL && lp_fam_change_notify())
|
||||
cnotify = fam_notify_init(smbd_event_context());
|
||||
#endif
|
||||
if (!cnotify) cnotify = hash_notify_init();
|
||||
|
||||
if (!cnotify) {
|
||||
DEBUG(0,("Failed to init change notify system\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
message_register(MSG_SMB_NOTIFY, notify_message_callback, NULL);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
struct sys_notify_context *sys_notify_context_create(struct share_params *scfg,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct event_context *ev)
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef HAVE_FAM_CHANGE_NOTIFY
|
||||
#if 0
|
||||
|
||||
#include <fam.h>
|
||||
|
||||
|
@ -1,278 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
change notify handling - hash based implementation
|
||||
Copyright (C) Jeremy Allison 1994-1998
|
||||
Copyright (C) Andrew Tridgell 2000
|
||||
Copyright (C) Volker Lendecke 2007
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
struct hash_change_data {
|
||||
time_t last_check_time; /* time we last checked this entry */
|
||||
struct timespec modify_time; /* Info from the directory we're
|
||||
* monitoring. */
|
||||
struct timespec status_time; /* Info from the directory we're
|
||||
* monitoring. */
|
||||
time_t total_time; /* Total time of all directory entries - don't care
|
||||
* if it wraps. */
|
||||
unsigned int num_entries; /* Zero or the number of files in the
|
||||
* directory. */
|
||||
unsigned int mode_sum;
|
||||
unsigned char name_hash[16];
|
||||
};
|
||||
|
||||
struct hash_notify_ctx {
|
||||
struct hash_change_data *data;
|
||||
files_struct *fsp;
|
||||
char *path;
|
||||
uint32 filter;
|
||||
};
|
||||
|
||||
/* Compare struct timespec. */
|
||||
#define TIMESTAMP_NEQ(x, y) (((x).tv_sec != (y).tv_sec) || ((x).tv_nsec != (y).tv_nsec))
|
||||
|
||||
/****************************************************************************
|
||||
Create the hash we will use to determine if the contents changed.
|
||||
*****************************************************************************/
|
||||
|
||||
static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
|
||||
struct hash_change_data *data,
|
||||
struct hash_change_data *old_data)
|
||||
{
|
||||
SMB_STRUCT_STAT st;
|
||||
pstring full_name;
|
||||
char *p;
|
||||
const char *fname;
|
||||
size_t remaining_len;
|
||||
size_t fullname_len;
|
||||
struct smb_Dir *dp;
|
||||
long offset;
|
||||
|
||||
ZERO_STRUCTP(data);
|
||||
|
||||
if(SMB_VFS_STAT(conn,path, &st) == -1)
|
||||
return False;
|
||||
|
||||
data->modify_time = get_mtimespec(&st);
|
||||
data->status_time = get_ctimespec(&st);
|
||||
|
||||
if (old_data) {
|
||||
/*
|
||||
* Shortcut to avoid directory scan if the time
|
||||
* has changed - we always must return true then.
|
||||
*/
|
||||
if (TIMESTAMP_NEQ(old_data->modify_time, data->modify_time) ||
|
||||
TIMESTAMP_NEQ(old_data->status_time, data->status_time) ) {
|
||||
return True;
|
||||
}
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode) &&
|
||||
(flags & ~(FILE_NOTIFY_CHANGE_FILE_NAME
|
||||
| FILE_NOTIFY_CHANGE_DIR_NAME)) == 0)
|
||||
{
|
||||
/* This is the case of a client wanting to know only when
|
||||
* the contents of a directory changes. Since any file
|
||||
* creation, rename or deletion will update the directory
|
||||
* timestamps, we don't need to create a hash.
|
||||
*/
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are to watch for changes that are only stored
|
||||
* in inodes of files, not in the directory inode, we must
|
||||
* scan the directory and produce a unique identifier with
|
||||
* which we can determine if anything changed. We use the
|
||||
* modify and change times from all the files in the
|
||||
* directory, added together (ignoring wrapping if it's
|
||||
* larger than the max time_t value).
|
||||
*/
|
||||
|
||||
dp = OpenDir(conn, path, NULL, 0);
|
||||
if (dp == NULL)
|
||||
return False;
|
||||
|
||||
data->num_entries = 0;
|
||||
|
||||
pstrcpy(full_name, path);
|
||||
pstrcat(full_name, "/");
|
||||
|
||||
fullname_len = strlen(full_name);
|
||||
remaining_len = sizeof(full_name) - fullname_len - 1;
|
||||
p = &full_name[fullname_len];
|
||||
|
||||
offset = 0;
|
||||
while ((fname = ReadDirName(dp, &offset))) {
|
||||
SET_STAT_INVALID(st);
|
||||
if(strequal(fname, ".") || strequal(fname, ".."))
|
||||
continue;
|
||||
|
||||
if (!is_visible_file(conn, path, fname, &st, True))
|
||||
continue;
|
||||
|
||||
data->num_entries++;
|
||||
safe_strcpy(p, fname, remaining_len);
|
||||
|
||||
/*
|
||||
* Do the stat - but ignore errors.
|
||||
*/
|
||||
if (!VALID_STAT(st)) {
|
||||
SMB_VFS_STAT(conn,full_name, &st);
|
||||
}
|
||||
|
||||
/*
|
||||
* Always sum the times.
|
||||
*/
|
||||
|
||||
data->total_time += (st.st_mtime + st.st_ctime);
|
||||
|
||||
/*
|
||||
* If requested hash the names.
|
||||
*/
|
||||
|
||||
if (flags & (FILE_NOTIFY_CHANGE_DIR_NAME
|
||||
|FILE_NOTIFY_CHANGE_FILE_NAME)) {
|
||||
int i;
|
||||
unsigned char tmp_hash[16];
|
||||
mdfour(tmp_hash, (const unsigned char *)fname,
|
||||
strlen(fname));
|
||||
for (i=0;i<16;i++)
|
||||
data->name_hash[i] ^= tmp_hash[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* If requested sum the mode_t's.
|
||||
*/
|
||||
|
||||
if (flags & (FILE_NOTIFY_CHANGE_ATTRIBUTES
|
||||
|FILE_NOTIFY_CHANGE_SECURITY))
|
||||
data->mode_sum += st.st_mode;
|
||||
}
|
||||
|
||||
CloseDir(dp);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static void hash_change_notify_handler(struct event_context *event_ctx,
|
||||
struct timed_event *te,
|
||||
const struct timeval *now,
|
||||
void *private_data)
|
||||
{
|
||||
struct hash_change_data *new_data;
|
||||
struct hash_notify_ctx *ctx =
|
||||
talloc_get_type_abort(private_data,
|
||||
struct hash_notify_ctx);
|
||||
|
||||
TALLOC_FREE(te);
|
||||
|
||||
if (!(new_data = TALLOC_P(ctx, struct hash_change_data))) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
/*
|
||||
* No new timed event;
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (!notify_hash(ctx->fsp->conn, ctx->fsp->fsp_name,
|
||||
ctx->filter, new_data, ctx->data)
|
||||
|| TIMESTAMP_NEQ(new_data->modify_time, ctx->data->modify_time)
|
||||
|| TIMESTAMP_NEQ(new_data->status_time, ctx->data->status_time)
|
||||
|| new_data->total_time != ctx->data->total_time
|
||||
|| new_data->num_entries != ctx->data->num_entries
|
||||
|| new_data->mode_sum != ctx->data->mode_sum
|
||||
|| (memcmp(new_data->name_hash, ctx->data->name_hash,
|
||||
sizeof(new_data->name_hash)))) {
|
||||
notify_fsp(ctx->fsp, 0, NULL);
|
||||
}
|
||||
|
||||
TALLOC_FREE(ctx->data);
|
||||
ctx->data = new_data;
|
||||
|
||||
event_add_timed(
|
||||
event_ctx, ctx,
|
||||
timeval_current_ofs(
|
||||
lp_change_notify_timeout(SNUM(ctx->fsp->conn)), 0),
|
||||
"hash_change_notify_handler",
|
||||
hash_change_notify_handler, ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void *hash_notify_add(TALLOC_CTX *mem_ctx,
|
||||
struct event_context *event_ctx,
|
||||
files_struct *fsp,
|
||||
uint32 *filter)
|
||||
{
|
||||
struct hash_notify_ctx *ctx;
|
||||
int timeout = lp_change_notify_timeout(SNUM(fsp->conn));
|
||||
|
||||
if (timeout <= 0) {
|
||||
/* It change notify timeout has been disabled, never scan the
|
||||
* directory. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(ctx = TALLOC_P(mem_ctx, struct hash_notify_ctx))) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(ctx->path = talloc_asprintf(ctx, "%s/%s", fsp->conn->connectpath,
|
||||
fsp->fsp_name))) {
|
||||
DEBUG(0, ("talloc_asprintf failed\n"));
|
||||
TALLOC_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(ctx->data = TALLOC_P(ctx, struct hash_change_data))) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
TALLOC_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->fsp = fsp;
|
||||
|
||||
/*
|
||||
* Don't change the Samba filter, hash can only be a very bad attempt
|
||||
* anyway.
|
||||
*/
|
||||
ctx->filter = *filter;
|
||||
|
||||
notify_hash(fsp->conn, ctx->path, ctx->filter, ctx->data, NULL);
|
||||
|
||||
event_add_timed(event_ctx, ctx, timeval_current_ofs(timeout, 0),
|
||||
"hash_change_notify_handler",
|
||||
hash_change_notify_handler, ctx);
|
||||
|
||||
return (void *)ctx;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Setup hash based change notify.
|
||||
****************************************************************************/
|
||||
|
||||
struct cnotify_fns *hash_notify_init(void)
|
||||
{
|
||||
static struct cnotify_fns cnotify;
|
||||
|
||||
cnotify.notify_add = hash_notify_add;
|
||||
|
||||
return &cnotify;
|
||||
}
|
@ -1,287 +0,0 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 3.0
|
||||
change notify handling - linux kernel based implementation
|
||||
Copyright (C) Andrew Tridgell 2000
|
||||
Copyright (C) Volker Lendecke 2007
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#if HAVE_KERNEL_CHANGE_NOTIFY
|
||||
|
||||
#ifndef DN_ACCESS
|
||||
#define DN_ACCESS 0x00000001 /* File accessed in directory */
|
||||
#define DN_MODIFY 0x00000002 /* File modified in directory */
|
||||
#define DN_CREATE 0x00000004 /* File created in directory */
|
||||
#define DN_DELETE 0x00000008 /* File removed from directory */
|
||||
#define DN_RENAME 0x00000010 /* File renamed in directory */
|
||||
#define DN_ATTRIB 0x00000020 /* File changed attribute */
|
||||
#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef RT_SIGNAL_NOTIFY
|
||||
#define RT_SIGNAL_NOTIFY (SIGRTMIN+2)
|
||||
#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.
|
||||
*****************************************************************************/
|
||||
|
||||
struct dnotify_ctx {
|
||||
struct dnotify_ctx *prev, *next;
|
||||
|
||||
int fd;
|
||||
files_struct *fsp;
|
||||
};
|
||||
|
||||
static struct dnotify_ctx *dnotify_list;
|
||||
static int dnotify_signal_pipe[2];
|
||||
|
||||
/****************************************************************************
|
||||
The signal handler for change notify.
|
||||
The Linux kernel has a bug in that we should be able to block any
|
||||
further delivery of RT signals until the kernel_check_notify() function
|
||||
unblocks them, but it seems that any signal mask we're setting here is
|
||||
being overwritten on exit from this handler. I should create a standalone
|
||||
test case for the kernel hackers. JRA.
|
||||
*****************************************************************************/
|
||||
|
||||
static void dnotify_signal_handler(int sig, siginfo_t *info, void *unused)
|
||||
{
|
||||
int saved_errno;
|
||||
|
||||
/*
|
||||
* According to http://www.opengroup.org/onlinepubs/009695399/ write
|
||||
* to a pipe either writes all or nothing, so we can safely write a
|
||||
* full sizeof(int) and not risk the pipe to become out of sync with
|
||||
* the receiving end.
|
||||
*
|
||||
* We don't care about the result of the write() call. If the pipe is
|
||||
* full, then this signal is lost, we can't do anything about it.
|
||||
*/
|
||||
|
||||
saved_errno = errno;
|
||||
write(dnotify_signal_pipe[1], (const void *)&info->si_fd, sizeof(int));
|
||||
errno = saved_errno;
|
||||
|
||||
sys_select_signal(RT_SIGNAL_NOTIFY);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
The upper level handler informed when the pipe is ready for reading
|
||||
*****************************************************************************/
|
||||
|
||||
static void dnotify_pipe_handler(struct event_context *event_ctx,
|
||||
struct fd_event *event,
|
||||
uint16 flags,
|
||||
void *private_data)
|
||||
{
|
||||
int res, fd;
|
||||
struct dnotify_ctx *ctx;
|
||||
|
||||
res = read(dnotify_signal_pipe[0], (void *)&fd, sizeof(int));
|
||||
|
||||
if (res == -1) {
|
||||
DEBUG(0, ("Read from the dnotify pipe failed: %s\n",
|
||||
strerror(errno)));
|
||||
TALLOC_FREE(event); /* Don't try again */
|
||||
return;
|
||||
}
|
||||
|
||||
if (res != sizeof(int)) {
|
||||
smb_panic("read from dnotify pipe gave wrong number of "
|
||||
"bytes\n");
|
||||
}
|
||||
|
||||
for (ctx = dnotify_list; ctx; ctx = ctx->next) {
|
||||
if (ctx->fd == fd) {
|
||||
notify_fsp(ctx->fsp, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Register a change notify request.
|
||||
*****************************************************************************/
|
||||
|
||||
static int kernel_register_notify(connection_struct *conn, char *path,
|
||||
uint32 flags)
|
||||
{
|
||||
int fd;
|
||||
unsigned long kernel_flags;
|
||||
|
||||
fd = sys_open(path,O_RDONLY, 0);
|
||||
|
||||
if (fd == -1) {
|
||||
DEBUG(3,("Failed to open directory %s for change notify\n",
|
||||
path));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sys_fcntl_long(fd, F_SETSIG, RT_SIGNAL_NOTIFY) == -1) {
|
||||
DEBUG(3,("Failed to set signal handler for change notify\n"));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
kernel_flags = DN_CREATE|DN_DELETE|DN_RENAME; /* creation/deletion
|
||||
* changes
|
||||
* everything! */
|
||||
if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags |= DN_MODIFY;
|
||||
if (flags & FILE_NOTIFY_CHANGE_DIR_NAME) kernel_flags
|
||||
|= DN_RENAME
|
||||
|DN_DELETE;
|
||||
if (flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) kernel_flags |= DN_ATTRIB;
|
||||
if (flags & FILE_NOTIFY_CHANGE_SIZE) kernel_flags |= DN_MODIFY;
|
||||
if (flags & FILE_NOTIFY_CHANGE_LAST_WRITE) kernel_flags |= DN_MODIFY;
|
||||
if (flags & FILE_NOTIFY_CHANGE_LAST_ACCESS) kernel_flags |= DN_ACCESS;
|
||||
if (flags & FILE_NOTIFY_CHANGE_CREATION) kernel_flags |= DN_CREATE;
|
||||
if (flags & FILE_NOTIFY_CHANGE_SECURITY) kernel_flags |= DN_ATTRIB;
|
||||
if (flags & FILE_NOTIFY_CHANGE_EA) kernel_flags |= DN_ATTRIB;
|
||||
if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags
|
||||
|= DN_RENAME
|
||||
|DN_DELETE;
|
||||
|
||||
if (sys_fcntl_long(fd, F_NOTIFY, kernel_flags) == -1) {
|
||||
DEBUG(3,("Failed to set async flag for change notify\n"));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG(3,("kernel change notify on %s (ntflags=0x%x flags=0x%x) "
|
||||
"fd=%d\n", path, (int)flags, (int)kernel_flags, fd));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
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 = sys_fcntl_long(fd, F_NOTIFY, 0);
|
||||
close(fd);
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
static int dnotify_ctx_destructor(struct dnotify_ctx *ctx)
|
||||
{
|
||||
close(ctx->fd);
|
||||
DLIST_REMOVE(dnotify_list, ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *kernel_notify_add(TALLOC_CTX *mem_ctx,
|
||||
struct event_context *event_ctx,
|
||||
files_struct *fsp,
|
||||
uint32 *filter)
|
||||
{
|
||||
struct dnotify_ctx *ctx;
|
||||
|
||||
if (!(ctx = TALLOC_P(mem_ctx, struct dnotify_ctx))) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->fsp = fsp;
|
||||
ctx->fd = kernel_register_notify(fsp->conn, fsp->fsp_name, *filter);
|
||||
|
||||
if (ctx->fd == -1) {
|
||||
TALLOC_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DLIST_ADD(dnotify_list, ctx);
|
||||
talloc_set_destructor(ctx, dnotify_ctx_destructor);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Setup kernel based change notify.
|
||||
****************************************************************************/
|
||||
|
||||
struct cnotify_fns *kernel_notify_init(struct event_context *event_ctx)
|
||||
{
|
||||
static struct cnotify_fns cnotify;
|
||||
struct sigaction act;
|
||||
|
||||
if (pipe(dnotify_signal_pipe) == -1) {
|
||||
DEBUG(0, ("Failed to create signal pipe: %s\n",
|
||||
strerror(errno)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((set_blocking(dnotify_signal_pipe[0], False) == -1)
|
||||
|| (set_blocking(dnotify_signal_pipe[1], False) == -1)) {
|
||||
DEBUG(0, ("Failed to set signal pipe to non-blocking: %s\n",
|
||||
strerror(errno)));
|
||||
close(dnotify_signal_pipe[0]);
|
||||
close(dnotify_signal_pipe[1]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (event_add_fd(event_ctx, NULL, dnotify_signal_pipe[0],
|
||||
EVENT_FD_READ, dnotify_pipe_handler, NULL) == NULL) {
|
||||
DEBUG(0, ("Failed to set signal event handler\n"));
|
||||
close(dnotify_signal_pipe[0]);
|
||||
close(dnotify_signal_pipe[1]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZERO_STRUCT(act);
|
||||
|
||||
act.sa_sigaction = dnotify_signal_handler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigemptyset( &act.sa_mask );
|
||||
if (sigaction(RT_SIGNAL_NOTIFY, &act, NULL) != 0) {
|
||||
DEBUG(0,("Failed to setup RT_SIGNAL_NOTIFY handler\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!kernel_notify_available())
|
||||
return NULL;
|
||||
|
||||
cnotify.notify_add = kernel_notify_add;
|
||||
|
||||
/* the signal can start off blocked due to a bug in bash */
|
||||
BlockSignals(False, RT_SIGNAL_NOTIFY);
|
||||
|
||||
return &cnotify;
|
||||
}
|
||||
|
||||
#else
|
||||
void notify_kernel_dummy(void);
|
||||
|
||||
void notify_kernel_dummy(void) {}
|
||||
#endif /* HAVE_KERNEL_CHANGE_NOTIFY */
|
@ -1945,8 +1945,8 @@ static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
|
||||
change_dir_owner_to_parent(conn, parent_dir, name, psbuf);
|
||||
}
|
||||
|
||||
notify_action(conn, parent_dir, dirname, FILE_NOTIFY_CHANGE_DIR_NAME,
|
||||
NOTIFY_ACTION_ADDED);
|
||||
notify_fname(conn, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_DIR_NAME,
|
||||
name);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
@ -1929,9 +1929,9 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
|
||||
count++;
|
||||
DEBUG(3,("unlink_internals: succesful unlink "
|
||||
"[%s]\n",fname));
|
||||
notify_action(conn, directory, dname,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME,
|
||||
NOTIFY_ACTION_REMOVED);
|
||||
notify_fname(conn, NOTIFY_ACTION_REMOVED,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME,
|
||||
fname);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1099,10 +1099,6 @@ extern void build_options(BOOL screen);
|
||||
if (!init_oplocks())
|
||||
exit(1);
|
||||
|
||||
/* Setup change notify */
|
||||
if (!init_change_notify())
|
||||
exit(1);
|
||||
|
||||
/* Setup aio signal handler. */
|
||||
initialize_async_io_handler();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user