diff options
-rw-r--r-- | source4/cluster/ctdb/opendb_ctdb.c | 20 | ||||
-rw-r--r-- | source4/ntvfs/common/opendb.c | 8 | ||||
-rw-r--r-- | source4/ntvfs/common/opendb.h | 1 | ||||
-rw-r--r-- | source4/ntvfs/common/opendb_tdb.c | 20 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 4 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_qfileinfo.c | 2 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_resolve.c | 93 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_setfileinfo.c | 32 | ||||
-rw-r--r-- | source4/samba4-knownfail | 2 | ||||
-rw-r--r-- | source4/torture/raw/chkpath.c | 77 | ||||
-rw-r--r-- | source4/torture/raw/setfileinfo.c | 115 |
11 files changed, 339 insertions, 35 deletions
diff --git a/source4/cluster/ctdb/opendb_ctdb.c b/source4/cluster/ctdb/opendb_ctdb.c index 3d67162d6d..e84f2364d4 100644 --- a/source4/cluster/ctdb/opendb_ctdb.c +++ b/source4/cluster/ctdb/opendb_ctdb.c @@ -543,6 +543,25 @@ static NTSTATUS odb_ctdb_rename(struct odb_lock *lck, const char *path) } /* + get the path of an open file +*/ +static NTSTATUS odb_ctdb_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_ctdb_set_delete_on_close(struct odb_lock *lck, bool del_on_close) @@ -653,6 +672,7 @@ static const struct opendb_ops opendb_ctdb_ops = { .odb_close_file = odb_ctdb_close_file, .odb_remove_pending = odb_ctdb_remove_pending, .odb_rename = odb_ctdb_rename, + .odb_get_path = odb_ctdb_get_path, .odb_set_delete_on_close = odb_ctdb_set_delete_on_close, .odb_get_delete_on_close = odb_ctdb_get_delete_on_close, .odb_can_open = odb_ctdb_can_open, 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_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..5ac9cedc48 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,8 +165,19 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs, return status; } + 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, name, name2->full_name); if (NT_STATUS_IS_OK(status)) { + status = odb_rename(lck, 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 +297,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 +399,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 +574,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 +706,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/samba4-knownfail b/source4/samba4-knownfail index aaa11774ae..4d850caae5 100644 --- a/source4/samba4-knownfail +++ b/source4/samba4-knownfail @@ -3,8 +3,6 @@ local.iconv.*.next_codepoint() base.delaywrite.finfo update on close base.delete.*.deltest20a base.delete.*.deltest20b -raw.oplock.*BATCH19 -raw.oplock.*BATCH20 rpc.winreg local.registry.*.security # Not implemented yet rpc.wkssvc diff --git a/source4/torture/raw/chkpath.c b/source4/torture/raw/chkpath.c index 42a3c3cebe..fa69c92caa 100644 --- a/source4/torture/raw/chkpath.c +++ b/source4/torture/raw/chkpath.c @@ -54,24 +54,68 @@ static NTSTATUS single_search(struct smbcli_state *cli, return status; } -static bool test_path(struct smbcli_state *cli, const char *path, NTSTATUS expected, NTSTATUS dos_expected) +static bool test_path_ex(struct smbcli_state *cli, struct torture_context *tctx, + const char *path, const char *path_expected, + NTSTATUS expected, NTSTATUS dos_expected) { union smb_chkpath io; + union smb_fileinfo finfo; NTSTATUS status; + io.chkpath.in.path = path; status = smb_raw_chkpath(cli->tree, &io); if (!NT_STATUS_EQUAL(status, expected) && !NT_STATUS_EQUAL(status, dos_expected)) { - printf("%-40s FAILED %s should be %s or %s\n", + printf("FAILED %-30s chkpath %s should be %s or %s\n", path, nt_errstr(status), nt_errstr(expected), nt_errstr(dos_expected)); return false; } else { - printf("%-40s correct (%s)\n", path, nt_errstr(status)); + printf("%-30s chkpath correct (%s)\n", path, nt_errstr(status)); + } + + if (NT_STATUS_EQUAL(expected, NT_STATUS_NOT_A_DIRECTORY)) { + expected = NT_STATUS_OK; + } + + ZERO_STRUCT(finfo); + finfo.generic.level = RAW_FILEINFO_NAME_INFO; + finfo.generic.in.file.path = path; + status = smb_raw_pathinfo(cli->tree, cli, &finfo); + if (!NT_STATUS_EQUAL(status, expected) && !NT_STATUS_EQUAL(status, dos_expected)) { + printf("FAILED: %-30s pathinfo %s should be %s or %s\n", + path, nt_errstr(status), nt_errstr(expected), nt_errstr(dos_expected)); + return false; + } + + if (!NT_STATUS_IS_OK(status)) { + printf("%-30s chkpath correct (%s)\n", path, nt_errstr(status)); + return true; + } + if (path_expected && + (!finfo.name_info.out.fname.s || + strcmp(finfo.name_info.out.fname.s, path_expected) != 0)) { + if (tctx && torture_setting_bool(tctx, "samba4", false)) { + printf("IGNORE: %-30s => %-20s should be %s\n", + path, finfo.name_info.out.fname.s, path_expected); + return true; + } + printf("FAILED: %-30s => %-20s should be %s\n", + path, finfo.name_info.out.fname.s, path_expected); + return false; } + printf("%-30s => %-20s correct\n", + path, finfo.name_info.out.fname.s); + return true; } -static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) +static bool test_path(struct smbcli_state *cli, const char *path, + NTSTATUS expected, NTSTATUS dos_expected) +{ + return test_path_ex(cli, NULL, path, path, expected, dos_expected); +} + +static bool test_chkpath(struct smbcli_state *cli, struct torture_context *tctx) { union smb_chkpath io; NTSTATUS status; @@ -86,7 +130,7 @@ static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) ret &= test_path(cli, BASEDIR "\\nodir", NT_STATUS_OBJECT_NAME_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath)); - fnum = create_complex_file(cli, mem_ctx, BASEDIR "\\test.txt.."); + fnum = create_complex_file(cli, tctx, BASEDIR "\\test.txt.."); if (fnum == -1) { printf("failed to open test.txt - %s\n", smbcli_errstr(cli->tree)); ret = false; @@ -101,9 +145,20 @@ static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) goto done; } - ret &= test_path(cli, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); - ret &= test_path(cli, BASEDIR "\\foo\\..\\test.txt..", NT_STATUS_NOT_A_DIRECTORY, NT_STATUS_DOS(ERRDOS,ERRbadpath)); - ret &= test_path(cli, "", NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR) + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\foo\\..") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\f\\o\\o\\..\\..\\..") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\foo\\\\\..\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR"\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR"\\\\..\\"BASEDIR, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR"\\\\\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, "\\\\\\\\"BASEDIR"\\\\\\\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, "\\\\\\\\"BASEDIR, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR "\\foo\\..\\test.txt..", BASEDIR "\\test.txt..", + NT_STATUS_NOT_A_DIRECTORY, NT_STATUS_DOS(ERRDOS,ERRbadpath)); + ret &= test_path_ex(cli, tctx, "", "\\", NT_STATUS_OK, NT_STATUS_OK); ret &= test_path(cli, ".", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath)); ret &= test_path(cli, ".\\", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath)); ret &= test_path(cli, "\\\\\\.\\", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath)); @@ -122,7 +177,7 @@ static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) give different NT status returns for chkpth and findfirst. */ printf("testing findfirst on %s\n", "\\.\\\\\\\\\\\\."); - status = single_search(cli, mem_ctx, "\\.\\\\\\\\\\\\."); + status = single_search(cli, tctx, "\\.\\\\\\\\\\\\."); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRinvalidname)); ret &= test_path(cli, "\\.\\\\\\\\\\\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath)); @@ -164,7 +219,7 @@ static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) ret &= test_path(cli, "\\..\\", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath)); ret &= test_path(cli, "\\..", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath)); ret &= test_path(cli, BASEDIR "\\.", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath)); - ret &= test_path(cli, BASEDIR "\\..", NT_STATUS_OK,NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR "\\..", "\\", NT_STATUS_OK,NT_STATUS_OK); ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb600", NT_STATUS_OBJECT_NAME_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath)); ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb6.exe", NT_STATUS_NOT_A_DIRECTORY,NT_STATUS_DOS(ERRDOS,ERRbadpath)); @@ -183,7 +238,7 @@ static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath)); printf("testing findfirst on %s\n", BASEDIR".\\.\\.\\.\\foo\\..\\.\\"); - status = single_search(cli, mem_ctx, BASEDIR".\\.\\.\\.\\foo\\..\\.\\"); + status = single_search(cli, tctx, BASEDIR".\\.\\.\\.\\foo\\..\\.\\"); CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath)); /* We expect this open to fail with the same error code as the chkpath below. */ diff --git a/source4/torture/raw/setfileinfo.c b/source4/torture/raw/setfileinfo.c index e58b3fd760..90ccde7213 100644 --- a/source4/torture/raw/setfileinfo.c +++ b/source4/torture/raw/setfileinfo.c @@ -453,6 +453,10 @@ bool torture_raw_sfileinfo_rename(struct torture_context *torture, char *fnum_fname_new; char *path_fname; char *path_fname_new; + char *path_dname; + char *path_dname_new; + char *saved_name; + char *saved_name_new; union smb_fileinfo finfo1, finfo2; union smb_setfileinfo sfinfo; NTSTATUS status, status2; @@ -464,6 +468,8 @@ bool torture_raw_sfileinfo_rename(struct torture_context *torture, asprintf(&path_fname_new, BASEDIR "\\fname_test_new_%d.txt", n); asprintf(&fnum_fname, BASEDIR "\\fnum_test_%d.txt", n); asprintf(&fnum_fname_new, BASEDIR "\\fnum_test_new_%d.txt", n); + asprintf(&path_dname, BASEDIR "\\dname_test_%d", n); + asprintf(&path_dname_new, BASEDIR "\\dname_test_new_%d", n); if (!torture_setup_dir(cli, BASEDIR)) { return false; @@ -553,17 +559,112 @@ bool torture_raw_sfileinfo_rename(struct torture_context *torture, sfinfo.rename_information.in.root_fid = d_fnum; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_INVALID_PARAMETER); CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname); + smbcli_close(cli->tree, d_fnum); -done: - smb_raw_exit(cli->session); - smbcli_close(cli->tree, fnum); - if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fnum_fname))) { - printf("Failed to delete %s - %s\n", fnum_fname, smbcli_errstr(cli->tree)); + printf("Trying rename directory\n"); + if (!torture_setup_dir(cli, path_dname)) { + ret = false; + goto done; } - if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, path_fname))) { - printf("Failed to delete %s - %s\n", path_fname, smbcli_errstr(cli->tree)); + saved_name = path_fname; + saved_name_new = path_fname_new; + path_fname = path_dname; + path_fname_new = path_dname_new; + sfinfo.rename_information.in.new_name = path_dname_new+strlen(BASEDIR)+1; + sfinfo.rename_information.in.overwrite = 0; + sfinfo.rename_information.in.root_fid = 0; + CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new); + path_fname = saved_name; + path_fname_new = saved_name_new; + + if (torture_setting_bool(torture, "samba3", false)) { + printf("SKIP: Trying rename directory with a handle\n"); + printf("SKIP: Trying rename by path while a handle is open\n"); + printf("SKIP: Trying rename directory by path while a handle is open\n"); + goto done; } + printf("Trying rename directory with a handle\n"); + status = create_directory_handle(cli->tree, path_dname_new, &d_fnum); + fnum_saved = fnum; + fnum = d_fnum; + saved_name = fnum_fname; + saved_name_new = fnum_fname_new; + fnum_fname = path_dname; + fnum_fname_new = path_dname_new; + sfinfo.rename_information.in.new_name = path_dname+strlen(BASEDIR)+1; + sfinfo.rename_information.in.overwrite = 0; + sfinfo.rename_information.in.root_fid = 0; + CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname); + smbcli_close(cli->tree, d_fnum); + fnum = fnum_saved; + fnum_fname = saved_name; + fnum_fname_new = saved_name_new; + + printf("Trying rename by path while a handle is open\n"); + fnum_saved = fnum; + fnum = create_complex_file(cli, torture, path_fname); + sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1; + sfinfo.rename_information.in.overwrite = 0; + sfinfo.rename_information.in.root_fid = 0; + CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new); + /* check that the handle returns the same name */ + check_fnum = true; + CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new); + /* rename it back on the handle */ + sfinfo.rename_information.in.new_name = path_fname+strlen(BASEDIR)+1; + CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_fname); + check_fnum = false; + CHECK_STR(NAME_INFO, name_info, fname.s, path_fname); + smbcli_close(cli->tree, fnum); + fnum = fnum_saved; + + printf("Trying rename directory by path while a handle is open\n"); + status = create_directory_handle(cli->tree, path_dname, &d_fnum); + fnum_saved = fnum; + fnum = d_fnum; + saved_name = path_fname; + saved_name_new = path_fname_new; + path_fname = path_dname; + path_fname_new = path_dname_new; + sfinfo.rename_information.in.new_name = path_dname_new+strlen(BASEDIR)+1; + sfinfo.rename_information.in.overwrite = 0; + sfinfo.rename_information.in.root_fid = 0; + CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new); + path_fname = saved_name; + path_fname_new = saved_name_new; + saved_name = fnum_fname; + saved_name_new = fnum_fname_new; + fnum_fname = path_dname; + fnum_fname_new = path_dname_new; + /* check that the handle returns the same name */ + check_fnum = true; + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new); + /* rename it back on the handle */ + sfinfo.rename_information.in.new_name = path_dname+strlen(BASEDIR)+1; + CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname); + fnum_fname = saved_name; + fnum_fname_new = saved_name_new; + saved_name = path_fname; + saved_name_new = path_fname_new; + path_fname = path_dname; + path_fname_new = path_dname_new; + check_fnum = false; + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname); + smbcli_close(cli->tree, d_fnum); + fnum = fnum_saved; + path_fname = saved_name; + path_fname_new = saved_name_new; + +done: + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); return ret; } |