X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source%2Flibsmb%2Fclilist.c;h=5da63096b13b48863d231c32072dd3bd6e98e013;hb=5c6c8e1fe93;hp=5138bca8df17b1fe670cbc844bbfa2db61873ce7;hpb=2ed7e30cbb3e194a08d5d9b46993652666193bec;p=samba.git diff --git a/source/libsmb/clilist.c b/source/libsmb/clilist.c index 5138bca8df1..5da63096b13 100644 --- a/source/libsmb/clilist.c +++ b/source/libsmb/clilist.c @@ -5,7 +5,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -14,14 +14,13 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . */ -#define NO_SYSLOG - #include "includes.h" +extern file_info def_finfo; + /**************************************************************************** Interpret a long filename structure - this is mostly guesses at the moment. The length of the structure is returned @@ -29,25 +28,30 @@ by NT and 2 is used by OS/2 ****************************************************************************/ -static int interpret_long_filename(struct cli_state *cli, - int level,char *p,file_info *finfo) +static size_t interpret_long_filename(struct cli_state *cli, int level,char *p,file_info *finfo, + uint32 *p_resume_key, DATA_BLOB *p_last_name_raw, uint32 *p_last_name_raw_len) { - extern file_info def_finfo; file_info finfo2; int len; char *base = p; - if (!finfo) finfo = &finfo2; + if (!finfo) { + finfo = &finfo2; + } + if (p_resume_key) { + *p_resume_key = 0; + } memcpy(finfo,&def_finfo,sizeof(*finfo)); + finfo->cli = cli; switch (level) { case 1: /* OS/2 understands this */ /* these dates are converted to GMT by make_unix_date */ - finfo->ctime = make_unix_date2(p+4); - finfo->atime = make_unix_date2(p+8); - finfo->mtime = make_unix_date2(p+12); + finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4)); + finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8)); + finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12)); finfo->size = IVAL(p,16); finfo->mode = CVAL(p,24); len = CVAL(p, 26); @@ -66,9 +70,9 @@ static int interpret_long_filename(struct cli_state *cli, case 2: /* this is what OS/2 uses mostly */ /* these dates are converted to GMT by make_unix_date */ - finfo->ctime = make_unix_date2(p+4); - finfo->atime = make_unix_date2(p+8); - finfo->mtime = make_unix_date2(p+12); + finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4)); + finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8)); + finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12)); finfo->size = IVAL(p,16); finfo->mode = CVAL(p,24); len = CVAL(p, 30); @@ -84,29 +88,19 @@ static int interpret_long_filename(struct cli_state *cli, { size_t namelen, slen; p += 4; /* next entry offset */ + + if (p_resume_key) { + *p_resume_key = IVAL(p,0); + } p += 4; /* fileindex */ - /* these dates appear to arrive in a - weird way. It seems to be localtime - plus the serverzone given in the - initial connect. This is GMT when - DST is not in effect and one hour - from GMT otherwise. Can this really - be right?? - - I suppose this could be called - kludge-GMT. Is is the GMT you get - by using the current DST setting on - a different localtime. It will be - cheap to calculate, I suppose, as - no DST tables will be needed */ - - finfo->ctime = interpret_long_date(p); + /* Offset zero is "create time", not "change time". */ p += 8; - finfo->atime = interpret_long_date(p); + finfo->atime_ts = interpret_long_date(p); p += 8; - finfo->mtime = interpret_long_date(p); + finfo->mtime_ts = interpret_long_date(p); p += 8; + finfo->ctime_ts = interpret_long_date(p); p += 8; finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0); p += 8; @@ -130,12 +124,28 @@ static int interpret_long_filename(struct cli_state *cli, clistr_pull(cli, finfo->name, p, sizeof(finfo->name), namelen, 0); - return SVAL(base, 0); + + /* To be robust in the face of unicode conversion failures + we need to copy the raw bytes of the last name seen here. + Namelen doesn't include the terminating unicode null, so + copy it here. */ + + if (p_last_name_raw && p_last_name_raw_len) { + if (namelen + 2 > p_last_name_raw->length) { + memset(p_last_name_raw->data, '\0', sizeof(p_last_name_raw->length)); + *p_last_name_raw_len = 0; + } else { + memcpy(p_last_name_raw->data, p, namelen); + SSVAL(p_last_name_raw->data, namelen, 0); + *p_last_name_raw_len = namelen + 2; + } + } + return (size_t)IVAL(base, 0); } } DEBUG(1,("Unknown long filename format %d\n",level)); - return(SVAL(p,0)); + return (size_t)IVAL(base,0); } /**************************************************************************** @@ -145,7 +155,7 @@ static int interpret_long_filename(struct cli_state *cli, int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, void (*fn)(const char *, file_info *, const char *, void *), void *state) { -#if 0 +#if 1 int max_matches = 1366; /* Match W2k - was 512. */ #else int max_matches = 512; @@ -155,30 +165,27 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, pstring mask; file_info finfo; int i; - char *tdl, *dirlist = NULL; + char *dirlist = NULL; int dirlist_len = 0; int total_received = -1; BOOL First = True; int ff_searchcount=0; int ff_eos=0; - int ff_lastname=0; int ff_dir_handle=0; int loop_count = 0; char *rparam=NULL, *rdata=NULL; unsigned int param_len, data_len; uint16 setup; pstring param; + const char *mnt; + uint32 resume_key = 0; + uint32 last_name_raw_len = 0; + DATA_BLOB last_name_raw = data_blob(NULL, 2*sizeof(pstring)); /* NT uses 260, OS/2 uses 2. Both accept 1. */ info_level = (cli->capabilities&CAP_NT_SMBS)?260:1; - /* when getting a directory listing from a 2k dfs root share, - we have to include the full path (\server\share\mask) here */ - - if ( cli->dfsroot ) - pstr_sprintf( mask, "\\%s\\%s\\%s", cli->desthost, cli->share, Mask ); - else - pstrcpy(mask,Mask); + pstrcpy(mask,Mask); while (ff_eos == 0) { loop_count++; @@ -202,13 +209,19 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, SSVAL(param,0,ff_dir_handle); SSVAL(param,2,max_matches); /* max count */ SSVAL(param,4,info_level); - SIVAL(param,6,0); /* ff_resume_key */ + /* For W2K servers serving out FAT filesystems we *must* set the + resume key. If it's not FAT then it's returned as zero. */ + SIVAL(param,6,resume_key); /* ff_resume_key */ /* NB. *DON'T* use continue here. If you do it seems that W2K and bretheren can miss filenames. Use last filename continue instead. JRA */ SSVAL(param,10,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END)); /* resume required + close on end */ p = param+12; - p += clistr_push(cli, param+12, mask, sizeof(param)-12, - STR_TERMINATE); + if (last_name_raw_len && (last_name_raw_len < (sizeof(param)-12))) { + memcpy(p, last_name_raw.data, last_name_raw_len); + p += last_name_raw_len; + } else { + p += clistr_push(cli, param+12, mask, sizeof(param)-12, STR_TERMINATE); + } } param_len = PTR_DIFF(p, param); @@ -237,6 +250,10 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, it gives ERRSRV/ERRerror temprarily */ uint8 eclass; uint32 ecode; + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + cli_dos_error(cli, &eclass, &ecode); if (eclass != ERRSRV || ecode != ERRerror) break; @@ -244,8 +261,11 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, continue; } - if (cli_is_error(cli) || !rdata || !rparam) + if (cli_is_error(cli) || !rdata || !rparam) { + SAFE_FREE(rdata); + SAFE_FREE(rparam); break; + } if (total_received == -1) total_received = 0; @@ -256,46 +276,54 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, ff_dir_handle = SVAL(p,0); ff_searchcount = SVAL(p,2); ff_eos = SVAL(p,4); - ff_lastname = SVAL(p,8); } else { ff_searchcount = SVAL(p,0); ff_eos = SVAL(p,2); - ff_lastname = SVAL(p,6); } - if (ff_searchcount == 0) + if (ff_searchcount == 0) { + SAFE_FREE(rdata); + SAFE_FREE(rparam); break; + } /* point to the data bytes */ p = rdata; /* we might need the lastname for continuations */ - - /* and add them to the dirlist pool */ - tdl = SMB_REALLOC(dirlist,dirlist_len + data_len); - - if (!tdl) { - DEBUG(0,("cli_list_new: Failed to expand dirlist\n")); - break; - } else { - dirlist = tdl; - } - - /* put in a length for the last entry, to ensure we can chain entries - into the next packet */ for (p2=p,i=0;i 0) { + if (ff_searchcount > 0) { pstrcpy(mask, finfo.name); } else { pstrcpy(mask,""); } /* grab the data for later use */ + /* and add them to the dirlist pool */ + dirlist = (char *)SMB_REALLOC(dirlist,dirlist_len + data_len); + + if (!dirlist) { + DEBUG(0,("cli_list_new: Failed to expand dirlist\n")); + SAFE_FREE(rdata); + SAFE_FREE(rparam); + break; + } + memcpy(dirlist+dirlist_len,p,data_len); dirlist_len += data_len; @@ -313,16 +341,23 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, First = False; } - for (p=dirlist,i=0;icli = cli; finfo->mode = CVAL(p,21); /* this date is converted to GMT by make_unix_date */ - finfo->ctime = make_unix_date(p+22); - finfo->mtime = finfo->atime = finfo->ctime; + finfo->ctime_ts.tv_sec = cli_make_unix_date(cli, p+22); + finfo->ctime_ts.tv_nsec = 0; + finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec; + finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0; finfo->size = IVAL(p,26); clistr_pull(cli, finfo->name, p+30, sizeof(finfo->name), 12, STR_ASCII); if (strcmp(finfo->name, "..") && strcmp(finfo->name, ".")) { @@ -369,7 +406,7 @@ int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute, int num_asked = (cli->max_xmit - 100)/DIR_STRUCT_SIZE; int num_received = 0; int i; - char *tdl, *dirlist = NULL; + char *dirlist = NULL; pstring mask; ZERO_ARRAY(status); @@ -414,14 +451,12 @@ int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute, first = False; - tdl = SMB_REALLOC(dirlist,(num_received + received)*DIR_STRUCT_SIZE); - - if (!tdl) { + dirlist = (char *)SMB_REALLOC( + dirlist,(num_received + received)*DIR_STRUCT_SIZE); + if (!dirlist) { DEBUG(0,("cli_list_old: failed to expand dirlist")); - SAFE_FREE(dirlist); return 0; } - else dirlist = tdl; p = smb_buf(cli->inbuf) + 3;