/* return info on a pathname */ static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_fileinfo *info) { struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_pathinfo(p->tree, req, info); } c_req = smb_raw_pathinfo_send(p->tree, info); ASYNC_RECV_TAIL(info, async_qpathinfo); }
static bool query_file_path_info2(void *mem_ctx, struct torture_context *torture, struct smbcli_state *cli, int fnum, const char *fname, struct unix_info2 *info2) { NTSTATUS result; union smb_fileinfo finfo; finfo.generic.level = RAW_FILEINFO_UNIX_INFO2; if (fname) { finfo.generic.in.file.path = fname; result = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); } else { finfo.generic.in.file.fnum = fnum; result = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); } torture_assert_ntstatus_equal(torture, result, NT_STATUS_OK, smbcli_errstr(cli->tree)); info2->end_of_file = finfo.unix_info2.out.end_of_file; info2->num_bytes = finfo.unix_info2.out.num_bytes; info2->status_change_time = finfo.unix_info2.out.status_change_time; info2->access_time = finfo.unix_info2.out.access_time; info2->change_time = finfo.unix_info2.out.change_time; info2->uid = finfo.unix_info2.out.uid; info2->gid = finfo.unix_info2.out.gid; info2->file_type = finfo.unix_info2.out.file_type; info2->dev_major = finfo.unix_info2.out.dev_major; info2->dev_minor = finfo.unix_info2.out.dev_minor; info2->unique_id = finfo.unix_info2.out.unique_id; info2->permissions = finfo.unix_info2.out.permissions; info2->nlink = finfo.unix_info2.out.nlink; info2->create_time = finfo.unix_info2.out.create_time; info2->file_flags = finfo.unix_info2.out.file_flags; info2->flags_mask = finfo.unix_info2.out.flags_mask; if (!check_unix_info2(torture, info2)) { return false; } return true; }
/* test seek ops */ static BOOL test_seek(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_seek io; union smb_fileinfo finfo; union smb_setfileinfo sfinfo; NTSTATUS status; BOOL ret = True; int fnum, fnum2; const char *fname = BASEDIR "\\test.txt"; uint8_t c[2]; if (!torture_setup_dir(cli, BASEDIR)) { return False; } fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE); if (fnum == -1) { printf("Failed to open test.txt - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; printf("Trying bad handle\n"); io.lseek.in.file.fnum = fnum+1; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("Trying simple seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = 17; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 17); status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("Trying relative seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = -3; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 14); printf("Trying end seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_END; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.all_info.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, finfo.all_info.out.size); printf("Trying max seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = -1; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 0xffffffff); printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("Trying max overflow\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = 1000; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 999); printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("trying write to update offset\n"); ZERO_STRUCT(c); if (smbcli_write(cli->tree, fnum, 0, c, 0, 2) != 2) { printf("Write failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 2); if (smbcli_read(cli->tree, fnum, c, 0, 1) != 1) { printf("Read failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 1); status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 1); printf("Testing position information\n"); fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE); if (fnum2 == -1) { printf("2nd open failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION; sfinfo.position_information.in.file.fnum = fnum2; sfinfo.position_information.in.position = 25; status = smb_raw_setfileinfo(cli->tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum2; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 25); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 1); printf("position_information via paths\n"); sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION; sfinfo.position_information.in.file.path = fname; sfinfo.position_information.in.position = 32; status = smb_raw_setpathinfo(cli->tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum2; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 25); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); done: smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* test SMBmv ops */ static bool test_mv(struct torture_context *tctx, struct smbcli_state *cli) { union smb_rename io; NTSTATUS status; bool ret = true; int fnum = -1; const char *fname1 = BASEDIR "\\test1.txt"; const char *fname2 = BASEDIR "\\test2.txt"; const char *Fname1 = BASEDIR "\\Test1.txt"; union smb_fileinfo finfo; union smb_open op; torture_comment(tctx, "Testing SMBmv\n"); if (!torture_setup_dir(cli, BASEDIR)) { return false; } torture_comment(tctx, "Trying simple rename\n"); op.generic.level = RAW_OPEN_NTCREATEX; op.ntcreatex.in.root_fid.fnum = 0; op.ntcreatex.in.flags = 0; op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; op.ntcreatex.in.create_options = 0; op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; op.ntcreatex.in.alloc_size = 0; op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; op.ntcreatex.in.security_flags = 0; op.ntcreatex.in.fname = fname1; status = smb_raw_open(cli->tree, tctx, &op); CHECK_STATUS(status, NT_STATUS_OK); fnum = op.ntcreatex.out.file.fnum; io.generic.level = RAW_RENAME_RENAME; io.rename.in.pattern1 = fname1; io.rename.in.pattern2 = fname2; io.rename.in.attrib = 0; torture_comment(tctx, "trying rename while first file open\n"); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); smbcli_close(cli->tree, fnum); op.ntcreatex.in.access_mask = SEC_FILE_READ_DATA; op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; status = smb_raw_open(cli->tree, tctx, &op); CHECK_STATUS(status, NT_STATUS_OK); fnum = op.ntcreatex.out.file.fnum; torture_comment(tctx, "trying rename while first file open with SHARE_ACCESS_DELETE\n"); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); io.rename.in.pattern1 = fname2; io.rename.in.pattern2 = fname1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Trying case-changing rename\n"); io.rename.in.pattern1 = fname1; io.rename.in.pattern2 = Fname1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.all_info.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); if (strcmp(finfo.all_info.out.fname.s, Fname1) != 0) { torture_warning(tctx, "(%s) Incorrect filename [%s] after case-changing " "rename, should be [%s]\n", __location__, finfo.all_info.out.fname.s, Fname1); } io.rename.in.pattern1 = fname1; io.rename.in.pattern2 = fname2; torture_comment(tctx, "trying rename while not open\n"); smb_raw_exit(cli->session); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Trying self rename\n"); io.rename.in.pattern1 = fname2; io.rename.in.pattern2 = fname2; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); io.rename.in.pattern1 = fname1; io.rename.in.pattern2 = fname1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); torture_comment(tctx, "trying wildcard rename\n"); io.rename.in.pattern1 = BASEDIR "\\*.txt"; io.rename.in.pattern2 = fname1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "and again\n"); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Trying extension change\n"); io.rename.in.pattern1 = BASEDIR "\\*.txt"; io.rename.in.pattern2 = BASEDIR "\\*.bak"; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE); torture_comment(tctx, "Checking attrib handling\n"); torture_set_file_attribute(cli->tree, BASEDIR "\\test1.bak", FILE_ATTRIBUTE_HIDDEN); io.rename.in.pattern1 = BASEDIR "\\test1.bak"; io.rename.in.pattern2 = BASEDIR "\\*.txt"; io.rename.in.attrib = 0; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE); io.rename.in.attrib = FILE_ATTRIBUTE_HIDDEN; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); done: smbcli_close(cli->tree, fnum); smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* test SMBntrename ops */ static bool test_ntrename(struct torture_context *tctx, struct smbcli_state *cli) { union smb_rename io; NTSTATUS status; bool ret = true; int fnum, i; const char *fname1 = BASEDIR "\\test1.txt"; const char *fname2 = BASEDIR "\\test2.txt"; union smb_fileinfo finfo; torture_comment(tctx, "Testing SMBntrename\n"); if (!torture_setup_dir(cli, BASEDIR)) { return false; } torture_comment(tctx, "Trying simple rename\n"); fnum = create_complex_file(cli, tctx, fname1); io.generic.level = RAW_RENAME_NTRENAME; io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = fname2; io.ntrename.in.attrib = 0; io.ntrename.in.cluster_size = 0; io.ntrename.in.flags = RENAME_FLAG_RENAME; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); smbcli_close(cli->tree, fnum); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Trying self rename\n"); io.ntrename.in.old_name = fname2; io.ntrename.in.new_name = fname2; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = fname1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); torture_comment(tctx, "trying wildcard rename\n"); io.ntrename.in.old_name = BASEDIR "\\*.txt"; io.ntrename.in.new_name = fname1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD); torture_comment(tctx, "Checking attrib handling\n"); torture_set_file_attribute(cli->tree, fname2, FILE_ATTRIBUTE_HIDDEN); io.ntrename.in.old_name = fname2; io.ntrename.in.new_name = fname1; io.ntrename.in.attrib = 0; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE); io.ntrename.in.attrib = FILE_ATTRIBUTE_HIDDEN; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL); torture_comment(tctx, "Checking hard link\n"); io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = fname2; io.ntrename.in.attrib = 0; io.ntrename.in.flags = RENAME_FLAG_HARD_LINK; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname2; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 2); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM); finfo.generic.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 2); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM); torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL); smbcli_unlink(cli->tree, fname2); finfo.generic.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL); torture_comment(tctx, "Checking copy\n"); io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = fname2; io.ntrename.in.attrib = 0; io.ntrename.in.flags = RENAME_FLAG_COPY; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname2; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL); torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname2; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL); finfo.generic.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM); torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL); smbcli_unlink(cli->tree, fname2); finfo.generic.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); torture_comment(tctx, "Checking invalid flags\n"); io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = fname2; io.ntrename.in.attrib = 0; io.ntrename.in.flags = 0; status = smb_raw_rename(cli->tree, &io); if (TARGET_IS_WIN7(tctx)) { CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } io.ntrename.in.flags = 300; status = smb_raw_rename(cli->tree, &io); if (TARGET_IS_WIN7(tctx)) { CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } io.ntrename.in.flags = 0x106; status = smb_raw_rename(cli->tree, &io); if (TARGET_IS_WIN7(tctx)) { CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } torture_comment(tctx, "Checking unknown field\n"); io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = fname2; io.ntrename.in.attrib = 0; io.ntrename.in.flags = RENAME_FLAG_RENAME; io.ntrename.in.cluster_size = 0xff; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Trying RENAME_FLAG_MOVE_CLUSTER_INFORMATION\n"); io.ntrename.in.old_name = fname2; io.ntrename.in.new_name = fname1; io.ntrename.in.attrib = 0; io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION; io.ntrename.in.cluster_size = 1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); io.ntrename.in.flags = RENAME_FLAG_COPY; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); #if 0 { char buf[16384]; fnum = smbcli_open(cli->tree, fname1, O_RDWR, DENY_NONE); memset(buf, 1, sizeof(buf)); smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf)); smbcli_close(cli->tree, fnum); fnum = smbcli_open(cli->tree, fname2, O_RDWR, DENY_NONE); memset(buf, 1, sizeof(buf)); smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf)-1); smbcli_close(cli->tree, fnum); torture_all_info(cli->tree, fname1); torture_all_info(cli->tree, fname2); } io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); for (i=0; i<20000; i++) { io.ntrename.in.cluster_size = i; status = smb_raw_rename(cli->tree, &io); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { torture_warning(tctx, "i=%d status=%s\n", i, nt_errstr(status)); } } #endif torture_comment(tctx, "Checking other flags\n"); for (i=0; i<0xFFF; i++) { if (i == RENAME_FLAG_RENAME || i == RENAME_FLAG_HARD_LINK || i == RENAME_FLAG_COPY) { continue; } io.ntrename.in.old_name = fname2; io.ntrename.in.new_name = fname1; io.ntrename.in.flags = i; io.ntrename.in.attrib = 0; io.ntrename.in.cluster_size = 0; status = smb_raw_rename(cli->tree, &io); if (TARGET_IS_WIN7(tctx)) { if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { torture_warning(tctx, "flags=0x%x status=%s\n", i, nt_errstr(status)); } } else { if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { torture_warning(tctx, "flags=0x%x status=%s\n", i, nt_errstr(status)); } } } done: smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
static bool test_osxrename(struct torture_context *tctx, struct smbcli_state *cli) { union smb_rename io; union smb_unlink io_un; NTSTATUS status; bool ret = true; int fnum = -1; const char *fname1 = BASEDIR "\\test1"; const char *FNAME1 = BASEDIR "\\TEST1"; union smb_fileinfo finfo; union smb_open op; torture_comment(tctx, "\nTesting OSX Rename\n"); if (!torture_setup_dir(cli, BASEDIR)) { return false; } op.generic.level = RAW_OPEN_NTCREATEX; op.ntcreatex.in.root_fid.fnum = 0; op.ntcreatex.in.flags = 0; op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; op.ntcreatex.in.create_options = 0; op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; op.ntcreatex.in.alloc_size = 0; op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; op.ntcreatex.in.security_flags = 0; op.ntcreatex.in.fname = fname1; status = smb_raw_open(cli->tree, tctx, &op); CHECK_STATUS(status, NT_STATUS_OK); fnum = op.ntcreatex.out.file.fnum; io.generic.level = RAW_RENAME_RENAME; io.rename.in.attrib = 0; smbcli_close(cli->tree, fnum); /* Rename by changing case. First check for the * existence of the file with the "newname". * If we find one and both the output and input are same case, * delete it. */ torture_comment(tctx, "Checking os X rename (case changing)\n"); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.all_info.in.file.path = FNAME1; torture_comment(tctx, "Looking for file %s \n",FNAME1); status = smb_raw_pathinfo(cli->tree, tctx, &finfo); if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) { torture_comment(tctx, "Name of the file found %s \n", finfo.all_info.out.fname.s); if (strcmp(finfo.all_info.out.fname.s, finfo.all_info.in.file.path) == 0) { /* If file is found with the same case delete it */ torture_comment(tctx, "Deleting File %s \n", finfo.all_info.out.fname.s); io_un.unlink.in.pattern = finfo.all_info.out.fname.s; io_un.unlink.in.attrib = 0; status = smb_raw_unlink(cli->tree, &io_un); CHECK_STATUS(status, NT_STATUS_OK); } } io.rename.in.pattern1 = fname1; io.rename.in.pattern2 = FNAME1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.all_info.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "File name after rename %s \n",finfo.all_info.out.fname.s); done: smbcli_close(cli->tree, fnum); smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* basic testing of all RAW_FILEINFO_* calls for each call we test that it succeeds, and where possible test for consistency between the calls. */ static bool torture_raw_qfileinfo_internals(struct torture_context *torture, TALLOC_CTX *mem_ctx, struct smbcli_tree *tree, int fnum, const char *fname, bool is_ipc) { int i; bool ret = true; int count; union smb_fileinfo *s1, *s2; NTTIME correct_time; uint64_t correct_size; uint32_t correct_attrib; const char *correct_name; bool skip_streams = false; /* scan all the fileinfo and pathinfo levels */ for (i=0; levels[i].name; i++) { if (!levels[i].only_paths) { levels[i].fnum_finfo.generic.level = levels[i].level; levels[i].fnum_finfo.generic.in.file.fnum = fnum; levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx, &levels[i].fnum_finfo); } if (!levels[i].only_handles) { levels[i].fname_finfo.generic.level = levels[i].level; levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname); levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx, &levels[i].fname_finfo); } } /* check for completely broken levels */ for (count=i=0; levels[i].name; i++) { uint32_t cap = tree->session->transport->negotiate.capabilities; /* see if this server claims to support this level */ if ((cap & levels[i].capability_mask) != levels[i].capability_mask) { continue; } if (is_ipc) { if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) { } else if (!levels[i].only_handles && NT_STATUS_EQUAL(levels[i].fname_status, NT_STATUS_NOT_SUPPORTED)) { torture_warning(torture, "fname level %s %s", levels[i].name, nt_errstr(levels[i].fname_status)); continue; } else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) { printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n", levels[i].name, nt_errstr(levels[i].fname_status)); count++; } if (!levels[i].only_paths && (NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_SUPPORTED) || NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_IMPLEMENTED))) { torture_warning(torture, "fnum level %s %s", levels[i].name, nt_errstr(levels[i].fnum_status)); continue; } if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) { printf("ERROR: fnum level %s failed, expected %s - %s\n", levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status), nt_errstr(levels[i].fnum_status)); count++; } } else { if (!levels[i].only_paths && (NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_SUPPORTED) || NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_IMPLEMENTED))) { torture_warning(torture, "fnum level %s %s", levels[i].name, nt_errstr(levels[i].fnum_status)); continue; } if (!levels[i].only_handles && (NT_STATUS_EQUAL(levels[i].fname_status, NT_STATUS_NOT_SUPPORTED) || NT_STATUS_EQUAL(levels[i].fname_status, NT_STATUS_NOT_IMPLEMENTED))) { torture_warning(torture, "fname level %s %s", levels[i].name, nt_errstr(levels[i].fname_status)); continue; } if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) { printf("ERROR: fnum level %s failed - %s\n", levels[i].name, nt_errstr(levels[i].fnum_status)); count++; } if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) { printf("ERROR: fname level %s failed - %s\n", levels[i].name, nt_errstr(levels[i].fname_status)); count++; } } } if (count != 0) { ret = false; printf("%d levels failed\n", count); if (count > 35) { torture_fail(torture, "too many level failures - giving up"); } } /* see if we can do streams */ s1 = fnum_find("STREAM_INFO"); if (!s1 || s1->stream_info.out.num_streams == 0) { if (!is_ipc) { printf("STREAM_INFO broken (%d) - skipping streams checks\n", s1 ? s1->stream_info.out.num_streams : -1); } skip_streams = true; } /* this code is incredibly repititive but doesn't lend itself to loops, so we use lots of macros to make it less painful */ /* first off we check the levels that are supposed to be aliases. It will be quite rare for this code to fail, but we need to check it for completeness */ #define ALIAS_CHECK(sname1, sname2) \ do { \ s1 = fnum_find(sname1); s2 = fnum_find(sname2); \ if (s1 && s2) { INFO_CHECK } \ s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2) { INFO_CHECK } \ s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2) { INFO_CHECK } \ } while (0) #define INFO_CHECK \ STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \ STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \ STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \ STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \ VAL_EQUAL (basic_info, attrib, basic_info, attrib); ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \ VAL_EQUAL(standard_info, size, standard_info, size); \ VAL_EQUAL(standard_info, nlink, standard_info, nlink); \ VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \ VAL_EQUAL(standard_info, directory, standard_info, directory); ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ VAL_EQUAL(ea_info, ea_size, ea_info, ea_size); ALIAS_CHECK("EA_INFO", "EA_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ STR_EQUAL(name_info, fname, name_info, fname); ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ STRUCT_EQUAL(all_info, create_time, all_info, create_time); \ STRUCT_EQUAL(all_info, access_time, all_info, access_time); \ STRUCT_EQUAL(all_info, write_time, all_info, write_time); \ STRUCT_EQUAL(all_info, change_time, all_info, change_time); \ VAL_EQUAL(all_info, attrib, all_info, attrib); \ VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \ VAL_EQUAL(all_info, size, all_info, size); \ VAL_EQUAL(all_info, nlink, all_info, nlink); \ VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \ VAL_EQUAL(all_info, directory, all_info, directory); \ VAL_EQUAL(all_info, ea_size, all_info, ea_size); \ STR_EQUAL(all_info, fname, all_info, fname); ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \ VAL_EQUAL(compression_info, format, compression_info, format); \ VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \ VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \ VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift); ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ STR_EQUAL(alt_name_info, fname, alt_name_info, fname); ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION"); #define TIME_CHECK_NT(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ nt_time_string(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ nt_time_string(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ }} while (0) #define TIME_CHECK_DOS(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ }} while (0) #if 0 /* unused */ #define TIME_CHECK_UNX(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ }} while (0) #endif /* now check that all the times that are supposed to be equal are correct */ s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.create_time; torture_comment(torture, "create_time: %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time); TIME_CHECK_DOS("GETATTRE", getattre, create_time); TIME_CHECK_DOS("STANDARD", standard, create_time); TIME_CHECK_DOS("EA_SIZE", ea_size, create_time); TIME_CHECK_NT ("ALL_INFO", all_info, create_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time); s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.access_time; torture_comment(torture, "access_time: %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time); TIME_CHECK_DOS("GETATTRE", getattre, access_time); TIME_CHECK_DOS("STANDARD", standard, access_time); TIME_CHECK_DOS("EA_SIZE", ea_size, access_time); TIME_CHECK_NT ("ALL_INFO", all_info, access_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time); s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.write_time; torture_comment(torture, "write_time : %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time); TIME_CHECK_DOS("GETATTR", getattr, write_time); TIME_CHECK_DOS("GETATTRE", getattre, write_time); TIME_CHECK_DOS("STANDARD", standard, write_time); TIME_CHECK_DOS("EA_SIZE", ea_size, write_time); TIME_CHECK_NT ("ALL_INFO", all_info, write_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time); s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.change_time; torture_comment(torture, "change_time: %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time); TIME_CHECK_NT ("ALL_INFO", all_info, change_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time); #define SIZE_CHECK(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && s1->stype.out.tfield != correct_size) { \ printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_size); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && s1->stype.out.tfield != correct_size) { \ printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_size); \ ret = false; \ }} while (0) s1 = fnum_find("STANDARD_INFO"); correct_size = s1->standard_info.out.size; torture_comment(torture, "size: %u\n", (unsigned int)correct_size); SIZE_CHECK("GETATTR", getattr, size); SIZE_CHECK("GETATTRE", getattre, size); SIZE_CHECK("STANDARD", standard, size); SIZE_CHECK("EA_SIZE", ea_size, size); SIZE_CHECK("STANDARD_INFO", standard_info, size); SIZE_CHECK("STANDARD_INFORMATION", standard_info, size); SIZE_CHECK("ALL_INFO", all_info, size); SIZE_CHECK("ALL_INFORMATION", all_info, size); SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size); SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size); SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size); if (!skip_streams) { SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size); SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size); } s1 = fnum_find("STANDARD_INFO"); correct_size = s1->standard_info.out.alloc_size; torture_comment(torture, "alloc_size: %u\n", (unsigned int)correct_size); SIZE_CHECK("GETATTRE", getattre, alloc_size); SIZE_CHECK("STANDARD", standard, alloc_size); SIZE_CHECK("EA_SIZE", ea_size, alloc_size); SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size); SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size); SIZE_CHECK("ALL_INFO", all_info, alloc_size); SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size); SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size); if (!skip_streams) { SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size); SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size); } #define ATTRIB_CHECK(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && s1->stype.out.tfield != correct_attrib) { \ printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_attrib); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && s1->stype.out.tfield != correct_attrib) { \ printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_attrib); \ ret = false; \ }} while (0) s1 = fnum_find("BASIC_INFO"); correct_attrib = s1->basic_info.out.attrib; torture_comment(torture, "attrib: 0x%x\n", (unsigned int)correct_attrib); ATTRIB_CHECK("GETATTR", getattr, attrib); if (!is_ipc) { ATTRIB_CHECK("GETATTRE", getattre, attrib); ATTRIB_CHECK("STANDARD", standard, attrib); ATTRIB_CHECK("EA_SIZE", ea_size, attrib); } ATTRIB_CHECK("BASIC_INFO", basic_info, attrib); ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib); ATTRIB_CHECK("ALL_INFO", all_info, attrib); ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib); ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib); ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib); correct_name = fname; torture_comment(torture, "name: %s\n", correct_name); #define NAME_CHECK(sname, stype, tfield, flags) do { \ s1 = fnum_find(sname); \ if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \ wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \ printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \ s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \ wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \ printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \ s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \ ret = false; \ }} while (0) NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE); NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE); /* the ALL_INFO file name is the full path on the filesystem */ s1 = fnum_find("ALL_INFO"); if (s1 && !s1->all_info.out.fname.s) { torture_fail(torture, "ALL_INFO didn't give a filename"); } if (s1 && s1->all_info.out.fname.s) { char *p = strrchr(s1->all_info.out.fname.s, '\\'); if (!p) { printf("Not a full path in all_info/fname? - '%s'\n", s1->all_info.out.fname.s); ret = false; } else { if (strcmp_safe(correct_name, p) != 0) { printf("incorrect basename in all_info/fname - '%s'\n", s1->all_info.out.fname.s); ret = false; } } if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) { printf("Should not null terminate all_info/fname\n"); ret = false; } } s1 = fnum_find("ALT_NAME_INFO"); if (s1) { correct_name = s1->alt_name_info.out.fname.s; } if (!correct_name) { torture_comment(torture, "no alternate name information\n"); } else { torture_comment(torture, "alt_name: %s\n", correct_name); NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE); NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE); /* and make sure we can open by alternate name */ smbcli_close(tree, fnum); fnum = smbcli_nt_create_full(tree, correct_name, 0, SEC_RIGHTS_FILE_ALL, FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_DELETE| NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0); if (fnum == -1) { printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree)); ret = false; } if (!skip_streams) { correct_name = "::$DATA"; torture_comment(torture, "stream_name: %s\n", correct_name); NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE); NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE); } } /* make sure the EAs look right */ s1 = fnum_find("ALL_EAS"); s2 = fnum_find("ALL_INFO"); if (s1) { for (i=0;i<s1->all_eas.out.num_eas;i++) { printf(" flags=%d %s=%*.*s\n", s1->all_eas.out.eas[i].flags, s1->all_eas.out.eas[i].name.s, (int)s1->all_eas.out.eas[i].value.length, (int)s1->all_eas.out.eas[i].value.length, s1->all_eas.out.eas[i].value.data); } } if (s1 && s2) { if (s1->all_eas.out.num_eas == 0) { if (s2->all_info.out.ea_size != 0) { printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n", s2->all_info.out.ea_size); } } else { if (s2->all_info.out.ea_size != ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) { printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n", (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas), (int)s2->all_info.out.ea_size); } } } s2 = fname_find(is_ipc, "ALL_EAS"); if (s2) { VAL_EQUAL(all_eas, num_eas, all_eas, num_eas); for (i=0;i<s1->all_eas.out.num_eas;i++) { VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags); STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name); VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length); } } #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \ s1 = fnum_find(sname1); s2 = fnum_find(sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ } \ s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ }} while (0) VAL_CHECK("STANDARD_INFO", standard_info, delete_pending, "ALL_INFO", all_info, delete_pending); VAL_CHECK("STANDARD_INFO", standard_info, directory, "ALL_INFO", all_info, directory); VAL_CHECK("STANDARD_INFO", standard_info, nlink, "ALL_INFO", all_info, nlink); s1 = fnum_find("BASIC_INFO"); if (s1 && is_ipc) { if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) { printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, (int)FILE_ATTRIBUTE_NORMAL); ret = false; } } s1 = fnum_find("STANDARD_INFO"); if (s1 && is_ipc) { if (s1->standard_info.out.nlink != 1) { printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink); ret = false; } if (s1->standard_info.out.delete_pending != 1) { printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending); ret = false; } } VAL_CHECK("EA_INFO", ea_info, ea_size, "ALL_INFO", all_info, ea_size); if (!is_ipc) { VAL_CHECK("EA_SIZE", ea_size, ea_size, "ALL_INFO", all_info, ea_size); } #define NAME_PATH_CHECK(sname, stype, field) do { \ s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \ if (s1 && s2) { \ VAL_EQUAL(stype, field, stype, field); \ } \ } while (0) s1 = fnum_find("INTERNAL_INFORMATION"); if (s1) { torture_comment(torture, "file_id=%.0f\n", (double)s1->internal_information.out.file_id); } NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id); NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position); if (s1 && s2) { printf("fnum pos = %.0f, fname pos = %.0f\n", (double)s2->position_information.out.position, (double)s1->position_information.out.position ); } NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode); NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement); NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib); NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag); #if 0 /* these are expected to differ */ NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags); #endif #if 0 /* unused */ #define UNKNOWN_CHECK(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && s1->stype.out.tfield != 0) { \ printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \ #stype, #tfield, \ (unsigned int)s1->stype.out.tfield); \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && s1->stype.out.tfield != 0) { \ printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \ #stype, #tfield, \ (unsigned int)s1->stype.out.tfield); \ }} while (0) #endif /* now get a bit fancier .... */ /* when we set the delete disposition then the link count should drop to 0 and delete_pending should be 1 */ return ret; }
/** * Test both the snia cifs RAW_SFILEINFO_END_OF_FILE_INFO and the undocumented * pass-through RAW_SFILEINFO_END_OF_FILE_INFORMATION in the context of * trans2setpathinfo. */ static bool torture_raw_sfileinfo_eof(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) { const char *fname = BASEDIR "\\test_sfileinfo_end_of_file.dat"; NTSTATUS status; bool ret = true; union smb_open io; union smb_setfileinfo sfi; union smb_fileinfo qfi; uint16_t fnum = 0; if (!torture_setup_dir(cli1, BASEDIR)) { return false; } /* cleanup */ smbcli_unlink(cli1->tree, fname); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; io.ntcreatex.in.flags = 0; /* Open the file sharing none. */ status = smb_raw_open(cli1->tree, tctx, &io); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); fnum = io.ntcreatex.out.file.fnum; /* Try to sfileinfo to extend the file. */ ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO; sfi.generic.in.file.path = fname; sfi.end_of_file_info.in.size = 100; status = smb_raw_setpathinfo(cli2->tree, &sfi); /* There should be share mode contention in this case. */ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done, "Status should be " "SHARING_VIOLATION"); /* Make sure the size is still 0. */ ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_STANDARD_INFO; qfi.generic.in.file.path = fname; status = smb_raw_pathinfo(cli2->tree, tctx, &qfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 0, "alloc_size should be 0 since the setpathinfo failed."); /* Try again with the pass through instead of documented version. */ ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; sfi.generic.in.file.path = fname; sfi.end_of_file_info.in.size = 100; status = smb_raw_setpathinfo(cli2->tree, &sfi); /* * Looks like a windows bug: * http://lists.samba.org/archive/cifs-protocol/2009-November/001130.html */ if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) { /* It succeeds! This is just weird! */ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); /* Verify that the file was actually extended to 100. */ ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_STANDARD_INFO; qfi.generic.in.file.path = fname; status = smb_raw_pathinfo(cli2->tree, tctx, &qfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 100, "alloc_size should be 100 since the setpathinfo " "succeeded."); } else { torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done, "Status should be " "SHARING_VIOLATION"); } /* close the first file. */ smbcli_close(cli1->tree, fnum); fnum = 0; /* Try to sfileinfo to extend the file again (non-pass-through). */ ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO; sfi.generic.in.file.path = fname; sfi.end_of_file_info.in.size = 200; status = smb_raw_setpathinfo(cli2->tree, &sfi); /* This should cause the client to retun invalid level. */ if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) { /* * Windows sends back an invalid packet that smbclient sees * and returns INTERNAL_ERROR. */ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INTERNAL_ERROR, ret, done, "Status should be " "INTERNAL_ERROR"); } else { torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INVALID_LEVEL, ret, done, "Status should be " "INVALID_LEVEL"); } /* Try to extend the file now with the passthrough level. */ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; status = smb_raw_setpathinfo(cli2->tree, &sfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); /* Verify that the file was actually extended to 200. */ ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_STANDARD_INFO; qfi.generic.in.file.path = fname; status = smb_raw_pathinfo(cli2->tree, tctx, &qfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 200, "alloc_size should be 200 since the setpathinfo succeeded."); /* Open the file so end of file can be set by handle. */ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_WRITE; status = smb_raw_open(cli1->tree, tctx, &io); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); fnum = io.ntcreatex.out.file.fnum; /* Try sfileinfo to extend the file by handle (non-pass-through). */ ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO; sfi.generic.in.file.fnum = fnum; sfi.end_of_file_info.in.size = 300; status = smb_raw_setfileinfo(cli1->tree, &sfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); /* Verify that the file was actually extended to 300. */ ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_STANDARD_INFO; qfi.generic.in.file.path = fname; status = smb_raw_pathinfo(cli1->tree, tctx, &qfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 300, "alloc_size should be 300 since the setpathinfo succeeded."); /* Try sfileinfo to extend the file by handle (pass-through). */ ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; sfi.generic.in.file.fnum = fnum; sfi.end_of_file_info.in.size = 400; status = smb_raw_setfileinfo(cli1->tree, &sfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); /* Verify that the file was actually extended to 300. */ ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_STANDARD_INFO; qfi.generic.in.file.path = fname; status = smb_raw_pathinfo(cli1->tree, tctx, &qfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 400, "alloc_size should be 400 since the setpathinfo succeeded."); done: if (fnum > 0) { smbcli_close(cli1->tree, fnum); fnum = 0; } smb_raw_exit(cli1->session); smb_raw_exit(cli2->session); smbcli_deltree(cli1->tree, BASEDIR); return ret; }
/* basic testing of all RAW_SEARCH_* calls using a single file */ static bool test_one_file(struct torture_context *tctx, struct smbcli_state *cli) { bool ret = true; int fnum; const char *fname = "\\torture_search.txt"; const char *fname2 = "\\torture_search-NOTEXIST.txt"; NTSTATUS status; int i; union smb_fileinfo all_info, alt_info, name_info, internal_info; union smb_search_data *s; fnum = create_complex_file(cli, tctx, fname); if (fnum == -1) { printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)); ret = false; goto done; } /* call all the levels */ for (i=0;i<ARRAY_SIZE(levels);i++) { NTSTATUS expected_status; uint32_t cap = cli->transport->negotiate.capabilities; torture_comment(tctx, "testing %s\n", levels[i].name); levels[i].status = torture_single_search(cli, tctx, fname, levels[i].level, levels[i].data_level, 0, &levels[i].data); /* see if this server claims to support this level */ if ((cap & levels[i].capability_mask) != levels[i].capability_mask) { printf("search level %s(%d) not supported by server\n", levels[i].name, (int)levels[i].level); continue; } if (!NT_STATUS_IS_OK(levels[i].status)) { printf("search level %s(%d) failed - %s\n", levels[i].name, (int)levels[i].level, nt_errstr(levels[i].status)); ret = false; continue; } status = torture_single_search(cli, tctx, fname2, levels[i].level, levels[i].data_level, 0, &levels[i].data); expected_status = NT_STATUS_NO_SUCH_FILE; if (levels[i].level == RAW_SEARCH_SEARCH || levels[i].level == RAW_SEARCH_FFIRST || levels[i].level == RAW_SEARCH_FUNIQUE) { expected_status = STATUS_NO_MORE_FILES; } if (!NT_STATUS_EQUAL(status, expected_status)) { printf("search level %s(%d) should fail with %s - %s\n", levels[i].name, (int)levels[i].level, nt_errstr(expected_status), nt_errstr(status)); ret = false; } } /* get the all_info file into to check against */ all_info.generic.level = RAW_FILEINFO_ALL_INFO; all_info.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, tctx, &all_info); torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_ALL_INFO failed"); alt_info.generic.level = RAW_FILEINFO_ALT_NAME_INFO; alt_info.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, tctx, &alt_info); torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_ALT_NAME_INFO failed"); internal_info.generic.level = RAW_FILEINFO_INTERNAL_INFORMATION; internal_info.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, tctx, &internal_info); torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_INTERNAL_INFORMATION failed"); name_info.generic.level = RAW_FILEINFO_NAME_INFO; name_info.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, tctx, &name_info); torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_NAME_INFO failed"); #define CHECK_VAL(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if ((s->sname1.field1) != (v.sname2.out.field2)) { \ printf("(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \ __location__, \ #sname1, #field1, (int)s->sname1.field1, \ #sname2, #field2, (int)v.sname2.out.field2); \ ret = false; \ } \ }} while (0) #define CHECK_TIME(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if (s->sname1.field1 != (~1 & nt_time_to_unix(v.sname2.out.field2))) { \ printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, timestring(tctx, s->sname1.field1), \ #sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \ ret = false; \ } \ }} while (0) #define CHECK_NTTIME(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if (s->sname1.field1 != v.sname2.out.field2) { \ printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, nt_time_string(tctx, s->sname1.field1), \ #sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \ ret = false; \ } \ }} while (0) #define CHECK_STR(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1 || strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \ printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, s->sname1.field1, \ #sname2, #field2, v.sname2.out.field2.s); \ ret = false; \ } \ }} while (0) #define CHECK_WSTR(name, sname1, field1, v, sname2, field2, flags) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1.s || \ strcmp(s->sname1.field1.s, v.sname2.out.field2.s) || \ wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \ printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, s->sname1.field1.s, \ #sname2, #field2, v.sname2.out.field2.s); \ ret = false; \ } \ }} while (0) #define CHECK_NAME(name, sname1, field1, fname, flags) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1.s || \ strcmp(s->sname1.field1.s, fname) || \ wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \ printf("(%s) %s/%s [%s] != %s\n", \ __location__, \ #sname1, #field1, s->sname1.field1.s, \ fname); \ ret = false; \ } \ }} while (0) #define CHECK_UNIX_NAME(name, sname1, field1, fname, flags) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1 || \ strcmp(s->sname1.field1, fname)) { \ printf("(%s) %s/%s [%s] != %s\n", \ __location__, \ #sname1, #field1, s->sname1.field1, \ fname); \ ret = false; \ } \ }} while (0) /* check that all the results are as expected */ CHECK_VAL("SEARCH", search, attrib, all_info, all_info, attrib&0xFFF); CHECK_VAL("STANDARD", standard, attrib, all_info, all_info, attrib&0xFFF); CHECK_VAL("EA_SIZE", ea_size, attrib, all_info, all_info, attrib&0xFFF); CHECK_VAL("DIRECTORY_INFO", directory_info, attrib, all_info, all_info, attrib); CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, attrib, all_info, all_info, attrib); CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, attrib, all_info, all_info, attrib); CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, attrib, all_info, all_info, attrib); CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, attrib, all_info, all_info, attrib); CHECK_TIME("SEARCH", search, write_time, all_info, all_info, write_time); CHECK_TIME("STANDARD", standard, write_time, all_info, all_info, write_time); CHECK_TIME("EA_SIZE", ea_size, write_time, all_info, all_info, write_time); CHECK_TIME("STANDARD", standard, create_time, all_info, all_info, create_time); CHECK_TIME("EA_SIZE", ea_size, create_time, all_info, all_info, create_time); CHECK_TIME("STANDARD", standard, access_time, all_info, all_info, access_time); CHECK_TIME("EA_SIZE", ea_size, access_time, all_info, all_info, access_time); CHECK_NTTIME("DIRECTORY_INFO", directory_info, write_time, all_info, all_info, write_time); CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, write_time, all_info, all_info, write_time); CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, write_time, all_info, all_info, write_time); CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, write_time, all_info, all_info, write_time); CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, write_time, all_info, all_info, write_time); CHECK_NTTIME("DIRECTORY_INFO", directory_info, create_time, all_info, all_info, create_time); CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, create_time, all_info, all_info, create_time); CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, create_time, all_info, all_info, create_time); CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, create_time, all_info, all_info, create_time); CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, create_time, all_info, all_info, create_time); CHECK_NTTIME("DIRECTORY_INFO", directory_info, access_time, all_info, all_info, access_time); CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, access_time, all_info, all_info, access_time); CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, access_time, all_info, all_info, access_time); CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, access_time, all_info, all_info, access_time); CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, access_time, all_info, all_info, access_time); CHECK_NTTIME("DIRECTORY_INFO", directory_info, change_time, all_info, all_info, change_time); CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, change_time, all_info, all_info, change_time); CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, change_time, all_info, all_info, change_time); CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, change_time, all_info, all_info, change_time); CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, change_time, all_info, all_info, change_time); CHECK_VAL("SEARCH", search, size, all_info, all_info, size); CHECK_VAL("STANDARD", standard, size, all_info, all_info, size); CHECK_VAL("EA_SIZE", ea_size, size, all_info, all_info, size); CHECK_VAL("DIRECTORY_INFO", directory_info, size, all_info, all_info, size); CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, size, all_info, all_info, size); CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, size, all_info, all_info, size); CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, size, all_info, all_info, size); CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, size, all_info, all_info, size); CHECK_VAL("UNIX_INFO", unix_info, size, all_info, all_info, size); CHECK_VAL("STANDARD", standard, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("EA_SIZE", ea_size, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("DIRECTORY_INFO", directory_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("UNIX_INFO", unix_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("EA_SIZE", ea_size, ea_size, all_info, all_info, ea_size); CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, ea_size, all_info, all_info, ea_size); CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, ea_size, all_info, all_info, ea_size); CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, ea_size, all_info, all_info, ea_size); CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, ea_size, all_info, all_info, ea_size); CHECK_STR("SEARCH", search, name, alt_info, alt_name_info, fname); CHECK_WSTR("BOTH_DIRECTORY_INFO", both_directory_info, short_name, alt_info, alt_name_info, fname, STR_UNICODE); CHECK_NAME("STANDARD", standard, name, fname+1, 0); CHECK_NAME("EA_SIZE", ea_size, name, fname+1, 0); CHECK_NAME("DIRECTORY_INFO", directory_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_NAME("FULL_DIRECTORY_INFO", full_directory_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_NAME("NAME_INFO", name_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_NAME("BOTH_DIRECTORY_INFO", both_directory_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_NAME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_NAME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_UNIX_NAME("UNIX_INFO", unix_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, file_id, internal_info, internal_information, file_id); CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, file_id, internal_info, internal_information, file_id); done: smb_raw_exit(cli->session); smbcli_unlink(cli->tree, fname); return ret; }
/* basic testing of all RAW_CLOSE_* calls */ BOOL torture_raw_close(struct torture_context *torture) { struct smbcli_state *cli; BOOL ret = True; TALLOC_CTX *mem_ctx; union smb_close io; union smb_flush io_flush; int fnum; const char *fname = "\\torture_close.txt"; time_t basetime = (time(NULL) + 3*86400) & ~1; union smb_fileinfo finfo, finfo2; NTSTATUS status; if (!torture_open_connection(&cli, 0)) { return False; } mem_ctx = talloc_init("torture_raw_close"); #define REOPEN do { \ fnum = create_complex_file(cli, mem_ctx, fname); \ if (fnum == -1) { \ printf("(%d) Failed to create %s\n", __LINE__, fname); \ ret = False; \ goto done; \ }} while (0) #define CHECK_STATUS(status, correct) do { \ if (!NT_STATUS_EQUAL(status, correct)) { \ printf("(%d) Incorrect status %s - should be %s\n", \ __LINE__, nt_errstr(status), nt_errstr(correct)); \ ret = False; \ goto done; \ }} while (0) REOPEN; io.close.level = RAW_CLOSE_CLOSE; io.close.in.file.fnum = fnum; io.close.in.write_time = basetime; status = smb_raw_close(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smb_raw_close(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("testing close.in.write_time\n"); /* the file should have the write time set */ finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); if (basetime != nt_time_to_unix(finfo.all_info.out.write_time)) { printf("Incorrect write time on file - %s - %s\n", timestring(mem_ctx, basetime), nt_time_string(mem_ctx, finfo.all_info.out.write_time)); dump_all_info(mem_ctx, &finfo); ret = False; } printf("testing other times\n"); /* none of the other times should be set to that time */ if (nt_time_equal(&finfo.all_info.out.write_time, &finfo.all_info.out.access_time) || nt_time_equal(&finfo.all_info.out.write_time, &finfo.all_info.out.create_time) || nt_time_equal(&finfo.all_info.out.write_time, &finfo.all_info.out.change_time)) { printf("Incorrect times after close - only write time should be set\n"); dump_all_info(mem_ctx, &finfo); ret = False; } smbcli_unlink(cli->tree, fname); REOPEN; finfo2.generic.level = RAW_FILEINFO_ALL_INFO; finfo2.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2); CHECK_STATUS(status, NT_STATUS_OK); io.close.level = RAW_CLOSE_CLOSE; io.close.in.file.fnum = fnum; io.close.in.write_time = 0; status = smb_raw_close(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); /* the file should have the write time set equal to access time */ finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); if (!nt_time_equal(&finfo.all_info.out.write_time, &finfo2.all_info.out.write_time)) { printf("Incorrect write time on file - 0 time should be ignored\n"); dump_all_info(mem_ctx, &finfo); ret = False; } printf("testing splclose\n"); /* check splclose on a file */ REOPEN; io.splclose.level = RAW_CLOSE_SPLCLOSE; io.splclose.in.file.fnum = fnum; status = smb_raw_close(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror)); printf("testing flush\n"); smbcli_close(cli->tree, fnum); io_flush.flush.level = RAW_FLUSH_FLUSH; io_flush.flush.in.file.fnum = fnum; status = smb_raw_flush(cli->tree, &io_flush); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); io_flush.flush_all.level = RAW_FLUSH_ALL; status = smb_raw_flush(cli->tree, &io_flush); CHECK_STATUS(status, NT_STATUS_OK); REOPEN; io_flush.flush.level = RAW_FLUSH_FLUSH; io_flush.flush.in.file.fnum = fnum; status = smb_raw_flush(cli->tree, &io_flush); CHECK_STATUS(status, NT_STATUS_OK); printf("Testing SMBexit\n"); smb_raw_exit(cli->session); io_flush.flush.level = RAW_FLUSH_FLUSH; io_flush.flush.in.file.fnum = fnum; status = smb_raw_flush(cli->tree, &io_flush); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); done: smbcli_close(cli->tree, fnum); smbcli_unlink(cli->tree, fname); torture_close_connection(cli); talloc_free(mem_ctx); return ret; }