00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "includes.h"
00022
00023 extern file_info def_finfo;
00024
00025
00026
00027
00028
00029
00030
00031
00032 static size_t interpret_long_filename(struct cli_state *cli, int level,char *p,file_info *finfo,
00033 uint32 *p_resume_key, DATA_BLOB *p_last_name_raw, uint32 *p_last_name_raw_len)
00034 {
00035 file_info finfo2;
00036 int len;
00037 char *base = p;
00038
00039 if (!finfo) {
00040 finfo = &finfo2;
00041 }
00042
00043 if (p_resume_key) {
00044 *p_resume_key = 0;
00045 }
00046 memcpy(finfo,&def_finfo,sizeof(*finfo));
00047 finfo->cli = cli;
00048
00049 switch (level) {
00050 case 1:
00051
00052
00053 finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4));
00054 finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8));
00055 finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12));
00056 finfo->size = IVAL(p,16);
00057 finfo->mode = CVAL(p,24);
00058 len = CVAL(p, 26);
00059 p += 27;
00060 p += clistr_align_in(cli, p, 0);
00061
00062
00063
00064
00065 p += clistr_pull(cli, finfo->name, p,
00066 sizeof(finfo->name),
00067 len+2,
00068 STR_TERMINATE);
00069 return PTR_DIFF(p, base);
00070
00071 case 2:
00072
00073
00074 finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4));
00075 finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8));
00076 finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12));
00077 finfo->size = IVAL(p,16);
00078 finfo->mode = CVAL(p,24);
00079 len = CVAL(p, 30);
00080 p += 31;
00081
00082 p += clistr_pull(cli, finfo->name, p,
00083 sizeof(finfo->name),
00084 len,
00085 STR_NOALIGN);
00086 return PTR_DIFF(p, base) + 1;
00087
00088 case 260:
00089 {
00090 size_t namelen, slen;
00091 p += 4;
00092
00093 if (p_resume_key) {
00094 *p_resume_key = IVAL(p,0);
00095 }
00096 p += 4;
00097
00098
00099 p += 8;
00100 finfo->atime_ts = interpret_long_date(p);
00101 p += 8;
00102 finfo->mtime_ts = interpret_long_date(p);
00103 p += 8;
00104 finfo->ctime_ts = interpret_long_date(p);
00105 p += 8;
00106 finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
00107 p += 8;
00108 p += 8;
00109 finfo->mode = CVAL(p,0);
00110 p += 4;
00111 namelen = IVAL(p,0);
00112 p += 4;
00113 p += 4;
00114 slen = SVAL(p, 0);
00115 p += 2;
00116 {
00117
00118 int flags = 0;
00119 if (p[1] == 0 && namelen > 1) flags |= STR_UNICODE;
00120 clistr_pull(cli, finfo->short_name, p,
00121 sizeof(finfo->short_name),
00122 slen, flags);
00123 }
00124 p += 24;
00125 clistr_pull(cli, finfo->name, p,
00126 sizeof(finfo->name),
00127 namelen, 0);
00128
00129
00130
00131
00132
00133
00134 if (p_last_name_raw && p_last_name_raw_len) {
00135 if (namelen + 2 > p_last_name_raw->length) {
00136 memset(p_last_name_raw->data, '\0', sizeof(p_last_name_raw->length));
00137 *p_last_name_raw_len = 0;
00138 } else {
00139 memcpy(p_last_name_raw->data, p, namelen);
00140 SSVAL(p_last_name_raw->data, namelen, 0);
00141 *p_last_name_raw_len = namelen + 2;
00142 }
00143 }
00144 return (size_t)IVAL(base, 0);
00145 }
00146 }
00147
00148 DEBUG(1,("Unknown long filename format %d\n",level));
00149 return (size_t)IVAL(base,0);
00150 }
00151
00152
00153
00154
00155
00156 int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
00157 void (*fn)(const char *, file_info *, const char *, void *), void *state)
00158 {
00159 #if 1
00160 int max_matches = 1366;
00161 #else
00162 int max_matches = 512;
00163 #endif
00164 int info_level;
00165 char *p, *p2;
00166 pstring mask;
00167 file_info finfo;
00168 int i;
00169 char *dirlist = NULL;
00170 int dirlist_len = 0;
00171 int total_received = -1;
00172 BOOL First = True;
00173 int ff_searchcount=0;
00174 int ff_eos=0;
00175 int ff_dir_handle=0;
00176 int loop_count = 0;
00177 char *rparam=NULL, *rdata=NULL;
00178 unsigned int param_len, data_len;
00179 uint16 setup;
00180 pstring param;
00181 const char *mnt;
00182 uint32 resume_key = 0;
00183 uint32 last_name_raw_len = 0;
00184 DATA_BLOB last_name_raw = data_blob(NULL, 2*sizeof(pstring));
00185
00186
00187 info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
00188
00189 pstrcpy(mask,Mask);
00190
00191 while (ff_eos == 0) {
00192 loop_count++;
00193 if (loop_count > 200) {
00194 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
00195 break;
00196 }
00197
00198 if (First) {
00199 setup = TRANSACT2_FINDFIRST;
00200 SSVAL(param,0,attribute);
00201 SSVAL(param,2,max_matches);
00202 SSVAL(param,4,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END));
00203 SSVAL(param,6,info_level);
00204 SIVAL(param,8,0);
00205 p = param+12;
00206 p += clistr_push(cli, param+12, mask, sizeof(param)-12,
00207 STR_TERMINATE);
00208 } else {
00209 setup = TRANSACT2_FINDNEXT;
00210 SSVAL(param,0,ff_dir_handle);
00211 SSVAL(param,2,max_matches);
00212 SSVAL(param,4,info_level);
00213
00214
00215 SIVAL(param,6,resume_key);
00216
00217
00218 SSVAL(param,10,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END));
00219 p = param+12;
00220 if (last_name_raw_len && (last_name_raw_len < (sizeof(param)-12))) {
00221 memcpy(p, last_name_raw.data, last_name_raw_len);
00222 p += last_name_raw_len;
00223 } else {
00224 p += clistr_push(cli, param+12, mask, sizeof(param)-12, STR_TERMINATE);
00225 }
00226 }
00227
00228 param_len = PTR_DIFF(p, param);
00229
00230 if (!cli_send_trans(cli, SMBtrans2,
00231 NULL,
00232 -1, 0,
00233 &setup, 1, 0,
00234 param, param_len, 10,
00235 NULL, 0,
00236 #if 0
00237
00238 MIN(16384,cli->max_xmit)
00239 #else
00240 cli->max_xmit
00241 #endif
00242 )) {
00243 break;
00244 }
00245
00246 if (!cli_receive_trans(cli, SMBtrans2,
00247 &rparam, ¶m_len,
00248 &rdata, &data_len) &&
00249 cli_is_dos_error(cli)) {
00250
00251
00252 uint8 eclass;
00253 uint32 ecode;
00254
00255 SAFE_FREE(rdata);
00256 SAFE_FREE(rparam);
00257
00258 cli_dos_error(cli, &eclass, &ecode);
00259
00260
00261
00262
00263
00264
00265
00266
00267 if (eclass == ERRDOS && ecode == ERRnofiles) {
00268 ff_searchcount = 0;
00269 cli_reset_error(cli);
00270 break;
00271 }
00272
00273 if (eclass != ERRSRV || ecode != ERRerror)
00274 break;
00275 smb_msleep(100);
00276 continue;
00277 }
00278
00279 if (cli_is_error(cli) || !rdata || !rparam) {
00280 SAFE_FREE(rdata);
00281 SAFE_FREE(rparam);
00282 break;
00283 }
00284
00285 if (total_received == -1)
00286 total_received = 0;
00287
00288
00289 p = rparam;
00290 if (First) {
00291 ff_dir_handle = SVAL(p,0);
00292 ff_searchcount = SVAL(p,2);
00293 ff_eos = SVAL(p,4);
00294 } else {
00295 ff_searchcount = SVAL(p,0);
00296 ff_eos = SVAL(p,2);
00297 }
00298
00299 if (ff_searchcount == 0) {
00300 SAFE_FREE(rdata);
00301 SAFE_FREE(rparam);
00302 break;
00303 }
00304
00305
00306 p = rdata;
00307
00308
00309 for (p2=p,i=0;i<ff_searchcount;i++) {
00310 if ((info_level == 260) && (i == ff_searchcount-1)) {
00311
00312 SIVAL(p2,0,PTR_DIFF((rdata + data_len),p2));
00313 }
00314 p2 += interpret_long_filename(cli,info_level,p2,&finfo,
00315 &resume_key,&last_name_raw,&last_name_raw_len);
00316
00317 if (!First && *mask && strcsequal(finfo.name, mask)) {
00318 DEBUG(0,("Error: Looping in FIND_NEXT as name %s has already been seen?\n",
00319 finfo.name));
00320 ff_eos = 1;
00321 break;
00322 }
00323 }
00324
00325 if (ff_searchcount > 0) {
00326 pstrcpy(mask, finfo.name);
00327 } else {
00328 pstrcpy(mask,"");
00329 }
00330
00331
00332
00333 dirlist = (char *)SMB_REALLOC(dirlist,dirlist_len + data_len);
00334
00335 if (!dirlist) {
00336 DEBUG(0,("cli_list_new: Failed to expand dirlist\n"));
00337 SAFE_FREE(rdata);
00338 SAFE_FREE(rparam);
00339 break;
00340 }
00341
00342 memcpy(dirlist+dirlist_len,p,data_len);
00343 dirlist_len += data_len;
00344
00345 total_received += ff_searchcount;
00346
00347 SAFE_FREE(rdata);
00348 SAFE_FREE(rparam);
00349
00350 DEBUG(3,("received %d entries (eos=%d)\n",
00351 ff_searchcount,ff_eos));
00352
00353 if (ff_searchcount > 0)
00354 loop_count = 0;
00355
00356 First = False;
00357 }
00358
00359 mnt = cli_cm_get_mntpoint( cli );
00360
00361
00362 if (cli_is_error(cli)) {
00363 total_received = -1;
00364 } else {
00365
00366 for (p=dirlist,i=0;i<total_received;i++) {
00367 p += interpret_long_filename(cli, info_level, p,
00368 &finfo,NULL,NULL,NULL);
00369 fn( mnt,&finfo, Mask, state );
00370 }
00371 }
00372
00373
00374 SAFE_FREE(dirlist);
00375 data_blob_free(&last_name_raw);
00376 return(total_received);
00377 }
00378
00379
00380
00381
00382
00383
00384 static int interpret_short_filename(struct cli_state *cli, char *p,file_info *finfo)
00385 {
00386
00387 *finfo = def_finfo;
00388
00389 finfo->cli = cli;
00390 finfo->mode = CVAL(p,21);
00391
00392
00393 finfo->ctime_ts.tv_sec = cli_make_unix_date(cli, p+22);
00394 finfo->ctime_ts.tv_nsec = 0;
00395 finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
00396 finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
00397 finfo->size = IVAL(p,26);
00398 clistr_pull(cli, finfo->name, p+30, sizeof(finfo->name), 12, STR_ASCII);
00399 if (strcmp(finfo->name, "..") && strcmp(finfo->name, ".")) {
00400 strncpy(finfo->short_name,finfo->name, sizeof(finfo->short_name)-1);
00401 finfo->short_name[sizeof(finfo->short_name)-1] = '\0';
00402 }
00403
00404 return(DIR_STRUCT_SIZE);
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414 int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute,
00415 void (*fn)(const char *, file_info *, const char *, void *), void *state)
00416 {
00417 char *p;
00418 int received = 0;
00419 BOOL first = True;
00420 char status[21];
00421 int num_asked = (cli->max_xmit - 100)/DIR_STRUCT_SIZE;
00422 int num_received = 0;
00423 int i;
00424 char *dirlist = NULL;
00425 pstring mask;
00426
00427 ZERO_ARRAY(status);
00428
00429 pstrcpy(mask,Mask);
00430
00431 while (1) {
00432 memset(cli->outbuf,'\0',smb_size);
00433 memset(cli->inbuf,'\0',smb_size);
00434
00435 set_message(cli->outbuf,2,0,True);
00436
00437 SCVAL(cli->outbuf,smb_com,SMBsearch);
00438
00439 SSVAL(cli->outbuf,smb_tid,cli->cnum);
00440 cli_setup_packet(cli);
00441
00442 SSVAL(cli->outbuf,smb_vwv0,num_asked);
00443 SSVAL(cli->outbuf,smb_vwv1,attribute);
00444
00445 p = smb_buf(cli->outbuf);
00446 *p++ = 4;
00447
00448 p += clistr_push(cli, p, first?mask:"", -1, STR_TERMINATE);
00449 *p++ = 5;
00450 if (first) {
00451 SSVAL(p,0,0);
00452 p += 2;
00453 } else {
00454 SSVAL(p,0,21);
00455 p += 2;
00456 memcpy(p,status,21);
00457 p += 21;
00458 }
00459
00460 cli_setup_bcc(cli, p);
00461 cli_send_smb(cli);
00462 if (!cli_receive_smb(cli)) break;
00463
00464 received = SVAL(cli->inbuf,smb_vwv0);
00465 if (received <= 0) break;
00466
00467 first = False;
00468
00469 dirlist = (char *)SMB_REALLOC(
00470 dirlist,(num_received + received)*DIR_STRUCT_SIZE);
00471 if (!dirlist) {
00472 DEBUG(0,("cli_list_old: failed to expand dirlist"));
00473 return 0;
00474 }
00475
00476 p = smb_buf(cli->inbuf) + 3;
00477
00478 memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
00479 p,received*DIR_STRUCT_SIZE);
00480
00481 memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
00482
00483 num_received += received;
00484
00485 if (cli_is_error(cli)) break;
00486 }
00487
00488 if (!first) {
00489 memset(cli->outbuf,'\0',smb_size);
00490 memset(cli->inbuf,'\0',smb_size);
00491
00492 set_message(cli->outbuf,2,0,True);
00493 SCVAL(cli->outbuf,smb_com,SMBfclose);
00494 SSVAL(cli->outbuf,smb_tid,cli->cnum);
00495 cli_setup_packet(cli);
00496
00497 SSVAL(cli->outbuf, smb_vwv0, 0);
00498 SSVAL(cli->outbuf, smb_vwv1, attribute);
00499
00500 p = smb_buf(cli->outbuf);
00501 *p++ = 4;
00502 fstrcpy(p, "");
00503 p += strlen(p) + 1;
00504 *p++ = 5;
00505 SSVAL(p, 0, 21);
00506 p += 2;
00507 memcpy(p,status,21);
00508 p += 21;
00509
00510 cli_setup_bcc(cli, p);
00511 cli_send_smb(cli);
00512 if (!cli_receive_smb(cli)) {
00513 DEBUG(0,("Error closing search: %s\n",cli_errstr(cli)));
00514 }
00515 }
00516
00517 for (p=dirlist,i=0;i<num_received;i++) {
00518 file_info finfo;
00519 p += interpret_short_filename(cli, p,&finfo);
00520 fn("\\", &finfo, Mask, state);
00521 }
00522
00523 SAFE_FREE(dirlist);
00524 return(num_received);
00525 }
00526
00527
00528
00529
00530
00531
00532 int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
00533 void (*fn)(const char *, file_info *, const char *, void *), void *state)
00534 {
00535 if (cli->protocol <= PROTOCOL_LANMAN1)
00536 return cli_list_old(cli, Mask, attribute, fn, state);
00537 return cli_list_new(cli, Mask, attribute, fn, state);
00538 }