Ignore:
Timestamp:
Nov 14, 2012, 12:59:34 PM (12 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to 3.6.0

File:
1 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified vendor/current/source3/libsmb/clilist.c

    r414 r740  
    1919
    2020#include "includes.h"
     21#include "libsmb/libsmb.h"
     22#include "../lib/util/tevent_ntstatus.h"
     23#include "async_smb.h"
     24#include "trans2.h"
    2125
    2226/****************************************************************************
     
    4751                                        struct cli_state *cli,
    4852                                        int level,
     53                                        const char *base_ptr,
     54                                        uint16_t recv_flags2,
    4955                                        const char *p,
    5056                                        const char *pdata_end,
    51                                         file_info *finfo,
     57                                        struct file_info *finfo,
    5258                                        uint32 *p_resume_key,
    5359                                        DATA_BLOB *p_last_name_raw)
     
    6369        }
    6470        ZERO_STRUCTP(finfo);
    65         finfo->cli = cli;
    6671
    6772        switch (level) {
     
    7277                                return pdata_end - base;
    7378                        }
    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));
    7785                        finfo->size = IVAL(p,16);
    7886                        finfo->mode = CVAL(p,24);
    7987                        len = CVAL(p, 26);
    8088                        p += 27;
    81                         p += clistr_align_in(cli, p, 0);
     89                        p += align_string(base_ptr, p, 0);
    8290
    8391                        /* We can safely use len here (which is required by OS/2)
     
    100108                           (tridge) */
    101109                        ret = clistr_pull_talloc(ctx,
    102                                                 cli->inbuf,
     110                                                base_ptr,
     111                                                recv_flags2,
    103112                                                &finfo->name,
    104113                                                p,
     
    117126                                return pdata_end - base;
    118127                        }
    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));
    122134                        finfo->size = IVAL(p,16);
    123135                        finfo->mode = CVAL(p,24);
     
    129141                        }
    130142                        ret = clistr_pull_talloc(ctx,
    131                                                 cli->inbuf,
     143                                                base_ptr,
     144                                                recv_flags2,
    132145                                                &finfo->name,
    133146                                                p,
     
    181194                                int flags = 0;
    182195                                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,
    184197                                            sizeof(finfo->short_name),
    185198                                            slen, flags);
     
    190203                        }
    191204                        ret = clistr_pull_talloc(ctx,
    192                                                 cli->inbuf,
     205                                                base_ptr,
     206                                                recv_flags2,
    193207                                                &finfo->name,
    194208                                                p,
     
    218232
    219233/****************************************************************************
    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 1
    227         int max_matches = 1366; /* Match W2k - was 512. */
    228 #else
    229         int max_matches = 512;
    230 #endif
    231         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 the
    293                            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 bretheren
    296                            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 0
    317                                     /* w2k value. */
    318                                     MIN(16384,cli->max_xmit) /* data, length, max. */
    319 #else
    320                                     cli->max_xmit           /* data, length, max. */
    321 #endif
    322                                     )) {
    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, &param_len,
    332                                        &rdata, &data_len) &&
    333                     cli_is_dos_error(cli)) {
    334                         /* We need to work around a Win95 bug - sometimes
    335                            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 zero
    347                          * 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 /****************************************************************************
    496234 Interpret a short filename structure.
    497235 The length of the structure is returned.
     
    501239                                struct cli_state *cli,
    502240                                char *p,
    503                                 file_info *finfo)
     241                                struct file_info *finfo)
    504242{
    505243        size_t ret;
    506244        ZERO_STRUCTP(finfo);
    507245
    508         finfo->cli = cli;
    509246        finfo->mode = CVAL(p,21);
    510247
    511248        /* 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);
    513250        finfo->ctime_ts.tv_nsec = 0;
    514251        finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
     
    517254        ret = clistr_pull_talloc(ctx,
    518255                        cli->inbuf,
     256                        SVAL(cli->inbuf, smb_flg2),
    519257                        &finfo->name,
    520258                        p+30,
     
    531269        }
    532270        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
     273struct 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
     286static void cli_list_old_done(struct tevent_req *subreq);
     287
     288static 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
     338static 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
     440static 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
     473NTSTATUS 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
     523struct 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
     544static void cli_list_trans_done(struct tevent_req *subreq);
     545
     546static 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;
    545556        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
     609static 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;
    551629        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                                &param, 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;
    604674                        break;
    605675                }
    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;
    662696                        break;
    663697                }
    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
     787static 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
     802NTSTATUS 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:
    667845        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
     852struct 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
     858static void cli_list_done(struct tevent_req *subreq);
     859
     860struct 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
     890static 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
     907NTSTATUS 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
     922NTSTATUS 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.