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,
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;
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;
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;
*/
#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
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;
+}
+
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;
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) {
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)) {
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) {
union smb_search_data *data)
{
uint_t len, ofs;
+ uint32_t ea_size;
+ DATA_BLOB eablob;
+ NTSTATUS status;
switch (level) {
case RAW_SEARCH_GENERIC:
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);
/*
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;
uint16_t must_attrib;
struct pvfs_dir *dir;
time_t last_used;
+ uint_t num_ea_names;
+ struct ea_name *ea_names;
};
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;
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);
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)) {
{
uint8_t *data;
uint_t ofs = trans->out.data.length;
+ uint32_t ea_size;
switch (state->level) {
case RAW_SEARCH_SEARCH:
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;
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;
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;
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)
{
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)
{
}
+/*
+ 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
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);