From 19fc6e8f511f028aa40122cc7e40c83908d07ebe Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 8 Nov 2004 03:54:12 +0000 Subject: [PATCH] r3615: split out struct pvfs_file_handle from struct pvfs_file. This is in preparation for adding code to pass the BASE-DENY1 and BASE-DENYDOS tests, which require a shared filesystem handle for some specific combinations of two DENY_DOS opens on the same connection. (This used to be commit 6e4fdf01d19051e3923d7703dbf990fc1722b09a) --- source4/include/smb_interfaces.h | 2 +- source4/ntvfs/common/opendb.c | 35 ++-- source4/ntvfs/posix/pvfs_flush.c | 4 +- source4/ntvfs/posix/pvfs_lock.c | 21 +- source4/ntvfs/posix/pvfs_open.c | 266 ++++++++++++++----------- source4/ntvfs/posix/pvfs_qfileinfo.c | 16 +- source4/ntvfs/posix/pvfs_read.c | 8 +- source4/ntvfs/posix/pvfs_seek.c | 12 +- source4/ntvfs/posix/pvfs_setfileinfo.c | 93 +++++++-- source4/ntvfs/posix/pvfs_write.c | 8 +- source4/ntvfs/posix/vfs_posix.c | 1 - source4/ntvfs/posix/vfs_posix.h | 58 ++++-- 12 files changed, 313 insertions(+), 211 deletions(-) diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h index 434f9513d2a..acc2d503bb1 100644 --- a/source4/include/smb_interfaces.h +++ b/source4/include/smb_interfaces.h @@ -794,7 +794,7 @@ union smb_setfileinfo { enum smb_setfileinfo_level level; union setfileinfo_file file; - struct { + struct smb_rename_information { uint8_t overwrite; uint32_t root_fid; const char *new_name; diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c index a1d4ed1ddbe..a07b657c339 100644 --- a/source4/ntvfs/common/opendb.c +++ b/source4/ntvfs/common/opendb.c @@ -44,7 +44,6 @@ struct odb_context { struct tdb_wrap *w; servid_t server; - uint16_t tid; struct messaging_context *messaging_ctx; }; @@ -54,8 +53,7 @@ struct odb_context { */ struct odb_entry { servid_t server; - uint16_t tid; - uint16_t fnum; + void *file_handle; uint32_t share_access; uint32_t create_options; uint32_t access_mask; @@ -78,7 +76,7 @@ struct odb_lock { talloc_free(). We need the messaging_ctx to allow for pending open notifications. */ -struct odb_context *odb_init(TALLOC_CTX *mem_ctx, servid_t server, uint16_t tid, +struct odb_context *odb_init(TALLOC_CTX *mem_ctx, servid_t server, struct messaging_context *messaging_ctx) { char *path; @@ -100,7 +98,6 @@ struct odb_context *odb_init(TALLOC_CTX *mem_ctx, servid_t server, uint16_t tid, } odb->server = server; - odb->tid = tid; odb->messaging_ctx = messaging_ctx; return odb; @@ -205,7 +202,7 @@ static BOOL share_conflict(struct odb_entry *e1, struct odb_entry *e2) register an open file in the open files database. This implements the share_access rules */ -NTSTATUS odb_open_file(struct odb_lock *lck, uint16_t fnum, +NTSTATUS odb_open_file(struct odb_lock *lck, void *file_handle, uint32_t share_access, uint32_t create_options, uint32_t access_mask) { @@ -219,8 +216,7 @@ NTSTATUS odb_open_file(struct odb_lock *lck, uint16_t fnum, dbuf = tdb_fetch(odb->w->tdb, lck->key); e.server = odb->server; - e.tid = odb->tid; - e.fnum = fnum; + e.file_handle = file_handle; e.share_access = share_access; e.create_options = create_options; e.access_mask = access_mask; @@ -276,8 +272,7 @@ NTSTATUS odb_open_file_pending(struct odb_lock *lck, void *private) dbuf = tdb_fetch(odb->w->tdb, lck->key); e.server = odb->server; - e.tid = odb->tid; - e.fnum = 0; + e.file_handle = NULL; e.share_access = 0; e.create_options = 0; e.access_mask = 0; @@ -314,7 +309,7 @@ NTSTATUS odb_open_file_pending(struct odb_lock *lck, void *private) /* remove a opendb entry */ -NTSTATUS odb_close_file(struct odb_lock *lck, uint16_t fnum) +NTSTATUS odb_close_file(struct odb_lock *lck, void *file_handle) { struct odb_context *odb = lck->odb; TDB_DATA dbuf; @@ -344,9 +339,8 @@ NTSTATUS odb_close_file(struct odb_lock *lck, uint16_t fnum) /* find the entry, and delete it */ for (i=0;iserver == elist[i].server && - odb->tid == elist[i].tid) { + if (file_handle == elist[i].file_handle && + odb->server == elist[i].server) { if (i < count-1) { memmove(elist+i, elist+i+1, (count - (i+1)) * sizeof(struct odb_entry)); @@ -399,8 +393,7 @@ NTSTATUS odb_remove_pending(struct odb_lock *lck, void *private) /* find the entry, and delete it */ for (i=0;iserver == elist[i].server && - odb->tid == elist[i].tid) { + odb->server == elist[i].server) { if (i < count-1) { memmove(elist+i, elist+i+1, (count - (i+1)) * sizeof(struct odb_entry)); @@ -434,7 +427,7 @@ NTSTATUS odb_remove_pending(struct odb_lock *lck, void *private) update create options on an open file */ NTSTATUS odb_set_create_options(struct odb_lock *lck, - uint16_t fnum, uint32_t create_options) + void *file_handle, uint32_t create_options) { struct odb_context *odb = lck->odb; TDB_DATA dbuf; @@ -452,9 +445,8 @@ NTSTATUS odb_set_create_options(struct odb_lock *lck, /* find the entry, and modify it */ for (i=0;iserver == elist[i].server && - odb->tid == elist[i].tid) { + if (file_handle == elist[i].file_handle && + odb->server == elist[i].server) { elist[i].create_options = create_options; break; } @@ -503,8 +495,7 @@ NTSTATUS odb_can_open(struct odb_context *odb, DATA_BLOB *key, } e.server = odb->server; - e.tid = odb->tid; - e.fnum = -1; + e.file_handle = NULL; e.share_access = share_access; e.create_options = create_options; e.access_mask = access_mask; diff --git a/source4/ntvfs/posix/pvfs_flush.c b/source4/ntvfs/posix/pvfs_flush.c index 6195d254ffc..66a0cc5edff 100644 --- a/source4/ntvfs/posix/pvfs_flush.c +++ b/source4/ntvfs/posix/pvfs_flush.c @@ -28,11 +28,11 @@ */ static void pvfs_flush_file(struct pvfs_state *pvfs, struct pvfs_file *f) { - if (f->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { + if (f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { return; } if (pvfs->flags & PVFS_FLAG_STRICT_SYNC) { - fsync(f->fd); + fsync(f->handle->fd); } } diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c index c8fc6c2de32..a2691cb5502 100644 --- a/source4/ntvfs/posix/pvfs_lock.c +++ b/source4/ntvfs/posix/pvfs_lock.c @@ -41,7 +41,7 @@ NTSTATUS pvfs_check_lock(struct pvfs_state *pvfs, } return brl_locktest(pvfs->brl_context, - &f->locking_key, + &f->handle->locking_key, f->fnum, smbpid, offset, count, rw); @@ -73,7 +73,7 @@ static void pvfs_lock_async_failed(struct pvfs_state *pvfs, /* undo the locks we just did */ for (i=i-1;i>=0;i--) { brl_unlock(pvfs->brl_context, - &f->locking_key, + &f->handle->locking_key, locks[i].pid, f->fnum, locks[i].offset, @@ -118,7 +118,7 @@ static void pvfs_pending_lock_continue(void *private, enum pvfs_wait_notice reas DLIST_REMOVE(f->pending_list, pending); status = brl_lock(pvfs->brl_context, - &f->locking_key, + &f->handle->locking_key, req->smbpid, f->fnum, locks[pending->pending_lock].offset, @@ -133,7 +133,8 @@ static void pvfs_pending_lock_continue(void *private, enum pvfs_wait_notice reas don't need the pending lock any more */ if (NT_STATUS_IS_OK(status) || timed_out) { NTSTATUS status2; - status2 = brl_remove_pending(pvfs->brl_context, &f->locking_key, pending); + status2 = brl_remove_pending(pvfs->brl_context, + &f->handle->locking_key, pending); if (!NT_STATUS_IS_OK(status2)) { DEBUG(0,("pvfs_lock: failed to remove pending lock - %s\n", nt_errstr(status2))); } @@ -170,7 +171,7 @@ static void pvfs_pending_lock_continue(void *private, enum pvfs_wait_notice reas } status = brl_lock(pvfs->brl_context, - &f->locking_key, + &f->handle->locking_key, req->smbpid, f->fnum, locks[i].offset, @@ -214,7 +215,7 @@ void pvfs_lock_close(struct pvfs_state *pvfs, struct pvfs_file *f) if (f->lock_count || f->pending_list) { DEBUG(5,("pvfs_lock: removing %.0f locks on close\n", (double)f->lock_count)); - brl_close(f->pvfs->brl_context, &f->locking_key, f->fnum); + brl_close(f->pvfs->brl_context, &f->handle->locking_key, f->fnum); f->lock_count = 0; } @@ -289,7 +290,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } - if (f->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { + if (f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { return NT_STATUS_FILE_IS_A_DIRECTORY; } @@ -337,7 +338,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, for (i=0;ilockx.in.ulock_cnt;i++) { status = brl_unlock(pvfs->brl_context, - &f->locking_key, + &f->handle->locking_key, locks[i].pid, f->fnum, locks[i].offset, @@ -356,7 +357,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, } status = brl_lock(pvfs->brl_context, - &f->locking_key, + &f->handle->locking_key, locks[i].pid, f->fnum, locks[i].offset, @@ -379,7 +380,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, /* undo the locks we just did */ for (i=i-1;i>=0;i--) { brl_unlock(pvfs->brl_context, - &f->locking_key, + &f->handle->locking_key, locks[i].pid, f->fnum, locks[i].offset, diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 1a25f57df16..5411f83e8db 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -47,6 +47,10 @@ struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs, return NULL; } + if (f->fnum != fnum) { + smb_panic("pvfs_find_fd: idtree_fnum corruption\n"); + } + if (req->session != f->session) { DEBUG(2,("pvfs_find_fd: attempt to use wrong session for fnum %d\n", fnum)); @@ -60,19 +64,28 @@ struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs, /* cleanup a open directory handle */ -static int pvfs_dir_fd_destructor(void *p) +static int pvfs_dir_handle_destructor(void *p) +{ + struct pvfs_file_handle *h = p; + + if (h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) { + if (rmdir(h->name->full_name) != 0) { + DEBUG(0,("pvfs_close: failed to rmdir '%s' - %s\n", + h->name->full_name, strerror(errno))); + } + } + + return 0; +} + +/* + cleanup a open directory fnum +*/ +static int pvfs_dir_fnum_destructor(void *p) { struct pvfs_file *f = p; DLIST_REMOVE(f->pvfs->open_files, f); idr_remove(f->pvfs->idtree_fnum, f->fnum); - - if (f->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) { - if (rmdir(f->name->full_name) != 0) { - DEBUG(0,("pvfs_close: failed to rmdir '%s' - %s\n", - f->name->full_name, strerror(errno))); - } - } - return 0; } @@ -124,34 +137,41 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, return NT_STATUS_NO_MEMORY; } + f->handle = talloc_p(f, struct pvfs_file_handle); + if (f->handle == NULL) { + return NT_STATUS_NO_MEMORY; + } + fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_DIR_FNUM, UINT16_MAX); if (fnum == -1) { return NT_STATUS_TOO_MANY_OPENED_FILES; } - f->fnum = fnum; - f->fd = -1; - f->name = talloc_steal(f, name); - f->session = req->session; - f->smbpid = req->smbpid; - f->pvfs = pvfs; + f->fnum = fnum; + f->session = req->session; + f->smbpid = req->smbpid; + f->pvfs = pvfs; f->pending_list = NULL; - f->lock_count = 0; - f->locking_key = data_blob(NULL, 0); - f->create_options = io->generic.in.create_options; - f->share_access = io->generic.in.share_access; - f->seek_offset = 0; - f->position = 0; - f->mode = 0; + f->lock_count = 0; + + f->handle->pvfs = pvfs; + f->handle->name = talloc_steal(f->handle, name); + f->handle->fd = -1; + f->handle->locking_key = data_blob(NULL, 0); + f->handle->create_options = io->generic.in.create_options; + f->handle->share_access = io->generic.in.share_access; + f->handle->seek_offset = 0; + f->handle->position = 0; + f->handle->mode = 0; DLIST_ADD(pvfs->open_files, f); /* TODO: should we check in the opendb? Do directory opens follow the share_access rules? */ - - /* setup a destructor to avoid leaks on abnormal termination */ - talloc_set_destructor(f, pvfs_dir_fd_destructor); + /* setup destructors to avoid leaks on abnormal termination */ + talloc_set_destructor(f->handle, pvfs_dir_handle_destructor); + talloc_set_destructor(f, pvfs_dir_fnum_destructor); if (!name->exists) { uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY; @@ -193,51 +213,61 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, return NT_STATUS_OK; } - /* - by using a destructor we make sure that abnormal cleanup will not - leak file descriptors (assuming at least the top level pointer is freed, which - will cascade down to here) + destroy a struct pvfs_file_handle */ -static int pvfs_fd_destructor(void *p) +static int pvfs_handle_destructor(void *p) { - struct pvfs_file *f = p; - struct odb_lock *lck; - NTSTATUS status; + struct pvfs_file_handle *h = p; - DLIST_REMOVE(f->pvfs->open_files, f); - - pvfs_lock_close(f->pvfs, f); - - if (f->fd != -1) { - close(f->fd); - f->fd = -1; + if (h->fd != -1) { + if (close(h->fd) != 0) { + DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n", + h->fd, h->name->full_name, strerror(errno))); + } + h->fd = -1; } - idr_remove(f->pvfs->idtree_fnum, f->fnum); - - if (f->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) { - if (unlink(f->name->full_name) != 0) { + if (h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) { + if (unlink(h->name->full_name) != 0) { DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", - f->name->full_name, strerror(errno))); + h->name->full_name, strerror(errno))); } } - lck = odb_lock(f, f->pvfs->odb_context, &f->locking_key); - if (lck == NULL) { - DEBUG(0,("Unable to lock opendb for close\n")); - return 0; - } + if (h->have_opendb_entry) { + struct odb_lock *lck; + NTSTATUS status; - if (f->have_opendb_entry) { - status = odb_close_file(lck, f->fnum); + lck = odb_lock(h, h->pvfs->odb_context, &h->locking_key); + if (lck == NULL) { + DEBUG(0,("Unable to lock opendb for close\n")); + return 0; + } + + status = odb_close_file(lck, h); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", - f->name->full_name, nt_errstr(status))); + h->name->full_name, nt_errstr(status))); } + + talloc_free(lck); } - talloc_free(lck); + return 0; +} + + +/* + destroy a struct pvfs_file +*/ +static int pvfs_fnum_destructor(void *p) +{ + struct pvfs_file *f = p; + + DLIST_REMOVE(f->pvfs->open_files, f); + pvfs_lock_close(f->pvfs, f); + idr_remove(f->pvfs->idtree_fnum, f->fnum); return 0; } @@ -310,6 +340,11 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, return NT_STATUS_NO_MEMORY; } + f->handle = talloc_p(f, struct pvfs_file_handle); + if (f->handle == NULL) { + return NT_STATUS_NO_MEMORY; + } + fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_NEW_FNUM, UINT16_MAX); if (fnum == -1) { return NT_STATUS_TOO_MANY_OPENED_FILES; @@ -343,7 +378,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, /* form the lock context used for byte range locking and opendb locking */ - status = pvfs_locking_key(name, f, &f->locking_key); + status = pvfs_locking_key(name, f->handle, &f->handle->locking_key); if (!NT_STATUS_IS_OK(status)) { idr_remove(pvfs->idtree_fnum, fnum); close(fd); @@ -351,7 +386,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, } /* grab a lock on the open file record */ - lck = odb_lock(req, pvfs->odb_context, &f->locking_key); + lck = odb_lock(req, pvfs->odb_context, &f->handle->locking_key); if (lck == NULL) { DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n", name->full_name)); @@ -362,7 +397,8 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, return NT_STATUS_INTERNAL_DB_CORRUPTION; } - status = odb_open_file(lck, fnum, share_access, create_options, access_mask); + status = odb_open_file(lck, f->handle, + share_access, create_options, access_mask); talloc_free(lck); if (!NT_STATUS_IS_OK(status)) { /* bad news, we must have hit a race */ @@ -372,26 +408,29 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, } f->fnum = fnum; - f->fd = fd; - f->name = talloc_steal(f, name); f->session = req->session; f->smbpid = req->smbpid; f->pvfs = pvfs; f->pending_list = NULL; f->lock_count = 0; - f->create_options = io->generic.in.create_options; - f->share_access = io->generic.in.share_access; - f->access_mask = access_mask; - f->seek_offset = 0; - f->position = 0; - f->mode = 0; - f->have_opendb_entry = True; + + f->handle->pvfs = pvfs; + f->handle->name = talloc_steal(f->handle, name); + f->handle->fd = fd; + f->handle->create_options = io->generic.in.create_options; + f->handle->share_access = io->generic.in.share_access; + f->handle->access_mask = access_mask; + f->handle->seek_offset = 0; + f->handle->position = 0; + f->handle->mode = 0; + f->handle->have_opendb_entry = True; DLIST_ADD(pvfs->open_files, f); /* setup a destructor to avoid file descriptor leaks on abnormal termination */ - talloc_set_destructor(f, pvfs_fd_destructor); + talloc_set_destructor(f, pvfs_fnum_destructor); + talloc_set_destructor(f->handle, pvfs_handle_destructor); io->generic.out.oplock_level = NO_OPLOCK; io->generic.out.fnum = f->fnum; @@ -518,7 +557,9 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs, r->ntvfs = ntvfs; r->req = req; r->io = io; - r->locking_key = data_blob_talloc(r, f->locking_key.data, f->locking_key.length); + r->locking_key = data_blob_talloc(r, + f->handle->locking_key.data, + f->handle->locking_key.length); end_time = timeval_add(&req->request_time, 0, pvfs->sharing_violation_delay); @@ -714,37 +755,44 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, return NT_STATUS_NO_MEMORY; } + f->handle = talloc_p(f, struct pvfs_file_handle); + if (f->handle == NULL) { + return NT_STATUS_NO_MEMORY; + } + /* allocate a fnum */ fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_FILE_FNUM, UINT16_MAX); if (fnum == -1) { return NT_STATUS_TOO_MANY_OPENED_FILES; } - f->fnum = fnum; - f->fd = -1; - f->name = talloc_steal(f, name); - f->session = req->session; - f->smbpid = req->smbpid; - f->pvfs = pvfs; + f->fnum = fnum; + f->session = req->session; + f->smbpid = req->smbpid; + f->pvfs = pvfs; f->pending_list = NULL; - f->lock_count = 0; - f->create_options = io->generic.in.create_options; - f->share_access = io->generic.in.share_access; - f->access_mask = access_mask; - f->seek_offset = 0; - f->position = 0; - f->have_opendb_entry = False; + f->lock_count = 0; + + f->handle->pvfs = pvfs; + f->handle->fd = -1; + f->handle->name = talloc_steal(f->handle, name); + f->handle->create_options = io->generic.in.create_options; + f->handle->share_access = io->generic.in.share_access; + f->handle->access_mask = access_mask; + f->handle->seek_offset = 0; + f->handle->position = 0; + f->handle->have_opendb_entry = False; /* form the lock context used for byte range locking and opendb locking */ - status = pvfs_locking_key(name, f, &f->locking_key); + status = pvfs_locking_key(name, f->handle, &f->handle->locking_key); if (!NT_STATUS_IS_OK(status)) { idr_remove(pvfs->idtree_fnum, f->fnum); return status; } /* get a lock on this file before the actual open */ - lck = odb_lock(req, pvfs->odb_context, &f->locking_key); + lck = odb_lock(req, pvfs->odb_context, &f->handle->locking_key); if (lck == NULL) { DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n", name->full_name)); @@ -758,11 +806,13 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, /* setup a destructor to avoid file descriptor leaks on abnormal termination */ - talloc_set_destructor(f, pvfs_fd_destructor); + talloc_set_destructor(f, pvfs_fnum_destructor); + talloc_set_destructor(f->handle, pvfs_handle_destructor); /* see if we are allowed to open at the same time as existing opens */ - status = odb_open_file(lck, f->fnum, share_access, create_options, access_mask); + status = odb_open_file(lck, f->handle, + share_access, create_options, access_mask); /* on a sharing violation we need to retry when the file is closed by the other user, or after 1 second */ @@ -776,19 +826,19 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, return status; } - f->have_opendb_entry = True; + f->handle->have_opendb_entry = True; /* do the actual open */ - fd = open(f->name->full_name, flags); + fd = open(f->handle->name->full_name, flags); if (fd == -1) { talloc_free(lck); return pvfs_map_errno(f->pvfs, errno); } - f->fd = fd; + f->handle->fd = fd; /* re-resolve the open fd */ - status = pvfs_resolve_name_fd(f->pvfs, fd, f->name); + status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name); if (!NT_STATUS_IS_OK(status)) { talloc_free(lck); return status; @@ -816,13 +866,13 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, io->generic.out.oplock_level = NO_OPLOCK; io->generic.out.fnum = f->fnum; io->generic.out.create_action = NTCREATEX_ACTION_EXISTED; - io->generic.out.create_time = f->name->dos.create_time; - io->generic.out.access_time = f->name->dos.access_time; - io->generic.out.write_time = f->name->dos.write_time; - io->generic.out.change_time = f->name->dos.change_time; - io->generic.out.attrib = f->name->dos.attrib; - io->generic.out.alloc_size = f->name->dos.alloc_size; - io->generic.out.size = f->name->st.st_size; + io->generic.out.create_time = name->dos.create_time; + io->generic.out.access_time = name->dos.access_time; + io->generic.out.write_time = name->dos.write_time; + io->generic.out.change_time = name->dos.change_time; + io->generic.out.attrib = name->dos.attrib; + io->generic.out.alloc_size = name->dos.alloc_size; + io->generic.out.size = name->st.st_size; io->generic.out.file_type = FILE_TYPE_DISK; io->generic.out.ipc_state = 0; io->generic.out.is_directory = 0; @@ -842,7 +892,6 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs, { struct pvfs_state *pvfs = ntvfs->private_data; struct pvfs_file *f; - NTSTATUS status; struct utimbuf unix_times; if (io->generic.level == RAW_CLOSE_SPLCLOSE) { @@ -861,21 +910,12 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs, if (!null_time(io->close.in.write_time)) { unix_times.actime = 0; unix_times.modtime = io->close.in.write_time; - utime(f->name->full_name, &unix_times); + utime(f->handle->name->full_name, &unix_times); } - if (f->fd != -1 && - close(f->fd) == -1) { - status = pvfs_map_errno(pvfs, errno); - } else { - status = NT_STATUS_OK; - } - f->fd = -1; - - /* the destructor takes care of the rest */ talloc_free(f); - return status; + return NT_STATUS_OK; } @@ -929,23 +969,23 @@ NTSTATUS pvfs_change_create_options(struct pvfs_state *pvfs, struct odb_lock *lck; NTSTATUS status; - if (f->create_options == create_options) { + if (f->handle->create_options == create_options) { return NT_STATUS_OK; } - if ((f->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && + if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) { return NT_STATUS_CANNOT_DELETE; } - lck = odb_lock(req, pvfs->odb_context, &f->locking_key); + lck = odb_lock(req, pvfs->odb_context, &f->handle->locking_key); if (lck == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } - status = odb_set_create_options(lck, f->fnum, create_options); + status = odb_set_create_options(lck, f->handle, create_options); if (NT_STATUS_IS_OK(status)) { - f->create_options = create_options; + f->handle->create_options = create_options; } return status; diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c index 5847b1a2cc5..fee3b19c9f7 100644 --- a/source4/ntvfs/posix/pvfs_qfileinfo.c +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -242,27 +242,29 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs, { struct pvfs_state *pvfs = ntvfs->private_data; struct pvfs_file *f; + struct pvfs_file_handle *h; NTSTATUS status; f = pvfs_find_fd(pvfs, req, info->generic.in.fnum); if (!f) { return NT_STATUS_INVALID_HANDLE; } + h = f->handle; /* update the file information */ - status = pvfs_resolve_name_fd(pvfs, f->fd, f->name); + status = pvfs_resolve_name_fd(pvfs, h->fd, h->name); if (!NT_STATUS_IS_OK(status)) { return status; } - status = pvfs_map_fileinfo(pvfs, req, f->name, info, f->fd); + status = pvfs_map_fileinfo(pvfs, req, h->name, info, h->fd); /* a qfileinfo can fill in a bit more info than a qpathinfo - now modify the levels that need to be fixed up */ switch (info->generic.level) { case RAW_FILEINFO_STANDARD_INFO: case RAW_FILEINFO_STANDARD_INFORMATION: - if (f->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) { + if (h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) { info->standard_info.out.delete_pending = 1; info->standard_info.out.nlink--; } @@ -270,22 +272,22 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs, case RAW_FILEINFO_ALL_INFO: case RAW_FILEINFO_ALL_INFORMATION: - if (f->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) { + if (h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) { info->all_info.out.delete_pending = 1; info->all_info.out.nlink--; } break; case RAW_FILEINFO_POSITION_INFORMATION: - info->position_information.out.position = f->position; + info->position_information.out.position = h->position; break; case RAW_FILEINFO_ACCESS_INFORMATION: - info->access_information.out.access_flags = f->access_mask; + info->access_information.out.access_flags = h->access_mask; break; case RAW_FILEINFO_MODE_INFORMATION: - info->mode_information.out.mode = f->mode; + info->mode_information.out.mode = h->mode; break; default: diff --git a/source4/ntvfs/posix/pvfs_read.c b/source4/ntvfs/posix/pvfs_read.c index f5df26f3d11..b14a1e601c6 100644 --- a/source4/ntvfs/posix/pvfs_read.c +++ b/source4/ntvfs/posix/pvfs_read.c @@ -46,7 +46,7 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } - if (f->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { + if (f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { return NT_STATUS_FILE_IS_A_DIRECTORY; } @@ -54,7 +54,7 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs, if (req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) { mask |= SA_RIGHT_FILE_EXECUTE; } - if (!(f->access_mask & mask)) { + if (!(f->handle->access_mask & mask)) { return NT_STATUS_ACCESS_DENIED; } @@ -71,7 +71,7 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs, return status; } - ret = pread(f->fd, + ret = pread(f->handle->fd, rd->readx.out.data, maxcnt, rd->readx.in.offset); @@ -79,7 +79,7 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs, return pvfs_map_errno(pvfs, errno); } - f->position = f->seek_offset = rd->readx.in.offset + ret; + f->handle->position = f->handle->seek_offset = rd->readx.in.offset + ret; rd->readx.out.nread = ret; rd->readx.out.remaining = 0xFFFF; diff --git a/source4/ntvfs/posix/pvfs_seek.c b/source4/ntvfs/posix/pvfs_seek.c index c90db952fc8..c4dd30bd85c 100644 --- a/source4/ntvfs/posix/pvfs_seek.c +++ b/source4/ntvfs/posix/pvfs_seek.c @@ -31,31 +31,33 @@ NTSTATUS pvfs_seek(struct ntvfs_module_context *ntvfs, { struct pvfs_state *pvfs = ntvfs->private_data; struct pvfs_file *f; + struct pvfs_file_handle *h; NTSTATUS status; f = pvfs_find_fd(pvfs, req, io->in.fnum); if (!f) { return NT_STATUS_INVALID_HANDLE; } + h = f->handle; status = NT_STATUS_OK; switch (io->in.mode) { case SEEK_MODE_START: - f->seek_offset = io->in.offset; + h->seek_offset = io->in.offset; break; case SEEK_MODE_CURRENT: - f->seek_offset += io->in.offset; + h->seek_offset += io->in.offset; break; case SEEK_MODE_END: - status = pvfs_resolve_name_fd(pvfs, f->fd, f->name); - f->seek_offset = f->name->st.st_size + io->in.offset; + status = pvfs_resolve_name_fd(pvfs, h->fd, h->name); + h->seek_offset = h->name->st.st_size + io->in.offset; break; } - io->out.offset = f->seek_offset; + io->out.offset = h->seek_offset; return status; } diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c index 15b7f168f2e..cad51c751cc 100644 --- a/source4/ntvfs/posix/pvfs_setfileinfo.c +++ b/source4/ntvfs/posix/pvfs_setfileinfo.c @@ -26,6 +26,47 @@ #include "librpc/gen_ndr/ndr_xattr.h" +/* + rename_information level +*/ +static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs, + struct smbsrv_request *req, + struct pvfs_filename *name, + struct smb_rename_information *r) +{ +#if 0 + NTSTATUS status; + struct pvfs_filename *name2; + char *base_dir, *p; + + /* renames are only allowed within a directory */ + if (strchr_m(r->new_name, '\\')) { + return NT_STATUS_NOT_SUPPORTED; + } + + if (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { + /* don't allow this for now */ + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + /* work out the base directory that the source file is in */ + base_dir = talloc_strdup(name, name->full_name); + p = strrchr(base_dir, '/'); + *p = 0; + + /* resolve the new name */ + status = pvfs_resolve_partial(pvfs, req, base_dir, r->new_name, &name2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (name2->exists && !r->overwrite) { + return NT_STATUS_OBJECT_NAME_COLLISION; + } +#endif + return NT_STATUS_UNSUCCESSFUL; +} + /* add a single DOS EA */ @@ -90,6 +131,7 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, struct pvfs_state *pvfs = ntvfs->private_data; struct utimbuf unix_times; struct pvfs_file *f; + struct pvfs_file_handle *h; uint32_t create_options; struct pvfs_filename newstats; NTSTATUS status; @@ -99,8 +141,10 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } + h = f->handle; + /* update the file information */ - status = pvfs_resolve_name_fd(pvfs, f->fd, f->name); + status = pvfs_resolve_name_fd(pvfs, h->fd, h->name); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -108,7 +152,7 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, /* we take a copy of the current file stats, then update newstats in each of the elements below. At the end we compare, and make any changes needed */ - newstats = *f->name; + newstats = *h->name; switch (info->generic.level) { case RAW_SFILEINFO_SETATTR: @@ -134,7 +178,8 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, break; case RAW_SFILEINFO_EA_SET: - return pvfs_setfileinfo_ea_set(pvfs, f->name, f->fd, &info->ea_set.in.ea); + return pvfs_setfileinfo_ea_set(pvfs, h->name, h->fd, + &info->ea_set.in.ea); case RAW_SFILEINFO_BASIC_INFO: case RAW_SFILEINFO_BASIC_INFORMATION: @@ -157,10 +202,10 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, case RAW_SFILEINFO_DISPOSITION_INFO: case RAW_SFILEINFO_DISPOSITION_INFORMATION: - if (!(f->access_mask & STD_RIGHT_DELETE_ACCESS)) { + if (!(h->access_mask & STD_RIGHT_DELETE_ACCESS)) { return NT_STATUS_ACCESS_DENIED; } - create_options = f->create_options; + create_options = h->create_options; if (info->disposition_info.in.delete_on_close) { create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; } else { @@ -182,7 +227,7 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, break; case RAW_SFILEINFO_POSITION_INFORMATION: - f->position = info->position_information.in.position; + h->position = info->position_information.in.position; break; case RAW_SFILEINFO_MODE_INFORMATION: @@ -193,23 +238,27 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, info->mode_information.in.mode != 6) { return NT_STATUS_INVALID_PARAMETER; } - f->mode = info->mode_information.in.mode; + h->mode = info->mode_information.in.mode; break; + case RAW_SFILEINFO_RENAME_INFORMATION: + return pvfs_setfileinfo_rename(pvfs, req, h->name, + &info->rename_information.in); + default: return NT_STATUS_INVALID_LEVEL; } /* possibly change the file size */ - if (newstats.st.st_size != f->name->st.st_size) { + if (newstats.st.st_size != h->name->st.st_size) { int ret; - if (f->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { + if (h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { return NT_STATUS_FILE_IS_A_DIRECTORY; } - if (f->access_mask & SA_RIGHT_FILE_WRITE_APPEND) { - ret = ftruncate(f->fd, newstats.st.st_size); + if (h->access_mask & SA_RIGHT_FILE_WRITE_APPEND) { + ret = ftruncate(h->fd, newstats.st.st_size); } else { - ret = truncate(f->name->full_name, newstats.st.st_size); + ret = truncate(h->name->full_name, newstats.st.st_size); } if (ret == -1) { return pvfs_map_errno(pvfs, errno); @@ -218,33 +267,33 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, /* possibly change the file timestamps */ ZERO_STRUCT(unix_times); - if (newstats.dos.access_time != f->name->dos.access_time) { + if (newstats.dos.access_time != h->name->dos.access_time) { unix_times.actime = nt_time_to_unix(newstats.dos.access_time); } - if (newstats.dos.write_time != f->name->dos.write_time) { + if (newstats.dos.write_time != h->name->dos.write_time) { unix_times.modtime = nt_time_to_unix(newstats.dos.write_time); } if (unix_times.actime != 0 || unix_times.modtime != 0) { - if (utime(f->name->full_name, &unix_times) == -1) { + if (utime(h->name->full_name, &unix_times) == -1) { return pvfs_map_errno(pvfs, errno); } } /* possibly change the attribute */ - if (newstats.dos.attrib != f->name->dos.attrib) { + if (newstats.dos.attrib != h->name->dos.attrib) { mode_t mode = pvfs_fileperms(pvfs, newstats.dos.attrib); - if (f->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { + if (h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { /* ignore on directories for now */ return NT_STATUS_OK; } - if (fchmod(f->fd, mode) == -1) { + if (fchmod(h->fd, mode) == -1) { return pvfs_map_errno(pvfs, errno); } } - *f->name = newstats; + *h->name = newstats; - return pvfs_dosattrib_save(pvfs, f->name, f->fd); + return pvfs_dosattrib_save(pvfs, h->name, h->fd); } @@ -349,6 +398,10 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs, } return NT_STATUS_OK; + case RAW_SFILEINFO_RENAME_INFORMATION: + return pvfs_setfileinfo_rename(pvfs, req, name, + &info->rename_information.in); + case RAW_SFILEINFO_DISPOSITION_INFO: case RAW_SFILEINFO_DISPOSITION_INFORMATION: case RAW_SFILEINFO_POSITION_INFORMATION: diff --git a/source4/ntvfs/posix/pvfs_write.c b/source4/ntvfs/posix/pvfs_write.c index ccf3a775a82..7b381239718 100644 --- a/source4/ntvfs/posix/pvfs_write.c +++ b/source4/ntvfs/posix/pvfs_write.c @@ -44,11 +44,11 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } - if (f->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { + if (f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { return NT_STATUS_FILE_IS_A_DIRECTORY; } - if (!(f->access_mask & SA_RIGHT_FILE_WRITE_APPEND)) { + if (!(f->handle->access_mask & SA_RIGHT_FILE_WRITE_APPEND)) { return NT_STATUS_ACCESS_VIOLATION; } @@ -60,7 +60,7 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs, return status; } - ret = pwrite(f->fd, + ret = pwrite(f->handle->fd, wr->writex.in.data, wr->writex.in.count, wr->writex.in.offset); @@ -71,7 +71,7 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs, return map_nt_error_from_unix(errno); } - f->seek_offset = wr->writex.in.offset + ret; + f->handle->seek_offset = wr->writex.in.offset + ret; wr->writex.out.nwritten = ret; wr->writex.out.remaining = 0; /* should fill this in? */ diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index da4296d0624..39f6717cae2 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -108,7 +108,6 @@ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs, pvfs->odb_context = odb_init(pvfs, pvfs->tcon->smb_conn->connection->server_id, - pvfs->tcon->service, pvfs->tcon->smb_conn->connection->messaging_ctx); if (pvfs->odb_context == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h index 91940e63550..3f74de4b63e 100644 --- a/source4/ntvfs/posix/vfs_posix.h +++ b/source4/ntvfs/posix/vfs_posix.h @@ -84,34 +84,21 @@ struct pvfs_filename { }; -/* open file state */ -struct pvfs_file { - struct pvfs_file *next, *prev; +/* open file handle state - encapsulates the posix fd + + Note that this is separated from the pvfs_file structure in order + to cope with the openx DENY_DOS semantics where a 2nd DENY_DOS open + on the same connection gets the same low level filesystem handle, + rather than a new handle +*/ +struct pvfs_file_handle { int fd; - uint16_t fnum; + struct pvfs_filename *name; - /* we need to remember the session it was opened on, - as it is illegal to operate on someone elses fnum */ - struct smbsrv_session *session; - - /* we need to remember the client pid that - opened the file so SMBexit works */ - uint16_t smbpid; - /* a unique file key to be used for file locking */ DATA_BLOB locking_key; - /* we need this hook back to our parent for lock destruction */ - struct pvfs_state *pvfs; - - /* a list of pending locks - used for locking cancel operations */ - struct pvfs_pending_lock *pending_list; - - /* a count of active locks - used to avoid calling brl_close on - file close */ - uint64_t lock_count; - uint32_t create_options; uint32_t share_access; uint32_t access_mask; @@ -124,6 +111,33 @@ struct pvfs_file { uint64_t position; BOOL have_opendb_entry; + + /* we need this hook back to our parent for lock destruction */ + struct pvfs_state *pvfs; +}; + +/* open file state */ +struct pvfs_file { + struct pvfs_file *next, *prev; + struct pvfs_file_handle *handle; + uint16_t fnum; + + struct pvfs_state *pvfs; + + /* we need to remember the session it was opened on, + as it is illegal to operate on someone elses fnum */ + struct smbsrv_session *session; + + /* we need to remember the client pid that + opened the file so SMBexit works */ + uint16_t smbpid; + + /* a list of pending locks - used for locking cancel operations */ + struct pvfs_pending_lock *pending_list; + + /* a count of active locks - used to avoid calling brl_close on + file close */ + uint64_t lock_count; };