📄 notify.c
字号:
/* Unix SMB/CIFS implementation. Copyright (C) Andrew Tridgell 2006 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 3 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, see <http://www.gnu.org/licenses/>.*//* this is the change notify database. It implements mechanisms for storing current change notify waiters in a tdb, and checking if a given event matches any of the stored notify waiiters.*/#include "includes.h"#include "system/filesys.h"#include "lib/tdb/include/tdb.h"#include "lib/util/util_tdb.h"#include "messaging/messaging.h"#include "tdb_wrap.h"#include "lib/messaging/irpc.h"#include "librpc/gen_ndr/ndr_notify.h"#include "lib/util/dlinklist.h"#include "ntvfs/common/ntvfs_common.h"#include "ntvfs/sysdep/sys_notify.h"#include "cluster/cluster.h"#include "param/param.h"struct notify_context { struct tdb_wrap *w; struct server_id server; struct messaging_context *messaging_ctx; struct notify_list *list; struct notify_array *array; int seqnum; struct sys_notify_context *sys_notify_ctx; struct smb_iconv_convenience *iconv_convenience;};struct notify_list { struct notify_list *next, *prev; void *private_data; void (*callback)(void *, const struct notify_event *); void *sys_notify_handle; int depth;};#define NOTIFY_KEY "notify array"#define NOTIFY_ENABLE "notify:enable"#define NOTIFY_ENABLE_DEFAULT truestatic NTSTATUS notify_remove_all(struct notify_context *notify);static void notify_handler(struct messaging_context *msg_ctx, void *private_data, uint32_t msg_type, struct server_id server_id, DATA_BLOB *data);/* destroy the notify context*/static int notify_destructor(struct notify_context *notify){ messaging_deregister(notify->messaging_ctx, MSG_PVFS_NOTIFY, notify); notify_remove_all(notify); return 0;}/* Open up the notify.tdb database. You should close it down using talloc_free(). We need the messaging_ctx to allow for notifications via internal messages*/struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server, struct messaging_context *messaging_ctx, struct loadparm_context *lp_ctx, struct event_context *ev, struct share_config *scfg){ struct notify_context *notify; if (share_bool_option(scfg, NOTIFY_ENABLE, NOTIFY_ENABLE_DEFAULT) != true) { return NULL; } if (ev == NULL) { return NULL; } notify = talloc(mem_ctx, struct notify_context); if (notify == NULL) { return NULL; } notify->w = cluster_tdb_tmp_open(notify, lp_ctx, "notify.tdb", TDB_SEQNUM); if (notify->w == NULL) { talloc_free(notify); return NULL; } notify->server = server; notify->messaging_ctx = messaging_ctx; notify->list = NULL; notify->array = NULL; notify->iconv_convenience = lp_iconv_convenience(lp_ctx); notify->seqnum = tdb_get_seqnum(notify->w->tdb); talloc_set_destructor(notify, notify_destructor); /* register with the messaging subsystem for the notify message type */ messaging_register(notify->messaging_ctx, notify, MSG_PVFS_NOTIFY, notify_handler); notify->sys_notify_ctx = sys_notify_context_create(scfg, notify, ev); return notify;}/* lock the notify db*/static NTSTATUS notify_lock(struct notify_context *notify){ if (tdb_lock_bystring(notify->w->tdb, NOTIFY_KEY) != 0) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } return NT_STATUS_OK;}/* unlock the notify db*/static void notify_unlock(struct notify_context *notify){ tdb_unlock_bystring(notify->w->tdb, NOTIFY_KEY);}/* load the notify array*/static NTSTATUS notify_load(struct notify_context *notify){ TDB_DATA dbuf; DATA_BLOB blob; enum ndr_err_code ndr_err; int seqnum; seqnum = tdb_get_seqnum(notify->w->tdb); if (seqnum == notify->seqnum && notify->array != NULL) { return NT_STATUS_OK; } notify->seqnum = seqnum; talloc_free(notify->array); notify->array = talloc_zero(notify, struct notify_array); NT_STATUS_HAVE_NO_MEMORY(notify->array); dbuf = tdb_fetch_bystring(notify->w->tdb, NOTIFY_KEY); if (dbuf.dptr == NULL) { return NT_STATUS_OK; } blob.data = dbuf.dptr; blob.length = dbuf.dsize; ndr_err = ndr_pull_struct_blob(&blob, notify->array, notify->iconv_convenience, notify->array, (ndr_pull_flags_fn_t)ndr_pull_notify_array); free(dbuf.dptr); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return ndr_map_error2ntstatus(ndr_err); } return NT_STATUS_OK;}/* compare notify entries for sorting*/static int notify_compare(const void *p1, const void *p2){ const struct notify_entry *e1 = p1, *e2 = p2; return strcmp(e1->path, e2->path);}/* save the notify array*/static NTSTATUS notify_save(struct notify_context *notify){ TDB_DATA dbuf; DATA_BLOB blob; enum ndr_err_code ndr_err; int ret; TALLOC_CTX *tmp_ctx; /* if possible, remove some depth arrays */ while (notify->array->num_depths > 0 && notify->array->depth[notify->array->num_depths-1].num_entries == 0) { notify->array->num_depths--; } /* we might just be able to delete the record */ if (notify->array->num_depths == 0) { ret = tdb_delete_bystring(notify->w->tdb, NOTIFY_KEY); if (ret != 0) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } return NT_STATUS_OK; } tmp_ctx = talloc_new(notify); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, notify->iconv_convenience, notify->array, (ndr_push_flags_fn_t)ndr_push_notify_array); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { talloc_free(tmp_ctx); return ndr_map_error2ntstatus(ndr_err); } dbuf.dptr = blob.data; dbuf.dsize = blob.length; ret = tdb_store_bystring(notify->w->tdb, NOTIFY_KEY, dbuf, TDB_REPLACE); talloc_free(tmp_ctx); if (ret != 0) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } return NT_STATUS_OK;}/* handle incoming notify messages*/static void notify_handler(struct messaging_context *msg_ctx, void *private_data, uint32_t msg_type, struct server_id server_id, DATA_BLOB *data){ struct notify_context *notify = talloc_get_type(private_data, struct notify_context); enum ndr_err_code ndr_err; struct notify_event ev; TALLOC_CTX *tmp_ctx = talloc_new(notify); struct notify_list *listel; if (tmp_ctx == NULL) { return; } ndr_err = ndr_pull_struct_blob(data, tmp_ctx, notify->iconv_convenience, &ev, (ndr_pull_flags_fn_t)ndr_pull_notify_event); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { talloc_free(tmp_ctx); return; } for (listel=notify->list;listel;listel=listel->next) { if (listel->private_data == ev.private_data) { listel->callback(listel->private_data, &ev); break; } } talloc_free(tmp_ctx); }/* callback from sys_notify telling us about changes from the OS*/static void sys_notify_callback(struct sys_notify_context *ctx, void *ptr, struct notify_event *ev){ struct notify_list *listel = talloc_get_type(ptr, struct notify_list); ev->private_data = listel; listel->callback(listel->private_data, ev);}/* add an entry to the notify array*/static NTSTATUS notify_add_array(struct notify_context *notify, struct notify_entry *e, void *private_data, int depth){ int i; struct notify_depth *d; struct notify_entry *ee; /* possibly expand the depths array */ if (depth >= notify->array->num_depths) { d = talloc_realloc(notify->array, notify->array->depth, struct notify_depth, depth+1); NT_STATUS_HAVE_NO_MEMORY(d); for (i=notify->array->num_depths;i<=depth;i++) { ZERO_STRUCT(d[i]); } notify->array->depth = d; notify->array->num_depths = depth+1; } d = ¬ify->array->depth[depth]; /* expand the entries array */ ee = talloc_realloc(notify->array->depth, d->entries, struct notify_entry, d->num_entries+1); NT_STATUS_HAVE_NO_MEMORY(ee); d->entries = ee; d->entries[d->num_entries] = *e; d->entries[d->num_entries].private_data = private_data; d->entries[d->num_entries].server = notify->server; d->entries[d->num_entries].path_len = strlen(e->path); d->num_entries++; d->max_mask |= e->filter; d->max_mask_subdir |= e->subdir_filter; if (d->num_entries > 1) { qsort(d->entries, d->num_entries, sizeof(d->entries[0]), notify_compare); } /* recalculate the maximum masks */ d->max_mask = 0; d->max_mask_subdir = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -