summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/libsmb/clientgen.c275
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, &param_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
****************************************************************************/