📄 notify.c
字号:
for (i=0;i<d->num_entries;i++) { d->max_mask |= d->entries[i].filter; d->max_mask_subdir |= d->entries[i].subdir_filter; } return notify_save(notify);}/* add a notify watch. This is called when a notify is first setup on a open directory handle.*/NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e0, void (*callback)(void *, const struct notify_event *), void *private_data){ struct notify_entry e = *e0; NTSTATUS status; char *tmp_path = NULL; struct notify_list *listel; size_t len; int depth; /* see if change notify is enabled at all */ if (notify == NULL) { return NT_STATUS_NOT_IMPLEMENTED; } status = notify_lock(notify); NT_STATUS_NOT_OK_RETURN(status); status = notify_load(notify); if (!NT_STATUS_IS_OK(status)) { goto done; } /* cope with /. on the end of the path */ len = strlen(e.path); if (len > 1 && e.path[len-1] == '.' && e.path[len-2] == '/') { tmp_path = talloc_strndup(notify, e.path, len-2); if (tmp_path == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } e.path = tmp_path; } depth = count_chars(e.path, '/'); listel = talloc_zero(notify, struct notify_list); if (listel == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } listel->private_data = private_data; listel->callback = callback; listel->depth = depth; DLIST_ADD(notify->list, listel); /* ignore failures from sys_notify */ if (notify->sys_notify_ctx != NULL) { /* this call will modify e.filter and e.subdir_filter to remove bits handled by the backend */ status = sys_notify_watch(notify->sys_notify_ctx, &e, sys_notify_callback, listel, &listel->sys_notify_handle); if (NT_STATUS_IS_OK(status)) { talloc_steal(listel, listel->sys_notify_handle); } } /* if the system notify handler couldn't handle some of the filter bits, or couldn't handle a request for recursion then we need to install it in the array used for the intra-samba notify handling */ if (e.filter != 0 || e.subdir_filter != 0) { status = notify_add_array(notify, &e, private_data, depth); }done: notify_unlock(notify); talloc_free(tmp_path); return status;}/* remove a notify watch. Called when the directory handle is closed*/NTSTATUS notify_remove(struct notify_context *notify, void *private_data){ NTSTATUS status; struct notify_list *listel; int i, depth; struct notify_depth *d; /* see if change notify is enabled at all */ if (notify == NULL) { return NT_STATUS_NOT_IMPLEMENTED; } for (listel=notify->list;listel;listel=listel->next) { if (listel->private_data == private_data) { DLIST_REMOVE(notify->list, listel); break; } } if (listel == NULL) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } depth = listel->depth; talloc_free(listel); status = notify_lock(notify); NT_STATUS_NOT_OK_RETURN(status); status = notify_load(notify); if (!NT_STATUS_IS_OK(status)) { notify_unlock(notify); return status; } if (depth >= notify->array->num_depths) { notify_unlock(notify); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } /* we only have to search at the depth of this element */ d = ¬ify->array->depth[depth]; for (i=0;i<d->num_entries;i++) { if (private_data == d->entries[i].private_data && cluster_id_equal(¬ify->server, &d->entries[i].server)) { break; } } if (i == d->num_entries) { notify_unlock(notify); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (i < d->num_entries-1) { memmove(&d->entries[i], &d->entries[i+1], sizeof(d->entries[i])*(d->num_entries-(i+1))); } d->num_entries--; status = notify_save(notify); notify_unlock(notify); return status;}/* remove all notify watches for this messaging server*/static NTSTATUS notify_remove_all(struct notify_context *notify){ NTSTATUS status; int i, depth, del_count=0; if (notify->list == NULL) { return NT_STATUS_OK; } status = notify_lock(notify); NT_STATUS_NOT_OK_RETURN(status); status = notify_load(notify); if (!NT_STATUS_IS_OK(status)) { notify_unlock(notify); return status; } /* we have to search for all entries across all depths, looking for matches for our server id */ for (depth=0;depth<notify->array->num_depths;depth++) { struct notify_depth *d = ¬ify->array->depth[depth]; for (i=0;i<d->num_entries;i++) { if (cluster_id_equal(¬ify->server, &d->entries[i].server)) { if (i < d->num_entries-1) { memmove(&d->entries[i], &d->entries[i+1], sizeof(d->entries[i])*(d->num_entries-(i+1))); } i--; d->num_entries--; del_count++; } } } if (del_count > 0) { status = notify_save(notify); } notify_unlock(notify); return status;}/* send a notify message to another messaging server*/static void notify_send(struct notify_context *notify, struct notify_entry *e, const char *path, uint32_t action){ struct notify_event ev; DATA_BLOB data; NTSTATUS status; enum ndr_err_code ndr_err; TALLOC_CTX *tmp_ctx; ev.action = action; ev.path = path; ev.private_data = e->private_data; tmp_ctx = talloc_new(notify); ndr_err = ndr_push_struct_blob(&data, tmp_ctx, notify->iconv_convenience, &ev, (ndr_push_flags_fn_t)ndr_push_notify_event); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { talloc_free(tmp_ctx); return; } status = messaging_send(notify->messaging_ctx, e->server, MSG_PVFS_NOTIFY, &data); talloc_free(tmp_ctx);}/* trigger a notify message for anyone waiting on a matching event This function is called a lot, and needs to be very fast. The unusual data structure and traversal is designed to be fast in the average case, even for large numbers of notifies*/void notify_trigger(struct notify_context *notify, uint32_t action, uint32_t filter, const char *path){ NTSTATUS status; int depth; const char *p, *next_p; /* see if change notify is enabled at all */ if (notify == NULL) { return; } status = notify_load(notify); if (!NT_STATUS_IS_OK(status)) { return; } /* loop along the given path, working with each directory depth separately */ for (depth=0,p=path; p && depth < notify->array->num_depths; p=next_p,depth++) { int p_len = p - path; int min_i, max_i, i; struct notify_depth *d = ¬ify->array->depth[depth]; next_p = strchr(p+1, '/'); /* see if there are any entries at this depth */ if (d->num_entries == 0) continue; /* try to skip based on the maximum mask. If next_p is NULL then we know it will be a 'this directory' match, otherwise it must be a subdir match */ if (next_p != NULL) { if (0 == (filter & d->max_mask_subdir)) { continue; } } else { if (0 == (filter & d->max_mask)) { continue; } } /* we know there is an entry here worth looking for. Use a bisection search to find the first entry with a matching path */ min_i = 0; max_i = d->num_entries-1; while (min_i < max_i) { struct notify_entry *e; int cmp; i = (min_i+max_i)/2; e = &d->entries[i]; cmp = strncmp(path, e->path, p_len); if (cmp == 0) { if (p_len == e->path_len) { max_i = i; } else { max_i = i-1; } } else if (cmp < 0) { max_i = i-1; } else { min_i = i+1; } } if (min_i != max_i) { /* none match */ continue; } /* we now know that the entries start at min_i */ for (i=min_i;i<d->num_entries;i++) { struct notify_entry *e = &d->entries[i]; if (p_len != e->path_len || strncmp(path, e->path, p_len) != 0) break; if (next_p != NULL) { if (0 == (filter & e->subdir_filter)) { continue; } } else { if (0 == (filter & e->filter)) { continue; } } notify_send(notify, e, path + e->path_len + 1, action); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -