Changeset 740 for vendor/current/source3/libsmb/clilist.c
- Timestamp:
- Nov 14, 2012, 12:59:34 PM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified vendor/current/source3/libsmb/clilist.c ¶
r414 r740 19 19 20 20 #include "includes.h" 21 #include "libsmb/libsmb.h" 22 #include "../lib/util/tevent_ntstatus.h" 23 #include "async_smb.h" 24 #include "trans2.h" 21 25 22 26 /**************************************************************************** … … 47 51 struct cli_state *cli, 48 52 int level, 53 const char *base_ptr, 54 uint16_t recv_flags2, 49 55 const char *p, 50 56 const char *pdata_end, 51 file_info *finfo,57 struct file_info *finfo, 52 58 uint32 *p_resume_key, 53 59 DATA_BLOB *p_last_name_raw) … … 63 69 } 64 70 ZERO_STRUCTP(finfo); 65 finfo->cli = cli;66 71 67 72 switch (level) { … … 72 77 return pdata_end - base; 73 78 } 74 finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4)); 75 finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8)); 76 finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12)); 79 finfo->ctime_ts = convert_time_t_to_timespec( 80 make_unix_date2(p+4, cli->serverzone)); 81 finfo->atime_ts = convert_time_t_to_timespec( 82 make_unix_date2(p+8, cli->serverzone)); 83 finfo->mtime_ts = convert_time_t_to_timespec( 84 make_unix_date2(p+12, cli->serverzone)); 77 85 finfo->size = IVAL(p,16); 78 86 finfo->mode = CVAL(p,24); 79 87 len = CVAL(p, 26); 80 88 p += 27; 81 p += clistr_align_in(cli, p, 0);89 p += align_string(base_ptr, p, 0); 82 90 83 91 /* We can safely use len here (which is required by OS/2) … … 100 108 (tridge) */ 101 109 ret = clistr_pull_talloc(ctx, 102 cli->inbuf, 110 base_ptr, 111 recv_flags2, 103 112 &finfo->name, 104 113 p, … … 117 126 return pdata_end - base; 118 127 } 119 finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4)); 120 finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8)); 121 finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12)); 128 finfo->ctime_ts = convert_time_t_to_timespec( 129 make_unix_date2(p+4, cli->serverzone)); 130 finfo->atime_ts = convert_time_t_to_timespec( 131 make_unix_date2(p+8, cli->serverzone)); 132 finfo->mtime_ts = convert_time_t_to_timespec( 133 make_unix_date2(p+12, cli->serverzone)); 122 134 finfo->size = IVAL(p,16); 123 135 finfo->mode = CVAL(p,24); … … 129 141 } 130 142 ret = clistr_pull_talloc(ctx, 131 cli->inbuf, 143 base_ptr, 144 recv_flags2, 132 145 &finfo->name, 133 146 p, … … 181 194 int flags = 0; 182 195 if (p[1] == 0 && namelen > 1) flags |= STR_UNICODE; 183 clistr_pull( cli->inbuf, finfo->short_name, p,196 clistr_pull(base_ptr, finfo->short_name, p, 184 197 sizeof(finfo->short_name), 185 198 slen, flags); … … 190 203 } 191 204 ret = clistr_pull_talloc(ctx, 192 cli->inbuf, 205 base_ptr, 206 recv_flags2, 193 207 &finfo->name, 194 208 p, … … 218 232 219 233 /**************************************************************************** 220 Do a directory listing, calling fn on each file found.221 ****************************************************************************/222 223 int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,224 void (*fn)(const char *, file_info *, const char *, void *), void *state)225 {226 #if 1227 int max_matches = 1366; /* Match W2k - was 512. */228 #else229 int max_matches = 512;230 #endif231 int info_level;232 char *p, *p2, *rdata_end;233 char *mask = NULL;234 file_info finfo;235 int i;236 char *dirlist = NULL;237 int dirlist_len = 0;238 int total_received = -1;239 bool First = True;240 int ff_searchcount=0;241 int ff_eos=0;242 int ff_dir_handle=0;243 int loop_count = 0;244 char *rparam=NULL, *rdata=NULL;245 unsigned int param_len, data_len;246 uint16 setup;247 char *param;248 uint32 resume_key = 0;249 TALLOC_CTX *frame = talloc_stackframe();250 DATA_BLOB last_name_raw = data_blob(NULL, 0);251 252 /* NT uses SMB_FIND_FILE_BOTH_DIRECTORY_INFO,253 OS/2 uses SMB_FIND_EA_SIZE. Both accept SMB_FIND_INFO_STANDARD. */254 info_level = (cli->capabilities&CAP_NT_SMBS)?255 SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;256 257 mask = SMB_STRDUP(Mask);258 if (!mask) {259 TALLOC_FREE(frame);260 return -1;261 }262 263 while (ff_eos == 0) {264 size_t nlen = 2*(strlen(mask)+1);265 266 loop_count++;267 if (loop_count > 200) {268 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));269 break;270 }271 272 param = SMB_MALLOC_ARRAY(char, 12+nlen+last_name_raw.length+2);273 if (!param) {274 break;275 }276 277 if (First) {278 setup = TRANSACT2_FINDFIRST;279 SSVAL(param,0,attribute); /* attribute */280 SSVAL(param,2,max_matches); /* max count */281 SSVAL(param,4,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END)); /* resume required + close on end */282 SSVAL(param,6,info_level);283 SIVAL(param,8,0);284 p = param+12;285 p += clistr_push(cli, param+12, mask,286 nlen, STR_TERMINATE);287 } else {288 setup = TRANSACT2_FINDNEXT;289 SSVAL(param,0,ff_dir_handle);290 SSVAL(param,2,max_matches); /* max count */291 SSVAL(param,4,info_level);292 /* For W2K servers serving out FAT filesystems we *must* set the293 resume key. If it's not FAT then it's returned as zero. */294 SIVAL(param,6,resume_key); /* ff_resume_key */295 /* NB. *DON'T* use continue here. If you do it seems that W2K and bretheren296 can miss filenames. Use last filename continue instead. JRA */297 SSVAL(param,10,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END)); /* resume required + close on end */298 p = param+12;299 if (last_name_raw.length) {300 memcpy(p, last_name_raw.data, last_name_raw.length);301 p += last_name_raw.length;302 } else {303 p += clistr_push(cli, param+12, mask,304 nlen, STR_TERMINATE);305 }306 }307 308 param_len = PTR_DIFF(p, param);309 310 if (!cli_send_trans(cli, SMBtrans2,311 NULL, /* Name */312 -1, 0, /* fid, flags */313 &setup, 1, 0, /* setup, length, max */314 param, param_len, 10, /* param, length, max */315 NULL, 0,316 #if 0317 /* w2k value. */318 MIN(16384,cli->max_xmit) /* data, length, max. */319 #else320 cli->max_xmit /* data, length, max. */321 #endif322 )) {323 SAFE_FREE(param);324 TALLOC_FREE(frame);325 break;326 }327 328 SAFE_FREE(param);329 330 if (!cli_receive_trans(cli, SMBtrans2,331 &rparam, ¶m_len,332 &rdata, &data_len) &&333 cli_is_dos_error(cli)) {334 /* We need to work around a Win95 bug - sometimes335 it gives ERRSRV/ERRerror temprarily */336 uint8 eclass;337 uint32 ecode;338 339 SAFE_FREE(rdata);340 SAFE_FREE(rparam);341 342 cli_dos_error(cli, &eclass, &ecode);343 344 /*345 * OS/2 might return "no more files",346 * which just tells us, that searchcount is zero347 * in this search.348 * Guenter Kukkukk <linux@kukkukk.com>349 */350 351 if (eclass == ERRDOS && ecode == ERRnofiles) {352 ff_searchcount = 0;353 cli_reset_error(cli);354 break;355 }356 357 if (eclass != ERRSRV || ecode != ERRerror)358 break;359 smb_msleep(100);360 continue;361 }362 363 if (cli_is_error(cli) || !rdata || !rparam) {364 SAFE_FREE(rdata);365 SAFE_FREE(rparam);366 break;367 }368 369 if (total_received == -1)370 total_received = 0;371 372 /* parse out some important return info */373 p = rparam;374 if (First) {375 ff_dir_handle = SVAL(p,0);376 ff_searchcount = SVAL(p,2);377 ff_eos = SVAL(p,4);378 } else {379 ff_searchcount = SVAL(p,0);380 ff_eos = SVAL(p,2);381 }382 383 if (ff_searchcount == 0) {384 SAFE_FREE(rdata);385 SAFE_FREE(rparam);386 break;387 }388 389 /* point to the data bytes */390 p = rdata;391 rdata_end = rdata + data_len;392 393 /* we might need the lastname for continuations */394 for (p2=p,i=0;i<ff_searchcount && p2 < rdata_end;i++) {395 if ((info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) &&396 (i == ff_searchcount-1)) {397 /* Last entry - fixup the last offset length. */398 SIVAL(p2,0,PTR_DIFF((rdata + data_len),p2));399 }400 p2 += interpret_long_filename(frame,401 cli,402 info_level,403 p2,404 rdata_end,405 &finfo,406 &resume_key,407 &last_name_raw);408 409 if (!finfo.name) {410 DEBUG(0,("cli_list_new: Error: unable to parse name from info level %d\n",411 info_level));412 ff_eos = 1;413 break;414 }415 if (!First && *mask && strcsequal(finfo.name, mask)) {416 DEBUG(0,("Error: Looping in FIND_NEXT as name %s has already been seen?\n",417 finfo.name));418 ff_eos = 1;419 break;420 }421 }422 423 SAFE_FREE(mask);424 if (ff_searchcount > 0 && ff_eos == 0 && finfo.name) {425 mask = SMB_STRDUP(finfo.name);426 } else {427 mask = SMB_STRDUP("");428 }429 if (!mask) {430 SAFE_FREE(rdata);431 SAFE_FREE(rparam);432 break;433 }434 435 /* grab the data for later use */436 /* and add them to the dirlist pool */437 dirlist = (char *)SMB_REALLOC(dirlist,dirlist_len + data_len);438 439 if (!dirlist) {440 DEBUG(0,("cli_list_new: Failed to expand dirlist\n"));441 SAFE_FREE(rdata);442 SAFE_FREE(rparam);443 break;444 }445 446 memcpy(dirlist+dirlist_len,p,data_len);447 dirlist_len += data_len;448 449 total_received += ff_searchcount;450 451 SAFE_FREE(rdata);452 SAFE_FREE(rparam);453 454 DEBUG(3,("received %d entries (eos=%d)\n",455 ff_searchcount,ff_eos));456 457 if (ff_searchcount > 0)458 loop_count = 0;459 460 First = False;461 }462 463 /* see if the server disconnected or the connection otherwise failed */464 if (cli_is_error(cli)) {465 total_received = -1;466 } else {467 /* no connection problem. let user function add each entry */468 rdata_end = dirlist + dirlist_len;469 for (p=dirlist,i=0;i<total_received;i++) {470 p += interpret_long_filename(frame,471 cli,472 info_level,473 p,474 rdata_end,475 &finfo,476 NULL,477 NULL);478 if (!finfo.name) {479 DEBUG(0,("cli_list_new: unable to parse name from info level %d\n",480 info_level));481 break;482 }483 fn(cli->dfs_mountpoint, &finfo, Mask, state);484 }485 }486 487 /* free up the dirlist buffer and last name raw blob */488 SAFE_FREE(dirlist);489 data_blob_free(&last_name_raw);490 SAFE_FREE(mask);491 TALLOC_FREE(frame);492 return(total_received);493 }494 495 /****************************************************************************496 234 Interpret a short filename structure. 497 235 The length of the structure is returned. … … 501 239 struct cli_state *cli, 502 240 char *p, 503 file_info *finfo)241 struct file_info *finfo) 504 242 { 505 243 size_t ret; 506 244 ZERO_STRUCTP(finfo); 507 245 508 finfo->cli = cli;509 246 finfo->mode = CVAL(p,21); 510 247 511 248 /* this date is converted to GMT by make_unix_date */ 512 finfo->ctime_ts.tv_sec = cli_make_unix_date(cli, p+22);249 finfo->ctime_ts.tv_sec = make_unix_date(p+22, cli->serverzone); 513 250 finfo->ctime_ts.tv_nsec = 0; 514 251 finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec; … … 517 254 ret = clistr_pull_talloc(ctx, 518 255 cli->inbuf, 256 SVAL(cli->inbuf, smb_flg2), 519 257 &finfo->name, 520 258 p+30, … … 531 269 } 532 270 return true; 533 return(DIR_STRUCT_SIZE); 534 } 535 536 /**************************************************************************** 537 Do a directory listing, calling fn on each file found. 538 this uses the old SMBsearch interface. It is needed for testing Samba, 539 but should otherwise not be used. 540 ****************************************************************************/ 541 542 int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute, 543 void (*fn)(const char *, file_info *, const char *, void *), void *state) 544 { 271 } 272 273 struct cli_list_old_state { 274 struct tevent_context *ev; 275 struct cli_state *cli; 276 uint16_t vwv[2]; 277 char *mask; 278 int num_asked; 279 uint16_t attribute; 280 uint8_t search_status[23]; 281 bool first; 282 bool done; 283 uint8_t *dirlist; 284 }; 285 286 static void cli_list_old_done(struct tevent_req *subreq); 287 288 static struct tevent_req *cli_list_old_send(TALLOC_CTX *mem_ctx, 289 struct tevent_context *ev, 290 struct cli_state *cli, 291 const char *mask, 292 uint16_t attribute) 293 { 294 struct tevent_req *req, *subreq; 295 struct cli_list_old_state *state; 296 uint8_t *bytes; 297 static const uint16_t zero = 0; 298 299 req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state); 300 if (req == NULL) { 301 return NULL; 302 } 303 state->ev = ev; 304 state->cli = cli; 305 state->attribute = attribute; 306 state->first = true; 307 state->mask = talloc_strdup(state, mask); 308 if (tevent_req_nomem(state->mask, req)) { 309 return tevent_req_post(req, ev); 310 } 311 state->num_asked = (cli->max_xmit - 100) / DIR_STRUCT_SIZE; 312 313 SSVAL(state->vwv + 0, 0, state->num_asked); 314 SSVAL(state->vwv + 1, 0, state->attribute); 315 316 bytes = talloc_array(state, uint8_t, 1); 317 if (tevent_req_nomem(bytes, req)) { 318 return tevent_req_post(req, ev); 319 } 320 bytes[0] = 4; 321 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), mask, 322 strlen(mask)+1, NULL); 323 324 bytes = smb_bytes_push_bytes(bytes, 5, (uint8_t *)&zero, 2); 325 if (tevent_req_nomem(bytes, req)) { 326 return tevent_req_post(req, ev); 327 } 328 329 subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch, 330 0, 2, state->vwv, talloc_get_size(bytes), bytes); 331 if (tevent_req_nomem(subreq, req)) { 332 return tevent_req_post(req, ev); 333 } 334 tevent_req_set_callback(subreq, cli_list_old_done, req); 335 return req; 336 } 337 338 static void cli_list_old_done(struct tevent_req *subreq) 339 { 340 struct tevent_req *req = tevent_req_callback_data( 341 subreq, struct tevent_req); 342 struct cli_list_old_state *state = tevent_req_data( 343 req, struct cli_list_old_state); 344 NTSTATUS status; 345 uint8_t cmd; 346 uint8_t wct; 347 uint16_t *vwv; 348 uint32_t num_bytes; 349 uint8_t *bytes; 350 uint16_t received; 351 size_t dirlist_len; 352 uint8_t *tmp; 353 354 status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes, 355 &bytes); 356 if (!NT_STATUS_IS_OK(status) 357 && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles)) 358 && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) { 359 TALLOC_FREE(subreq); 360 tevent_req_nterror(req, status); 361 return; 362 } 363 if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles)) 364 || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) { 365 received = 0; 366 } else { 367 if (wct < 1) { 368 TALLOC_FREE(subreq); 369 tevent_req_nterror( 370 req, NT_STATUS_INVALID_NETWORK_RESPONSE); 371 return; 372 } 373 received = SVAL(vwv + 0, 0); 374 } 375 376 if (received > 0) { 377 /* 378 * I don't think this can wrap. received is 379 * initialized from a 16-bit value. 380 */ 381 if (num_bytes < (received * DIR_STRUCT_SIZE + 3)) { 382 TALLOC_FREE(subreq); 383 tevent_req_nterror( 384 req, NT_STATUS_INVALID_NETWORK_RESPONSE); 385 return; 386 } 387 388 dirlist_len = talloc_get_size(state->dirlist); 389 390 tmp = TALLOC_REALLOC_ARRAY( 391 state, state->dirlist, uint8_t, 392 dirlist_len + received * DIR_STRUCT_SIZE); 393 if (tevent_req_nomem(tmp, req)) { 394 return; 395 } 396 state->dirlist = tmp; 397 memcpy(state->dirlist + dirlist_len, bytes + 3, 398 received * DIR_STRUCT_SIZE); 399 400 SSVAL(state->search_status, 0, 21); 401 memcpy(state->search_status + 2, 402 bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21); 403 cmd = SMBsearch; 404 } else { 405 if (state->first || state->done) { 406 tevent_req_done(req); 407 return; 408 } 409 state->done = true; 410 state->num_asked = 0; 411 cmd = SMBfclose; 412 } 413 TALLOC_FREE(subreq); 414 415 state->first = false; 416 417 SSVAL(state->vwv + 0, 0, state->num_asked); 418 SSVAL(state->vwv + 1, 0, state->attribute); 419 420 bytes = talloc_array(state, uint8_t, 1); 421 if (tevent_req_nomem(bytes, req)) { 422 return; 423 } 424 bytes[0] = 4; 425 bytes = smb_bytes_push_str(bytes, cli_ucs2(state->cli), "", 426 1, NULL); 427 bytes = smb_bytes_push_bytes(bytes, 5, state->search_status, 428 sizeof(state->search_status)); 429 if (tevent_req_nomem(bytes, req)) { 430 return; 431 } 432 subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0, 433 2, state->vwv, talloc_get_size(bytes), bytes); 434 if (tevent_req_nomem(subreq, req)) { 435 return; 436 } 437 tevent_req_set_callback(subreq, cli_list_old_done, req); 438 } 439 440 static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, 441 struct file_info **pfinfo) 442 { 443 struct cli_list_old_state *state = tevent_req_data( 444 req, struct cli_list_old_state); 445 NTSTATUS status; 446 size_t i, num_received; 447 struct file_info *finfo; 448 449 if (tevent_req_is_nterror(req, &status)) { 450 return status; 451 } 452 453 num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE; 454 455 finfo = TALLOC_ARRAY(mem_ctx, struct file_info, num_received); 456 if (finfo == NULL) { 457 return NT_STATUS_NO_MEMORY; 458 } 459 460 for (i=0; i<num_received; i++) { 461 if (!interpret_short_filename( 462 finfo, state->cli, 463 (char *)state->dirlist + i * DIR_STRUCT_SIZE, 464 &finfo[i])) { 465 TALLOC_FREE(finfo); 466 return NT_STATUS_NO_MEMORY; 467 } 468 } 469 *pfinfo = finfo; 470 return NT_STATUS_OK; 471 } 472 473 NTSTATUS cli_list_old(struct cli_state *cli, const char *mask, 474 uint16 attribute, 475 NTSTATUS (*fn)(const char *, struct file_info *, 476 const char *, void *), void *state) 477 { 478 TALLOC_CTX *frame = talloc_stackframe(); 479 struct event_context *ev; 480 struct tevent_req *req; 481 NTSTATUS status = NT_STATUS_NO_MEMORY; 482 struct file_info *finfo; 483 size_t i, num_finfo; 484 485 if (cli_has_async_calls(cli)) { 486 /* 487 * Can't use sync call while an async call is in flight 488 */ 489 status = NT_STATUS_INVALID_PARAMETER; 490 goto fail; 491 } 492 ev = event_context_init(frame); 493 if (ev == NULL) { 494 goto fail; 495 } 496 req = cli_list_old_send(frame, ev, cli, mask, attribute); 497 if (req == NULL) { 498 goto fail; 499 } 500 if (!tevent_req_poll(req, ev)) { 501 status = map_nt_error_from_unix(errno); 502 goto fail; 503 } 504 status = cli_list_old_recv(req, frame, &finfo); 505 if (!NT_STATUS_IS_OK(status)) { 506 goto fail; 507 } 508 num_finfo = talloc_array_length(finfo); 509 for (i=0; i<num_finfo; i++) { 510 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state); 511 if (!NT_STATUS_IS_OK(status)) { 512 goto fail; 513 } 514 } 515 fail: 516 TALLOC_FREE(frame); 517 if (!NT_STATUS_IS_OK(status)) { 518 cli_set_error(cli, status); 519 } 520 return status; 521 } 522 523 struct cli_list_trans_state { 524 struct tevent_context *ev; 525 struct cli_state *cli; 526 char *mask; 527 uint16_t attribute; 528 uint16_t info_level; 529 530 int loop_count; 531 int total_received; 532 uint16_t max_matches; 533 bool first; 534 535 int ff_eos; 536 int ff_dir_handle; 537 538 uint16_t setup[1]; 539 uint8_t *param; 540 541 struct file_info *finfo; 542 }; 543 544 static void cli_list_trans_done(struct tevent_req *subreq); 545 546 static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx, 547 struct tevent_context *ev, 548 struct cli_state *cli, 549 const char *mask, 550 uint16_t attribute, 551 uint16_t info_level) 552 { 553 struct tevent_req *req, *subreq; 554 struct cli_list_trans_state *state; 555 size_t nlen, param_len; 545 556 char *p; 546 int received = 0; 547 bool first = True; 548 char status[21]; 549 int num_asked = (cli->max_xmit - 100)/DIR_STRUCT_SIZE; 550 int num_received = 0; 557 558 req = tevent_req_create(mem_ctx, &state, 559 struct cli_list_trans_state); 560 if (req == NULL) { 561 return NULL; 562 } 563 state->ev = ev; 564 state->cli = cli; 565 state->mask = talloc_strdup(state, mask); 566 if (tevent_req_nomem(state->mask, req)) { 567 return tevent_req_post(req, ev); 568 } 569 state->attribute = attribute; 570 state->info_level = info_level; 571 state->loop_count = 0; 572 state->first = true; 573 574 state->max_matches = 1366; /* Match W2k */ 575 576 SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST); 577 578 nlen = 2*(strlen(mask)+1); 579 state->param = TALLOC_ARRAY(state, uint8_t, 12+nlen+2); 580 if (tevent_req_nomem(state->param, req)) { 581 return tevent_req_post(req, ev); 582 } 583 584 SSVAL(state->param, 0, state->attribute); 585 SSVAL(state->param, 2, state->max_matches); 586 SSVAL(state->param, 4, 587 FLAG_TRANS2_FIND_REQUIRE_RESUME 588 |FLAG_TRANS2_FIND_CLOSE_IF_END); 589 SSVAL(state->param, 6, state->info_level); 590 SIVAL(state->param, 8, 0); 591 592 p = ((char *)state->param)+12; 593 p += clistr_push(state->cli, p, state->mask, nlen, 594 STR_TERMINATE); 595 param_len = PTR_DIFF(p, state->param); 596 597 subreq = cli_trans_send(state, state->ev, state->cli, 598 SMBtrans2, NULL, -1, 0, 0, 599 state->setup, 1, 0, 600 state->param, param_len, 10, 601 NULL, 0, cli->max_xmit); 602 if (tevent_req_nomem(subreq, req)) { 603 return tevent_req_post(req, ev); 604 } 605 tevent_req_set_callback(subreq, cli_list_trans_done, req); 606 return req; 607 } 608 609 static void cli_list_trans_done(struct tevent_req *subreq) 610 { 611 struct tevent_req *req = tevent_req_callback_data( 612 subreq, struct tevent_req); 613 struct cli_list_trans_state *state = tevent_req_data( 614 req, struct cli_list_trans_state); 615 NTSTATUS status; 616 uint8_t *param; 617 uint32_t num_param; 618 uint8_t *data; 619 char *data_end; 620 uint32_t num_data; 621 uint32_t min_param; 622 struct file_info *tmp; 623 size_t old_num_finfo; 624 uint16_t recv_flags2; 625 int ff_searchcount; 626 bool ff_eos; 627 char *p, *p2; 628 uint32_t resume_key = 0; 551 629 int i; 552 char *dirlist = NULL; 553 char *mask = NULL; 554 TALLOC_CTX *frame = NULL; 555 556 ZERO_ARRAY(status); 557 558 mask = SMB_STRDUP(Mask); 559 if (!mask) { 560 return -1; 561 } 562 563 while (1) { 564 memset(cli->outbuf,'\0',smb_size); 565 memset(cli->inbuf,'\0',smb_size); 566 567 cli_set_message(cli->outbuf,2,0,True); 568 569 SCVAL(cli->outbuf,smb_com,SMBsearch); 570 571 SSVAL(cli->outbuf,smb_tid,cli->cnum); 572 cli_setup_packet(cli); 573 574 SSVAL(cli->outbuf,smb_vwv0,num_asked); 575 SSVAL(cli->outbuf,smb_vwv1,attribute); 576 577 p = smb_buf(cli->outbuf); 578 *p++ = 4; 579 580 p += clistr_push(cli, p, first?mask:"", 581 cli->bufsize - PTR_DIFF(p,cli->outbuf), 582 STR_TERMINATE); 583 *p++ = 5; 584 if (first) { 585 SSVAL(p,0,0); 586 p += 2; 587 } else { 588 SSVAL(p,0,21); 589 p += 2; 590 memcpy(p,status,21); 591 p += 21; 592 } 593 594 cli_setup_bcc(cli, p); 595 cli_send_smb(cli); 596 if (!cli_receive_smb(cli)) break; 597 598 received = SVAL(cli->inbuf,smb_vwv0); 599 if (received <= 0) break; 600 601 /* Ensure we received enough data. */ 602 if ((cli->inbuf+4+smb_len(cli->inbuf) - (smb_buf(cli->inbuf)+3)) < 603 received*DIR_STRUCT_SIZE) { 630 DATA_BLOB last_name_raw; 631 struct file_info *finfo = NULL; 632 size_t nlen, param_len; 633 634 min_param = (state->first ? 6 : 4); 635 636 status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2, 637 NULL, 0, NULL, 638 ¶m, min_param, &num_param, 639 &data, 0, &num_data); 640 TALLOC_FREE(subreq); 641 if (!NT_STATUS_IS_OK(status)) { 642 /* 643 * TODO: retry, OS/2 nofiles 644 */ 645 tevent_req_nterror(req, status); 646 return; 647 } 648 649 if (state->first) { 650 state->ff_dir_handle = SVAL(param, 0); 651 ff_searchcount = SVAL(param, 2); 652 ff_eos = SVAL(param, 4) != 0; 653 } else { 654 ff_searchcount = SVAL(param, 0); 655 ff_eos = SVAL(param, 2) != 0; 656 } 657 658 old_num_finfo = talloc_array_length(state->finfo); 659 660 tmp = TALLOC_REALLOC_ARRAY(state, state->finfo, struct file_info, 661 old_num_finfo + ff_searchcount); 662 if (tevent_req_nomem(tmp, req)) { 663 return; 664 } 665 state->finfo = tmp; 666 667 p2 = p = (char *)data; 668 data_end = (char *)data + num_data; 669 last_name_raw = data_blob_null; 670 671 for (i=0; i<ff_searchcount; i++) { 672 if (p2 >= data_end) { 673 ff_eos = true; 604 674 break; 605 675 } 606 607 first = False; 608 609 dirlist = (char *)SMB_REALLOC( 610 dirlist,(num_received + received)*DIR_STRUCT_SIZE); 611 if (!dirlist) { 612 DEBUG(0,("cli_list_old: failed to expand dirlist")); 613 SAFE_FREE(mask); 614 return 0; 615 } 616 617 p = smb_buf(cli->inbuf) + 3; 618 619 memcpy(dirlist+num_received*DIR_STRUCT_SIZE, 620 p,received*DIR_STRUCT_SIZE); 621 622 memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21); 623 624 num_received += received; 625 626 if (cli_is_error(cli)) break; 627 } 628 629 if (!first) { 630 memset(cli->outbuf,'\0',smb_size); 631 memset(cli->inbuf,'\0',smb_size); 632 633 cli_set_message(cli->outbuf,2,0,True); 634 SCVAL(cli->outbuf,smb_com,SMBfclose); 635 SSVAL(cli->outbuf,smb_tid,cli->cnum); 636 cli_setup_packet(cli); 637 638 SSVAL(cli->outbuf, smb_vwv0, 0); /* find count? */ 639 SSVAL(cli->outbuf, smb_vwv1, attribute); 640 641 p = smb_buf(cli->outbuf); 642 *p++ = 4; 643 fstrcpy(p, ""); 644 p += strlen(p) + 1; 645 *p++ = 5; 646 SSVAL(p, 0, 21); 647 p += 2; 648 memcpy(p,status,21); 649 p += 21; 650 651 cli_setup_bcc(cli, p); 652 cli_send_smb(cli); 653 if (!cli_receive_smb(cli)) { 654 DEBUG(0,("Error closing search: %s\n",cli_errstr(cli))); 655 } 656 } 657 658 frame = talloc_stackframe(); 659 for (p=dirlist,i=0;i<num_received;i++) { 660 file_info finfo; 661 if (!interpret_short_filename(frame, cli, p, &finfo)) { 676 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) 677 && (i == ff_searchcount-1)) { 678 /* Last entry - fixup the last offset length. */ 679 SIVAL(p2, 0, PTR_DIFF((data + num_data), p2)); 680 } 681 682 data_blob_free(&last_name_raw); 683 684 finfo = &state->finfo[old_num_finfo + i]; 685 686 p2 += interpret_long_filename( 687 state->finfo, /* Stick fname to the array as such */ 688 state->cli, state->info_level, 689 (char *)data, recv_flags2, p2, 690 data_end, finfo, &resume_key, &last_name_raw); 691 692 if (finfo->name == NULL) { 693 DEBUG(1, ("cli_list: Error: unable to parse name from " 694 "info level %d\n", state->info_level)); 695 ff_eos = true; 662 696 break; 663 697 } 664 p += DIR_STRUCT_SIZE; 665 fn("\\", &finfo, Mask, state); 666 } 698 if (!state->first && (state->mask[0] != '\0') && 699 strcsequal(finfo->name, state->mask)) { 700 DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has " 701 "already been seen?\n", finfo->name)); 702 ff_eos = true; 703 break; 704 } 705 } 706 707 if (ff_searchcount == 0) { 708 ff_eos = true; 709 } 710 711 TALLOC_FREE(param); 712 TALLOC_FREE(data); 713 714 /* 715 * Shrink state->finfo to the real length we received 716 */ 717 tmp = TALLOC_REALLOC_ARRAY(state, state->finfo, struct file_info, 718 old_num_finfo + i); 719 if (tevent_req_nomem(tmp, req)) { 720 return; 721 } 722 state->finfo = tmp; 723 724 state->first = false; 725 726 if (ff_eos) { 727 data_blob_free(&last_name_raw); 728 tevent_req_done(req); 729 return; 730 } 731 732 TALLOC_FREE(state->mask); 733 state->mask = talloc_strdup(state, finfo->name); 734 if (tevent_req_nomem(state->mask, req)) { 735 return; 736 } 737 738 SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT); 739 740 nlen = 2*(strlen(state->mask) + 1); 741 742 param = TALLOC_REALLOC_ARRAY(state, state->param, uint8_t, 743 12 + nlen + last_name_raw.length + 2); 744 if (tevent_req_nomem(param, req)) { 745 return; 746 } 747 state->param = param; 748 749 SSVAL(param, 0, state->ff_dir_handle); 750 SSVAL(param, 2, state->max_matches); /* max count */ 751 SSVAL(param, 4, state->info_level); 752 /* 753 * For W2K servers serving out FAT filesystems we *must* set 754 * the resume key. If it's not FAT then it's returned as zero. 755 */ 756 SIVAL(param, 6, resume_key); /* ff_resume_key */ 757 /* 758 * NB. *DON'T* use continue here. If you do it seems that W2K 759 * and bretheren can miss filenames. Use last filename 760 * continue instead. JRA 761 */ 762 SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME 763 |FLAG_TRANS2_FIND_CLOSE_IF_END)); 764 p = ((char *)param)+12; 765 if (last_name_raw.length) { 766 memcpy(p, last_name_raw.data, last_name_raw.length); 767 p += last_name_raw.length; 768 data_blob_free(&last_name_raw); 769 } else { 770 p += clistr_push(state->cli, p, state->mask, nlen, 771 STR_TERMINATE); 772 } 773 774 param_len = PTR_DIFF(p, param); 775 776 subreq = cli_trans_send(state, state->ev, state->cli, 777 SMBtrans2, NULL, -1, 0, 0, 778 state->setup, 1, 0, 779 state->param, param_len, 10, 780 NULL, 0, state->cli->max_xmit); 781 if (tevent_req_nomem(subreq, req)) { 782 return; 783 } 784 tevent_req_set_callback(subreq, cli_list_trans_done, req); 785 } 786 787 static NTSTATUS cli_list_trans_recv(struct tevent_req *req, 788 TALLOC_CTX *mem_ctx, 789 struct file_info **finfo) 790 { 791 struct cli_list_trans_state *state = tevent_req_data( 792 req, struct cli_list_trans_state); 793 NTSTATUS status; 794 795 if (tevent_req_is_nterror(req, &status)) { 796 return status; 797 } 798 *finfo = talloc_move(mem_ctx, &state->finfo); 799 return NT_STATUS_OK; 800 } 801 802 NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask, 803 uint16_t attribute, int info_level, 804 NTSTATUS (*fn)(const char *mnt, struct file_info *finfo, 805 const char *mask, void *private_data), 806 void *private_data) 807 { 808 TALLOC_CTX *frame = talloc_stackframe(); 809 struct event_context *ev; 810 struct tevent_req *req; 811 int i, num_finfo; 812 struct file_info *finfo = NULL; 813 NTSTATUS status = NT_STATUS_NO_MEMORY; 814 815 if (cli_has_async_calls(cli)) { 816 /* 817 * Can't use sync call while an async call is in flight 818 */ 819 status = NT_STATUS_INVALID_PARAMETER; 820 goto fail; 821 } 822 ev = event_context_init(frame); 823 if (ev == NULL) { 824 goto fail; 825 } 826 req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level); 827 if (req == NULL) { 828 goto fail; 829 } 830 if (!tevent_req_poll_ntstatus(req, ev, &status)) { 831 goto fail; 832 } 833 status = cli_list_trans_recv(req, frame, &finfo); 834 if (!NT_STATUS_IS_OK(status)) { 835 goto fail; 836 } 837 num_finfo = talloc_array_length(finfo); 838 for (i=0; i<num_finfo; i++) { 839 status = fn(cli->dfs_mountpoint, &finfo[i], mask, private_data); 840 if (!NT_STATUS_IS_OK(status)) { 841 goto fail; 842 } 843 } 844 fail: 667 845 TALLOC_FREE(frame); 668 669 SAFE_FREE(mask); 670 SAFE_FREE(dirlist); 671 return(num_received); 672 } 673 674 /**************************************************************************** 675 Do a directory listing, calling fn on each file found. 676 This auto-switches between old and new style. 677 ****************************************************************************/ 678 679 int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute, 680 void (*fn)(const char *, file_info *, const char *, void *), void *state) 681 { 682 if (cli->protocol <= PROTOCOL_LANMAN1) 683 return cli_list_old(cli, Mask, attribute, fn, state); 684 return cli_list_new(cli, Mask, attribute, fn, state); 685 } 846 if (!NT_STATUS_IS_OK(status)) { 847 cli_set_error(cli, status); 848 } 849 return status; 850 } 851 852 struct cli_list_state { 853 NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx, 854 struct file_info **finfo); 855 struct file_info *finfo; 856 }; 857 858 static void cli_list_done(struct tevent_req *subreq); 859 860 struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx, 861 struct tevent_context *ev, 862 struct cli_state *cli, 863 const char *mask, 864 uint16_t attribute, 865 uint16_t info_level) 866 { 867 struct tevent_req *req, *subreq; 868 struct cli_list_state *state; 869 870 req = tevent_req_create(mem_ctx, &state, struct cli_list_state); 871 if (req == NULL) { 872 return NULL; 873 } 874 875 if (cli->protocol <= PROTOCOL_LANMAN1) { 876 subreq = cli_list_old_send(state, ev, cli, mask, attribute); 877 state->recv_fn = cli_list_old_recv; 878 } else { 879 subreq = cli_list_trans_send(state, ev, cli, mask, attribute, 880 info_level); 881 state->recv_fn = cli_list_trans_recv; 882 } 883 if (tevent_req_nomem(subreq, req)) { 884 return tevent_req_post(req, ev); 885 } 886 tevent_req_set_callback(subreq, cli_list_done, req); 887 return req; 888 } 889 890 static void cli_list_done(struct tevent_req *subreq) 891 { 892 struct tevent_req *req = tevent_req_callback_data( 893 subreq, struct tevent_req); 894 struct cli_list_state *state = tevent_req_data( 895 req, struct cli_list_state); 896 NTSTATUS status; 897 898 status = state->recv_fn(subreq, state, &state->finfo); 899 TALLOC_FREE(subreq); 900 if (!NT_STATUS_IS_OK(status)) { 901 tevent_req_nterror(req, status); 902 return; 903 } 904 tevent_req_done(req); 905 } 906 907 NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, 908 struct file_info **finfo, size_t *num_finfo) 909 { 910 struct cli_list_state *state = tevent_req_data( 911 req, struct cli_list_state); 912 NTSTATUS status; 913 914 if (tevent_req_is_nterror(req, &status)) { 915 return status; 916 } 917 *num_finfo = talloc_array_length(state->finfo); 918 *finfo = talloc_move(mem_ctx, &state->finfo); 919 return NT_STATUS_OK; 920 } 921 922 NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute, 923 NTSTATUS (*fn)(const char *, struct file_info *, const char *, 924 void *), void *state) 925 { 926 TALLOC_CTX *frame = talloc_stackframe(); 927 struct event_context *ev; 928 struct tevent_req *req; 929 NTSTATUS status = NT_STATUS_NO_MEMORY; 930 struct file_info *finfo; 931 size_t i, num_finfo; 932 uint16_t info_level; 933 934 if (cli_has_async_calls(cli)) { 935 /* 936 * Can't use sync call while an async call is in flight 937 */ 938 status = NT_STATUS_INVALID_PARAMETER; 939 goto fail; 940 } 941 ev = event_context_init(frame); 942 if (ev == NULL) { 943 goto fail; 944 } 945 946 info_level = (cli->capabilities & CAP_NT_SMBS) 947 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD; 948 949 req = cli_list_send(frame, ev, cli, mask, attribute, info_level); 950 if (req == NULL) { 951 goto fail; 952 } 953 if (!tevent_req_poll(req, ev)) { 954 status = map_nt_error_from_unix(errno); 955 goto fail; 956 } 957 958 status = cli_list_recv(req, frame, &finfo, &num_finfo); 959 if (!NT_STATUS_IS_OK(status)) { 960 goto fail; 961 } 962 963 for (i=0; i<num_finfo; i++) { 964 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state); 965 if (!NT_STATUS_IS_OK(status)) { 966 goto fail; 967 } 968 } 969 fail: 970 TALLOC_FREE(frame); 971 if (!NT_STATUS_IS_OK(status)) { 972 cli_set_error(cli, status); 973 } 974 return status; 975 }
Note:
See TracChangeset
for help on using the changeset viewer.