diff options
-rw-r--r-- | source3/libsmb/clientgen.c | 275 |
1 files changed, 272 insertions, 3 deletions
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 0892714b39..81842d920f 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -847,7 +847,6 @@ BOOL cli_unlink(struct cli_state *cli, char *fname) return True; } - /**************************************************************************** create a directory ****************************************************************************/ @@ -1259,7 +1258,8 @@ BOOL cli_setatr(struct cli_state *cli, char *fname, int attr, time_t t) send a qpathinfo call ****************************************************************************/ BOOL cli_qpathinfo(struct cli_state *cli, char *fname, - time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size) + time_t *c_time, time_t *a_time, time_t *m_time, + uint32 *size, int *mode) { int data_len = 0; int param_len = 0; @@ -1305,6 +1305,9 @@ BOOL cli_qpathinfo(struct cli_state *cli, char *fname, if (size) { *size = IVAL(rdata, 12); } + if (mode) { + *mode = SVAL(rdata,l1_attrFile); + } if (rdata) free(rdata); if (rparam) free(rparam); @@ -1376,7 +1379,8 @@ BOOL cli_qpathinfo2(struct cli_state *cli, char *fname, send a qfileinfo call ****************************************************************************/ BOOL cli_qfileinfo(struct cli_state *cli, int fnum, - time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size) + time_t *c_time, time_t *a_time, time_t *m_time, + uint32 *size, int *mode) { int data_len = 0; int param_len = 0; @@ -1422,12 +1426,277 @@ BOOL cli_qfileinfo(struct cli_state *cli, int fnum, if (size) { *size = IVAL(rdata, 12); } + if (mode) { + *mode = SVAL(rdata,l1_attrFile); + } if (rdata) free(rdata); if (rparam) free(rparam); return True; } + +/**************************************************************************** +interpret a long filename structure - this is mostly guesses at the moment +The length of the structure is returned +The structure of a long filename depends on the info level. 260 is used +by NT and 2 is used by OS/2 +****************************************************************************/ +static int interpret_long_filename(int level,char *p,file_info *finfo) +{ + extern file_info def_finfo; + + if (finfo) + memcpy(finfo,&def_finfo,sizeof(*finfo)); + + switch (level) + { + case 1: /* OS/2 understands this */ + if (finfo) { + /* 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->size = IVAL(p,16); + finfo->mode = CVAL(p,24); + pstrcpy(finfo->name,p+27); + } + return(28 + CVAL(p,26)); + + case 2: /* this is what OS/2 uses mostly */ + if (finfo) { + /* 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->size = IVAL(p,16); + finfo->mode = CVAL(p,24); + pstrcpy(finfo->name,p+31); + } + return(32 + CVAL(p,30)); + + /* levels 3 and 4 are untested */ + case 3: + if (finfo) { + /* these dates are probably like the other ones */ + finfo->ctime = make_unix_date2(p+8); + finfo->atime = make_unix_date2(p+12); + finfo->mtime = make_unix_date2(p+16); + finfo->size = IVAL(p,20); + finfo->mode = CVAL(p,28); + pstrcpy(finfo->name,p+33); + } + return(SVAL(p,4)+4); + + case 4: + if (finfo) { + /* these dates are probably like the other ones */ + finfo->ctime = make_unix_date2(p+8); + finfo->atime = make_unix_date2(p+12); + finfo->mtime = make_unix_date2(p+16); + finfo->size = IVAL(p,20); + finfo->mode = CVAL(p,28); + pstrcpy(finfo->name,p+37); + } + return(SVAL(p,4)+4); + + case 260: /* NT uses this, but also accepts 2 */ + if (finfo) { + int ret = SVAL(p,0); + int namelen; + p += 4; /* next entry offset */ + 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); p += 8; + finfo->atime = interpret_long_date(p); p += 8; + finfo->mtime = interpret_long_date(p); p += 8; p += 8; + finfo->size = IVAL(p,0); p += 8; + p += 8; /* alloc size */ + finfo->mode = CVAL(p,0); p += 4; + namelen = IVAL(p,0); p += 4; + p += 4; /* EA size */ + p += 2; /* short name len? */ + p += 24; /* short name? */ + StrnCpy(finfo->name,p,namelen); + return(ret); + } + return(SVAL(p,0)); + } + + DEBUG(1,("Unknown long filename format %d\n",level)); + return(SVAL(p,0)); +} + + +/**************************************************************************** + do a directory listing, calling fn on each file found + ****************************************************************************/ +int cli_list(struct cli_state *cli,char *Mask,int attribute,void (*fn)(file_info *)) +{ + int max_matches = 512; + /* NT uses 260, OS/2 uses 2. Both accept 1. */ + int info_level = cli->protocol<PROTOCOL_NT1?1:260; + char *p, *p2; + pstring mask; + file_info finfo; + int i; + char *dirlist = NULL; + int dirlist_len = 0; + int total_received = 0; + BOOL First = True; + int ff_resume_key = 0; + 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; + int param_len, data_len; + + uint16 setup; + pstring param; + + pstrcpy(mask,Mask); + + while (ff_eos == 0) { + loop_count++; + if (loop_count > 200) { + DEBUG(0,("Error: Looping in FIND_NEXT??\n")); + break; + } + + param_len = 12+strlen(mask)+1; + + if (First) { + setup = TRANSACT2_FINDFIRST; + SSVAL(param,0,attribute); /* attribute */ + SSVAL(param,2,max_matches); /* max count */ + SSVAL(param,4,8+4+2); /* resume required + close on end + continue */ + SSVAL(param,6,info_level); + SIVAL(param,8,0); + pstrcpy(param+12,mask); + } else { + setup = TRANSACT2_FINDNEXT; + SSVAL(param,0,ff_dir_handle); + SSVAL(param,2,max_matches); /* max count */ + SSVAL(param,4,info_level); + SIVAL(param,6,ff_resume_key); /* ff_resume_key */ + SSVAL(param,10,8+4+2); /* resume required + close on end + continue */ + pstrcpy(param+12,mask); + + DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n", + ff_dir_handle,ff_resume_key,ff_lastname,mask)); + } + + if (!cli_send_trans(cli, SMBtrans2, + NULL, 0, /* Name, length */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 10, /* param, length, max */ + NULL, 0, + cli->max_xmit /* data, length, max */ + )) { + return -1; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return -1; + } + + /* parse out some important return info */ + p = rparam; + if (First) { + 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) + break; + + /* point to the data bytes */ + p = rdata; + + /* we might need the lastname for continuations */ + if (ff_lastname > 0) { + switch(info_level) + { + case 260: + ff_resume_key =0; + StrnCpy(mask,p+ff_lastname, + data_len-ff_lastname); + break; + case 1: + pstrcpy(mask,p + ff_lastname + 1); + ff_resume_key = 0; + break; + } + } else { + pstrcpy(mask,""); + } + + /* and add them to the dirlist pool */ + dirlist = Realloc(dirlist,dirlist_len + data_len); + + if (!dirlist) { + DEBUG(0,("Failed to expand dirlist\n")); + break; + } + + /* put in a length for the last entry, to ensure we can chain entries + into the next packet */ + for (p2=p,i=0;i<(ff_searchcount-1);i++) + p2 += interpret_long_filename(info_level,p2,NULL); + SSVAL(p2,0,data_len - PTR_DIFF(p2,p)); + + /* grab the data for later use */ + memcpy(dirlist+dirlist_len,p,data_len); + dirlist_len += data_len; + + total_received += ff_searchcount; + + if (rdata) free(rdata); rdata = NULL; + if (rparam) free(rparam); rparam = NULL; + + DEBUG(3,("received %d entries (eos=%d resume=%d)\n", + ff_searchcount,ff_eos,ff_resume_key)); + + First = False; + } + + for (p=dirlist,i=0;i<total_received;i++) { + p += interpret_long_filename(info_level,p,&finfo); + fn(&finfo); + } + + /* free up the dirlist buffer */ + if (dirlist) free(dirlist); + return(total_received); +} + + /**************************************************************************** Send a SamOEMChangePassword command ****************************************************************************/ |