~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libsmb/clilist.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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)
 
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,
 
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,
 
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,
 
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,
 
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,
 
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
}