mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +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
|
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 \
|
NOTIFY_OBJ = smbd/notify.o smbd/notify_fam.o smbd/notify_inotify.o \
|
||||||
smbd/notify_fam.o smbd/notify_inotify.o smbd/notify_internal.o
|
smbd/notify_internal.o
|
||||||
|
|
||||||
VFS_DEFAULT_OBJ = modules/vfs_default.o
|
VFS_DEFAULT_OBJ = modules/vfs_default.o
|
||||||
VFS_AUDIT_OBJ = modules/vfs_audit.o
|
VFS_AUDIT_OBJ = modules/vfs_audit.o
|
||||||
|
@ -1685,15 +1685,6 @@ struct kernel_oplocks {
|
|||||||
int notification_fd;
|
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"
|
#include "smb_macros.h"
|
||||||
|
|
||||||
#define MAX_NETBIOSNAME_LEN 16
|
#define MAX_NETBIOSNAME_LEN 16
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
static struct cnotify_fns *cnotify;
|
|
||||||
static struct notify_mid_map *notify_changes_by_mid;
|
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,
|
void notify_fname(connection_struct *conn, uint32 action, uint32 filter,
|
||||||
const char *path)
|
const char *path)
|
||||||
{
|
{
|
||||||
@ -514,30 +362,6 @@ void notify_fsp(files_struct *fsp, uint32 action, const char *name)
|
|||||||
fsp->notify->num_changes = 0;
|
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 *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter)
|
||||||
{
|
{
|
||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
@ -576,34 +400,6 @@ char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter)
|
|||||||
return result;
|
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,
|
struct sys_notify_context *sys_notify_context_create(struct share_params *scfg,
|
||||||
TALLOC_CTX *mem_ctx,
|
TALLOC_CTX *mem_ctx,
|
||||||
struct event_context *ev)
|
struct event_context *ev)
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
#ifdef HAVE_FAM_CHANGE_NOTIFY
|
#if 0
|
||||||
|
|
||||||
#include <fam.h>
|
#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);
|
change_dir_owner_to_parent(conn, parent_dir, name, psbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
notify_action(conn, parent_dir, dirname, FILE_NOTIFY_CHANGE_DIR_NAME,
|
notify_fname(conn, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_DIR_NAME,
|
||||||
NOTIFY_ACTION_ADDED);
|
name);
|
||||||
|
|
||||||
return NT_STATUS_OK;
|
return NT_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
@ -1929,9 +1929,9 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
|
|||||||
count++;
|
count++;
|
||||||
DEBUG(3,("unlink_internals: succesful unlink "
|
DEBUG(3,("unlink_internals: succesful unlink "
|
||||||
"[%s]\n",fname));
|
"[%s]\n",fname));
|
||||||
notify_action(conn, directory, dname,
|
notify_fname(conn, NOTIFY_ACTION_REMOVED,
|
||||||
FILE_NOTIFY_CHANGE_FILE_NAME,
|
FILE_NOTIFY_CHANGE_FILE_NAME,
|
||||||
NOTIFY_ACTION_REMOVED);
|
fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1099,10 +1099,6 @@ extern void build_options(BOOL screen);
|
|||||||
if (!init_oplocks())
|
if (!init_oplocks())
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
/* Setup change notify */
|
|
||||||
if (!init_change_notify())
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
/* Setup aio signal handler. */
|
/* Setup aio signal handler. */
|
||||||
initialize_async_io_handler();
|
initialize_async_io_handler();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user