Changeset 988 for vendor/current/source3/smbd/notify.c
- Timestamp:
- Nov 24, 2016, 1:14:11 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/source3/smbd/notify.c
r746 r988 24 24 #include "smbd/globals.h" 25 25 #include "../librpc/gen_ndr/ndr_notify.h" 26 #include "librpc/gen_ndr/ndr_file_id.h" 27 28 struct notify_change_event { 29 struct timespec when; 30 uint32_t action; 31 const char *name; 32 }; 33 34 struct notify_change_buf { 35 /* 36 * If no requests are pending, changes are queued here. Simple array, 37 * we only append. 38 */ 39 40 /* 41 * num_changes == -1 means that we have got a catch-all change, when 42 * asked we just return NT_STATUS_OK without specific changes. 43 */ 44 int num_changes; 45 struct notify_change_event *changes; 46 47 /* 48 * If no changes are around requests are queued here. Using a linked 49 * list, because we have to append at the end and delete from the top. 50 */ 51 struct notify_change_request *requests; 52 }; 26 53 27 54 struct notify_change_request { … … 29 56 struct files_struct *fsp; /* backpointer for cancel by mid */ 30 57 struct smb_request *req; 31 uint32 filter;32 uint32 max_param;58 uint32_t filter; 59 uint32_t max_param; 33 60 void (*reply_fn)(struct smb_request *req, 34 61 NTSTATUS error_code, … … 38 65 }; 39 66 40 static void notify_fsp(files_struct *fsp, uint32 action, const char *name); 67 static void notify_fsp(files_struct *fsp, struct timespec when, 68 uint32_t action, const char *name); 69 70 bool change_notify_fsp_has_changes(struct files_struct *fsp) 71 { 72 if (fsp == NULL) { 73 return false; 74 } 75 76 if (fsp->notify == NULL) { 77 return false; 78 } 79 80 if (fsp->notify->num_changes == 0) { 81 return false; 82 } 83 84 return true; 85 } 41 86 42 87 /* … … 51 96 }; 52 97 53 static bool notify_change_record_identical(struct notify_change *c1,54 struct notify_change*c2)98 static bool notify_change_record_identical(struct notify_change_event *c1, 99 struct notify_change_event *c2) 55 100 { 56 101 /* Note this is deliberately case sensitive. */ … … 62 107 } 63 108 109 static int compare_notify_change_events(const void *p1, const void *p2) 110 { 111 const struct notify_change_event *e1 = p1; 112 const struct notify_change_event *e2 = p2; 113 114 return timespec_compare(&e1->when, &e2->when); 115 } 116 64 117 static bool notify_marshall_changes(int num_changes, 65 uint32 max_offset,66 struct notify_change *changes,118 uint32_t max_offset, 119 struct notify_change_event *changes, 67 120 DATA_BLOB *final_blob) 68 121 { … … 73 126 } 74 127 128 /* 129 * Sort the notifies by timestamp when the event happened to avoid 130 * coalescing and thus dropping events. 131 */ 132 133 qsort(changes, num_changes, 134 sizeof(*changes), compare_notify_change_events); 135 75 136 for (i=0; i<num_changes; i++) { 76 137 enum ndr_err_code ndr_err; 77 struct notify_change *c;138 struct notify_change_event *c; 78 139 struct FILE_NOTIFY_INFORMATION m; 79 140 DATA_BLOB blob; 141 uint16_t pad = 0; 80 142 81 143 /* Coalesce any identical records. */ … … 91 153 m.FileNameLength = strlen_m(c->name)*2; 92 154 m.Action = c->action; 93 m.NextEntryOffset = (i == num_changes-1) ? 0 : ndr_size_FILE_NOTIFY_INFORMATION(&m, 0); 155 156 m._pad = data_blob_null; 94 157 95 158 /* 96 159 * Offset to next entry, only if there is one 97 160 */ 161 162 if (i == (num_changes-1)) { 163 m.NextEntryOffset = 0; 164 } else { 165 if ((m.FileNameLength % 4) == 2) { 166 m._pad = data_blob_const(&pad, 2); 167 } 168 m.NextEntryOffset = 169 ndr_size_FILE_NOTIFY_INFORMATION(&m, 0); 170 } 98 171 99 172 ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &m, … … 168 241 } 169 242 170 static void notify_callback(void *private_data, const struct notify_event *e) 243 static void notify_callback(void *private_data, struct timespec when, 244 const struct notify_event *e) 171 245 { 172 246 files_struct *fsp = (files_struct *)private_data; 173 247 DEBUG(10, ("notify_callback called for %s\n", fsp_str_dbg(fsp))); 174 notify_fsp(fsp, e->action, e->path);175 } 176 177 NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter,248 notify_fsp(fsp, when, e->action, e->path); 249 } 250 251 NTSTATUS change_notify_create(struct files_struct *fsp, uint32_t filter, 178 252 bool recursive) 179 253 { 180 254 char *fullpath; 181 struct notify_entry e; 182 NTSTATUS status; 183 184 SMB_ASSERT(fsp->notify == NULL); 185 186 if (!(fsp->notify = TALLOC_ZERO_P(NULL, struct notify_change_buf))) { 255 size_t len; 256 uint32_t subdir_filter; 257 NTSTATUS status = NT_STATUS_NOT_IMPLEMENTED; 258 259 if (fsp->notify != NULL) { 260 DEBUG(1, ("change_notify_create: fsp->notify != NULL, " 261 "fname = %s\n", fsp->fsp_name->base_name)); 262 return NT_STATUS_INVALID_PARAMETER; 263 } 264 265 if (!(fsp->notify = talloc_zero(NULL, struct notify_change_buf))) { 187 266 DEBUG(0, ("talloc failed\n")); 188 267 return NT_STATUS_NO_MEMORY; … … 190 269 191 270 /* Do notify operations on the base_name. */ 192 if (asprintf(&fullpath, "%s/%s", fsp->conn->connectpath, 193 fsp->fsp_name->base_name) == -1) { 194 DEBUG(0, ("asprintf failed\n")); 271 fullpath = talloc_asprintf( 272 talloc_tos(), "%s/%s", fsp->conn->connectpath, 273 fsp->fsp_name->base_name); 274 if (fullpath == NULL) { 275 DEBUG(0, ("talloc_asprintf failed\n")); 195 276 TALLOC_FREE(fsp->notify); 196 277 return NT_STATUS_NO_MEMORY; 197 278 } 198 279 199 ZERO_STRUCT(e); 200 e.path = fullpath; 201 e.dir_fd = fsp->fh->fd; 202 e.dir_id = fsp->file_id; 203 e.filter = filter; 204 e.subdir_filter = 0; 205 if (recursive) { 206 e.subdir_filter = filter; 207 } 208 209 status = notify_add(fsp->conn->notify_ctx, &e, notify_callback, fsp); 210 SAFE_FREE(fullpath); 211 280 /* 281 * Avoid /. at the end of the path name. notify can't deal with it. 282 */ 283 len = strlen(fullpath); 284 if (len > 1 && fullpath[len-1] == '.' && fullpath[len-2] == '/') { 285 fullpath[len-2] = '\0'; 286 } 287 288 subdir_filter = recursive ? filter : 0; 289 290 if ((filter != 0) || (subdir_filter != 0)) { 291 status = notify_add(fsp->conn->sconn->notify_ctx, 292 fullpath, filter, subdir_filter, 293 notify_callback, fsp); 294 } 295 TALLOC_FREE(fullpath); 212 296 return status; 213 297 } 214 298 215 299 NTSTATUS change_notify_add_request(struct smb_request *req, 216 uint32 max_param,217 uint32 filter, bool recursive,300 uint32_t max_param, 301 uint32_t filter, bool recursive, 218 302 struct files_struct *fsp, 219 303 void (*reply_fn)(struct smb_request *req, … … 244 328 request->backend_data = NULL; 245 329 246 DLIST_ADD_END(fsp->notify->requests, request, 247 struct notify_change_request *); 330 DLIST_ADD_END(fsp->notify->requests, request); 248 331 249 332 map->mid = request->req->mid; … … 282 365 } 283 366 367 static void smbd_notify_cancel_by_map(struct notify_mid_map *map) 368 { 369 struct smb_request *smbreq = map->req->req; 370 struct smbd_server_connection *sconn = smbreq->sconn; 371 struct smbd_smb2_request *smb2req = smbreq->smb2req; 372 NTSTATUS notify_status = NT_STATUS_CANCELLED; 373 374 if (smb2req != NULL) { 375 if (smb2req->session == NULL) { 376 notify_status = STATUS_NOTIFY_CLEANUP; 377 } else if (!NT_STATUS_IS_OK(smb2req->session->status)) { 378 notify_status = STATUS_NOTIFY_CLEANUP; 379 } 380 if (smb2req->tcon == NULL) { 381 notify_status = STATUS_NOTIFY_CLEANUP; 382 } else if (!NT_STATUS_IS_OK(smb2req->tcon->status)) { 383 notify_status = STATUS_NOTIFY_CLEANUP; 384 } 385 } 386 387 change_notify_reply(smbreq, notify_status, 388 0, NULL, map->req->reply_fn); 389 change_notify_remove_request(sconn, map->req); 390 } 391 284 392 /**************************************************************************** 285 393 Delete entries by mid from the change notify pending queue. Always send reply. … … 301 409 } 302 410 303 change_notify_reply(map->req->req, 304 NT_STATUS_CANCELLED, 0, NULL, map->req->reply_fn); 305 change_notify_remove_request(sconn, map->req); 411 smbd_notify_cancel_by_map(map); 306 412 } 307 413 … … 321 427 } 322 428 323 change_notify_reply(map->req->req, 324 NT_STATUS_CANCELLED, 0, NULL, map->req->reply_fn); 325 change_notify_remove_request(sconn, map->req); 429 smbd_notify_cancel_by_map(map); 430 } 431 432 static struct files_struct *smbd_notify_cancel_deleted_fn( 433 struct files_struct *fsp, void *private_data) 434 { 435 struct file_id *fid = talloc_get_type_abort( 436 private_data, struct file_id); 437 438 if (file_id_equal(&fsp->file_id, fid)) { 439 remove_pending_change_notify_requests_by_fid( 440 fsp, NT_STATUS_DELETE_PENDING); 441 } 442 return NULL; 443 } 444 445 void smbd_notify_cancel_deleted(struct messaging_context *msg, 446 void *private_data, uint32_t msg_type, 447 struct server_id server_id, DATA_BLOB *data) 448 { 449 struct smbd_server_connection *sconn = talloc_get_type_abort( 450 private_data, struct smbd_server_connection); 451 struct file_id *fid; 452 enum ndr_err_code ndr_err; 453 454 fid = talloc(talloc_tos(), struct file_id); 455 if (fid == NULL) { 456 DEBUG(1, ("talloc failed\n")); 457 return; 458 } 459 460 ndr_err = ndr_pull_struct_blob_all( 461 data, fid, fid, (ndr_pull_flags_fn_t)ndr_pull_file_id); 462 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 463 DEBUG(10, ("%s: ndr_pull_file_id failed: %s\n", __func__, 464 ndr_errstr(ndr_err))); 465 goto done; 466 } 467 468 files_forall(sconn, smbd_notify_cancel_deleted_fn, fid); 469 470 done: 471 TALLOC_FREE(fid); 326 472 } 327 473 … … 346 492 } 347 493 348 static void notify_parent_dir(connection_struct *conn, 349 uint32 action, uint32 filter, 350 const char *path) 351 { 352 struct smb_filename smb_fname_parent; 353 char *parent; 354 const char *name; 355 char *oldwd; 356 357 if (!parent_dirname(talloc_tos(), path, &parent, &name)) { 358 return; 359 } 360 361 ZERO_STRUCT(smb_fname_parent); 362 smb_fname_parent.base_name = parent; 363 364 oldwd = vfs_GetWd(parent, conn); 365 if (oldwd == NULL) { 366 goto done; 367 } 368 if (vfs_ChDir(conn, conn->connectpath) == -1) { 369 goto done; 370 } 371 372 if (SMB_VFS_STAT(conn, &smb_fname_parent) == -1) { 373 goto chdir_done; 374 } 375 376 notify_onelevel(conn->notify_ctx, action, filter, 377 SMB_VFS_FILE_ID_CREATE(conn, &smb_fname_parent.st), 378 name); 379 chdir_done: 380 vfs_ChDir(conn, oldwd); 381 done: 382 TALLOC_FREE(parent); 383 } 384 385 void notify_fname(connection_struct *conn, uint32 action, uint32 filter, 494 void notify_fname(connection_struct *conn, uint32_t action, uint32_t filter, 386 495 const char *path) 387 496 { 388 char *fullpath;497 struct notify_context *notify_ctx = conn->sconn->notify_ctx; 389 498 390 499 if (path[0] == '.' && path[1] == '/') { 391 500 path += 2; 392 501 } 393 notify_parent_dir(conn, action, filter, path); 394 395 fullpath = talloc_asprintf(talloc_tos(), "%s/%s", conn->connectpath, 396 path); 397 if (fullpath == NULL) { 398 DEBUG(0, ("asprintf failed\n")); 399 return; 400 } 401 notify_trigger(conn->notify_ctx, action, filter, fullpath); 402 TALLOC_FREE(fullpath); 403 } 404 405 static void notify_fsp(files_struct *fsp, uint32 action, const char *name) 406 { 407 struct notify_change *change, *changes; 502 503 notify_trigger(notify_ctx, action, filter, conn->connectpath, path); 504 } 505 506 static void notify_fsp(files_struct *fsp, struct timespec when, 507 uint32_t action, const char *name) 508 { 509 struct notify_change_event *change, *changes; 408 510 char *tmp; 409 511 … … 449 551 } 450 552 451 if (!(changes = TALLOC_REALLOC_ARRAY(553 if (!(changes = talloc_realloc( 452 554 fsp->notify, fsp->notify->changes, 453 struct notify_change, fsp->notify->num_changes+1))) { 555 struct notify_change_event, 556 fsp->notify->num_changes+1))) { 454 557 DEBUG(0, ("talloc_realloc failed\n")); 455 558 return; … … 468 571 change->name = tmp; 469 572 573 change->when = when; 470 574 change->action = action; 471 575 fsp->notify->num_changes += 1; … … 501 605 } 502 606 503 char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter)607 char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32_t filter) 504 608 { 505 609 char *result = NULL; … … 539 643 } 540 644 541 struct sys_notify_context *sys_notify_context_create(connection_struct *conn, 542 TALLOC_CTX *mem_ctx, 543 struct event_context *ev) 645 struct sys_notify_context *sys_notify_context_create(TALLOC_CTX *mem_ctx, 646 struct tevent_context *ev) 544 647 { 545 648 struct sys_notify_context *ctx; 546 649 547 if (!(ctx = TALLOC_P(mem_ctx, struct sys_notify_context))) {650 if (!(ctx = talloc(mem_ctx, struct sys_notify_context))) { 548 651 DEBUG(0, ("talloc failed\n")); 549 652 return NULL; … … 551 654 552 655 ctx->ev = ev; 553 ctx->conn = conn;554 656 ctx->private_data = NULL; 555 657 return ctx; 556 658 } 557 558 NTSTATUS sys_notify_watch(struct sys_notify_context *ctx,559 struct notify_entry *e,560 void (*callback)(struct sys_notify_context *ctx,561 void *private_data,562 struct notify_event *ev),563 void *private_data, void *handle)564 {565 return SMB_VFS_NOTIFY_WATCH(ctx->conn, ctx, e, callback, private_data,566 handle);567 }568
Note:
See TracChangeset
for help on using the changeset viewer.