2 Unix SMB/CIFS implementation.
3 client directory search routines
4 Copyright (C) James Myers 2003 <myersjj@samba.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libcli/raw/libcliraw.h"
24 /****************************************************************************
25 Old style search backend - process output.
26 ****************************************************************************/
27 static void smb_raw_search_backend(struct smbcli_request *req,
31 BOOL (*callback)(void *private, union smb_search_data *file))
34 union smb_search_data search_data;
38 if (req->in.data_size < 3 + count*43) {
39 req->status = NT_STATUS_INVALID_PARAMETER;
45 for (i=0; i < count; i++) {
48 search_data.search.id.reserved = CVAL(p, 0);
49 memcpy(search_data.search.id.name, p+1, 11);
50 search_data.search.id.handle = CVAL(p, 12);
51 search_data.search.id.server_cookie = IVAL(p, 13);
52 search_data.search.id.client_cookie = IVAL(p, 17);
53 search_data.search.attrib = CVAL(p, 21);
54 search_data.search.write_time = raw_pull_dos_date(req->transport,
56 search_data.search.size = IVAL(p, 26);
57 smbcli_req_pull_ascii(req, mem_ctx, &name, p+30, 13, STR_ASCII);
58 search_data.search.name = name;
59 if (!callback(private, &search_data)) {
66 /****************************************************************************
67 Old style search first.
68 ****************************************************************************/
69 static NTSTATUS smb_raw_search_first_old(struct smbcli_tree *tree,
71 union smb_search_first *io, void *private,
72 BOOL (*callback)(void *private, union smb_search_data *file))
75 struct smbcli_request *req;
76 uint8_t op = SMBsearch;
78 if (io->generic.level == RAW_SEARCH_FFIRST) {
80 } else if (io->generic.level == RAW_SEARCH_FUNIQUE) {
84 req = smbcli_request_setup(tree, op, 2, 0);
86 return NT_STATUS_NO_MEMORY;
89 SSVAL(req->out.vwv, VWV(0), io->search_first.in.max_count);
90 SSVAL(req->out.vwv, VWV(1), io->search_first.in.search_attrib);
91 smbcli_req_append_ascii4(req, io->search_first.in.pattern, STR_TERMINATE);
92 smbcli_req_append_var_block(req, NULL, 0);
94 if (!smbcli_request_send(req) ||
95 !smbcli_request_receive(req)) {
96 return smbcli_request_destroy(req);
99 if (NT_STATUS_IS_OK(req->status)) {
100 io->search_first.out.count = SVAL(req->in.vwv, VWV(0));
101 smb_raw_search_backend(req, mem_ctx, io->search_first.out.count, private, callback);
104 return smbcli_request_destroy(req);
107 /****************************************************************************
108 Old style search next.
109 ****************************************************************************/
110 static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree,
112 union smb_search_next *io, void *private,
113 BOOL (*callback)(void *private, union smb_search_data *file))
116 struct smbcli_request *req;
117 uint8_t var_block[21];
118 uint8_t op = SMBsearch;
120 if (io->generic.level == RAW_SEARCH_FFIRST) {
124 req = smbcli_request_setup(tree, op, 2, 0);
126 return NT_STATUS_NO_MEMORY;
129 SSVAL(req->out.vwv, VWV(0), io->search_next.in.max_count);
130 SSVAL(req->out.vwv, VWV(1), io->search_next.in.search_attrib);
131 smbcli_req_append_ascii4(req, "", STR_TERMINATE);
133 SCVAL(var_block, 0, io->search_next.in.id.reserved);
134 memcpy(&var_block[1], io->search_next.in.id.name, 11);
135 SCVAL(var_block, 12, io->search_next.in.id.handle);
136 SIVAL(var_block, 13, io->search_next.in.id.server_cookie);
137 SIVAL(var_block, 17, io->search_next.in.id.client_cookie);
139 smbcli_req_append_var_block(req, var_block, 21);
141 if (!smbcli_request_send(req) ||
142 !smbcli_request_receive(req)) {
143 return smbcli_request_destroy(req);
146 if (NT_STATUS_IS_OK(req->status)) {
147 io->search_next.out.count = SVAL(req->in.vwv, VWV(0));
148 smb_raw_search_backend(req, mem_ctx, io->search_next.out.count, private, callback);
151 return smbcli_request_destroy(req);
155 /****************************************************************************
156 Old style search next.
157 ****************************************************************************/
158 static NTSTATUS smb_raw_search_close_old(struct smbcli_tree *tree,
159 union smb_search_close *io)
161 struct smbcli_request *req;
162 uint8_t var_block[21];
164 req = smbcli_request_setup(tree, SMBfclose, 2, 0);
166 return NT_STATUS_NO_MEMORY;
169 SSVAL(req->out.vwv, VWV(0), io->fclose.in.max_count);
170 SSVAL(req->out.vwv, VWV(1), io->fclose.in.search_attrib);
171 smbcli_req_append_ascii4(req, "", STR_TERMINATE);
173 SCVAL(var_block, 0, io->fclose.in.id.reserved);
174 memcpy(&var_block[1], io->fclose.in.id.name, 11);
175 SCVAL(var_block, 12, io->fclose.in.id.handle);
176 SIVAL(var_block, 13, io->fclose.in.id.server_cookie);
177 SIVAL(var_block, 17, io->fclose.in.id.client_cookie);
179 smbcli_req_append_var_block(req, var_block, 21);
181 if (!smbcli_request_send(req) ||
182 !smbcli_request_receive(req)) {
183 return smbcli_request_destroy(req);
186 return smbcli_request_destroy(req);
191 /****************************************************************************
192 Very raw search first - returns param/data blobs.
193 ****************************************************************************/
194 static NTSTATUS smb_raw_search_first_blob(struct smbcli_tree *tree,
195 TALLOC_CTX *mem_ctx, /* used to allocate output blobs */
196 union smb_search_first *io,
198 DATA_BLOB *out_param_blob,
199 DATA_BLOB *out_data_blob)
201 struct smb_trans2 tp;
202 uint16_t setup = TRANSACT2_FINDFIRST;
208 tp.in.setup_count = 1;
209 tp.in.data = data_blob(NULL, 0);
210 tp.in.max_param = 10;
211 tp.in.max_data = 0xFFFF;
212 tp.in.setup = &setup;
214 if (info_level == RAW_SEARCH_EA_LIST) {
215 if (!ea_push_name_list(mem_ctx,
217 io->t2ffirst.in.num_names,
218 io->t2ffirst.in.ea_names)) {
219 return NT_STATUS_NO_MEMORY;
223 tp.in.params = data_blob_talloc(mem_ctx, NULL, 12);
224 if (!tp.in.params.data) {
225 return NT_STATUS_NO_MEMORY;
228 SSVAL(tp.in.params.data, 0, io->t2ffirst.in.search_attrib);
229 SSVAL(tp.in.params.data, 2, io->t2ffirst.in.max_count);
230 SSVAL(tp.in.params.data, 4, io->t2ffirst.in.flags);
231 SSVAL(tp.in.params.data, 6, info_level);
232 SIVAL(tp.in.params.data, 8, io->t2ffirst.in.storage_type);
234 smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params,
235 io->t2ffirst.in.pattern, STR_TERMINATE);
237 status = smb_raw_trans2(tree, mem_ctx, &tp);
238 if (!NT_STATUS_IS_OK(status)) {
242 out_param_blob->length = tp.out.params.length;
243 out_param_blob->data = tp.out.params.data;
244 out_data_blob->length = tp.out.data.length;
245 out_data_blob->data = tp.out.data.data;
251 /****************************************************************************
252 Very raw search first - returns param/data blobs.
253 Used in CIFS-on-CIFS NTVFS.
254 ****************************************************************************/
255 static NTSTATUS smb_raw_search_next_blob(struct smbcli_tree *tree,
257 union smb_search_next *io,
259 DATA_BLOB *out_param_blob,
260 DATA_BLOB *out_data_blob)
262 struct smb_trans2 tp;
263 uint16_t setup = TRANSACT2_FINDNEXT;
269 tp.in.setup_count = 1;
270 tp.in.data = data_blob(NULL, 0);
271 tp.in.max_param = 10;
272 tp.in.max_data = 0xFFFF;
273 tp.in.setup = &setup;
275 if (info_level == RAW_SEARCH_EA_LIST) {
276 if (!ea_push_name_list(mem_ctx,
278 io->t2fnext.in.num_names,
279 io->t2fnext.in.ea_names)) {
280 return NT_STATUS_NO_MEMORY;
284 tp.in.params = data_blob_talloc(mem_ctx, NULL, 12);
285 if (!tp.in.params.data) {
286 return NT_STATUS_NO_MEMORY;
289 SSVAL(tp.in.params.data, 0, io->t2fnext.in.handle);
290 SSVAL(tp.in.params.data, 2, io->t2fnext.in.max_count);
291 SSVAL(tp.in.params.data, 4, info_level);
292 SIVAL(tp.in.params.data, 6, io->t2fnext.in.resume_key);
293 SSVAL(tp.in.params.data, 10, io->t2fnext.in.flags);
295 smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params,
296 io->t2fnext.in.last_name,
299 status = smb_raw_trans2(tree, mem_ctx, &tp);
300 if (!NT_STATUS_IS_OK(status)) {
304 out_param_blob->length = tp.out.params.length;
305 out_param_blob->data = tp.out.params.data;
306 out_data_blob->length = tp.out.data.length;
307 out_data_blob->data = tp.out.data.data;
314 parse the wire search formats that are in common between SMB and
317 NTSTATUS smb_raw_search_common(TALLOC_CTX *mem_ctx,
318 enum smb_search_level level,
319 const DATA_BLOB *blob,
320 union smb_search_data *data,
326 if (blob->length < 4) {
327 return NT_STATUS_INFO_LENGTH_MISMATCH;
330 *next_ofs = IVAL(blob->data, 0);
331 if (*next_ofs != 0) {
338 case RAW_SEARCH_DIRECTORY_INFO:
339 if (blen < 65) return NT_STATUS_INFO_LENGTH_MISMATCH;
340 data->directory_info.file_index = IVAL(blob->data, 4);
341 data->directory_info.create_time = smbcli_pull_nttime(blob->data, 8);
342 data->directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
343 data->directory_info.write_time = smbcli_pull_nttime(blob->data, 24);
344 data->directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
345 data->directory_info.size = BVAL(blob->data, 40);
346 data->directory_info.alloc_size = BVAL(blob->data, 48);
347 data->directory_info.attrib = IVAL(blob->data, 56);
348 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
349 &data->directory_info.name,
351 if (*next_ofs != 0 && *next_ofs < 64+len) {
352 return NT_STATUS_INFO_LENGTH_MISMATCH;
356 case RAW_SEARCH_FULL_DIRECTORY_INFO:
357 if (blen < 69) return NT_STATUS_INFO_LENGTH_MISMATCH;
358 data->full_directory_info.file_index = IVAL(blob->data, 4);
359 data->full_directory_info.create_time = smbcli_pull_nttime(blob->data, 8);
360 data->full_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
361 data->full_directory_info.write_time = smbcli_pull_nttime(blob->data, 24);
362 data->full_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
363 data->full_directory_info.size = BVAL(blob->data, 40);
364 data->full_directory_info.alloc_size = BVAL(blob->data, 48);
365 data->full_directory_info.attrib = IVAL(blob->data, 56);
366 data->full_directory_info.ea_size = IVAL(blob->data, 64);
367 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
368 &data->full_directory_info.name,
370 if (*next_ofs != 0 && *next_ofs < 68+len) {
371 return NT_STATUS_INFO_LENGTH_MISMATCH;
375 case RAW_SEARCH_NAME_INFO:
376 if (blen < 13) return NT_STATUS_INFO_LENGTH_MISMATCH;
377 data->name_info.file_index = IVAL(blob->data, 4);
378 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
379 &data->name_info.name,
381 if (*next_ofs != 0 && *next_ofs < 12+len) {
382 return NT_STATUS_INFO_LENGTH_MISMATCH;
387 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
388 if (blen < 95) return NT_STATUS_INFO_LENGTH_MISMATCH;
389 data->both_directory_info.file_index = IVAL(blob->data, 4);
390 data->both_directory_info.create_time = smbcli_pull_nttime(blob->data, 8);
391 data->both_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
392 data->both_directory_info.write_time = smbcli_pull_nttime(blob->data, 24);
393 data->both_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
394 data->both_directory_info.size = BVAL(blob->data, 40);
395 data->both_directory_info.alloc_size = BVAL(blob->data, 48);
396 data->both_directory_info.attrib = IVAL(blob->data, 56);
397 data->both_directory_info.ea_size = IVAL(blob->data, 64);
398 smbcli_blob_pull_string(NULL, mem_ctx, blob,
399 &data->both_directory_info.short_name,
400 68, 70, STR_LEN8BIT | STR_UNICODE);
401 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
402 &data->both_directory_info.name,
404 if (*next_ofs != 0 && *next_ofs < 94+len) {
405 return NT_STATUS_INFO_LENGTH_MISMATCH;
410 case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
411 if (blen < 81) return NT_STATUS_INFO_LENGTH_MISMATCH;
412 data->id_full_directory_info.file_index = IVAL(blob->data, 4);
413 data->id_full_directory_info.create_time = smbcli_pull_nttime(blob->data, 8);
414 data->id_full_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
415 data->id_full_directory_info.write_time = smbcli_pull_nttime(blob->data, 24);
416 data->id_full_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
417 data->id_full_directory_info.size = BVAL(blob->data, 40);
418 data->id_full_directory_info.alloc_size = BVAL(blob->data, 48);
419 data->id_full_directory_info.attrib = IVAL(blob->data, 56);
420 data->id_full_directory_info.ea_size = IVAL(blob->data, 64);
421 data->id_full_directory_info.file_id = BVAL(blob->data, 72);
422 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
423 &data->id_full_directory_info.name,
425 if (*next_ofs != 0 && *next_ofs < 80+len) {
426 return NT_STATUS_INFO_LENGTH_MISMATCH;
430 case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO:
431 if (blen < 105) return NT_STATUS_INFO_LENGTH_MISMATCH;
432 data->id_both_directory_info.file_index = IVAL(blob->data, 4);
433 data->id_both_directory_info.create_time = smbcli_pull_nttime(blob->data, 8);
434 data->id_both_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
435 data->id_both_directory_info.write_time = smbcli_pull_nttime(blob->data, 24);
436 data->id_both_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
437 data->id_both_directory_info.size = BVAL(blob->data, 40);
438 data->id_both_directory_info.alloc_size = BVAL(blob->data, 48);
439 data->id_both_directory_info.attrib = SVAL(blob->data, 56);
440 data->id_both_directory_info.ea_size = IVAL(blob->data, 64);
441 smbcli_blob_pull_string(NULL, mem_ctx, blob,
442 &data->id_both_directory_info.short_name,
443 68, 70, STR_LEN8BIT | STR_UNICODE);
444 data->id_both_directory_info.file_id = BVAL(blob->data, 96);
445 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
446 &data->id_both_directory_info.name,
448 if (*next_ofs != 0 && *next_ofs < 104+len) {
449 return NT_STATUS_INFO_LENGTH_MISMATCH;
458 return NT_STATUS_INVALID_INFO_CLASS;
463 parse a trans2 search response.
464 Return the number of bytes consumed
465 return 0 for success with end of list
466 return -1 for a parse error
468 static int parse_trans2_search(struct smbcli_tree *tree,
470 enum smb_search_level level,
473 union smb_search_data *data)
481 case RAW_SEARCH_GENERIC:
482 case RAW_SEARCH_SEARCH:
483 case RAW_SEARCH_FFIRST:
484 case RAW_SEARCH_FUNIQUE:
485 case RAW_SEARCH_SMB2:
486 /* handled elsewhere */
489 case RAW_SEARCH_STANDARD:
490 if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
491 if (blob->length < 4) return -1;
492 data->standard.resume_key = IVAL(blob->data, 0);
496 if (blob->length < 24) return -1;
497 data->standard.create_time = raw_pull_dos_date2(tree->session->transport,
499 data->standard.access_time = raw_pull_dos_date2(tree->session->transport,
501 data->standard.write_time = raw_pull_dos_date2(tree->session->transport,
503 data->standard.size = IVAL(blob->data, 12);
504 data->standard.alloc_size = IVAL(blob->data, 16);
505 data->standard.attrib = SVAL(blob->data, 20);
506 len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
507 &data->standard.name,
508 22, 23, STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM);
511 case RAW_SEARCH_EA_SIZE:
512 if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
513 if (blob->length < 4) return -1;
514 data->ea_size.resume_key = IVAL(blob->data, 0);
518 if (blob->length < 28) return -1;
519 data->ea_size.create_time = raw_pull_dos_date2(tree->session->transport,
521 data->ea_size.access_time = raw_pull_dos_date2(tree->session->transport,
523 data->ea_size.write_time = raw_pull_dos_date2(tree->session->transport,
525 data->ea_size.size = IVAL(blob->data, 12);
526 data->ea_size.alloc_size = IVAL(blob->data, 16);
527 data->ea_size.attrib = SVAL(blob->data, 20);
528 data->ea_size.ea_size = IVAL(blob->data, 22);
529 len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
531 26, 27, STR_LEN8BIT | STR_TERMINATE | STR_NOALIGN);
534 case RAW_SEARCH_EA_LIST:
535 if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
536 if (blob->length < 4) return -1;
537 data->ea_list.resume_key = IVAL(blob->data, 0);
541 if (blob->length < 28) return -1;
542 data->ea_list.create_time = raw_pull_dos_date2(tree->session->transport,
544 data->ea_list.access_time = raw_pull_dos_date2(tree->session->transport,
546 data->ea_list.write_time = raw_pull_dos_date2(tree->session->transport,
548 data->ea_list.size = IVAL(blob->data, 12);
549 data->ea_list.alloc_size = IVAL(blob->data, 16);
550 data->ea_list.attrib = SVAL(blob->data, 20);
551 ea_size = IVAL(blob->data, 22);
552 if (ea_size > 0xFFFF) {
555 eablob.data = blob->data + 22;
556 eablob.length = ea_size;
557 if (eablob.length > blob->length - 24) {
560 status = ea_pull_list(&eablob, mem_ctx,
561 &data->ea_list.eas.num_eas,
562 &data->ea_list.eas.eas);
563 if (!NT_STATUS_IS_OK(status)) {
566 len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
568 22+ea_size, 23+ea_size,
569 STR_LEN8BIT | STR_NOALIGN);
570 return len + ea_size + 23 + 1;
572 case RAW_SEARCH_UNIX_INFO:
573 if (blob->length < 109) return -1;
574 ofs = IVAL(blob->data, 0);
575 data->unix_info.file_index = IVAL(blob->data, 4);
576 data->unix_info.size = BVAL(blob->data, 8);
577 data->unix_info.alloc_size = BVAL(blob->data, 16);
578 data->unix_info.status_change_time = smbcli_pull_nttime(blob->data, 24);
579 data->unix_info.access_time = smbcli_pull_nttime(blob->data, 32);
580 data->unix_info.change_time = smbcli_pull_nttime(blob->data, 40);
581 data->unix_info.uid = IVAL(blob->data, 48);
582 data->unix_info.gid = IVAL(blob->data, 56);
583 data->unix_info.file_type = IVAL(blob->data, 64);
584 data->unix_info.dev_major = BVAL(blob->data, 68);
585 data->unix_info.dev_minor = BVAL(blob->data, 76);
586 data->unix_info.unique_id = BVAL(blob->data, 84);
587 data->unix_info.permissions = IVAL(blob->data, 92);
588 data->unix_info.nlink = IVAL(blob->data, 100);
589 /* There is no length field for this name but we know it's null terminated. */
590 len = smbcli_blob_pull_unix_string(tree->session, mem_ctx, blob,
591 &data->unix_info.name, 108, 0);
592 if (ofs != 0 && ofs < 108+len) {
597 case RAW_SEARCH_DIRECTORY_INFO:
598 case RAW_SEARCH_FULL_DIRECTORY_INFO:
599 case RAW_SEARCH_NAME_INFO:
600 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
601 case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
602 case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO: {
603 uint_t str_flags = STR_UNICODE;
604 if (!(tree->session->transport->negotiate.capabilities & CAP_UNICODE)) {
605 str_flags = STR_ASCII;
608 status = smb_raw_search_common(mem_ctx, level, blob, data, &ofs, str_flags);
609 if (!NT_STATUS_IS_OK(status)) {
620 /****************************************************************************
621 Trans2 search backend - process output.
622 ****************************************************************************/
623 static NTSTATUS smb_raw_t2search_backend(struct smbcli_tree *tree,
625 enum smb_search_level level,
630 BOOL (*callback)(void *private, union smb_search_data *file))
636 blob2.data = blob->data;
637 blob2.length = blob->length;
639 for (i=0; i < count; i++) {
640 union smb_search_data search_data;
643 len = parse_trans2_search(tree, mem_ctx, level, flags, &blob2, &search_data);
645 return NT_STATUS_INVALID_PARAMETER;
648 /* the callback function can tell us that no more will
649 fit - in that case we stop, but it isn't an error */
650 if (!callback(private, &search_data)) {
664 /* Implements trans2findfirst2 and old search
666 NTSTATUS smb_raw_search_first(struct smbcli_tree *tree,
668 union smb_search_first *io, void *private,
669 BOOL (*callback)(void *private, union smb_search_data *file))
671 uint16_t info_level = 0;
672 DATA_BLOB p_blob, d_blob;
675 if (io->generic.level == RAW_SEARCH_SEARCH ||
676 io->generic.level == RAW_SEARCH_FFIRST ||
677 io->generic.level == RAW_SEARCH_FUNIQUE) {
678 return smb_raw_search_first_old(tree, mem_ctx, io, private, callback);
680 if (io->generic.level >= RAW_SEARCH_GENERIC) {
681 return NT_STATUS_INVALID_LEVEL;
683 info_level = (uint16_t)io->generic.level;
685 status = smb_raw_search_first_blob(tree, mem_ctx,
686 io, info_level, &p_blob, &d_blob);
687 if (!NT_STATUS_IS_OK(status)) {
691 if (p_blob.length < 10) {
692 DEBUG(1,("smb_raw_search_first: parms wrong size %d != expected_param_size\n",
693 (int)p_blob.length));
694 return NT_STATUS_INVALID_PARAMETER;
697 /* process output data */
698 io->t2ffirst.out.handle = SVAL(p_blob.data, 0);
699 io->t2ffirst.out.count = SVAL(p_blob.data, 2);
700 io->t2ffirst.out.end_of_search = SVAL(p_blob.data, 4);
702 status = smb_raw_t2search_backend(tree, mem_ctx,
704 io->t2ffirst.in.flags, io->t2ffirst.out.count,
705 &d_blob, private, callback);
710 /* Implements trans2findnext2 and old smbsearch
712 NTSTATUS smb_raw_search_next(struct smbcli_tree *tree,
714 union smb_search_next *io, void *private,
715 BOOL (*callback)(void *private, union smb_search_data *file))
717 uint16_t info_level = 0;
718 DATA_BLOB p_blob, d_blob;
721 if (io->generic.level == RAW_SEARCH_SEARCH ||
722 io->generic.level == RAW_SEARCH_FFIRST) {
723 return smb_raw_search_next_old(tree, mem_ctx, io, private, callback);
725 if (io->generic.level >= RAW_SEARCH_GENERIC) {
726 return NT_STATUS_INVALID_LEVEL;
728 info_level = (uint16_t)io->generic.level;
730 status = smb_raw_search_next_blob(tree, mem_ctx,
731 io, info_level, &p_blob, &d_blob);
732 if (!NT_STATUS_IS_OK(status)) {
736 if (p_blob.length != 8) {
737 DEBUG(1,("smb_raw_search_next: parms wrong size %d != expected_param_size\n",
738 (int)p_blob.length));
739 return NT_STATUS_INVALID_PARAMETER;
742 /* process output data */
743 io->t2fnext.out.count = SVAL(p_blob.data, 0);
744 io->t2fnext.out.end_of_search = SVAL(p_blob.data, 2);
746 status = smb_raw_t2search_backend(tree, mem_ctx,
748 io->t2fnext.in.flags, io->t2fnext.out.count,
749 &d_blob, private, callback);
755 Implements trans2findclose2
757 NTSTATUS smb_raw_search_close(struct smbcli_tree *tree,
758 union smb_search_close *io)
760 struct smbcli_request *req;
762 if (io->generic.level == RAW_FINDCLOSE_FCLOSE) {
763 return smb_raw_search_close_old(tree, io);
766 req = smbcli_request_setup(tree, SMBfindclose, 1, 0);
768 return NT_STATUS_NO_MEMORY;
771 SSVAL(req->out.vwv, VWV(0), io->findclose.in.handle);
773 if (smbcli_request_send(req)) {
774 (void) smbcli_request_receive(req);
777 return smbcli_request_destroy(req);