diff options
author | Andrew Tridgell <tridge@samba.org> | 2004-12-18 04:38:43 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:07:29 -0500 |
commit | ed42a64901ba0a7ad8cbaac582600688af1b7d72 (patch) | |
tree | b68217a14fbd61d1f58b702d7ecc5b9ee66f2ce5 /source4 | |
parent | b02c5abfb470575a67ced192b2913b5a1c73dd3e (diff) | |
download | samba-ed42a64901ba0a7ad8cbaac582600688af1b7d72.tar.gz samba-ed42a64901ba0a7ad8cbaac582600688af1b7d72.tar.bz2 samba-ed42a64901ba0a7ad8cbaac582600688af1b7d72.zip |
r4263: added support for the trans2 RAW_SEARCH_EA_LIST information
level. This is quite a strange level that we've never seen before, but
is used by the os2 workplace shell.
note w2k screws up this level when unicode is negotiated, so it only
passes the RAW-SEARCH test when you force non-unicode
(This used to be commit 25189b8fbf6515d573e3398dc9fca56505dc37b9)
Diffstat (limited to 'source4')
-rw-r--r-- | source4/include/smb_interfaces.h | 22 | ||||
-rw-r--r-- | source4/include/trans2.h | 1 | ||||
-rw-r--r-- | source4/lib/data_blob.c | 13 | ||||
-rw-r--r-- | source4/libcli/raw/rawfileinfo.c | 2 | ||||
-rw-r--r-- | source4/libcli/raw/rawsearch.c | 61 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_qfileinfo.c | 10 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_search.c | 21 | ||||
-rw-r--r-- | source4/smb_server/trans2.c | 42 | ||||
-rw-r--r-- | source4/torture/raw/eas.c | 8 | ||||
-rw-r--r-- | source4/torture/raw/search.c | 118 |
10 files changed, 283 insertions, 15 deletions
diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h index 9916bf2385..91ed102d6a 100644 --- a/source4/include/smb_interfaces.h +++ b/source4/include/smb_interfaces.h @@ -1675,6 +1675,7 @@ enum smb_search_level {RAW_SEARCH_GENERIC = 0xF000, RAW_SEARCH_FUNIQUE, /* SMBfunique */ RAW_SEARCH_STANDARD = SMB_FIND_STANDARD, RAW_SEARCH_EA_SIZE = SMB_FIND_EA_SIZE, + RAW_SEARCH_EA_LIST = SMB_FIND_EA_LIST, RAW_SEARCH_DIRECTORY_INFO = SMB_FIND_DIRECTORY_INFO, RAW_SEARCH_FULL_DIRECTORY_INFO = SMB_FIND_FULL_DIRECTORY_INFO, RAW_SEARCH_NAME_INFO = SMB_FIND_NAME_INFO, @@ -1715,6 +1716,10 @@ union smb_search_first { uint16_t flags; uint32_t storage_type; const char *pattern; + + /* the ea names are only used for RAW_SEARCH_EA_LIST */ + uint_t num_names; + struct ea_name *ea_names; } in; struct { uint16_t handle; @@ -1761,6 +1766,10 @@ union smb_search_next { uint32_t resume_key; uint16_t flags; const char *last_name; + + /* the ea names are only used for RAW_SEARCH_EA_LIST */ + uint_t num_names; + struct ea_name *ea_names; } in; struct { uint16_t count; @@ -1805,6 +1814,19 @@ union smb_search_data { WIRE_STRING name; } ea_size; + /* trans2 findfirst RAW_SEARCH_EA_LIST level */ + struct { + uint32_t resume_key; + time_t create_time; + time_t access_time; + time_t write_time; + uint32_t size; + uint32_t alloc_size; + uint16_t attrib; + struct smb_ea_list eas; + WIRE_STRING name; + } ea_list; + /* RAW_SEARCH_DIRECTORY_INFO interface */ struct { uint32_t file_index; diff --git a/source4/include/trans2.h b/source4/include/trans2.h index 9afb9d4c2d..06251ddefe 100644 --- a/source4/include/trans2.h +++ b/source4/include/trans2.h @@ -253,6 +253,7 @@ Found 0 aliased levels */ #define SMB_FIND_STANDARD 1 #define SMB_FIND_EA_SIZE 2 +#define SMB_FIND_EA_LIST 3 #define SMB_FIND_DIRECTORY_INFO 0x101 #define SMB_FIND_FULL_DIRECTORY_INFO 0x102 #define SMB_FIND_NAME_INFO 0x103 diff --git a/source4/lib/data_blob.c b/source4/lib/data_blob.c index a4506fee45..1551879933 100644 --- a/source4/lib/data_blob.c +++ b/source4/lib/data_blob.c @@ -160,3 +160,16 @@ char *data_blob_hex_string(TALLOC_CTX *mem_ctx, DATA_BLOB *blob) return hex_string; } + +/* + useful for constructing data blobs in test suites, while + avoiding const warnings +*/ +DATA_BLOB data_blob_string_const(const char *str) +{ + DATA_BLOB blob; + blob.data = discard_const(str); + blob.length = strlen(str); + return blob; +} + diff --git a/source4/libcli/raw/rawfileinfo.c b/source4/libcli/raw/rawfileinfo.c index 8f694a23d8..ad7b9b900a 100644 --- a/source4/libcli/raw/rawfileinfo.c +++ b/source4/libcli/raw/rawfileinfo.c @@ -550,7 +550,7 @@ NTSTATUS smb_raw_fileinfo(struct smbcli_tree *tree, Query path info (async send) ****************************************************************************/ struct smbcli_request *smb_raw_pathinfo_send(struct smbcli_tree *tree, - union smb_fileinfo *parms) + union smb_fileinfo *parms) { DATA_BLOB data; struct smbcli_request *req; diff --git a/source4/libcli/raw/rawsearch.c b/source4/libcli/raw/rawsearch.c index d55a47ca26..3c271253e5 100644 --- a/source4/libcli/raw/rawsearch.c +++ b/source4/libcli/raw/rawsearch.c @@ -210,6 +210,15 @@ static NTSTATUS smb_raw_search_first_blob(struct smbcli_tree *tree, tp.in.max_param = 10; tp.in.max_data = smb_raw_max_trans_data(tree, 10); tp.in.setup = &setup; + + if (info_level == RAW_SEARCH_EA_LIST) { + if (!ea_push_name_list(mem_ctx, + &tp.in.data, + io->t2ffirst.in.num_names, + io->t2ffirst.in.ea_names)) { + return NT_STATUS_NO_MEMORY; + } + } tp.in.params = data_blob_talloc(mem_ctx, NULL, 12); if (!tp.in.params.data) { @@ -223,7 +232,7 @@ static NTSTATUS smb_raw_search_first_blob(struct smbcli_tree *tree, SIVAL(tp.in.params.data, 8, io->t2ffirst.in.storage_type); smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params, - io->t2ffirst.in.pattern, STR_TERMINATE); + io->t2ffirst.in.pattern, STR_TERMINATE); status = smb_raw_trans2(tree, mem_ctx, &tp); if (!NT_STATUS_IS_OK(status)) { @@ -262,6 +271,15 @@ static NTSTATUS smb_raw_search_next_blob(struct smbcli_tree *tree, tp.in.max_param = 10; tp.in.max_data = smb_raw_max_trans_data(tree, 10); tp.in.setup = &setup; + + if (info_level == RAW_SEARCH_EA_LIST) { + if (!ea_push_name_list(mem_ctx, + &tp.in.data, + io->t2fnext.in.num_names, + io->t2fnext.in.ea_names)) { + return NT_STATUS_NO_MEMORY; + } + } tp.in.params = data_blob_talloc(mem_ctx, NULL, 12); if (!tp.in.params.data) { @@ -306,6 +324,9 @@ static int parse_trans2_search(struct smbcli_tree *tree, union smb_search_data *data) { uint_t len, ofs; + uint32_t ea_size; + DATA_BLOB eablob; + NTSTATUS status; switch (level) { case RAW_SEARCH_GENERIC: @@ -360,6 +381,44 @@ static int parse_trans2_search(struct smbcli_tree *tree, 26, 27, STR_LEN8BIT | STR_TERMINATE | STR_NOALIGN); return len + 27 + 1; + case RAW_SEARCH_EA_LIST: + if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) { + if (blob->length < 4) return -1; + data->ea_list.resume_key = IVAL(blob->data, 0); + blob->data += 4; + blob->length -= 4; + } + if (blob->length < 28) return -1; + data->ea_list.create_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 0); + data->ea_list.access_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 4); + data->ea_list.write_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 8); + data->ea_list.size = IVAL(blob->data, 12); + data->ea_list.alloc_size = IVAL(blob->data, 16); + data->ea_list.attrib = SVAL(blob->data, 20); + ea_size = IVAL(blob->data, 22); + if (ea_size > 0xFFFF) { + return -1; + } + eablob.data = blob->data + 22; + eablob.length = ea_size; + if (eablob.length > blob->length - 24) { + return -1; + } + status = ea_pull_list(&eablob, mem_ctx, + &data->ea_list.eas.num_eas, + &data->ea_list.eas.eas); + if (!NT_STATUS_IS_OK(status)) { + return -1; + } + len = smbcli_blob_pull_string(tree->session, mem_ctx, blob, + &data->ea_list.name, + 22+ea_size, 23+ea_size, + STR_LEN8BIT | STR_TERMINATE | STR_NOALIGN); + return len + ea_size + 23 + 1; + case RAW_SEARCH_DIRECTORY_INFO: if (blob->length < 65) return -1; ofs = IVAL(blob->data, 0); diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c index ae55ad5e98..75a9909492 100644 --- a/source4/ntvfs/posix/pvfs_qfileinfo.c +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -27,11 +27,11 @@ /* reply to a RAW_FILEINFO_EA_LIST call */ -static NTSTATUS pvfs_query_ea_list(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, - struct pvfs_filename *name, int fd, - uint_t num_names, - struct ea_name *names, - struct smb_ea_list *eas) +NTSTATUS pvfs_query_ea_list(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, + struct pvfs_filename *name, int fd, + uint_t num_names, + struct ea_name *names, + struct smb_ea_list *eas) { NTSTATUS status; int i; diff --git a/source4/ntvfs/posix/pvfs_search.c b/source4/ntvfs/posix/pvfs_search.c index c336035218..34f5f2208e 100644 --- a/source4/ntvfs/posix/pvfs_search.c +++ b/source4/ntvfs/posix/pvfs_search.c @@ -35,6 +35,8 @@ struct pvfs_search_state { uint16_t must_attrib; struct pvfs_dir *dir; time_t last_used; + uint_t num_ea_names; + struct ea_name *ea_names; }; @@ -118,6 +120,20 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs, file->ea_size.name.s = fname; return NT_STATUS_OK; + case RAW_SEARCH_EA_LIST: + file->ea_list.resume_key = dir_index; + file->ea_list.create_time = nt_time_to_unix(name->dos.create_time); + file->ea_list.access_time = nt_time_to_unix(name->dos.access_time); + file->ea_list.write_time = nt_time_to_unix(name->dos.write_time); + file->ea_list.size = name->st.st_size; + file->ea_list.alloc_size = name->dos.alloc_size; + file->ea_list.attrib = name->dos.attrib; + file->ea_list.name.s = fname; + return pvfs_query_ea_list(pvfs, file, name, -1, + search->num_ea_names, + search->ea_names, + &file->ea_list.eas); + case RAW_SEARCH_DIRECTORY_INFO: file->directory_info.file_index = dir_index; file->directory_info.create_time = name->dos.create_time; @@ -471,6 +487,8 @@ NTSTATUS pvfs_search_first(struct ntvfs_module_context *ntvfs, search->search_attrib = search_attrib; search->must_attrib = 0; search->last_used = 0; + search->num_ea_names = io->t2ffirst.in.num_names; + search->ea_names = io->t2ffirst.in.ea_names; talloc_set_destructor(search, pvfs_search_destructor); @@ -550,6 +568,9 @@ NTSTATUS pvfs_search_next(struct ntvfs_module_context *ntvfs, return status; } + search->num_ea_names = io->t2fnext.in.num_names; + search->ea_names = io->t2fnext.in.ea_names; + status = pvfs_search_fill(pvfs, req, io->t2fnext.in.max_count, search, io->generic.level, &reply_count, search_private, callback); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/smb_server/trans2.c b/source4/smb_server/trans2.c index 0c827c92a1..12a4be0e35 100644 --- a/source4/smb_server/trans2.c +++ b/source4/smb_server/trans2.c @@ -1011,6 +1011,7 @@ static void find_fill_info(struct smbsrv_request *req, { uint8_t *data; uint_t ofs = trans->out.data.length; + uint32_t ea_size; switch (state->level) { case RAW_SEARCH_SEARCH: @@ -1061,6 +1062,29 @@ static void find_fill_info(struct smbsrv_request *req, trans->out.data.data[trans->out.data.length-1] = 0; break; + case RAW_SEARCH_EA_LIST: + ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas); + if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) { + trans2_grow_data(req, trans, ofs + 27 + ea_size); + SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key); + ofs += 4; + } else { + trans2_grow_data(req, trans, ofs + 23 + ea_size); + } + data = trans->out.data.data + ofs; + srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time); + srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time); + srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time); + SIVAL(data, 12, file->ea_list.size); + SIVAL(data, 16, file->ea_list.alloc_size); + SSVAL(data, 20, file->ea_list.attrib); + ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas); + trans2_append_data_string(req, trans, &file->ea_list.name, + ofs + 22 + ea_size, STR_LEN8BIT | STR_NOALIGN); + trans2_grow_data(req, trans, trans->out.data.length + 1); + trans->out.data.data[trans->out.data.length-1] = 0; + break; + case RAW_SEARCH_DIRECTORY_INFO: trans2_grow_data(req, trans, ofs + 64); data = trans->out.data.data + ofs; @@ -1233,6 +1257,15 @@ static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct smb_trans2 * return NT_STATUS_INVALID_LEVEL; } + if (search.t2ffirst.level == RAW_SEARCH_EA_LIST) { + status = ea_pull_name_list(&trans->in.data, req, + &search.t2ffirst.in.num_names, + &search.t2ffirst.in.ea_names); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + /* setup the private state structure that the backend will give us in the callback */ state.req = req; state.trans = trans; @@ -1294,6 +1327,15 @@ static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct smb_trans2 *t return NT_STATUS_INVALID_LEVEL; } + if (search.t2fnext.level == RAW_SEARCH_EA_LIST) { + status = ea_pull_name_list(&trans->in.data, req, + &search.t2fnext.in.num_names, + &search.t2fnext.in.ea_names); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + /* setup the private state structure that the backend will give us in the callback */ state.req = req; state.trans = trans; diff --git a/source4/torture/raw/eas.c b/source4/torture/raw/eas.c index 572a551d17..2361091a9b 100644 --- a/source4/torture/raw/eas.c +++ b/source4/torture/raw/eas.c @@ -34,14 +34,6 @@ goto done; \ }} while (0) -static DATA_BLOB data_blob_string_const(const char *str) -{ - DATA_BLOB blob; - blob.data = discard_const(str); - blob.length = strlen(str); - return blob; -} - static BOOL check_ea(struct smbcli_state *cli, const char *fname, const char *eaname, const char *value) { diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c index 395b9ff559..ada71f3ee7 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -548,6 +548,13 @@ static NTSTATUS multiple_search(struct smbcli_state *cli, ret = False; \ }} while (0) +#define CHECK_STRING(v, correct) do { \ + if (StrCaseCmp(v, correct) != 0) { \ + printf("(%s) Incorrect value %s='%s' - should be '%s'\n", \ + __location__, #v, v, correct); \ + ret = False; \ + }} while (0) + static int search_both_compare(union smb_search_data *d1, union smb_search_data *d2) { @@ -1171,6 +1178,116 @@ done: } +/* + testing of the rather strange ea_list level +*/ +static BOOL test_ea_list(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) +{ + int fnum; + BOOL ret = True; + NTSTATUS status; + union smb_search_first io; + union smb_search_next nxt; + struct multiple_result result; + union smb_setfileinfo setfile; + + if (!torture_setup_dir(cli, BASEDIR)) { + return False; + } + + printf("Testing RAW_SEARCH_EA_LIST level\n"); + + fnum = smbcli_open(cli->tree, BASEDIR "\\file1.txt", O_CREAT|O_RDWR, DENY_NONE); + smbcli_close(cli->tree, fnum); + + fnum = smbcli_open(cli->tree, BASEDIR "\\file2.txt", O_CREAT|O_RDWR, DENY_NONE); + smbcli_close(cli->tree, fnum); + + fnum = smbcli_open(cli->tree, BASEDIR "\\file3.txt", O_CREAT|O_RDWR, DENY_NONE); + smbcli_close(cli->tree, fnum); + + setfile.generic.level = RAW_SFILEINFO_EA_SET; + setfile.generic.file.fname = BASEDIR "\\file2.txt"; + setfile.ea_set.in.num_eas = 2; + setfile.ea_set.in.eas = talloc_array_p(mem_ctx, struct ea_struct, 2); + setfile.ea_set.in.eas[0].flags = 0; + setfile.ea_set.in.eas[0].name.s = "EA ONE"; + setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE 1"); + setfile.ea_set.in.eas[1].flags = 0; + setfile.ea_set.in.eas[1].name.s = "SECOND EA"; + setfile.ea_set.in.eas[1].value = data_blob_string_const("Value Two"); + + status = smb_raw_setpathinfo(cli->tree, &setfile); + CHECK_STATUS(status, NT_STATUS_OK); + + setfile.generic.file.fname = BASEDIR "\\file3.txt"; + status = smb_raw_setpathinfo(cli->tree, &setfile); + CHECK_STATUS(status, NT_STATUS_OK); + + ZERO_STRUCT(result); + result.mem_ctx = mem_ctx; + + io.t2ffirst.level = RAW_SEARCH_EA_LIST; + io.t2ffirst.in.search_attrib = 0; + io.t2ffirst.in.max_count = 2; + io.t2ffirst.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME; + io.t2ffirst.in.storage_type = 0; + io.t2ffirst.in.pattern = BASEDIR "\\*"; + io.t2ffirst.in.num_names = 2; + io.t2ffirst.in.ea_names = talloc_array_p(mem_ctx, struct ea_name, 2); + io.t2ffirst.in.ea_names[0].name.s = "SECOND EA"; + io.t2ffirst.in.ea_names[1].name.s = "THIRD EA"; + + status = smb_raw_search_first(cli->tree, mem_ctx, + &io, &result, multiple_search_callback); + CHECK_STATUS(status, NT_STATUS_OK); + + nxt.t2fnext.level = RAW_SEARCH_EA_LIST; + nxt.t2fnext.in.handle = io.t2ffirst.out.handle; + nxt.t2fnext.in.max_count = 2; + nxt.t2fnext.in.resume_key = result.list[1].ea_list.resume_key; + nxt.t2fnext.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME | FLAG_TRANS2_FIND_CONTINUE; + nxt.t2fnext.in.last_name = "file2.txt"; + nxt.t2fnext.in.num_names = 2; + nxt.t2fnext.in.ea_names = talloc_array_p(mem_ctx, struct ea_name, 2); + nxt.t2fnext.in.ea_names[0].name.s = "SECOND EA"; + nxt.t2fnext.in.ea_names[1].name.s = "THIRD EA"; + + status = smb_raw_search_next(cli->tree, mem_ctx, + &nxt, &result, multiple_search_callback); + CHECK_STATUS(status, NT_STATUS_OK); + + + CHECK_VALUE(result.count, 3); + CHECK_VALUE(result.list[0].ea_list.eas.num_eas, 2); + CHECK_STRING(result.list[0].ea_list.name.s, "file1.txt"); + CHECK_STRING(result.list[0].ea_list.eas.eas[0].name.s, "SECOND EA"); + CHECK_VALUE(result.list[0].ea_list.eas.eas[0].value.length, 0); + CHECK_STRING(result.list[0].ea_list.eas.eas[1].name.s, "THIRD EA"); + CHECK_VALUE(result.list[0].ea_list.eas.eas[1].value.length, 0); + + CHECK_STRING(result.list[1].ea_list.name.s, "file2.txt"); + CHECK_STRING(result.list[1].ea_list.eas.eas[0].name.s, "SECOND EA"); + CHECK_VALUE(result.list[1].ea_list.eas.eas[0].value.length, 9); + CHECK_STRING(result.list[1].ea_list.eas.eas[0].value.data, "Value Two"); + CHECK_STRING(result.list[1].ea_list.eas.eas[1].name.s, "THIRD EA"); + CHECK_VALUE(result.list[1].ea_list.eas.eas[1].value.length, 0); + + CHECK_STRING(result.list[2].ea_list.name.s, "file3.txt"); + CHECK_STRING(result.list[2].ea_list.eas.eas[0].name.s, "SECOND EA"); + CHECK_VALUE(result.list[2].ea_list.eas.eas[0].value.length, 9); + CHECK_STRING(result.list[2].ea_list.eas.eas[0].value.data, "Value Two"); + CHECK_STRING(result.list[2].ea_list.eas.eas[1].name.s, "THIRD EA"); + CHECK_VALUE(result.list[2].ea_list.eas.eas[1].value.length, 0); + +done: + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + + return ret; +} + + /* basic testing of all RAW_SEARCH_* calls using a single file @@ -1193,6 +1310,7 @@ BOOL torture_raw_search(void) ret &= test_modify_search(cli, mem_ctx); ret &= test_many_dirs(cli, mem_ctx); ret &= test_os2_delete(cli, mem_ctx); + ret &= test_ea_list(cli, mem_ctx); torture_close_connection(cli); talloc_destroy(mem_ctx); |