r2469: complete overhaul of the old-style RAW_SEARCH_ calls (the OS/2 and
authorAndrew Tridgell <tridge@samba.org>
Tue, 21 Sep 2004 08:46:47 +0000 (08:46 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:58:56 +0000 (12:58 -0500)
original core level calls). The old code was completely wrong in many respects.

also fixed the EA_SIZE level in the server

extended the RAW-SEARCH test suite to test the new code properly

source/include/smb_interfaces.h
source/libcli/clilist.c
source/libcli/raw/rawsearch.c
source/ntvfs/posix/pvfs_search.c
source/ntvfs/posix/vfs_posix.h
source/smb_server/reply.c
source/smb_server/request.c
source/smb_server/search.c
source/smb_server/trans2.c
source/torture/raw/search.c

index 14f8ecfc13cd7ded5738557e4e49e6b9611c82a8..72ca1477dcae81ea97c77a079519a1811e44917f 100644 (file)
@@ -1694,17 +1694,18 @@ struct smb_notify {
 
 
 enum smb_search_level {RAW_SEARCH_GENERIC                 = 0xF000, 
-                  RAW_SEARCH_SEARCH,                 /* SMBsearch */ 
-                  RAW_SEARCH_FCLOSE,                 /* SMBfclose */
-                  RAW_SEARCH_STANDARD                = SMB_FIND_STANDARD,
-                  RAW_SEARCH_EA_SIZE                 = SMB_FIND_EA_SIZE,
-                  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,
-                  RAW_SEARCH_BOTH_DIRECTORY_INFO     = SMB_FIND_BOTH_DIRECTORY_INFO,
-                  RAW_SEARCH_ID_FULL_DIRECTORY_INFO  = SMB_FIND_ID_FULL_DIRECTORY_INFO,
-                  RAW_SEARCH_ID_BOTH_DIRECTORY_INFO  = SMB_FIND_ID_BOTH_DIRECTORY_INFO,
-                  RAW_SEARCH_UNIX_INFO               = SMB_FIND_UNIX_INFO};
+                      RAW_SEARCH_SEARCH,                 /* SMBsearch */ 
+                      RAW_SEARCH_FFIRST,                 /* SMBffirst */ 
+                      RAW_SEARCH_FUNIQUE,                /* SMBfunique */ 
+                      RAW_SEARCH_STANDARD                = SMB_FIND_STANDARD,
+                      RAW_SEARCH_EA_SIZE                 = SMB_FIND_EA_SIZE,
+                      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,
+                      RAW_SEARCH_BOTH_DIRECTORY_INFO     = SMB_FIND_BOTH_DIRECTORY_INFO,
+                      RAW_SEARCH_ID_FULL_DIRECTORY_INFO  = SMB_FIND_ID_FULL_DIRECTORY_INFO,
+                      RAW_SEARCH_ID_BOTH_DIRECTORY_INFO  = SMB_FIND_ID_BOTH_DIRECTORY_INFO,
+                      RAW_SEARCH_UNIX_INFO               = SMB_FIND_UNIX_INFO};
 
        
 /* union for file search */
@@ -1713,7 +1714,8 @@ union smb_search_first {
                enum smb_search_level level;
        } generic;
        
-       /* search (old) findfirst interface */
+       /* search (old) findfirst interface. 
+          Also used for ffirst and funique. */
        struct {
                enum smb_search_level level;
        
@@ -1752,14 +1754,21 @@ union smb_search_next {
                enum smb_search_level level;
        } generic;
 
-       /* search (old) findnext interface */
+       /* search (old) findnext interface. Also used
+          for ffirst when continuing */
        struct {
                enum smb_search_level level;
        
                struct {
                        uint16_t max_count;
                        uint16_t search_attrib;
-                       DATA_BLOB search_id;
+                       struct smb_search_id {
+                               uint8_t reserved;
+                               char name[11];
+                               uint8_t handle;
+                               uint32_t server_cookie;
+                               uint32_t client_cookie;
+                       } id;
                } in;
                struct {
                        uint16_t count;
@@ -1791,7 +1800,7 @@ union smb_search_data {
                uint16_t attrib;
                time_t write_time;
                uint32_t size;
-               DATA_BLOB search_id;  /* used to resume search from this point */
+               struct smb_search_id id;
                char *name;
        } search;
        
@@ -1920,7 +1929,7 @@ union smb_search_data {
 };
 
 
-enum smb_search_close_level {RAW_FINDCLOSE_GENERIC, RAW_FINDCLOSE_CLOSE};
+enum smb_search_close_level {RAW_FINDCLOSE_GENERIC, RAW_FINDCLOSE_FCLOSE, RAW_FINDCLOSE_FINDCLOSE};
 
 /* union for file search close */
 union smb_search_close {
@@ -1933,14 +1942,12 @@ union smb_search_close {
                enum smb_search_close_level level;
        
                struct {
+                       /* max_count and search_attrib are not used, but are present */
                        uint16_t max_count;
                        uint16_t search_attrib;
-                       DATA_BLOB search_id;
+                       struct smb_search_id id;
                } in;
-               struct {
-                       uint16_t count;
-               } out;
-       } search_next;
+       } fclose;
        
        /* SMBfindclose interface */
        struct {
index 0e2cdabc0aebcc782137e189f53860a814177faa..91a989d361f9acd6e3e19e091b4ffb7645fd730c 100644 (file)
@@ -29,7 +29,7 @@ struct search_private {
        int total_received;  /* total received all together */
        enum smb_search_level info_level;
        const char *last_name;     /* used to continue trans2 search */
-       DATA_BLOB status;       /* used for old-style search */
+       struct smb_search_id id;   /* used for old-style search */
 };
 
 
@@ -238,7 +238,7 @@ static BOOL smbcli_list_old_callback(void *private, union smb_search_data *file)
 
        state->total_received++;
        state->ff_searchcount++;
-       state->status = file->search.search_id; /* return resume info */
+       state->id = file->search.id; /* return resume info */
        
        return True;
 }
@@ -294,7 +294,7 @@ int smbcli_list_old(struct smbcli_tree *tree, const char *Mask, uint16_t attribu
                        next_parms.search_next.level = RAW_SEARCH_SEARCH;
                        next_parms.search_next.in.max_count = num_asked;
                        next_parms.search_next.in.search_attrib = attribute;
-                       next_parms.search_next.in.search_id = state.status;
+                       next_parms.search_next.in.id = state.id;
                        
                        status = smb_raw_search_next(tree, state.mem_ctx,
                                                     &next_parms,
index 67410283ed64b92bd52f5700b45e6a7e5171ae5f..df44dbffa4fee84d4661e7b624908f29153e249d 100644 (file)
@@ -42,11 +42,15 @@ static void smb_raw_search_backend(struct smbcli_request *req,
        p = req->in.data + 3;
 
        for (i=0; i < count; i++) {
-               search_data.search.search_id  = smbcli_req_pull_blob(req, mem_ctx, p, 21);
-               search_data.search.attrib     = CVAL(p,            21);
-               search_data.search.write_time = raw_pull_dos_date(req->transport,
-                                                                 p + 22);
-               search_data.search.size       = IVAL(p,            26);
+               search_data.search.id.reserved      = CVAL(p, 0);
+               memcpy(search_data.search.id.name,    p+1, 11);
+               search_data.search.id.handle        = CVAL(p, 12);
+               search_data.search.id.server_cookie = IVAL(p, 13);
+               search_data.search.id.client_cookie = IVAL(p, 17);
+               search_data.search.attrib           = CVAL(p, 21);
+               search_data.search.write_time       = raw_pull_dos_date(req->transport,
+                                                                       p + 22);
+               search_data.search.size             = IVAL(p, 26);
                smbcli_req_pull_ascii(req, mem_ctx, &search_data.search.name, p+30, 13, STR_ASCII);
                if (!callback(private, &search_data)) {
                        break;
@@ -65,8 +69,15 @@ static NTSTATUS smb_raw_search_first_old(struct smbcli_tree *tree,
 
 {
        struct smbcli_request *req; 
-       
-       req = smbcli_request_setup(tree, SMBsearch, 2, 0);
+       uint8_t op = SMBsearch;
+
+       if (io->generic.level == RAW_SEARCH_FFIRST) {
+               op = SMBffirst;
+       } else if (io->generic.level == RAW_SEARCH_FUNIQUE) {
+               op = SMBfunique;
+       }
+
+       req = smbcli_request_setup(tree, op, 2, 0);
        if (!req) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -99,8 +110,14 @@ static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree,
 
 {
        struct smbcli_request *req; 
+       uint8_t var_block[21];
+       uint8_t op = SMBsearch;
+
+       if (io->generic.level == RAW_SEARCH_FFIRST) {
+               op = SMBffirst;
+       }
        
-       req = smbcli_request_setup(tree, SMBsearch, 2, 0);
+       req = smbcli_request_setup(tree, op, 2, 0);
        if (!req) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -108,7 +125,14 @@ static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree,
        SSVAL(req->out.vwv, VWV(0), io->search_next.in.max_count);
        SSVAL(req->out.vwv, VWV(1), io->search_next.in.search_attrib);
        smbcli_req_append_ascii4(req, "", STR_TERMINATE);
-       smbcli_req_append_var_block(req, io->search_next.in.search_id.data, 21);
+
+       SCVAL(var_block,  0, io->search_next.in.id.reserved);
+       memcpy(&var_block[1], io->search_next.in.id.name, 11);
+       SCVAL(var_block, 12, io->search_next.in.id.handle);
+       SIVAL(var_block, 13, io->search_next.in.id.server_cookie);
+       SIVAL(var_block, 17, io->search_next.in.id.client_cookie);
+
+       smbcli_req_append_var_block(req, var_block, 21);
 
        if (!smbcli_request_send(req) ||
            !smbcli_request_receive(req)) {
@@ -123,6 +147,43 @@ static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree,
        return smbcli_request_destroy(req);
 }
 
+
+/****************************************************************************
+ Old style search next.
+****************************************************************************/
+static NTSTATUS smb_raw_search_close_old(struct smbcli_tree *tree,
+                                        union smb_search_close *io)
+{
+       struct smbcli_request *req; 
+       uint8_t var_block[21];
+
+       req = smbcli_request_setup(tree, SMBfclose, 2, 0);
+       if (!req) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       SSVAL(req->out.vwv, VWV(0), io->fclose.in.max_count);
+       SSVAL(req->out.vwv, VWV(1), io->fclose.in.search_attrib);
+       smbcli_req_append_ascii4(req, "", STR_TERMINATE);
+
+       SCVAL(var_block,  0, io->fclose.in.id.reserved);
+       memcpy(&var_block[1], io->fclose.in.id.name, 11);
+       SCVAL(var_block, 12, io->fclose.in.id.handle);
+       SIVAL(var_block, 13, io->fclose.in.id.server_cookie);
+       SIVAL(var_block, 17, io->fclose.in.id.client_cookie);
+
+       smbcli_req_append_var_block(req, var_block, 21);
+
+       if (!smbcli_request_send(req) ||
+           !smbcli_request_receive(req)) {
+               return smbcli_request_destroy(req);
+       }
+
+       return smbcli_request_destroy(req);
+}
+
+
+
 /****************************************************************************
  Very raw search first - returns param/data blobs.
 ****************************************************************************/
@@ -245,6 +306,8 @@ static int parse_trans2_search(struct smbcli_tree *tree,
        switch (level) {
        case RAW_SEARCH_GENERIC:
        case RAW_SEARCH_SEARCH:
+       case RAW_SEARCH_FFIRST:
+       case RAW_SEARCH_FUNIQUE:
                /* handled elsewhere */
                return -1;
 
@@ -499,7 +562,9 @@ NTSTATUS smb_raw_search_first(struct smbcli_tree *tree,
        DATA_BLOB p_blob, d_blob;
        NTSTATUS status;
                        
-       if (io->generic.level == RAW_SEARCH_SEARCH) {
+       if (io->generic.level == RAW_SEARCH_SEARCH ||
+           io->generic.level == RAW_SEARCH_FFIRST ||
+           io->generic.level == RAW_SEARCH_FUNIQUE) {
                return smb_raw_search_first_old(tree, mem_ctx, io, private, callback);
        }
        if (io->generic.level >= RAW_SEARCH_GENERIC) {
@@ -543,7 +608,8 @@ NTSTATUS smb_raw_search_next(struct smbcli_tree *tree,
        DATA_BLOB p_blob, d_blob;
        NTSTATUS status;
 
-       if (io->generic.level == RAW_SEARCH_SEARCH) {
+       if (io->generic.level == RAW_SEARCH_SEARCH ||
+           io->generic.level == RAW_SEARCH_FFIRST) {
                return smb_raw_search_next_old(tree, mem_ctx, io, private, callback);
        }
        if (io->generic.level >= RAW_SEARCH_GENERIC) {
@@ -582,6 +648,10 @@ NTSTATUS smb_raw_search_close(struct smbcli_tree *tree,
                              union smb_search_close *io)
 {
        struct smbcli_request *req;
+
+       if (io->generic.level == RAW_FINDCLOSE_FCLOSE) {
+               return smb_raw_search_close_old(tree, io);
+       }
        
        req = smbcli_request_setup(tree, SMBfindclose, 1, 0);
        if (!req) {
index 548d7ad77e07a02e9e49575aad3d08a9e0244a25..3004e92d51ecd1c504e48e8bebd104cac945e2b3 100644 (file)
@@ -102,31 +102,14 @@ NTSTATUS pvfs_search_first(struct smbsrv_request *req, union smb_search_first *i
        NTSTATUS status;
        struct pvfs_filename *name;
 
-       switch (io->generic.level) {
-       case RAW_SEARCH_SEARCH:
+       if (io->generic.level == RAW_SEARCH_SEARCH) {
                max_count     = io->search_first.in.max_count;
                search_attrib = io->search_first.in.search_attrib;
                pattern       = io->search_first.in.pattern;
-               break;
-
-       case RAW_SEARCH_STANDARD:
-       case RAW_SEARCH_EA_SIZE:
-       case RAW_SEARCH_DIRECTORY_INFO:
-       case RAW_SEARCH_FULL_DIRECTORY_INFO:
-       case RAW_SEARCH_NAME_INFO:
-       case RAW_SEARCH_BOTH_DIRECTORY_INFO:
-       case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
-       case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO:
-       case RAW_SEARCH_UNIX_INFO:
+       } else {
                max_count     = io->t2ffirst.in.max_count;
                search_attrib = io->t2ffirst.in.search_attrib;
                pattern       = io->t2ffirst.in.pattern;
-               break;
-
-       case RAW_SEARCH_FCLOSE:
-       case RAW_SEARCH_GENERIC:
-               DEBUG(0,("WARNING: Invalid search class %d in pvfs_search_first\n", io->generic.level));
-               return NT_STATUS_INVALID_INFO_CLASS;
        }
 
        /* resolve the cifs name to a posix name */
@@ -232,7 +215,94 @@ NTSTATUS pvfs_search_next(struct smbsrv_request *req, union smb_search_next *io,
                          void *search_private, 
                          BOOL (*callback)(void *, union smb_search_data *))
 {
-       return NT_STATUS_NOT_IMPLEMENTED;
+#if 0
+       struct pvfs_state *pvfs = req->tcon->ntvfs_private;
+       struct search_state *search;
+       union smb_search_data file;
+       uint_t max_count;
+       uint16_t handle;
+       int i;
+
+       if (io->generic.level == RAW_SEARCH_SEARCH) {
+               max_count     = io->search_next.in.max_count;
+               search_attrib = io->search_next.in.search_attrib;
+       } else {
+               handle = io->t2fnext.in.handle;
+       }
+
+       if (io->generic.level != RAW_SEARCH_BOTH_DIRECTORY_INFO) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       for (search=private->search; search; search = search->next) {
+               if (search->handle == io->t2fnext.in.handle) break;
+       }
+       
+       if (!search) {
+               /* we didn't find the search handle */
+               return NT_STATUS_FOOBAR;
+       }
+
+       dir = search->dir;
+
+       /* the client might be asking for something other than just continuing
+          with the search */
+       if (!(io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE) &&
+           (io->t2fnext.in.flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) &&
+           io->t2fnext.in.last_name && *io->t2fnext.in.last_name) {
+               /* look backwards first */
+               for (i=search->current_index; i > 0; i--) {
+                       if (strcmp(io->t2fnext.in.last_name, dir->files[i-1].name) == 0) {
+                               search->current_index = i;
+                               goto found;
+                       }
+               }
+
+               /* then look forwards */
+               for (i=search->current_index+1; i <= dir->count; i++) {
+                       if (strcmp(io->t2fnext.in.last_name, dir->files[i-1].name) == 0) {
+                               search->current_index = i;
+                               goto found;
+                       }
+               }
+       }
+
+found: 
+       max_count = search->current_index + io->t2fnext.in.max_count;
+
+       if (max_count > dir->count) {
+               max_count = dir->count;
+       }
+
+       for (i = search->current_index; i < max_count;i++) {
+               ZERO_STRUCT(file);
+               unix_to_nt_time(&file.both_directory_info.create_time, dir->files[i].st.st_ctime);
+               unix_to_nt_time(&file.both_directory_info.access_time, dir->files[i].st.st_atime);
+               unix_to_nt_time(&file.both_directory_info.write_time,  dir->files[i].st.st_mtime);
+               unix_to_nt_time(&file.both_directory_info.change_time, dir->files[i].st.st_mtime);
+               file.both_directory_info.name.s = dir->files[i].name;
+               file.both_directory_info.short_name.s = dir->files[i].name;
+               file.both_directory_info.size = dir->files[i].st.st_size;
+               file.both_directory_info.attrib = pvfs_unix_to_dos_attrib(dir->files[i].st.st_mode);
+
+               if (!callback(search_private, &file)) {
+                       break;
+               }
+       }
+
+       io->t2fnext.out.count = i - search->current_index;
+       io->t2fnext.out.end_of_search = (i == dir->count) ? 1 : 0;
+
+       search->current_index = i;
+
+       /* work out if we are going to keep the search state */
+       if ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE) ||
+           ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && (i == dir->count))) {
+               DLIST_REMOVE(private->search, search);
+               talloc_free(search);
+       }
+#endif
+       return NT_STATUS_OK;
 }
 
 /* close a search */
index 12955ced5ca92c45a233e828eafa86c4c05cac71..8b7ddfad88f6cfddf954205cd19cf7d7f7c33cd9 100644 (file)
@@ -92,9 +92,9 @@ struct pvfs_dir {
 /* the state of a search started with pvfs_search_first() */
 struct pvfs_search_state {
        struct pvfs_search_state *next, *prev;
-       uint16_t search_attrib;
        uint16_t handle;
        uint_t current_index;
+       uint16_t search_attrib;
        struct pvfs_dir *dir;
 };
 
index 5827d64bcddabc5647334669ed7dc615eeb9a230..a1922d54c1759e31c2e055a15d7821e014ba0dfa 100644 (file)
@@ -2136,7 +2136,7 @@ void reply_findclose(struct smbsrv_request *req)
        NTSTATUS status;
        union smb_search_close io;
 
-       io.findclose.level = RAW_FINDCLOSE_CLOSE;
+       io.findclose.level = RAW_FINDCLOSE_FINDCLOSE;
 
        /* parse request */
        REQ_CHECK_WCT(req, 1);
index 80663b9ccc8b99980ae13c9f43b20caffb9c3ce7..07b2ee0575b0c99bf0197916cdbc652008200bba 100644 (file)
@@ -395,7 +395,7 @@ size_t req_push_str(struct smbsrv_request *req, char *dest, const char *str, int
   return the number of bytes added
 */
 size_t req_append_bytes(struct smbsrv_request *req, 
-               const uint8_t *bytes, size_t byte_len)
+                       const uint8_t *bytes, size_t byte_len)
 {
        req_grow_allocation(req, byte_len + req->out.data_size);
        memcpy(req->out.data + req->out.data_size, bytes, byte_len);
index e18ecda88722ceeeeba3a76bb9885ae1884eb8de..a99958d6c6c7782f12a6cfd8cb9e86272ac43619 100644 (file)
@@ -42,8 +42,8 @@
        }} while (0)
 
 /* useful wrapper for talloc with NO_MEMORY reply */
-#define REQ_TALLOC(ptr, size) do { \
-       ptr = talloc(req, size); \
+#define REQ_TALLOC(ptr) do { \
+       ptr = talloc(req, sizeof(*(ptr))); \
        if (!ptr) { \
                req_reply_error(req, NT_STATUS_NO_MEMORY); \
                return; \
@@ -68,23 +68,21 @@ struct search_state {
 static void find_fill_info(struct smbsrv_request *req,
                           union smb_search_data *file)
 {
-       char *p = req->out.data + req->out.data_size;
-       uint32_t dos_date;
-       char search_name[13];
+       char *p;
        
-       DEBUG(9,("find_fill_info: input file data: attr=0x%x size=%u time=0x%x name=%13s\n",
-               file->search.attrib, file->search.size,
-               (uint32_t)file->search.write_time, file->search.name));
-
-       p += req_append_bytes(req, file->search.search_id.data, 21);
-       p += req_append_bytes(req, (char*)&file->search.attrib, 1);
-       srv_push_dos_date(req->smb_conn, (uint8_t *)&dos_date, 0, file->search.write_time);
-       p += req_append_bytes(req, (char*)&dos_date, 4);
-       p += req_append_bytes(req, (char*)&file->search.size, 4);
-       memset(&search_name[0], ' ', 13);
-       memcpy(&search_name[0], file->search.name, 
-               MAX(13, strlen(file->search.name)));
-       p += req_append_bytes(req, &search_name[0], 13);
+       req_grow_data(req, req->out.data_size + 43);
+       p = req->out.data + req->out.data_size - 43;
+
+       SCVAL(p,  0, file->search.id.reserved);
+       memcpy(p+1, file->search.id.name, 11);
+       SCVAL(p, 12, file->search.id.handle);
+       SIVAL(p, 13, file->search.id.server_cookie);
+       SIVAL(p, 17, file->search.id.client_cookie);
+       SCVAL(p, 21, file->search.attrib);
+       srv_push_dos_date(req->smb_conn, p, 22, file->search.write_time);
+       SIVAL(p, 26, file->search.size);
+       memset(p+30, ' ', 13);
+       memcpy(p+30, file->search.name, MIN(strlen(file->search.name)+1, 13));
 }
 
 /* callback function for search first/next */
@@ -104,12 +102,20 @@ void reply_search(struct smbsrv_request *req)
 {
        union smb_search_first *sf;
        union smb_search_next *sn;
-       DATA_BLOB resume_key;
        uint16_t resume_key_length;
        struct search_state state;
        char *p;
+       NTSTATUS status;
+       enum smb_search_level level = RAW_SEARCH_SEARCH;
+       uint8_t op = CVAL(req->in.hdr,HDR_COM);
+
+       if (op == SMBffirst) {
+               level = RAW_SEARCH_FFIRST;
+       } else if (op == SMBfunique) {
+               level = RAW_SEARCH_FUNIQUE;
+       }
 
-       REQ_TALLOC(sf, sizeof(*sf));
+       REQ_TALLOC(sf);
        
        /* parse request */
        if (req->in.wct != 2) {
@@ -119,18 +125,22 @@ void reply_search(struct smbsrv_request *req)
        
        p = req->in.data;
        p += req_pull_ascii4(req, &sf->search_first.in.pattern, 
-               p, STR_TERMINATE);
+                            p, STR_TERMINATE);
        if (!sf->search_first.in.pattern) {
                req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
                return;
        }
-       /* pull in type 5 byte and length */
-       if (!req_pull_blob(req, p, 3, &resume_key))
+
+       if (req_data_oob(req, p, 3)) {
                req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
-       resume_key_length = SVAL(resume_key.data, 1);
+               return;
+       }
+       if (*p != 5) {
+               req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+       resume_key_length = SVAL(p, 1);
        p += 3;
-       DEBUG(19,("reply_search: pattern=%s, key_length=%d\n",
-               sf->search_first.in.pattern, resume_key_length));
        
        /* setup state for callback */
        state.req = req;
@@ -141,34 +151,46 @@ void reply_search(struct smbsrv_request *req)
        req_setup_reply(req, 1, 0);
        req_append_var_block(req, NULL, 0);
 
-       if (resume_key_length > 0) {
-               /* do a search next operation */
-               REQ_TALLOC(sn, sizeof(*sn));
-               sn->search_next.level = RAW_SEARCH_SEARCH;
-               req->async.private = sn;
-               if (!req_pull_blob(req, req->in.data, resume_key_length, 
-                               &(sn->search_next.in.search_id)))
+       if (resume_key_length != 0) {
+               if (resume_key_length != 21 || 
+                   req_data_oob(req, p, 21) ||
+                   level == RAW_SEARCH_FUNIQUE) {
                        req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
-               sn->search_next.in.search_attrib = SVAL(req->in.vwv, VWV(1));
+                       return;
+               }
+
+               /* do a search next operation */
+               REQ_TALLOC(sn);
+
+               sn->search_next.in.id.reserved      = CVAL(p, 0);
+               memcpy(sn->search_next.in.id.name,    p+1, 11);
+               sn->search_next.in.id.handle        = CVAL(p, 12);
+               sn->search_next.in.id.server_cookie = IVAL(p, 13);
+               sn->search_next.in.id.client_cookie = IVAL(p, 17);
+
+               sn->search_next.level = level;
                sn->search_next.in.max_count     = SVAL(req->in.vwv, VWV(0));
+               sn->search_next.in.search_attrib = SVAL(req->in.vwv, VWV(1));
                
                /* call backend */
-               req->async.status = req->tcon->ntvfs_ops->search_next(req, 
-                       sn, &state, find_callback);
+               status = req->tcon->ntvfs_ops->search_next(req, sn, &state, find_callback);
                SSVAL(req->out.vwv, VWV(0), sn->search_next.out.count);
        } else {
                /* do a search first operation */
-               req->async.private = sf;
-               sf->search_first.level = RAW_SEARCH_SEARCH;
+               sf->search_first.level = level;
                sf->search_first.in.search_attrib = SVAL(req->in.vwv, VWV(1));
                sf->search_first.in.max_count     = SVAL(req->in.vwv, VWV(0));
                
                /* call backend */
-               req->async.status = req->tcon->ntvfs_ops->search_first(req, 
-                       sf, &state, find_callback);
+               status = req->tcon->ntvfs_ops->search_first(req, sf, &state, find_callback);
                SSVAL(req->out.vwv, VWV(0), sf->search_first.out.count);
        }
 
+       if (!NT_STATUS_IS_OK(status)) {
+               req_reply_error(req, status);
+               return;
+       }
+
        req_send_reply(req);
 }
 
@@ -183,6 +205,8 @@ static void reply_fclose_send(struct smbsrv_request *req)
        /* construct reply */
        req_setup_reply(req, 1, 0);
 
+       SSVAL(req->out.vwv, VWV(0), 0);
+
        req_send_reply(req);
 }
 
@@ -192,11 +216,12 @@ static void reply_fclose_send(struct smbsrv_request *req)
 ****************************************************************************/
 void reply_fclose(struct smbsrv_request *req)
 {
-       union smb_search_next *sn;
-       DATA_BLOB resume_key;
+       union smb_search_close *sc;
        uint16_t resume_key_length;
+       char *p;
+       const char *pattern;
 
-       REQ_TALLOC(sn, sizeof(*sn));
+       REQ_TALLOC(sc);
 
        /* parse request */
        if (req->in.wct != 2) {
@@ -204,26 +229,49 @@ void reply_fclose(struct smbsrv_request *req)
                return;
        }
        
-       sn->search_next.level = RAW_SEARCH_FCLOSE;
+       p = req->in.data;
+       p += req_pull_ascii4(req, &pattern, p, STR_TERMINATE);
+       if (pattern && *pattern) {
+               req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
        
-       /* pull in type 5 byte and length */
-       if (!req_pull_blob(req, req->in.data, 3, &resume_key))
+       if (req_data_oob(req, p, 3)) {
                req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
-       resume_key_length = SVAL(resume_key.data, 1);
-       if (resume_key_length > 0) {
-               /* do a search close operation */
-               if (!req_pull_blob(req, req->in.data, resume_key_length, 
-                               &(sn->search_next.in.search_id)))
-                       req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
-       } else
+               return;
+       }
+       if (*p != 5) {
                req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+       resume_key_length = SVAL(p, 1);
+       p += 3;
+
+       if (resume_key_length != 21) {
+               req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
+       if (req_data_oob(req, p, 21)) {
+               req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
+       sc->fclose.level               = RAW_FINDCLOSE_FCLOSE;
+       sc->fclose.in.max_count        = SVAL(req->in.vwv, VWV(0));
+       sc->fclose.in.search_attrib    = SVAL(req->in.vwv, VWV(1));
+       sc->fclose.in.id.reserved      = CVAL(p, 0);
+       memcpy(sc->fclose.in.id.name,    p+1, 11);
+       sc->fclose.in.id.handle        = CVAL(p, 12);
+       sc->fclose.in.id.server_cookie = IVAL(p, 13);
+       sc->fclose.in.id.client_cookie = IVAL(p, 17);
 
+       /* do a search close operation */
        req->async.send_fn = reply_fclose_send;
-       req->async.private = sn;
+       req->async.private = sc;
 
        /* call backend */
-       req->async.status = req->tcon->ntvfs_ops->search_next(req, sn,
-               NULL, NULL);
+       req->async.status = req->tcon->ntvfs_ops->search_close(req, sc);
 
        REQ_ASYNC_TAIL;
 }
index 57a385fe272bff6649190ee121b46da71a90ce33..6e02ddc90d2bcdb36771dcc8bfc9388141ffbdbf 100644 (file)
@@ -885,6 +885,8 @@ static void find_fill_info(struct smbsrv_request *req,
 
        switch (state->level) {
        case RAW_SEARCH_SEARCH:
+       case RAW_SEARCH_FFIRST:
+       case RAW_SEARCH_FUNIQUE:
        case RAW_SEARCH_GENERIC:
                /* handled elsewhere */
                break;
@@ -926,6 +928,8 @@ static void find_fill_info(struct smbsrv_request *req,
                SIVAL(data, 22, file->ea_size.ea_size);
                trans2_append_data_string(req, trans, &file->ea_size.name, 
                                          ofs + 26, 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:
index d1619d91913f7328e9e70e7060d33bdb6332cd92..3a469b3a2d6387e723ca70ce2fa5c19277cc6b49 100644 (file)
@@ -45,10 +45,13 @@ static NTSTATUS single_search(struct smbcli_state *cli,
                              union smb_search_data *data)
 {
        union smb_search_first io;
+       union smb_search_close c;
        NTSTATUS status;
 
        io.generic.level = level;
-       if (level == RAW_SEARCH_SEARCH) {
+       if (level == RAW_SEARCH_SEARCH ||
+           level == RAW_SEARCH_FFIRST ||
+           level == RAW_SEARCH_FUNIQUE) {
                io.search_first.in.max_count = 1;
                io.search_first.in.search_attrib = 0;
                io.search_first.in.pattern = pattern;
@@ -62,6 +65,14 @@ static NTSTATUS single_search(struct smbcli_state *cli,
 
        status = smb_raw_search_first(cli->tree, mem_ctx,
                                      &io, (void *)data, single_search_callback);
+
+       if (NT_STATUS_IS_OK(status) && level == RAW_SEARCH_FFIRST) {
+               c.fclose.level = RAW_FINDCLOSE_FCLOSE;
+               c.fclose.in.max_count = 1;
+               c.fclose.in.search_attrib = 0;
+               c.fclose.in.id = data->search.id;
+               status = smb_raw_search_close(cli->tree, &c);
+       }
        
        return status;
 }
@@ -74,6 +85,8 @@ static struct {
        NTSTATUS status;
        union smb_search_data data;
 } levels[] = {
+       {"FFIRST",                 RAW_SEARCH_FFIRST, },
+       {"FUNIQUE",                RAW_SEARCH_FUNIQUE, },
        {"SEARCH",                 RAW_SEARCH_SEARCH, },
        {"STANDARD",               RAW_SEARCH_STANDARD, },
        {"EA_SIZE",                RAW_SEARCH_EA_SIZE, },
@@ -151,7 +164,9 @@ static BOOL test_one_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
                                       levels[i].level, &levels[i].data);
                
                expected_status = NT_STATUS_NO_SUCH_FILE;
-               if (levels[i].level == RAW_SEARCH_SEARCH) {
+               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)) {
@@ -447,7 +462,7 @@ static NTSTATUS multiple_search(struct smbcli_state *cli,
                if (level == RAW_SEARCH_SEARCH) {
                        io2.search_next.in.max_count = per_search;
                        io2.search_next.in.search_attrib = 0;
-                       io2.search_next.in.search_id = result->list[result->count-1].search.search_id;
+                       io2.search_next.in.id = result->list[result->count-1].search.id;
                } else {
                        io2.t2fnext.in.handle = io.t2ffirst.out.handle;
                        io2.t2fnext.in.max_count = per_search;