summaryrefslogtreecommitdiff
path: root/source4/ntvfs/posix
diff options
context:
space:
mode:
Diffstat (limited to 'source4/ntvfs/posix')
-rw-r--r--source4/ntvfs/posix/pvfs_open.c95
-rw-r--r--source4/ntvfs/posix/pvfs_qfileinfo.c8
-rw-r--r--source4/ntvfs/posix/pvfs_rename.c131
-rw-r--r--source4/ntvfs/posix/pvfs_resolve.c100
-rw-r--r--source4/ntvfs/posix/pvfs_setfileinfo.c31
-rw-r--r--source4/ntvfs/posix/pvfs_xattr.c2
6 files changed, 277 insertions, 90 deletions
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index a01352f60c..adf4c1ac18 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);
}
@@ -151,8 +144,8 @@ static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
form the lock context used for opendb locking. Note that we must
zero here to take account of possible padding on some architectures
*/
-static NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
- TALLOC_CTX *mem_ctx, DATA_BLOB *key)
+NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
+ TALLOC_CTX *mem_ctx, DATA_BLOB *key)
{
struct {
dev_t device;
@@ -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..6bc21e5e3e 100644
--- a/source4/ntvfs/posix/pvfs_qfileinfo.c
+++ b/source4/ntvfs/posix/pvfs_qfileinfo.c
@@ -368,7 +368,7 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
}
/* update the file information */
- status = pvfs_resolve_name_fd(pvfs, h->fd, h->name);
+ status = pvfs_resolve_name_handle(pvfs, h);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -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..29b2d03005 100644
--- a/source4/ntvfs/posix/pvfs_rename.c
+++ b/source4/ntvfs/posix/pvfs_rename.c
@@ -28,16 +28,22 @@
/*
do a file rename, and send any notify triggers
*/
-NTSTATUS pvfs_do_rename(struct pvfs_state *pvfs, const struct pvfs_filename *name1,
+NTSTATUS pvfs_do_rename(struct pvfs_state *pvfs,
+ struct odb_lock *lck,
+ const struct pvfs_filename *name1,
const char *name2)
{
const char *r1, *r2;
uint32_t mask;
+ NTSTATUS status;
if (rename(name1->full_name, name2) == -1) {
return pvfs_map_errno(pvfs, errno);
}
+ status = odb_rename(lck, name2);
+ NT_STATUS_NOT_OK_RETURN(status);
+
if (name1->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
mask = FILE_NOTIFY_CHANGE_DIR_NAME;
} else {
@@ -134,12 +140,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 +187,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 +280,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;
}
@@ -237,11 +321,7 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
return NT_STATUS_NO_MEMORY;
}
- status = pvfs_do_rename(pvfs, name1, fname2);
-
- if (NT_STATUS_IS_OK(status)) {
- status = odb_rename(lck, fname2);
- }
+ status = pvfs_do_rename(pvfs, lck, name1, fname2);
failed:
talloc_free(mem_ctx);
@@ -354,14 +434,25 @@ 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;
}
- status = pvfs_do_rename(pvfs, name1, name2->full_name);
- if (NT_STATUS_IS_OK(status)) {
- status = odb_rename(lck, name2->full_name);
+ status = pvfs_do_rename(pvfs, lck, name1, name2->full_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
return NT_STATUS_OK;
@@ -377,6 +468,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 +514,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;
}
@@ -431,7 +534,7 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
case RENAME_FLAG_RENAME:
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);
+ status = pvfs_do_rename(pvfs, lck, name1, 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..325bc74f8f 100644
--- a/source4/ntvfs/posix/pvfs_resolve.c
+++ b/source4/ntvfs/posix/pvfs_resolve.c
@@ -265,8 +265,15 @@ static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name,
of a name */
return NT_STATUS_ILLEGAL_CHARACTER;
}
- if (p > p_start && p[1] == 0) {
- *p = 0;
+ if (p > p_start && (p[1] == '\\' || p[1] == '\0')) {
+ /* see if it is definately a "\\" or
+ * a trailing "\". If it is then fail here,
+ * and let the next layer up try again after
+ * pvfs_reduce_name() if it wants to. This is
+ * much more efficient on average than always
+ * scanning for these separately
+ */
+ return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
} else {
*p = '/';
}
@@ -329,14 +336,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;
@@ -398,7 +406,7 @@ static NTSTATUS pvfs_reduce_name(TALLOC_CTX *mem_ctx, const char **fname, uint_t
if (ISDOTDOT(components[i])) {
if (i < 1) return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
memmove(&components[i-1], &components[i+1],
- sizeof(char *)*(num_components-(i+1)));
+ sizeof(char *)*(num_components-i));
i -= 2;
continue;
}
@@ -471,7 +479,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;
}
@@ -615,6 +623,86 @@ NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd,
return pvfs_fill_dos_info(pvfs, name, fd);
}
+/*
+ fill in the pvfs_filename info for an open file, given the current
+ info for a (possibly) non-open file. This is used by places that need
+ to update the pvfs_filename stat information, and the path
+ after a possible rename on a different handle.
+*/
+NTSTATUS pvfs_resolve_name_handle(struct pvfs_state *pvfs,
+ struct pvfs_file_handle *h)
+{
+ NTSTATUS status;
+
+ if (h->have_opendb_entry) {
+ struct odb_lock *lck;
+ const char *name = NULL;
+
+ lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
+ if (lck == NULL) {
+ DEBUG(0,("%s: failed to lock file '%s' in opendb\n",
+ __FUNCTION__, h->name->full_name));
+ /* we were supposed to do a blocking lock, so something
+ is badly wrong! */
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ status = odb_get_path(lck, &name);
+ if (NT_STATUS_IS_OK(status)) {
+ /*
+ * This relies an the fact that
+ * renames of open files are only
+ * allowed by setpathinfo() and setfileinfo()
+ * and there're only renames within the same
+ * directory supported
+ */
+ if (strcmp(h->name->full_name, name) != 0) {
+ const char *orig_dir;
+ const char *new_file;
+ const char *new_orig;
+ char *delim;
+
+ delim = strrchr(name, '/');
+ if (!delim) {
+ talloc_free(lck);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ new_file = delim + 1;
+ delim = strrchr(h->name->original_name, '\\');
+ if (delim) {
+ delim[0] = '\0';
+ orig_dir = h->name->original_name;
+ new_orig = talloc_asprintf(h->name, "%s\\%s",
+ orig_dir, new_file);
+ if (!new_orig) {
+ talloc_free(lck);
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ new_orig = talloc_strdup(h->name, new_file);
+ if (!new_orig) {
+ talloc_free(lck);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ talloc_free(h->name->original_name);
+ talloc_free(h->name->full_name);
+ h->name->full_name = talloc_steal(h->name, name);
+ h->name->original_name = new_orig;
+ }
+ }
+
+ talloc_free(lck);
+ }
+
+ status = pvfs_resolve_name_fd(pvfs, h->fd, h->name);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ return NT_STATUS_OK;
+}
+
/*
resolve the parent of a given name
diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c
index da1e31e639..ad47fe90c9 100644
--- a/source4/ntvfs/posix/pvfs_setfileinfo.c
+++ b/source4/ntvfs/posix/pvfs_setfileinfo.c
@@ -82,11 +82,13 @@ static uint32_t pvfs_setfileinfo_access(union smb_setfileinfo *info)
static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
struct ntvfs_request *req,
struct pvfs_filename *name,
+ DATA_BLOB *odb_locking_key,
union smb_setfileinfo *info)
{
NTSTATUS status;
struct pvfs_filename *name2;
char *new_name, *p;
+ struct odb_lock *lck = NULL;
/* renames are only allowed within a directory */
if (strchr_m(info->rename_information.in.new_name, '\\') &&
@@ -94,11 +96,6 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
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;
- }
-
/* don't allow stream renames for now */
if (name->stream_name) {
return NT_STATUS_INVALID_PARAMETER;
@@ -168,7 +165,15 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
return status;
}
- status = pvfs_do_rename(pvfs, name, name2->full_name);
+ lck = odb_lock(req, pvfs->odb_context, odb_locking_key);
+ if (lck == NULL) {
+ DEBUG(0,("Unable to lock opendb for can_stat\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ status = pvfs_do_rename(pvfs, lck, name, name2->full_name);
+ talloc_free(lck);
+ NT_STATUS_NOT_OK_RETURN(status);
if (NT_STATUS_IS_OK(status)) {
name->full_name = talloc_steal(name, name2->full_name);
name->original_name = talloc_steal(name, name2->original_name);
@@ -289,7 +294,7 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
}
/* update the file information */
- status = pvfs_resolve_name_fd(pvfs, h->fd, h->name);
+ status = pvfs_resolve_name_handle(pvfs, h);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -391,7 +396,8 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
case RAW_SFILEINFO_RENAME_INFORMATION:
case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
- return pvfs_setfileinfo_rename(pvfs, req, h->name,
+ return pvfs_setfileinfo_rename(pvfs, req, h->name,
+ &h->odb_locking_key,
info);
case RAW_SFILEINFO_SEC_DESC:
@@ -565,6 +571,7 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
uint32_t access_needed;
uint32_t change_mask = 0;
struct odb_lock *lck = NULL;
+ DATA_BLOB odb_locking_key;
/* resolve the cifs name to a posix name */
status = pvfs_resolve_name(pvfs, req, info->generic.in.file.path,
@@ -696,8 +703,12 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
case RAW_SFILEINFO_RENAME_INFORMATION:
case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
- return pvfs_setfileinfo_rename(pvfs, req, name,
- info);
+ status = pvfs_locking_key(name, name, &odb_locking_key);
+ NT_STATUS_NOT_OK_RETURN(status);
+ status = pvfs_setfileinfo_rename(pvfs, req, name,
+ &odb_locking_key, info);
+ NT_STATUS_NOT_OK_RETURN(status);
+ return NT_STATUS_OK;
case RAW_SFILEINFO_DISPOSITION_INFO:
case RAW_SFILEINFO_DISPOSITION_INFORMATION:
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);