diff options
Diffstat (limited to 'source4/ntvfs/posix')
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 91 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_qfileinfo.c | 6 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_rename.c | 112 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_resolve.c | 7 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_xattr.c | 2 |
5 files changed, 154 insertions, 64 deletions
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index a01352f60c..740a0a9d13 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -50,29 +50,10 @@ struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs, */ static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h) { - int open_count; - char *path = NULL; - - if (h->name->stream_name == NULL && - pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) && - open_count == 1) { - NTSTATUS status; - status = pvfs_xattr_unlink_hook(h->pvfs, path); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n", - path, nt_errstr(status))); - } - if (rmdir(path) != 0) { - DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n", - path, strerror(errno))); - } - } - - talloc_free(path); - if (h->have_opendb_entry) { struct odb_lock *lck; NTSTATUS status; + const char *delete_path = NULL; lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); if (lck == NULL) { @@ -80,12 +61,24 @@ static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h) return 0; } - status = odb_close_file(lck, h); + status = odb_close_file(lck, h, &delete_path); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", + DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", h->name->full_name, nt_errstr(status))); } + if (h->name->stream_name == NULL && delete_path) { + status = pvfs_xattr_unlink_hook(h->pvfs, delete_path); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n", + delete_path, nt_errstr(status))); + } + if (rmdir(delete_path) != 0) { + DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n", + delete_path, strerror(errno))); + } + } + talloc_free(lck); } @@ -410,9 +403,6 @@ cleanup_delete: */ static int pvfs_handle_destructor(struct pvfs_file_handle *h) { - int open_count; - char *path = NULL; - /* the write time is no longer sticky */ if (h->sticky_write_time) { NTSTATUS status; @@ -441,32 +431,10 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h) h->fd = -1; } - if (h->name->stream_name == NULL && - h->open_completed && - pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) && - open_count == 1) { - NTSTATUS status; - status = pvfs_xattr_unlink_hook(h->pvfs, path); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n", - path, nt_errstr(status))); - } - if (unlink(path) != 0) { - DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", - path, strerror(errno))); - } else { - notify_trigger(h->pvfs->notify_context, - NOTIFY_ACTION_REMOVED, - FILE_NOTIFY_CHANGE_FILE_NAME, - path); - } - } - - talloc_free(path); - if (h->have_opendb_entry) { struct odb_lock *lck; NTSTATUS status; + const char *delete_path = NULL; lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); if (lck == NULL) { @@ -474,12 +442,30 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h) return 0; } - status = odb_close_file(lck, h); + status = odb_close_file(lck, h, &delete_path); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", h->name->full_name, nt_errstr(status))); } + if (h->name->stream_name == NULL && + h->open_completed && delete_path) { + status = pvfs_xattr_unlink_hook(h->pvfs, delete_path); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n", + delete_path, nt_errstr(status))); + } + if (unlink(delete_path) != 0) { + DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", + delete_path, strerror(errno))); + } else { + notify_trigger(h->pvfs->notify_context, + NOTIFY_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_FILE_NAME, + delete_path); + } + } + talloc_free(lck); } @@ -574,7 +560,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, status = pvfs_locking_key(parent, req, &locking_key); NT_STATUS_NOT_OK_RETURN(status); status = odb_get_delete_on_close(pvfs->odb_context, &locking_key, - &del_on_close, NULL, NULL); + &del_on_close); NT_STATUS_NOT_OK_RETURN(status); if (del_on_close) { return NT_STATUS_DELETE_PENDING; @@ -1738,14 +1724,13 @@ NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, /* determine if delete on close is set on */ -bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h, - int *open_count, char **path) +bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h) { NTSTATUS status; bool del_on_close; status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key, - &del_on_close, open_count, path); + &del_on_close); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("WARNING: unable to determine delete on close status for open file\n")); return false; diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c index 8d23d707a4..6ed729541f 100644 --- a/source4/ntvfs/posix/pvfs_qfileinfo.c +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -380,7 +380,7 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs, switch (info->generic.level) { case RAW_FILEINFO_STANDARD_INFO: case RAW_FILEINFO_STANDARD_INFORMATION: - if (pvfs_delete_on_close_set(pvfs, h, NULL, NULL)) { + if (pvfs_delete_on_close_set(pvfs, h)) { info->standard_info.out.delete_pending = 1; info->standard_info.out.nlink--; } @@ -388,7 +388,7 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs, case RAW_FILEINFO_ALL_INFO: case RAW_FILEINFO_ALL_INFORMATION: - if (pvfs_delete_on_close_set(pvfs, h, NULL, NULL)) { + if (pvfs_delete_on_close_set(pvfs, h)) { info->all_info.out.delete_pending = 1; info->all_info.out.nlink--; } @@ -407,7 +407,7 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs, break; case RAW_FILEINFO_SMB2_ALL_INFORMATION: - if (pvfs_delete_on_close_set(pvfs, h, NULL, NULL)) { + if (pvfs_delete_on_close_set(pvfs, h)) { info->all_info2.out.delete_pending = 1; info->all_info2.out.nlink--; } diff --git a/source4/ntvfs/posix/pvfs_rename.c b/source4/ntvfs/posix/pvfs_rename.c index 5693e79314..185e35f800 100644 --- a/source4/ntvfs/posix/pvfs_rename.c +++ b/source4/ntvfs/posix/pvfs_rename.c @@ -134,12 +134,12 @@ static const char *pvfs_resolve_wildcard_component(TALLOC_CTX *mem_ctx, resolve a wildcard rename pattern. */ static const char *pvfs_resolve_wildcard(TALLOC_CTX *mem_ctx, + struct smb_iconv_convenience *iconv_convenience, const char *fname, const char *pattern) { const char *base1, *base2; const char *ext1, *ext2; - struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(global_loadparm); char *p; /* break into base part plus extension */ @@ -181,6 +181,84 @@ static const char *pvfs_resolve_wildcard(TALLOC_CTX *mem_ctx, } /* + retry an rename after a sharing violation +*/ +static void pvfs_retry_rename(struct pvfs_odb_retry *r, + struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + void *_io, + void *private_data, + enum pvfs_wait_notice reason) +{ + union smb_rename *io = talloc_get_type(_io, union smb_rename); + NTSTATUS status = NT_STATUS_INTERNAL_ERROR; + + talloc_free(r); + + switch (reason) { + case PVFS_WAIT_CANCEL: +/*TODO*/ + status = NT_STATUS_CANCELLED; + break; + case PVFS_WAIT_TIMEOUT: + /* if it timed out, then give the failure + immediately */ +/*TODO*/ + status = NT_STATUS_SHARING_VIOLATION; + break; + case PVFS_WAIT_EVENT: + + /* try the open again, which could trigger another retry setup + if it wants to, so we have to unmark the async flag so we + will know if it does a second async reply */ + req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC; + + status = pvfs_rename(ntvfs, req, io); + if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) { + /* the 2nd try also replied async, so we don't send + the reply yet */ + return; + } + + /* re-mark it async, just in case someone up the chain does + paranoid checking */ + req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; + break; + } + + /* send the reply up the chain */ + req->async_states->status = status; + req->async_states->send_fn(req); +} + +/* + setup for a rename retry after a sharing violation + or a non granted oplock +*/ +static NTSTATUS pvfs_rename_setup_retry(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_rename *io, + struct odb_lock *lck, + NTSTATUS status) +{ + struct pvfs_state *pvfs = ntvfs->private_data; + struct timeval end_time; + + if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) { + end_time = timeval_add(&req->statistics.request_time, + 0, pvfs->sharing_violation_delay); + } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) { + end_time = timeval_add(&req->statistics.request_time, + pvfs->oplock_break_timeout, 0); + } else { + return NT_STATUS_INTERNAL_ERROR; + } + + return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL, + pvfs_retry_rename); +} + +/* rename one file from a wildcard set */ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs, @@ -196,7 +274,7 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs, NTSTATUS status; /* resolve the wildcard pattern for this name */ - fname2 = pvfs_resolve_wildcard(mem_ctx, fname1, fname2); + fname2 = pvfs_resolve_wildcard(mem_ctx, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), fname1, fname2); if (fname2 == NULL) { return NT_STATUS_NO_MEMORY; } @@ -354,8 +432,19 @@ static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs, } status = pvfs_can_rename(pvfs, req, name1, &lck); + /* + * on a sharing violation we need to retry when the file is closed by + * the other user, or after 1 second + * on a non granted oplock we need to retry when the file is closed by + * the other user, or after 30 seconds + */ + if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) || + NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) && + (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { + return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status); + } + if (!NT_STATUS_IS_OK(status)) { - talloc_free(lck); return status; } @@ -377,6 +466,7 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs, struct pvfs_state *pvfs = ntvfs->private_data; NTSTATUS status; struct pvfs_filename *name1, *name2; + struct odb_lock *lck = NULL; switch (ren->ntrename.in.flags) { case RENAME_FLAG_RENAME: @@ -422,7 +512,18 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs, return status; } - status = pvfs_can_rename(pvfs, req, name1, NULL); + status = pvfs_can_rename(pvfs, req, name1, &lck); + /* + * on a sharing violation we need to retry when the file is closed by + * the other user, or after 1 second + * on a non granted oplock we need to retry when the file is closed by + * the other user, or after 30 seconds + */ + if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) || + NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) && + (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { + return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status); + } if (!NT_STATUS_IS_OK(status)) { return status; } @@ -432,6 +533,9 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs, status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE); NT_STATUS_NOT_OK_RETURN(status); status = pvfs_do_rename(pvfs, name1, name2->full_name); + if (NT_STATUS_IS_OK(status)) { + status = odb_rename(lck, name2->full_name); + } NT_STATUS_NOT_OK_RETURN(status); break; diff --git a/source4/ntvfs/posix/pvfs_resolve.c b/source4/ntvfs/posix/pvfs_resolve.c index cf74816391..2bfc47beff 100644 --- a/source4/ntvfs/posix/pvfs_resolve.c +++ b/source4/ntvfs/posix/pvfs_resolve.c @@ -329,14 +329,15 @@ static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name, reduce a name that contains .. components or repeated \ separators return NULL if it can't be reduced */ -static NTSTATUS pvfs_reduce_name(TALLOC_CTX *mem_ctx, const char **fname, uint_t flags) +static NTSTATUS pvfs_reduce_name(TALLOC_CTX *mem_ctx, + struct smb_iconv_convenience *iconv_convenience, + const char **fname, uint_t flags) { codepoint_t c; size_t c_size, len; int i, num_components, err_count; char **components; char *p, *s, *ret; - struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(global_loadparm); s = talloc_strdup(mem_ctx, *fname); if (s == NULL) return NT_STATUS_NO_MEMORY; @@ -471,7 +472,7 @@ NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) { /* it might contain .. components which need to be reduced */ - status = pvfs_reduce_name(*name, &cifs_name, flags); + status = pvfs_reduce_name(*name, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), &cifs_name, flags); if (!NT_STATUS_IS_OK(status)) { return status; } diff --git a/source4/ntvfs/posix/pvfs_xattr.c b/source4/ntvfs/posix/pvfs_xattr.c index 39090bf702..b66d252a45 100644 --- a/source4/ntvfs/posix/pvfs_xattr.c +++ b/source4/ntvfs/posix/pvfs_xattr.c @@ -140,7 +140,7 @@ _PUBLIC_ NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs, NTSTATUS status; enum ndr_err_code ndr_err; - ndr_err = ndr_push_struct_blob(&blob, mem_ctx, lp_iconv_convenience(global_loadparm), p, (ndr_push_flags_fn_t)push_fn); + ndr_err = ndr_push_struct_blob(&blob, mem_ctx, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), p, (ndr_push_flags_fn_t)push_fn); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { talloc_free(mem_ctx); return ndr_map_error2ntstatus(ndr_err); |