root/source3/libsmb/clilist.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. calc_next_entry_offset
  2. interpret_long_filename
  3. cli_list_new
  4. interpret_short_filename
  5. cli_list_old
  6. cli_list

   1 /*
   2    Unix SMB/CIFS implementation.
   3    client directory list routines
   4    Copyright (C) Andrew Tridgell 1994-1998
   5 
   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 3 of the License, or
   9    (at your option) any later version.
  10 
  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.
  15 
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 #include "includes.h"
  21 
  22 /****************************************************************************
  23  Calculate a safe next_entry_offset.
  24 ****************************************************************************/
  25 
  26 static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
     /* [<][>][^][v][top][bottom][index][help] */
  27 {
  28         size_t next_entry_offset = (size_t)IVAL(base,0);
  29 
  30         if (next_entry_offset == 0 ||
  31                         base + next_entry_offset < base ||
  32                         base + next_entry_offset > pdata_end) {
  33                 next_entry_offset = pdata_end - base;
  34         }
  35         return next_entry_offset;
  36 }
  37 
  38 /****************************************************************************
  39  Interpret a long filename structure - this is mostly guesses at the moment.
  40  The length of the structure is returned
  41  The structure of a long filename depends on the info level. 260 is used
  42  by NT and 2 is used by OS/2
  43 ****************************************************************************/
  44 
  45 static size_t interpret_long_filename(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  46                                         struct cli_state *cli,
  47                                         int level,
  48                                         const char *p,
  49                                         const char *pdata_end,
  50                                         file_info *finfo,
  51                                         uint32 *p_resume_key,
  52                                         DATA_BLOB *p_last_name_raw)
  53 {
  54         int len;
  55         size_t ret;
  56         const char *base = p;
  57 
  58         data_blob_free(p_last_name_raw);
  59 
  60         if (p_resume_key) {
  61                 *p_resume_key = 0;
  62         }
  63         ZERO_STRUCTP(finfo);
  64         finfo->cli = cli;
  65 
  66         switch (level) {
  67                 case 1: /* OS/2 understands this */
  68                         /* these dates are converted to GMT by
  69                            make_unix_date */
  70                         if (pdata_end - base < 27) {
  71                                 return pdata_end - base;
  72                         }
  73                         finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4));
  74                         finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8));
  75                         finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12));
  76                         finfo->size = IVAL(p,16);
  77                         finfo->mode = CVAL(p,24);
  78                         len = CVAL(p, 26);
  79                         p += 27;
  80                         p += clistr_align_in(cli, p, 0);
  81 
  82                         /* We can safely use len here (which is required by OS/2)
  83                          * and the NAS-BASIC server instead of +2 or +1 as the
  84                          * STR_TERMINATE flag below is
  85                          * actually used as the length calculation.
  86                          * The len is merely an upper bound.
  87                          * Due to the explicit 2 byte null termination
  88                          * in cli_receive_trans/cli_receive_nt_trans
  89                          * we know this is safe. JRA + kukks
  90                          */
  91 
  92                         if (p + len > pdata_end) {
  93                                 return pdata_end - base;
  94                         }
  95 
  96                         /* the len+2 below looks strange but it is
  97                            important to cope with the differences
  98                            between win2000 and win9x for this call
  99                            (tridge) */
 100                         ret = clistr_pull_talloc(ctx,
 101                                                 cli->inbuf,
 102                                                 &finfo->name,
 103                                                 p,
 104                                                 len+2,
 105                                                 STR_TERMINATE);
 106                         if (ret == (size_t)-1) {
 107                                 return pdata_end - base;
 108                         }
 109                         p += ret;
 110                         return PTR_DIFF(p, base);
 111 
 112                 case 2: /* this is what OS/2 uses mostly */
 113                         /* these dates are converted to GMT by
 114                            make_unix_date */
 115                         if (pdata_end - base < 31) {
 116                                 return pdata_end - base;
 117                         }
 118                         finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4));
 119                         finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8));
 120                         finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12));
 121                         finfo->size = IVAL(p,16);
 122                         finfo->mode = CVAL(p,24);
 123                         len = CVAL(p, 30);
 124                         p += 31;
 125                         /* check for unisys! */
 126                         if (p + len + 1 > pdata_end) {
 127                                 return pdata_end - base;
 128                         }
 129                         ret = clistr_pull_talloc(ctx,
 130                                                 cli->inbuf,
 131                                                 &finfo->name,
 132                                                 p,
 133                                                 len,
 134                                                 STR_NOALIGN);
 135                         if (ret == (size_t)-1) {
 136                                 return pdata_end - base;
 137                         }
 138                         p += ret;
 139                         return PTR_DIFF(p, base) + 1;
 140 
 141                 case 260: /* NT uses this, but also accepts 2 */
 142                 {
 143                         size_t namelen, slen;
 144 
 145                         if (pdata_end - base < 94) {
 146                                 return pdata_end - base;
 147                         }
 148 
 149                         p += 4; /* next entry offset */
 150 
 151                         if (p_resume_key) {
 152                                 *p_resume_key = IVAL(p,0);
 153                         }
 154                         p += 4; /* fileindex */
 155 
 156                         /* Offset zero is "create time", not "change time". */
 157                         p += 8;
 158                         finfo->atime_ts = interpret_long_date(p);
 159                         p += 8;
 160                         finfo->mtime_ts = interpret_long_date(p);
 161                         p += 8;
 162                         finfo->ctime_ts = interpret_long_date(p);
 163                         p += 8;
 164                         finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
 165                         p += 8;
 166                         p += 8; /* alloc size */
 167                         finfo->mode = CVAL(p,0);
 168                         p += 4;
 169                         namelen = IVAL(p,0);
 170                         p += 4;
 171                         p += 4; /* EA size */
 172                         slen = SVAL(p, 0);
 173                         if (slen > 24) {
 174                                 /* Bad short name length. */
 175                                 return pdata_end - base;
 176                         }
 177                         p += 2;
 178                         {
 179                                 /* stupid NT bugs. grr */
 180                                 int flags = 0;
 181                                 if (p[1] == 0 && namelen > 1) flags |= STR_UNICODE;
 182                                 clistr_pull(cli->inbuf, finfo->short_name, p,
 183                                             sizeof(finfo->short_name),
 184                                             slen, flags);
 185                         }
 186                         p += 24; /* short name? */
 187                         if (p + namelen < p || p + namelen > pdata_end) {
 188                                 return pdata_end - base;
 189                         }
 190                         ret = clistr_pull_talloc(ctx,
 191                                                 cli->inbuf,
 192                                                 &finfo->name,
 193                                                 p,
 194                                                 namelen,
 195                                                 0);
 196                         if (ret == (size_t)-1) {
 197                                 return pdata_end - base;
 198                         }
 199 
 200                         /* To be robust in the face of unicode conversion failures
 201                            we need to copy the raw bytes of the last name seen here.
 202                            Namelen doesn't include the terminating unicode null, so
 203                            copy it here. */
 204 
 205                         if (p_last_name_raw) {
 206                                 *p_last_name_raw = data_blob(NULL, namelen+2);
 207                                 memcpy(p_last_name_raw->data, p, namelen);
 208                                 SSVAL(p_last_name_raw->data, namelen, 0);
 209                         }
 210                         return calc_next_entry_offset(base, pdata_end);
 211                 }
 212         }
 213 
 214         DEBUG(1,("Unknown long filename format %d\n",level));
 215         return calc_next_entry_offset(base, pdata_end);
 216 }
 217 
 218 /****************************************************************************
 219  Do a directory listing, calling fn on each file found.
 220 ****************************************************************************/
 221 
 222 int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
     /* [<][>][^][v][top][bottom][index][help] */
 223                  void (*fn)(const char *, file_info *, const char *, void *), void *state)
 224 {
 225 #if 1
 226         int max_matches = 1366; /* Match W2k - was 512. */
 227 #else
 228         int max_matches = 512;
 229 #endif
 230         int info_level;
 231         char *p, *p2, *rdata_end;
 232         char *mask = NULL;
 233         file_info finfo;
 234         int i;
 235         char *dirlist = NULL;
 236         int dirlist_len = 0;
 237         int total_received = -1;
 238         bool First = True;
 239         int ff_searchcount=0;
 240         int ff_eos=0;
 241         int ff_dir_handle=0;
 242         int loop_count = 0;
 243         char *rparam=NULL, *rdata=NULL;
 244         unsigned int param_len, data_len;
 245         uint16 setup;
 246         char *param;
 247         uint32 resume_key = 0;
 248         TALLOC_CTX *frame = talloc_stackframe();
 249         DATA_BLOB last_name_raw = data_blob(NULL, 0);
 250 
 251         /* NT uses 260, OS/2 uses 2. Both accept 1. */
 252         info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
 253 
 254         mask = SMB_STRDUP(Mask);
 255         if (!mask) {
 256                 TALLOC_FREE(frame);
 257                 return -1;
 258         }
 259 
 260         while (ff_eos == 0) {
 261                 size_t nlen = 2*(strlen(mask)+1);
 262 
 263                 loop_count++;
 264                 if (loop_count > 200) {
 265                         DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
 266                         break;
 267                 }
 268 
 269                 param = SMB_MALLOC_ARRAY(char, 12+nlen+last_name_raw.length+2);
 270                 if (!param) {
 271                         break;
 272                 }
 273 
 274                 if (First) {
 275                         setup = TRANSACT2_FINDFIRST;
 276                         SSVAL(param,0,attribute); /* attribute */
 277                         SSVAL(param,2,max_matches); /* max count */
 278                         SSVAL(param,4,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END)); /* resume required + close on end */
 279                         SSVAL(param,6,info_level);
 280                         SIVAL(param,8,0);
 281                         p = param+12;
 282                         p += clistr_push(cli, param+12, mask,
 283                                          nlen, STR_TERMINATE);
 284                 } else {
 285                         setup = TRANSACT2_FINDNEXT;
 286                         SSVAL(param,0,ff_dir_handle);
 287                         SSVAL(param,2,max_matches); /* max count */
 288                         SSVAL(param,4,info_level);
 289                         /* For W2K servers serving out FAT filesystems we *must* set the
 290                            resume key. If it's not FAT then it's returned as zero. */
 291                         SIVAL(param,6,resume_key); /* ff_resume_key */
 292                         /* NB. *DON'T* use continue here. If you do it seems that W2K and bretheren
 293                            can miss filenames. Use last filename continue instead. JRA */
 294                         SSVAL(param,10,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END));        /* resume required + close on end */
 295                         p = param+12;
 296                         if (last_name_raw.length) {
 297                                 memcpy(p, last_name_raw.data, last_name_raw.length);
 298                                 p += last_name_raw.length;
 299                         } else {
 300                                 p += clistr_push(cli, param+12, mask,
 301                                                 nlen, STR_TERMINATE);
 302                         }
 303                 }
 304 
 305                 param_len = PTR_DIFF(p, param);
 306 
 307                 if (!cli_send_trans(cli, SMBtrans2,
 308                                     NULL,                   /* Name */
 309                                     -1, 0,                  /* fid, flags */
 310                                     &setup, 1, 0,           /* setup, length, max */
 311                                     param, param_len, 10,   /* param, length, max */
 312                                     NULL, 0,
 313 #if 0
 314                                     /* w2k value. */
 315                                     MIN(16384,cli->max_xmit) /* data, length, max. */
 316 #else
 317                                     cli->max_xmit           /* data, length, max. */
 318 #endif
 319                                     )) {
 320                         SAFE_FREE(param);
 321                         TALLOC_FREE(frame);
 322                         break;
 323                 }
 324 
 325                 SAFE_FREE(param);
 326 
 327                 if (!cli_receive_trans(cli, SMBtrans2,
 328                                        &rparam, &param_len,
 329                                        &rdata, &data_len) &&
 330                     cli_is_dos_error(cli)) {
 331                         /* We need to work around a Win95 bug - sometimes
 332                            it gives ERRSRV/ERRerror temprarily */
 333                         uint8 eclass;
 334                         uint32 ecode;
 335 
 336                         SAFE_FREE(rdata);
 337                         SAFE_FREE(rparam);
 338 
 339                         cli_dos_error(cli, &eclass, &ecode);
 340 
 341                         /*
 342                          * OS/2 might return "no more files",
 343                          * which just tells us, that searchcount is zero
 344                          * in this search.
 345                          * Guenter Kukkukk <linux@kukkukk.com>
 346                          */
 347 
 348                         if (eclass == ERRDOS && ecode == ERRnofiles) {
 349                                 ff_searchcount = 0;
 350                                 cli_reset_error(cli);
 351                                 break;
 352                         }
 353 
 354                         if (eclass != ERRSRV || ecode != ERRerror)
 355                                 break;
 356                         smb_msleep(100);
 357                         continue;
 358                 }
 359 
 360                 if (cli_is_error(cli) || !rdata || !rparam) {
 361                         SAFE_FREE(rdata);
 362                         SAFE_FREE(rparam);
 363                         break;
 364                 }
 365 
 366                 if (total_received == -1)
 367                         total_received = 0;
 368 
 369                 /* parse out some important return info */
 370                 p = rparam;
 371                 if (First) {
 372                         ff_dir_handle = SVAL(p,0);
 373                         ff_searchcount = SVAL(p,2);
 374                         ff_eos = SVAL(p,4);
 375                 } else {
 376                         ff_searchcount = SVAL(p,0);
 377                         ff_eos = SVAL(p,2);
 378                 }
 379 
 380                 if (ff_searchcount == 0) {
 381                         SAFE_FREE(rdata);
 382                         SAFE_FREE(rparam);
 383                         break;
 384                 }
 385 
 386                 /* point to the data bytes */
 387                 p = rdata;
 388                 rdata_end = rdata + data_len;
 389 
 390                 /* we might need the lastname for continuations */
 391                 for (p2=p,i=0;i<ff_searchcount && p2 < rdata_end;i++) {
 392                         if ((info_level == 260) && (i == ff_searchcount-1)) {
 393                                 /* Last entry - fixup the last offset length. */
 394                                 SIVAL(p2,0,PTR_DIFF((rdata + data_len),p2));
 395                         }
 396                         p2 += interpret_long_filename(frame,
 397                                                         cli,
 398                                                         info_level,
 399                                                         p2,
 400                                                         rdata_end,
 401                                                         &finfo,
 402                                                         &resume_key,
 403                                                         &last_name_raw);
 404 
 405                         if (!finfo.name) {
 406                                 DEBUG(0,("cli_list_new: Error: unable to parse name from info level %d\n",
 407                                         info_level));
 408                                 ff_eos = 1;
 409                                 break;
 410                         }
 411                         if (!First && *mask && strcsequal(finfo.name, mask)) {
 412                                 DEBUG(0,("Error: Looping in FIND_NEXT as name %s has already been seen?\n",
 413                                         finfo.name));
 414                                 ff_eos = 1;
 415                                 break;
 416                         }
 417                 }
 418 
 419                 SAFE_FREE(mask);
 420                 if (ff_searchcount > 0 && ff_eos == 0 && finfo.name) {
 421                         mask = SMB_STRDUP(finfo.name);
 422                 } else {
 423                         mask = SMB_STRDUP("");
 424                 }
 425                 if (!mask) {
 426                         SAFE_FREE(rdata);
 427                         SAFE_FREE(rparam);
 428                         break;
 429                 }
 430 
 431                 /* grab the data for later use */
 432                 /* and add them to the dirlist pool */
 433                 dirlist = (char *)SMB_REALLOC(dirlist,dirlist_len + data_len);
 434 
 435                 if (!dirlist) {
 436                         DEBUG(0,("cli_list_new: Failed to expand dirlist\n"));
 437                         SAFE_FREE(rdata);
 438                         SAFE_FREE(rparam);
 439                         break;
 440                 }
 441 
 442                 memcpy(dirlist+dirlist_len,p,data_len);
 443                 dirlist_len += data_len;
 444 
 445                 total_received += ff_searchcount;
 446 
 447                 SAFE_FREE(rdata);
 448                 SAFE_FREE(rparam);
 449 
 450                 DEBUG(3,("received %d entries (eos=%d)\n",
 451                          ff_searchcount,ff_eos));
 452 
 453                 if (ff_searchcount > 0)
 454                         loop_count = 0;
 455 
 456                 First = False;
 457         }
 458 
 459         /* see if the server disconnected or the connection otherwise failed */
 460         if (cli_is_error(cli)) {
 461                 total_received = -1;
 462         } else {
 463                 /* no connection problem.  let user function add each entry */
 464                 rdata_end = dirlist + dirlist_len;
 465                 for (p=dirlist,i=0;i<total_received;i++) {
 466                         p += interpret_long_filename(frame,
 467                                                         cli,
 468                                                         info_level,
 469                                                         p,
 470                                                         rdata_end,
 471                                                         &finfo,
 472                                                         NULL,
 473                                                         NULL);
 474                         if (!finfo.name) {
 475                                 DEBUG(0,("cli_list_new: unable to parse name from info level %d\n",
 476                                         info_level));
 477                                 break;
 478                         }
 479                         fn(cli->dfs_mountpoint, &finfo, Mask, state);
 480                 }
 481         }
 482 
 483         /* free up the dirlist buffer and last name raw blob */
 484         SAFE_FREE(dirlist);
 485         data_blob_free(&last_name_raw);
 486         SAFE_FREE(mask);
 487         TALLOC_FREE(frame);
 488         return(total_received);
 489 }
 490 
 491 /****************************************************************************
 492  Interpret a short filename structure.
 493  The length of the structure is returned.
 494 ****************************************************************************/
 495 
 496 static bool interpret_short_filename(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 497                                 struct cli_state *cli,
 498                                 char *p,
 499                                 file_info *finfo)
 500 {
 501         size_t ret;
 502         ZERO_STRUCTP(finfo);
 503 
 504         finfo->cli = cli;
 505         finfo->mode = CVAL(p,21);
 506 
 507         /* this date is converted to GMT by make_unix_date */
 508         finfo->ctime_ts.tv_sec = cli_make_unix_date(cli, p+22);
 509         finfo->ctime_ts.tv_nsec = 0;
 510         finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
 511         finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
 512         finfo->size = IVAL(p,26);
 513         ret = clistr_pull_talloc(ctx,
 514                         cli->inbuf,
 515                         &finfo->name,
 516                         p+30,
 517                         12,
 518                         STR_ASCII);
 519         if (ret == (size_t)-1) {
 520                 return false;
 521         }
 522 
 523         if (finfo->name) {
 524                 strlcpy(finfo->short_name,
 525                         finfo->name,
 526                         sizeof(finfo->short_name));
 527         }
 528         return true;
 529         return(DIR_STRUCT_SIZE);
 530 }
 531 
 532 /****************************************************************************
 533  Do a directory listing, calling fn on each file found.
 534  this uses the old SMBsearch interface. It is needed for testing Samba,
 535  but should otherwise not be used.
 536 ****************************************************************************/
 537 
 538 int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute,
     /* [<][>][^][v][top][bottom][index][help] */
 539                  void (*fn)(const char *, file_info *, const char *, void *), void *state)
 540 {
 541         char *p;
 542         int received = 0;
 543         bool first = True;
 544         char status[21];
 545         int num_asked = (cli->max_xmit - 100)/DIR_STRUCT_SIZE;
 546         int num_received = 0;
 547         int i;
 548         char *dirlist = NULL;
 549         char *mask = NULL;
 550         TALLOC_CTX *frame = NULL;
 551 
 552         ZERO_ARRAY(status);
 553 
 554         mask = SMB_STRDUP(Mask);
 555         if (!mask) {
 556                 return -1;
 557         }
 558 
 559         while (1) {
 560                 memset(cli->outbuf,'\0',smb_size);
 561                 memset(cli->inbuf,'\0',smb_size);
 562 
 563                 cli_set_message(cli->outbuf,2,0,True);
 564 
 565                 SCVAL(cli->outbuf,smb_com,SMBsearch);
 566 
 567                 SSVAL(cli->outbuf,smb_tid,cli->cnum);
 568                 cli_setup_packet(cli);
 569 
 570                 SSVAL(cli->outbuf,smb_vwv0,num_asked);
 571                 SSVAL(cli->outbuf,smb_vwv1,attribute);
 572 
 573                 p = smb_buf(cli->outbuf);
 574                 *p++ = 4;
 575 
 576                 p += clistr_push(cli, p, first?mask:"",
 577                                 cli->bufsize - PTR_DIFF(p,cli->outbuf),
 578                                 STR_TERMINATE);
 579                 *p++ = 5;
 580                 if (first) {
 581                         SSVAL(p,0,0);
 582                         p += 2;
 583                 } else {
 584                         SSVAL(p,0,21);
 585                         p += 2;
 586                         memcpy(p,status,21);
 587                         p += 21;
 588                 }
 589 
 590                 cli_setup_bcc(cli, p);
 591                 cli_send_smb(cli);
 592                 if (!cli_receive_smb(cli)) break;
 593 
 594                 received = SVAL(cli->inbuf,smb_vwv0);
 595                 if (received <= 0) break;
 596 
 597                 /* Ensure we received enough data. */
 598                 if ((cli->inbuf+4+smb_len(cli->inbuf) - (smb_buf(cli->inbuf)+3)) <
 599                                 received*DIR_STRUCT_SIZE) {
 600                         break;
 601                 }
 602 
 603                 first = False;
 604 
 605                 dirlist = (char *)SMB_REALLOC(
 606                         dirlist,(num_received + received)*DIR_STRUCT_SIZE);
 607                 if (!dirlist) {
 608                         DEBUG(0,("cli_list_old: failed to expand dirlist"));
 609                         SAFE_FREE(mask);
 610                         return 0;
 611                 }
 612 
 613                 p = smb_buf(cli->inbuf) + 3;
 614 
 615                 memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
 616                        p,received*DIR_STRUCT_SIZE);
 617 
 618                 memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
 619 
 620                 num_received += received;
 621 
 622                 if (cli_is_error(cli)) break;
 623         }
 624 
 625         if (!first) {
 626                 memset(cli->outbuf,'\0',smb_size);
 627                 memset(cli->inbuf,'\0',smb_size);
 628 
 629                 cli_set_message(cli->outbuf,2,0,True);
 630                 SCVAL(cli->outbuf,smb_com,SMBfclose);
 631                 SSVAL(cli->outbuf,smb_tid,cli->cnum);
 632                 cli_setup_packet(cli);
 633 
 634                 SSVAL(cli->outbuf, smb_vwv0, 0); /* find count? */
 635                 SSVAL(cli->outbuf, smb_vwv1, attribute);
 636 
 637                 p = smb_buf(cli->outbuf);
 638                 *p++ = 4;
 639                 fstrcpy(p, "");
 640                 p += strlen(p) + 1;
 641                 *p++ = 5;
 642                 SSVAL(p, 0, 21);
 643                 p += 2;
 644                 memcpy(p,status,21);
 645                 p += 21;
 646 
 647                 cli_setup_bcc(cli, p);
 648                 cli_send_smb(cli);
 649                 if (!cli_receive_smb(cli)) {
 650                         DEBUG(0,("Error closing search: %s\n",cli_errstr(cli)));
 651                 }
 652         }
 653 
 654         frame = talloc_stackframe();
 655         for (p=dirlist,i=0;i<num_received;i++) {
 656                 file_info finfo;
 657                 if (!interpret_short_filename(frame, cli, p, &finfo)) {
 658                         break;
 659                 }
 660                 p += DIR_STRUCT_SIZE;
 661                 fn("\\", &finfo, Mask, state);
 662         }
 663         TALLOC_FREE(frame);
 664 
 665         SAFE_FREE(mask);
 666         SAFE_FREE(dirlist);
 667         return(num_received);
 668 }
 669 
 670 /****************************************************************************
 671  Do a directory listing, calling fn on each file found.
 672  This auto-switches between old and new style.
 673 ****************************************************************************/
 674 
 675 int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
     /* [<][>][^][v][top][bottom][index][help] */
 676              void (*fn)(const char *, file_info *, const char *, void *), void *state)
 677 {
 678         if (cli->protocol <= PROTOCOL_LANMAN1)
 679                 return cli_list_old(cli, Mask, attribute, fn, state);
 680         return cli_list_new(cli, Mask, attribute, fn, state);
 681 }

/* [<][>][^][v][top][bottom][index][help] */