mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
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 25189b8fbf
)
This commit is contained in:
parent
b02c5abfb4
commit
ed42a64901
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -211,6 +211,15 @@ static NTSTATUS smb_raw_search_first_blob(struct smbcli_tree *tree,
|
||||
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) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
@ -263,6 +272,15 @@ static NTSTATUS smb_raw_search_next_blob(struct smbcli_tree *tree,
|
||||
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) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
@ -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);
|
||||
|
@ -27,7 +27,7 @@
|
||||
/*
|
||||
reply to a RAW_FILEINFO_EA_LIST call
|
||||
*/
|
||||
static NTSTATUS pvfs_query_ea_list(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
|
||||
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,
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user