Ignore:
Timestamp:
Nov 24, 2016, 1:14:11 PM (9 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to version 4.4.3

File:
1 edited

Legend:

Unmodified
Added
Removed
  • vendor/current/source3/smbd/notify.c

    r746 r988  
    2424#include "smbd/globals.h"
    2525#include "../librpc/gen_ndr/ndr_notify.h"
     26#include "librpc/gen_ndr/ndr_file_id.h"
     27
     28struct notify_change_event {
     29        struct timespec when;
     30        uint32_t action;
     31        const char *name;
     32};
     33
     34struct 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};
    2653
    2754struct notify_change_request {
     
    2956        struct files_struct *fsp;       /* backpointer for cancel by mid */
    3057        struct smb_request *req;
    31         uint32 filter;
    32         uint32 max_param;
     58        uint32_t filter;
     59        uint32_t max_param;
    3360        void (*reply_fn)(struct smb_request *req,
    3461                         NTSTATUS error_code,
     
    3865};
    3966
    40 static void notify_fsp(files_struct *fsp, uint32 action, const char *name);
     67static void notify_fsp(files_struct *fsp, struct timespec when,
     68                       uint32_t action, const char *name);
     69
     70bool 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}
    4186
    4287/*
     
    5196};
    5297
    53 static bool notify_change_record_identical(struct notify_change *c1,
    54                                         struct notify_change *c2)
     98static bool notify_change_record_identical(struct notify_change_event *c1,
     99                                           struct notify_change_event *c2)
    55100{
    56101        /* Note this is deliberately case sensitive. */
     
    62107}
    63108
     109static 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
    64117static 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,
    67120                                DATA_BLOB *final_blob)
    68121{
     
    73126        }
    74127
     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
    75136        for (i=0; i<num_changes; i++) {
    76137                enum ndr_err_code ndr_err;
    77                 struct notify_change *c;
     138                struct notify_change_event *c;
    78139                struct FILE_NOTIFY_INFORMATION m;
    79140                DATA_BLOB blob;
     141                uint16_t pad = 0;
    80142
    81143                /* Coalesce any identical records. */
     
    91153                m.FileNameLength = strlen_m(c->name)*2;
    92154                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;
    94157
    95158                /*
    96159                 * Offset to next entry, only if there is one
    97160                 */
     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                }
    98171
    99172                ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &m,
     
    168241}
    169242
    170 static void notify_callback(void *private_data, const struct notify_event *e)
     243static void notify_callback(void *private_data, struct timespec when,
     244                            const struct notify_event *e)
    171245{
    172246        files_struct *fsp = (files_struct *)private_data;
    173247        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
     251NTSTATUS change_notify_create(struct files_struct *fsp, uint32_t filter,
    178252                              bool recursive)
    179253{
    180254        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))) {
    187266                DEBUG(0, ("talloc failed\n"));
    188267                return NT_STATUS_NO_MEMORY;
     
    190269
    191270        /* 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"));
    195276                TALLOC_FREE(fsp->notify);
    196277                return NT_STATUS_NO_MEMORY;
    197278        }
    198279
    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);
    212296        return status;
    213297}
    214298
    215299NTSTATUS 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,
    218302                                struct files_struct *fsp,
    219303                                void (*reply_fn)(struct smb_request *req,
     
    244328        request->backend_data = NULL;
    245329
    246         DLIST_ADD_END(fsp->notify->requests, request,
    247                       struct notify_change_request *);
     330        DLIST_ADD_END(fsp->notify->requests, request);
    248331
    249332        map->mid = request->req->mid;
     
    282365}
    283366
     367static 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
    284392/****************************************************************************
    285393 Delete entries by mid from the change notify pending queue. Always send reply.
     
    301409        }
    302410
    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);
    306412}
    307413
     
    321427        }
    322428
    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
     432static 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
     445void 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
     470done:
     471        TALLOC_FREE(fid);
    326472}
    327473
     
    346492}
    347493
    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,
     494void notify_fname(connection_struct *conn, uint32_t action, uint32_t filter,
    386495                  const char *path)
    387496{
    388         char *fullpath;
     497        struct notify_context *notify_ctx = conn->sconn->notify_ctx;
    389498
    390499        if (path[0] == '.' && path[1] == '/') {
    391500                path += 2;
    392501        }
    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
     506static void notify_fsp(files_struct *fsp, struct timespec when,
     507                       uint32_t action, const char *name)
     508{
     509        struct notify_change_event *change, *changes;
    408510        char *tmp;
    409511
     
    449551        }
    450552
    451         if (!(changes = TALLOC_REALLOC_ARRAY(
     553        if (!(changes = talloc_realloc(
    452554                      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))) {
    454557                DEBUG(0, ("talloc_realloc failed\n"));
    455558                return;
     
    468571        change->name = tmp;     
    469572
     573        change->when = when;
    470574        change->action = action;
    471575        fsp->notify->num_changes += 1;
     
    501605}
    502606
    503 char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter)
     607char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32_t filter)
    504608{
    505609        char *result = NULL;
     
    539643}
    540644
    541 struct sys_notify_context *sys_notify_context_create(connection_struct *conn,
    542                                                      TALLOC_CTX *mem_ctx,
    543                                                      struct event_context *ev)
     645struct sys_notify_context *sys_notify_context_create(TALLOC_CTX *mem_ctx,
     646                                                     struct tevent_context *ev)
    544647{
    545648        struct sys_notify_context *ctx;
    546649
    547         if (!(ctx = TALLOC_P(mem_ctx, struct sys_notify_context))) {
     650        if (!(ctx = talloc(mem_ctx, struct sys_notify_context))) {
    548651                DEBUG(0, ("talloc failed\n"));
    549652                return NULL;
     
    551654
    552655        ctx->ev = ev;
    553         ctx->conn = conn;
    554656        ctx->private_data = NULL;
    555657        return ctx;
    556658}
    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.