The branch, master has been updated via b43a581 ntvfs/posix: don't advertise FS_ATTR_SPARSE_FILES via 5e3b5b5 torture: trivial test_ioctl_network_interface_info cleanup via a3aee061 torture: test FSCTL_SET_SPARSE without SetSparse buffer via 9a3e88b torture: test FSCTL_SET_SPARSE against a directory via 9dc7aaf torture: test FSCTL_SET_SPARSE via de2164b idl: define sparse file fsctl structures from 0751495 dosmode: fix FSCTL_SET_SPARSE request validation
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit b43a5810f839df823af2eb74fa2290c64e5dfaf6 Author: David Disseldorp <dd...@samba.org> Date: Fri Aug 29 12:22:56 2014 +0200 ntvfs/posix: don't advertise FS_ATTR_SPARSE_FILES Handling of the FSCTL_SET_SPARSE ioctl in ntvfs is broken. Removing FS_ATTR_SPARSE_FILES from the filesystem attributes ensures that clients, including the smbtorture ioctl tests, don't attempt to use this functionality. Signed-off-by: David Disseldorp <dd...@samba.org> Reviewed-by: Jeremy Allson <j...@samba.org> Autobuild-User(master): David Disseldorp <dd...@samba.org> Autobuild-Date(master): Fri Aug 29 22:06:21 CEST 2014 on sn-devel-104 commit 5e3b5b53b28edfc4d343b3162d9656e6952fac07 Author: David Disseldorp <dd...@samba.org> Date: Wed Aug 27 15:20:08 2014 +0200 torture: trivial test_ioctl_network_interface_info cleanup Signed-off-by: David Disseldorp <dd...@samba.org> Reviewed-by: Jeremy Allson <j...@samba.org> commit a3aee061b4be5d4813940a102f042f18d744e82e Author: David Disseldorp <dd...@samba.org> Date: Wed Aug 27 15:17:04 2014 +0200 torture: test FSCTL_SET_SPARSE without SetSparse buffer This test checks for the following MS-FSCC 2.3.63 behaviour: If there is no data element, the sparse flag for the file is set, exactly as if the FILE_SET_SPARSE_BUFFER element was supplied and had a SetSparse value of TRUE. Signed-off-by: David Disseldorp <dd...@samba.org> Reviewed-by: Jeremy Allson <j...@samba.org> commit 9a3e88bc0a60ba672c5f72c0e9e60622e0818960 Author: David Disseldorp <dd...@samba.org> Date: Wed Aug 27 14:45:58 2014 +0200 torture: test FSCTL_SET_SPARSE against a directory Expect STATUS_INVALID_PARAMETER, as is returned by Windows Server 2012 and 2008. Samba is currently broken, in that it currently processes the request and sets the sparse DOS attribute on the directory - fix to follow. Signed-off-by: David Disseldorp <dd...@samba.org> Reviewed-by: Jeremy Allson <j...@samba.org> commit 9dc7aaf952e3dd9930cb04b9282883065e01c0e0 Author: David Disseldorp <dd...@samba.org> Date: Tue Aug 26 19:30:39 2014 +0200 torture: test FSCTL_SET_SPARSE Check that the FILE_ATTRIBUTE_SPARSE is set following FSCTL_SET_SPARSE. Also confirm that adding the attribute on create doesn't carry through to subsequent SMB2_GETINFO_FILE requests. Signed-off-by: David Disseldorp <dd...@samba.org> Reviewed-by: Jeremy Allson <j...@samba.org> commit de2164bb3d1923cb0271c20f1594c8eb6b7864d4 Author: David Disseldorp <dd...@samba.org> Date: Tue Aug 26 19:28:55 2014 +0200 idl: define sparse file fsctl structures As documented in MS-FSCC 2.3. Signed-off-by: David Disseldorp <dd...@samba.org> Reviewed-by: Jeremy Allson <j...@samba.org> ----------------------------------------------------------------------- Summary of changes: librpc/idl/ioctl.idl | 35 +++++ source4/ntvfs/posix/vfs_posix.c | 3 +- source4/torture/smb2/ioctl.c | 279 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 310 insertions(+), 7 deletions(-) Changeset truncated at 500 lines: diff --git a/librpc/idl/ioctl.idl b/librpc/idl/ioctl.idl index a0a9950..8248092 100644 --- a/librpc/idl/ioctl.idl +++ b/librpc/idl/ioctl.idl @@ -144,3 +144,38 @@ interface netinterface fsctl_sockaddr_storage sockaddr; } fsctl_net_iface_info; } + +interface sparse +{ + /* MS-FSCC 2.3.33 FSCTL_QUERY_ALLOCATED_RANGES Request */ + typedef [public] struct { + hyper file_off; + hyper len; + } file_alloced_range_buf; + + typedef [public] struct { + file_alloced_range_buf buf; + } fsctl_query_alloced_ranges_req; + + /* + * 2.3.34 FSCTL_QUERY_ALLOCATED_RANGES Reply + * ... + * The number of FILE_ALLOCATED_RANGE_BUFFER elements returned is + * computed by dividing the size of the returned output buffer (from + * either SMB or SMB2, the lower-layer protocol that carries the FSCTL) + * by the size of the FILE_ALLOCATED_RANGE_BUFFER element. + */ + typedef [public] struct { + file_alloced_range_buf *array; + } fsctl_query_alloced_ranges_rsp; + + /* 2.3.65 FSCTL_SET_ZERO_DATA Request */ + typedef [public] struct { + hyper file_off; + hyper beyond_final_zero; + } file_zero_data_info; + + typedef [public] struct { + file_zero_data_info info; + } fsctl_set_zero_data_req; +} diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index 304a9ff..0ce2e6f 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -114,8 +114,7 @@ static void pvfs_setup_options(struct pvfs_state *pvfs) pvfs->fs_attribs = FS_ATTR_CASE_SENSITIVE_SEARCH | FS_ATTR_CASE_PRESERVED_NAMES | - FS_ATTR_UNICODE_ON_DISK | - FS_ATTR_SPARSE_FILES; + FS_ATTR_UNICODE_ON_DISK; /* allow xattrs to be stored in a external tdb */ eadb = share_string_option(pvfs, scfg, PVFS_EADB, NULL); diff --git a/source4/torture/smb2/ioctl.c b/source4/torture/smb2/ioctl.c index 053a7c8..df98b04 100644 --- a/source4/torture/smb2/ioctl.c +++ b/source4/torture/smb2/ioctl.c @@ -2449,16 +2449,278 @@ static bool test_ioctl_network_interface_info(struct torture_context *torture, torture_assert_ndr_success(torture, ndr_ret, "ndr_pull_fsctl_net_iface_info"); - ndr_print_debug((ndr_print_fn_t)ndr_print_fsctl_net_iface_info - , "Network Interface Info", &net_iface); + ndr_print_debug((ndr_print_fn_t)ndr_print_fsctl_net_iface_info, + "Network Interface Info", &net_iface); talloc_free(tmp_ctx); return true; } +static NTSTATUS test_ioctl_sparse_fs_supported(struct torture_context *torture, + struct smb2_tree *tree, + TALLOC_CTX *mem_ctx, + struct smb2_handle *fh, + bool *sparse_support) +{ + NTSTATUS status; + union smb_fsinfo info; + + ZERO_STRUCT(info); + info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION; + info.generic.handle = *fh; + status = smb2_getinfo_fs(tree, tree, &info); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (info.attribute_info.out.fs_attr & FILE_SUPPORTS_SPARSE_FILES) { + *sparse_support = true; + } else { + *sparse_support = false; + } + return NT_STATUS_OK; +} + +static NTSTATUS test_ioctl_sparse_req(struct torture_context *torture, + TALLOC_CTX *mem_ctx, + struct smb2_tree *tree, + struct smb2_handle fh, + bool set) +{ + union smb_ioctl ioctl; + NTSTATUS status; + uint8_t set_sparse; + + ZERO_STRUCT(ioctl); + ioctl.smb2.level = RAW_IOCTL_SMB2; + ioctl.smb2.in.file.handle = fh; + ioctl.smb2.in.function = FSCTL_SET_SPARSE; + ioctl.smb2.in.max_response_size = 0; + ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL; + set_sparse = (set ? 0xFF : 0x0); + ioctl.smb2.in.out.data = &set_sparse; + ioctl.smb2.in.out.length = sizeof(set_sparse); + + status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2); + return status; +} + +static NTSTATUS test_sparse_get(struct torture_context *torture, + TALLOC_CTX *mem_ctx, + struct smb2_tree *tree, + struct smb2_handle fh, + bool *_is_sparse) +{ + union smb_fileinfo io; + NTSTATUS status; + + ZERO_STRUCT(io); + io.generic.level = RAW_FILEINFO_BASIC_INFORMATION; + io.generic.in.file.handle = fh; + status = smb2_getinfo_file(tree, mem_ctx, &io); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + *_is_sparse = !!(io.basic_info.out.attrib & FILE_ATTRIBUTE_SPARSE); + + return status; +} + +static bool test_ioctl_sparse_file_flag(struct torture_context *torture, + struct smb2_tree *tree) +{ + struct smb2_handle fh; + union smb_fileinfo io; + NTSTATUS status; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + bool ok; + bool is_sparse; + + ok = test_setup_create_fill(torture, tree, tmp_ctx, + FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL, + FILE_ATTRIBUTE_NORMAL); + torture_assert(torture, ok, "setup file"); + + status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh, + &ok); + torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS"); + if (!ok) { + smb2_util_close(tree, fh); + torture_skip(torture, "Sparse files not supported\n"); + } + + ZERO_STRUCT(io); + io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION; + io.generic.in.file.handle = fh; + status = smb2_getinfo_file(tree, tmp_ctx, &io); + torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE"); + + torture_assert(torture, + ((io.all_info2.out.attrib & FILE_ATTRIBUTE_SPARSE) == 0), + "sparse attr before set"); + + status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true); + torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE"); + + status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse); + torture_assert_ntstatus_ok(torture, status, "test_sparse_get"); + torture_assert(torture, is_sparse, "no sparse attr after set"); + + status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false); + torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE"); + + status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse); + torture_assert_ntstatus_ok(torture, status, "test_sparse_get"); + torture_assert(torture, !is_sparse, "sparse attr after unset"); + + smb2_util_close(tree, fh); + talloc_free(tmp_ctx); + return true; +} + +static bool test_ioctl_sparse_file_attr(struct torture_context *torture, + struct smb2_tree *tree) +{ + struct smb2_handle fh; + NTSTATUS status; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + bool ok; + bool is_sparse; + + ok = test_setup_create_fill(torture, tree, tmp_ctx, + FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL, + (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_SPARSE)); + torture_assert(torture, ok, "setup file"); + + status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh, + &ok); + torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS"); + if (!ok) { + smb2_util_close(tree, fh); + torture_skip(torture, "Sparse files not supported\n"); + } + + status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse); + torture_assert_ntstatus_ok(torture, status, "test_sparse_get"); + torture_assert(torture, !is_sparse, "sparse attr on open"); + + smb2_util_close(tree, fh); + talloc_free(tmp_ctx); + return true; +} + +static bool test_ioctl_sparse_dir_flag(struct torture_context *torture, + struct smb2_tree *tree) +{ + struct smb2_handle dirh; + NTSTATUS status; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + bool ok; + + smb2_deltree(tree, DNAME); + ok = test_setup_create_fill(torture, tree, tmp_ctx, + DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL, + FILE_ATTRIBUTE_DIRECTORY); + torture_assert(torture, ok, "setup sparse directory"); + + status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &dirh, + &ok); + torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS"); + if (!ok) { + smb2_util_close(tree, dirh); + smb2_deltree(tree, DNAME); + torture_skip(torture, "Sparse files not supported\n"); + } + + /* set sparse dir should fail, check for 2k12 & 2k8 response */ + status = test_ioctl_sparse_req(torture, tmp_ctx, tree, dirh, true); + torture_assert_ntstatus_equal(torture, status, + NT_STATUS_INVALID_PARAMETER, + "dir FSCTL_SET_SPARSE status"); + + smb2_util_close(tree, dirh); + smb2_deltree(tree, DNAME); + talloc_free(tmp_ctx); + return true; +} + /* - basic testing of SMB2 ioctls -*/ + * FSCTL_SET_SPARSE can be sent with (already tested) or without a SetSparse + * buffer to indicate whether the flag should be set or cleared. When sent + * without a buffer, it must be handled as if SetSparse=TRUE. + */ +static bool test_ioctl_sparse_set_nobuf(struct torture_context *torture, + struct smb2_tree *tree) +{ + struct smb2_handle fh; + union smb_ioctl ioctl; + NTSTATUS status; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + bool ok; + bool is_sparse; + + ok = test_setup_create_fill(torture, tree, tmp_ctx, + FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL, + FILE_ATTRIBUTE_NORMAL); + torture_assert(torture, ok, "setup file"); + + status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh, + &ok); + torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS"); + if (!ok) { + smb2_util_close(tree, fh); + torture_skip(torture, "Sparse files not supported\n"); + } + + status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse); + torture_assert_ntstatus_ok(torture, status, "test_sparse_get"); + torture_assert(torture, !is_sparse, "sparse attr before set"); + + ZERO_STRUCT(ioctl); + ioctl.smb2.level = RAW_IOCTL_SMB2; + ioctl.smb2.in.file.handle = fh; + ioctl.smb2.in.function = FSCTL_SET_SPARSE; + ioctl.smb2.in.max_response_size = 0; + ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL; + /* ioctl.smb2.in.out is zeroed, no SetSparse buffer */ + + status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2); + torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE"); + + status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse); + torture_assert_ntstatus_ok(torture, status, "test_sparse_get"); + torture_assert(torture, is_sparse, "no sparse attr after set"); + + /* second non-SetSparse request shouldn't toggle sparse */ + ZERO_STRUCT(ioctl); + ioctl.smb2.level = RAW_IOCTL_SMB2; + ioctl.smb2.in.file.handle = fh; + ioctl.smb2.in.function = FSCTL_SET_SPARSE; + ioctl.smb2.in.max_response_size = 0; + ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL; + + status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2); + torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE"); + + status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse); + torture_assert_ntstatus_ok(torture, status, "test_sparse_get"); + torture_assert(torture, is_sparse, "no sparse attr after 2nd set"); + + status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false); + torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE"); + + status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse); + torture_assert_ntstatus_ok(torture, status, "test_sparse_get"); + torture_assert(torture, !is_sparse, "sparse attr after unset"); + + smb2_util_close(tree, fh); + talloc_free(tmp_ctx); + return true; +} + +/* + * basic testing of SMB2 ioctls + */ struct torture_suite *torture_smb2_ioctl_init(void) { struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "ioctl"); @@ -2523,7 +2785,14 @@ struct torture_suite *torture_smb2_ioctl_init(void) test_ioctl_compress_perms); torture_suite_add_1smb2_test(suite, "network_interface_info", test_ioctl_network_interface_info); - + torture_suite_add_1smb2_test(suite, "sparse_file_flag", + test_ioctl_sparse_file_flag); + torture_suite_add_1smb2_test(suite, "sparse_file_attr", + test_ioctl_sparse_file_attr); + torture_suite_add_1smb2_test(suite, "sparse_dir_flag", + test_ioctl_sparse_dir_flag); + torture_suite_add_1smb2_test(suite, "sparse_set_nobuf", + test_ioctl_sparse_set_nobuf); suite->description = talloc_strdup(suite, "SMB2-IOCTL tests"); -- Samba Shared Repository