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;