r4263: added support for the trans2 RAW_SEARCH_EA_LIST information
authorAndrew Tridgell <tridge@samba.org>
Sat, 18 Dec 2004 04:38:43 +0000 (04:38 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:07:29 +0000 (13:07 -0500)
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)

source4/include/smb_interfaces.h
source4/include/trans2.h
source4/lib/data_blob.c
source4/libcli/raw/rawfileinfo.c
source4/libcli/raw/rawsearch.c
source4/ntvfs/posix/pvfs_qfileinfo.c
source4/ntvfs/posix/pvfs_search.c
source4/smb_server/trans2.c
source4/torture/raw/eas.c
source4/torture/raw/search.c

index 9916bf2385e1770ce25bbe32d2c75c38407dfc4e..91ed102d6aeaeb016d450e2bc42338fb601fd3fb 100644 (file)
@@ -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;
index 9afb9d4c2d88c66ca9e152c85063dc06cf382798..06251ddefe2141c542145d21f3de6ef6d884c4b8 100644 (file)
@@ -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
index a4506fee4548101afe6797effa5e7a1651bd716d..15518799335f57ebd296bcff683d96b672e7da18 100644 (file)
@@ -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;
+}
+
index 8f694a23d87056aad1dc8e581f58214d43c5fc85..ad7b9b900ac06dda6c4de4e9d9f518d6ef9e8acc 100644 (file)
@@ -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;
index d55a47ca265e95fc0bb925a847ae17fd9d8ed40d..3c271253e5bbf15cf80ca6f48b222ed1172ad8bf 100644 (file)
@@ -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);
index ae55ad5e98a00a477c73813b7bd61f461aaa92cb..75a99094925eec418f9baf9dcec28bf151244b44 100644 (file)
 /*
   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;
index c3360352180797457e6093394c4d57b27be7c5e9..34f5f2208e8e2c3403d2ec10c2c437dcda40b7a3 100644 (file)
@@ -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)) {
index 0c827c92a1e07cf468dcdfdf45e6a9a2a16d0e6d..12a4be0e35e12ef19bac42eee8c625cbf6ded810 100644 (file)
@@ -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;
index 572a551d1762b75b06db0693244ff85e71daf81b..2361091a9baaba0b68a8d2a109e03b1bfca35481 100644 (file)
                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)
 {
index 395b9ff559e9d0ceb7956d94d0da17c0d240e5b5..ada71f3ee74bda5871557d4d8eed59e5f5e11dd0 100644 (file)
@@ -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);