summaryrefslogtreecommitdiff
path: root/source4/ntvfs
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2008-03-03 10:50:53 +0100
committerJelmer Vernooij <jelmer@samba.org>2008-03-03 10:50:53 +0100
commit7dd0cd26d32980d4edb9db5c77c98a2b112e24cb (patch)
tree025dad49b789c0e9f2eb03d87ec386295630b3f0 /source4/ntvfs
parent80e9b72e018fb7d7f2cd5ff383e4a533b4ccc705 (diff)
parent4d4a898742a0439d3f60c84194b02901412f4679 (diff)
downloadsamba-7dd0cd26d32980d4edb9db5c77c98a2b112e24cb.tar.gz
samba-7dd0cd26d32980d4edb9db5c77c98a2b112e24cb.tar.bz2
samba-7dd0cd26d32980d4edb9db5c77c98a2b112e24cb.zip
Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-gmake3
Conflicts: source/Makefile source/build/smb_build/makefile.pm source/librpc/config.mk (This used to be commit 3e02fcfd3fb6683f51417ba39f4ec177494eff3e)
Diffstat (limited to 'source4/ntvfs')
-rw-r--r--source4/ntvfs/common/opendb.c8
-rw-r--r--source4/ntvfs/common/opendb.h1
-rw-r--r--source4/ntvfs/common/opendb_tdb.c20
-rw-r--r--source4/ntvfs/posix/pvfs_open.c4
-rw-r--r--source4/ntvfs/posix/pvfs_qfileinfo.c2
-rw-r--r--source4/ntvfs/posix/pvfs_rename.c25
-rw-r--r--source4/ntvfs/posix/pvfs_resolve.c93
-rw-r--r--source4/ntvfs/posix/pvfs_setfileinfo.c31
8 files changed, 155 insertions, 29 deletions
diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c
index d8cb67686b..6c1a9c070a 100644
--- a/source4/ntvfs/common/opendb.c
+++ b/source4/ntvfs/common/opendb.c
@@ -143,6 +143,14 @@ _PUBLIC_ NTSTATUS odb_rename(struct odb_lock *lck, const char *path)
}
/*
+ get back the path of an open file
+*/
+_PUBLIC_ NTSTATUS odb_get_path(struct odb_lock *lck, const char **path)
+{
+ return ops->odb_get_path(lck, path);
+}
+
+/*
update delete on close flag on an open file
*/
_PUBLIC_ NTSTATUS odb_set_delete_on_close(struct odb_lock *lck, bool del_on_close)
diff --git a/source4/ntvfs/common/opendb.h b/source4/ntvfs/common/opendb.h
index 33f2e1c88d..69a7f718ba 100644
--- a/source4/ntvfs/common/opendb.h
+++ b/source4/ntvfs/common/opendb.h
@@ -36,6 +36,7 @@ struct opendb_ops {
const char **delete_path);
NTSTATUS (*odb_remove_pending)(struct odb_lock *lck, void *private);
NTSTATUS (*odb_rename)(struct odb_lock *lck, const char *path);
+ NTSTATUS (*odb_get_path)(struct odb_lock *lck, const char **path);
NTSTATUS (*odb_set_delete_on_close)(struct odb_lock *lck, bool del_on_close);
NTSTATUS (*odb_get_delete_on_close)(struct odb_context *odb,
DATA_BLOB *key, bool *del_on_close);
diff --git a/source4/ntvfs/common/opendb_tdb.c b/source4/ntvfs/common/opendb_tdb.c
index 37c1c0850b..47b35f594c 100644
--- a/source4/ntvfs/common/opendb_tdb.c
+++ b/source4/ntvfs/common/opendb_tdb.c
@@ -714,6 +714,25 @@ static NTSTATUS odb_tdb_rename(struct odb_lock *lck, const char *path)
}
/*
+ get the path of an open file
+*/
+static NTSTATUS odb_tdb_get_path(struct odb_lock *lck, const char **path)
+{
+ struct opendb_file file;
+ NTSTATUS status;
+
+ *path = NULL;
+
+ status = odb_pull_record(lck, &file);
+ /* we don't ignore NT_STATUS_OBJECT_NAME_NOT_FOUND here */
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *path = file.path;
+
+ return NT_STATUS_OK;
+}
+
+/*
update delete on close flag on an open file
*/
static NTSTATUS odb_tdb_set_delete_on_close(struct odb_lock *lck, bool del_on_close)
@@ -802,6 +821,7 @@ static const struct opendb_ops opendb_tdb_ops = {
.odb_close_file = odb_tdb_close_file,
.odb_remove_pending = odb_tdb_remove_pending,
.odb_rename = odb_tdb_rename,
+ .odb_get_path = odb_tdb_get_path,
.odb_set_delete_on_close = odb_tdb_set_delete_on_close,
.odb_get_delete_on_close = odb_tdb_get_delete_on_close,
.odb_can_open = odb_tdb_can_open,
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index 740a0a9d13..adf4c1ac18 100644
--- a/source4/ntvfs/posix/pvfs_open.c
+++ b/source4/ntvfs/posix/pvfs_open.c
@@ -144,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;
diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c
index 6ed729541f..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;
}
diff --git a/source4/ntvfs/posix/pvfs_rename.c b/source4/ntvfs/posix/pvfs_rename.c
index 185e35f800..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 {
@@ -315,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);
@@ -448,9 +450,9 @@ static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
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;
@@ -532,10 +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);
- if (NT_STATUS_IS_OK(status)) {
- status = odb_rename(lck, 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 2bfc47beff..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 = '/';
}
@@ -399,7 +406,7 @@ static NTSTATUS pvfs_reduce_name(TALLOC_CTX *mem_ctx,
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;
}
@@ -616,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: