00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "includes.h"
00024
00025
00026 extern int max_send;
00027
00028 struct notify_change_request {
00029 struct notify_change_request *prev, *next;
00030 struct files_struct *fsp;
00031 char request_buf[smb_size];
00032 uint32 filter;
00033 uint32 max_param;
00034 struct notify_mid_map *mid_map;
00035 void *backend_data;
00036 };
00037
00038 static void notify_fsp(files_struct *fsp, uint32 action, const char *name);
00039
00040 static struct notify_mid_map *notify_changes_by_mid;
00041
00042
00043
00044
00045
00046
00047 struct notify_mid_map {
00048 struct notify_mid_map *prev, *next;
00049 struct notify_change_request *req;
00050 uint16 mid;
00051 };
00052
00053 static BOOL notify_change_record_identical(struct notify_change *c1,
00054 struct notify_change *c2)
00055 {
00056
00057 if (c1->action == c2->action &&
00058 strcmp(c1->name, c2->name) == 0) {
00059 return True;
00060 }
00061 return False;
00062 }
00063
00064 static BOOL notify_marshall_changes(int num_changes,
00065 uint32 max_offset,
00066 struct notify_change *changes,
00067 prs_struct *ps)
00068 {
00069 int i;
00070 UNISTR uni_name;
00071
00072 uni_name.buffer = NULL;
00073
00074 for (i=0; i<num_changes; i++) {
00075 struct notify_change *c;
00076 size_t namelen;
00077 uint32 u32_tmp;
00078
00079
00080
00081 while (i+1 < num_changes &&
00082 notify_change_record_identical(&changes[i],
00083 &changes[i+1])) {
00084 i++;
00085 }
00086
00087 c = &changes[i];
00088
00089 namelen = convert_string_allocate(
00090 NULL, CH_UNIX, CH_UTF16LE, c->name, strlen(c->name)+1,
00091 &uni_name.buffer, True);
00092 if ((namelen == -1) || (uni_name.buffer == NULL)) {
00093 goto fail;
00094 }
00095
00096 namelen -= 2;
00097
00098
00099
00100
00101
00102 u32_tmp = (i == num_changes-1) ? 0 : namelen + 12;
00103 if (!prs_uint32("offset", ps, 1, &u32_tmp)) goto fail;
00104
00105 u32_tmp = c->action;
00106 if (!prs_uint32("action", ps, 1, &u32_tmp)) goto fail;
00107
00108 u32_tmp = namelen;
00109 if (!prs_uint32("namelen", ps, 1, &u32_tmp)) goto fail;
00110
00111 if (!prs_unistr("name", ps, 1, &uni_name)) goto fail;
00112
00113
00114
00115
00116 prs_set_offset(ps, prs_offset(ps)-2);
00117
00118 SAFE_FREE(uni_name.buffer);
00119
00120 if (prs_offset(ps) > max_offset) {
00121
00122 return False;
00123 }
00124 }
00125
00126 return True;
00127
00128 fail:
00129 SAFE_FREE(uni_name.buffer);
00130 return False;
00131 }
00132
00133
00134
00135
00136
00137 static void change_notify_reply_packet(const char *request_buf,
00138 NTSTATUS error_code)
00139 {
00140 char outbuf[smb_size+38];
00141
00142 memset(outbuf, '\0', sizeof(outbuf));
00143 construct_reply_common(request_buf, outbuf);
00144
00145 ERROR_NT(error_code);
00146
00147
00148
00149
00150
00151 set_message(outbuf,18,0,False);
00152
00153 show_msg(outbuf);
00154 if (!send_smb(smbd_server_fd(),outbuf))
00155 exit_server_cleanly("change_notify_reply_packet: send_smb "
00156 "failed.");
00157 }
00158
00159 void change_notify_reply(const char *request_buf, uint32 max_param,
00160 struct notify_change_buf *notify_buf)
00161 {
00162 char *outbuf = NULL;
00163 prs_struct ps;
00164 size_t buflen;
00165
00166 if (notify_buf->num_changes == -1) {
00167 change_notify_reply_packet(request_buf, NT_STATUS_OK);
00168 notify_buf->num_changes = 0;
00169 return;
00170 }
00171
00172 prs_init(&ps, 0, NULL, MARSHALL);
00173
00174 if (!notify_marshall_changes(notify_buf->num_changes, max_param,
00175 notify_buf->changes, &ps)) {
00176
00177
00178
00179
00180 change_notify_reply_packet(request_buf, NT_STATUS_OK);
00181 goto done;
00182 }
00183
00184 buflen = smb_size+38+prs_offset(&ps) + 4 ;
00185
00186 if (buflen > max_send) {
00187
00188
00189
00190
00191 change_notify_reply_packet(request_buf, NT_STATUS_OK);
00192 goto done;
00193 }
00194
00195 if (!(outbuf = SMB_MALLOC_ARRAY(char, buflen))) {
00196 change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY);
00197 goto done;
00198 }
00199
00200 construct_reply_common(request_buf, outbuf);
00201
00202 if (send_nt_replies(outbuf, buflen, NT_STATUS_OK, prs_data_p(&ps),
00203 prs_offset(&ps), NULL, 0) == -1) {
00204 exit_server("change_notify_reply_packet: send_smb failed.");
00205 }
00206
00207 done:
00208 SAFE_FREE(outbuf);
00209 prs_mem_free(&ps);
00210
00211 TALLOC_FREE(notify_buf->changes);
00212 notify_buf->num_changes = 0;
00213 }
00214
00215 static void notify_callback(void *private_data, const struct notify_event *e)
00216 {
00217 files_struct *fsp = (files_struct *)private_data;
00218 DEBUG(10, ("notify_callback called for %s\n", fsp->fsp_name));
00219 notify_fsp(fsp, e->action, e->path);
00220 }
00221
00222 NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter,
00223 BOOL recursive)
00224 {
00225 char *fullpath;
00226 struct notify_entry e;
00227 NTSTATUS status;
00228
00229 SMB_ASSERT(fsp->notify == NULL);
00230
00231 if (!(fsp->notify = TALLOC_ZERO_P(NULL, struct notify_change_buf))) {
00232 DEBUG(0, ("talloc failed\n"));
00233 return NT_STATUS_NO_MEMORY;
00234 }
00235
00236 if (asprintf(&fullpath, "%s/%s", fsp->conn->connectpath,
00237 fsp->fsp_name) == -1) {
00238 DEBUG(0, ("asprintf failed\n"));
00239 return NT_STATUS_NO_MEMORY;
00240 }
00241
00242 e.path = fullpath;
00243 e.filter = filter;
00244 e.subdir_filter = 0;
00245 if (recursive) {
00246 e.subdir_filter = filter;
00247 }
00248
00249 status = notify_add(fsp->conn->notify_ctx, &e, notify_callback, fsp);
00250 SAFE_FREE(fullpath);
00251
00252 return status;
00253 }
00254
00255 NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param,
00256 uint32 filter, BOOL recursive,
00257 struct files_struct *fsp)
00258 {
00259 struct notify_change_request *request = NULL;
00260 struct notify_mid_map *map = NULL;
00261
00262 if (!(request = SMB_MALLOC_P(struct notify_change_request))
00263 || !(map = SMB_MALLOC_P(struct notify_mid_map))) {
00264 SAFE_FREE(request);
00265 return NT_STATUS_NO_MEMORY;
00266 }
00267
00268 request->mid_map = map;
00269 map->req = request;
00270
00271 memcpy(request->request_buf, inbuf, sizeof(request->request_buf));
00272 request->max_param = max_param;
00273 request->filter = filter;
00274 request->fsp = fsp;
00275 request->backend_data = NULL;
00276
00277 DLIST_ADD_END(fsp->notify->requests, request,
00278 struct notify_change_request *);
00279
00280 map->mid = SVAL(inbuf, smb_mid);
00281 DLIST_ADD(notify_changes_by_mid, map);
00282
00283
00284 srv_defer_sign_response(SVAL(inbuf,smb_mid));
00285
00286 return NT_STATUS_OK;
00287 }
00288
00289 static void change_notify_remove_request(struct notify_change_request *remove_req)
00290 {
00291 files_struct *fsp;
00292 struct notify_change_request *req;
00293
00294
00295
00296
00297
00298
00299 fsp = remove_req->fsp;
00300 SMB_ASSERT(fsp->notify != NULL);
00301
00302 for (req = fsp->notify->requests; req; req = req->next) {
00303 if (req == remove_req) {
00304 break;
00305 }
00306 }
00307
00308 if (req == NULL) {
00309 smb_panic("notify_req not found in fsp's requests\n");
00310 }
00311
00312 DLIST_REMOVE(fsp->notify->requests, req);
00313 DLIST_REMOVE(notify_changes_by_mid, req->mid_map);
00314 SAFE_FREE(req->mid_map);
00315 TALLOC_FREE(req->backend_data);
00316 SAFE_FREE(req);
00317 }
00318
00319
00320
00321
00322
00323 void remove_pending_change_notify_requests_by_mid(uint16 mid)
00324 {
00325 struct notify_mid_map *map;
00326
00327 for (map = notify_changes_by_mid; map; map = map->next) {
00328 if (map->mid == mid) {
00329 break;
00330 }
00331 }
00332
00333 if (map == NULL) {
00334 return;
00335 }
00336
00337 change_notify_reply_packet(map->req->request_buf, NT_STATUS_CANCELLED);
00338 change_notify_remove_request(map->req);
00339 }
00340
00341
00342
00343
00344
00345 void remove_pending_change_notify_requests_by_fid(files_struct *fsp,
00346 NTSTATUS status)
00347 {
00348 if (fsp->notify == NULL) {
00349 return;
00350 }
00351
00352 while (fsp->notify->requests != NULL) {
00353 change_notify_reply_packet(
00354 fsp->notify->requests->request_buf, status);
00355 change_notify_remove_request(fsp->notify->requests);
00356 }
00357 }
00358
00359 void notify_fname(connection_struct *conn, uint32 action, uint32 filter,
00360 const char *path)
00361 {
00362 char *fullpath;
00363
00364 if (asprintf(&fullpath, "%s/%s", conn->connectpath, path) == -1) {
00365 DEBUG(0, ("asprintf failed\n"));
00366 return;
00367 }
00368
00369 notify_trigger(conn->notify_ctx, action, filter, fullpath);
00370 SAFE_FREE(fullpath);
00371 }
00372
00373 static void notify_fsp(files_struct *fsp, uint32 action, const char *name)
00374 {
00375 struct notify_change *change, *changes;
00376 pstring name2;
00377
00378 if (fsp->notify == NULL) {
00379
00380
00381
00382 return;
00383 }
00384
00385 pstrcpy(name2, name);
00386 string_replace(name2, '/', '\\');
00387
00388
00389
00390
00391
00392
00393 if ((fsp->notify->num_changes > 1000) || (name == NULL)) {
00394
00395
00396
00397
00398 TALLOC_FREE(fsp->notify->changes);
00399 fsp->notify->num_changes = -1;
00400 return;
00401 }
00402
00403 if (fsp->notify->num_changes == -1) {
00404 return;
00405 }
00406
00407 if (!(changes = TALLOC_REALLOC_ARRAY(
00408 fsp->notify, fsp->notify->changes,
00409 struct notify_change, fsp->notify->num_changes+1))) {
00410 DEBUG(0, ("talloc_realloc failed\n"));
00411 return;
00412 }
00413
00414 fsp->notify->changes = changes;
00415
00416 change = &(fsp->notify->changes[fsp->notify->num_changes]);
00417
00418 if (!(change->name = talloc_strdup(changes, name2))) {
00419 DEBUG(0, ("talloc_strdup failed\n"));
00420 return;
00421 }
00422
00423 change->action = action;
00424 fsp->notify->num_changes += 1;
00425
00426 if (fsp->notify->requests == NULL) {
00427
00428
00429
00430 return;
00431 }
00432
00433 if (action == NOTIFY_ACTION_OLD_NAME) {
00434
00435
00436
00437
00438 return;
00439 }
00440
00441
00442
00443
00444
00445
00446
00447 change_notify_reply(fsp->notify->requests->request_buf,
00448 fsp->notify->requests->max_param,
00449 fsp->notify);
00450
00451 change_notify_remove_request(fsp->notify->requests);
00452 }
00453
00454 char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter)
00455 {
00456 char *result = NULL;
00457
00458 result = talloc_strdup(mem_ctx, "");
00459
00460 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
00461 result = talloc_asprintf_append(result, "FILE_NAME|");
00462 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
00463 result = talloc_asprintf_append(result, "DIR_NAME|");
00464 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
00465 result = talloc_asprintf_append(result, "ATTRIBUTES|");
00466 if (filter & FILE_NOTIFY_CHANGE_SIZE)
00467 result = talloc_asprintf_append(result, "SIZE|");
00468 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
00469 result = talloc_asprintf_append(result, "LAST_WRITE|");
00470 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
00471 result = talloc_asprintf_append(result, "LAST_ACCESS|");
00472 if (filter & FILE_NOTIFY_CHANGE_CREATION)
00473 result = talloc_asprintf_append(result, "CREATION|");
00474 if (filter & FILE_NOTIFY_CHANGE_EA)
00475 result = talloc_asprintf_append(result, "EA|");
00476 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
00477 result = talloc_asprintf_append(result, "SECURITY|");
00478 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
00479 result = talloc_asprintf_append(result, "STREAM_NAME|");
00480 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
00481 result = talloc_asprintf_append(result, "STREAM_SIZE|");
00482 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
00483 result = talloc_asprintf_append(result, "STREAM_WRITE|");
00484
00485 if (result == NULL) return NULL;
00486 if (*result == '\0') return result;
00487
00488 result[strlen(result)-1] = '\0';
00489 return result;
00490 }
00491
00492 struct sys_notify_context *sys_notify_context_create(connection_struct *conn,
00493 TALLOC_CTX *mem_ctx,
00494 struct event_context *ev)
00495 {
00496 struct sys_notify_context *ctx;
00497
00498 if (!(ctx = TALLOC_P(mem_ctx, struct sys_notify_context))) {
00499 DEBUG(0, ("talloc failed\n"));
00500 return NULL;
00501 }
00502
00503 ctx->ev = ev;
00504 ctx->conn = conn;
00505 ctx->private_data = NULL;
00506 return ctx;
00507 }
00508
00509 NTSTATUS sys_notify_watch(struct sys_notify_context *ctx,
00510 struct notify_entry *e,
00511 void (*callback)(struct sys_notify_context *ctx,
00512 void *private_data,
00513 struct notify_event *ev),
00514 void *private_data, void *handle)
00515 {
00516 return SMB_VFS_NOTIFY_WATCH(ctx->conn, ctx, e, callback, private_data,
00517 handle);
00518 }
00519