From e0c21df69ad2558a96a24567a89594d9ed7ee6ed Mon Sep 17 00:00:00 2001 From: Richard Sharpe Date: Sat, 11 Apr 1998 07:52:13 +0000 Subject: Changes to client.c support the need for directories to be processed by whatever action is passed to do_dir. Changes to clitar.c as requested by Canon Information Systems Research Australia: 1. Support restoring long file names 2. Write directory entries to TAR files as first part of setting directory create times 3. Ensure zero length files get correct mtime 4. Allow DOS and UNIX pathnames in command line parameters. (This used to be commit 0c228f0b33950c8d38de0529e88a38848742a50d) --- source3/client/client.c | 40 +++--- source3/client/clitar.c | 326 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 298 insertions(+), 68 deletions(-) (limited to 'source3/client') diff --git a/source3/client/client.c b/source3/client/client.c index ef942c9867..d58644e09b 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -80,7 +80,7 @@ extern BOOL have_ip; extern int max_xmit; static int interpret_long_filename(int level,char *p,file_info *finfo); -static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir); +static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir, BOOL dirstoo); static int interpret_short_filename(char *p,file_info *finfo); static BOOL do_this_one(file_info *finfo); @@ -478,7 +478,7 @@ static void display_finfo(file_info *finfo) do a directory listing, calling fn on each file found. Use the TRANSACT2 call for long filenames ****************************************************************************/ -static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir) +static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir, BOOL dirstoo) { int max_matches = 512; int info_level = Protocol= PROTOCOL_LANMAN2) { - if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir) > 0) + if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir,dirstoo) > 0) return; } expand_mask(Mask,False); - do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir); + do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir,dirstoo); return; } @@ -973,8 +973,11 @@ static int interpret_long_filename(int level,char *p,file_info *finfo) /**************************************************************************** act on the files in a dir listing + + RJS, 4-Apr-1998, dirstoo added to allow caller to indicate that directories + should be processed as well. ****************************************************************************/ -static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir) +static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir, BOOL dirstoo) { if (!((finfo->mode & aDIR) == 0 && *fileselection && @@ -986,6 +989,11 @@ static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,B { pstring mask2; pstring sav_dir; + + if (fn && dirstoo && do_this_one(finfo)) { /* Do dirs, RJS */ + fn(finfo); + } + strcpy(sav_dir,cur_dir); strcat(cur_dir,finfo->name); strcat(cur_dir,"\\"); @@ -997,9 +1005,9 @@ static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,B strcat(mask2,"*"); if (longdir) - do_long_dir(inbuf,outbuf,mask2,attribute,fn,True); + do_long_dir(inbuf,outbuf,mask2,attribute,fn,True, dirstoo); else - do_dir(inbuf,outbuf,mask2,attribute,fn,True); + do_dir(inbuf,outbuf,mask2,attribute,fn,True, dirstoo); strcpy(cur_dir,sav_dir); } @@ -1038,7 +1046,7 @@ static void cmd_dir(char *inbuf,char *outbuf) strcat(mask,"*"); } - do_dir(inbuf,outbuf,mask,attribute,NULL,recurse); + do_dir(inbuf,outbuf,mask,attribute,NULL,recurse,False); do_dskattr(); @@ -1541,7 +1549,7 @@ static void do_mget(file_info *finfo) strcat(mget_mask,"*"); do_dir((char *)inbuf,(char *)outbuf, - mget_mask,aSYSTEM | aHIDDEN | aDIR,do_mget,False); + mget_mask,aSYSTEM | aHIDDEN | aDIR,do_mget,False, False); chdir(".."); strcpy(cur_dir,saved_curdir); free(inbuf);free(outbuf); @@ -1610,7 +1618,7 @@ static void cmd_mget(char *inbuf,char *outbuf) strcpy(mget_mask,p); else strcat(mget_mask,p); - do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False); + do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False,False); } if (! *mget_mask) @@ -1619,7 +1627,7 @@ static void cmd_mget(char *inbuf,char *outbuf) if(mget_mask[strlen(mget_mask)-1]!='\\') strcat(mget_mask,"\\"); strcat(mget_mask,"*"); - do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False); + do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False,False); } } @@ -2674,7 +2682,7 @@ static void cmd_del(char *inbuf,char *outbuf ) } strcat(mask,buf); - do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_del,False); + do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_del,False,False); } diff --git a/source3/client/clitar.c b/source3/client/clitar.c index 36cefeec55..130c5e7a27 100644 --- a/source3/client/clitar.c +++ b/source3/client/clitar.c @@ -18,10 +18,22 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* The following changes developed by Richard Sharpe for Canon Information + Systems Research Australia (CISRA) are Copyright (C) 1998 by CISRA and are + made available under the terms of the GPL as listed above: + + 1. Restore can now restore files with long file names + 2. Save now saves directory information so that we can restore + directory creation times + 3. tar now accepts both UNIX path names and DOS path names. I prefer + those lovely /'s to those UGLY \'s :-) + +*/ #include "includes.h" #include "clitar.h" +#include extern BOOL recurse; @@ -72,7 +84,8 @@ extern int Protocol; int blocksize=20; int tarhandle; -static void writetarheader(); +static void writetarheader(int f, char *aname, int size, time_t mtime, + char *amode, unsigned char ftype); static void do_atar(); static void do_tar(); static void oct_it(); @@ -97,12 +110,14 @@ static void unfixtarname(); Write a tar header to buffer ****************************************************************************/ static void writetarheader(int f, char *aname, int size, time_t mtime, - char *amode) + char *amode, unsigned char ftype) { union hblock hb; int i, chk, l; char *jp; + DEBUG(5, ("WriteTarHdr, Type = %c, Name = %s\n", ftype, aname)); + memset(hb.dummy, 0, sizeof(hb.dummy)); l=strlen(aname); @@ -114,7 +129,7 @@ static void writetarheader(int f, char *aname, int size, time_t mtime, DEBUG(0,("out of memory\n")); exit(1); } - writetarheader(f, "/./@LongLink", l+1, 0, " 0 \0"); + writetarheader(f, "/./@LongLink", l+1, 0, " 0 \0", 'L'); memset(b, 0, l+TBLOCK+100); fixtarname(b, aname, l+1); i = strlen(b)+1; @@ -138,12 +153,7 @@ static void writetarheader(int f, char *aname, int size, time_t mtime, oct_it((long) mtime, 13, hb.dbuf.mtime); memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum)); memset(hb.dbuf.linkname, 0, NAMSIZ); - if (strcmp("/./@LongLink", aname) == 0) { - /* we're doing a GNU tar long filename */ - hb.dbuf.linkflag='L'; - } else { - hb.dbuf.linkflag='0'; - } + hb.dbuf.linkflag=ftype; for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++); @@ -196,14 +206,21 @@ static long readtarheader(union hblock *hb, file_info *finfo, char *prefix) unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name, strlen(hb->dbuf.name) + 1); -/* can't handle links at present */ - if (hb->dbuf.linkflag != '0') { +/* can't handle some links at present */ + if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) { if (hb->dbuf.linkflag == 0) { DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n", finfo->name)); } else { - DEBUG(0, ("this tar file appears to contain some kind of link - ignoring\n")); - return -2; + if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */ + /* Do nothing here at the moment. do_tarput will handle this + as long as the longlink gets back to it, as it has to advance + the buffer pointer, etc */ + + } else { + DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n")); + return -2; + } } } @@ -264,7 +281,7 @@ static int dotarbuf(int f, char *b, int n) } /**************************************************************************** -Write a zeros to buffer / tape +Write zeros to buffer / tape ****************************************************************************/ static void dozerobuf(int f, int n) { @@ -275,6 +292,7 @@ static void dozerobuf(int f, int n) if (n+tp >= tbufsiz) { memset(tarbuf+tp, 0, tbufsiz-tp); + write(f, tarbuf, tbufsiz); memset(tarbuf, 0, (tp+=n-tbufsiz)); } @@ -292,7 +310,7 @@ static void initarbuf() { /* initialize tar buffer */ tbufsiz=blocksize*TBLOCK; - tarbuf=malloc(tbufsiz); + tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */ /* reset tar buffer pointer and tar file counter and total dumped */ tp=0; ntarf=0; ttarf=0; @@ -428,6 +446,70 @@ static int strslashcmp(char *s1, char *s2) /* * general smb utility functions */ +/********************************************************************** +do_setrtime, set time on a file or dir ... +**********************************************************************/ + +static int do_setrtime(char *fname, int mtime) +{ + char *inbuf, *outbuf, *p; + char *name; + + name = (char *)malloc(strlen(fname) + 1 + 1); + if (name == NULL) { + + DEBUG(0, ("Failed to allocate space while setting time on file: %s", fname)); + return False; + + } + + strcpy(name, fname); + strcpy(fname, "\\"); + strcat(fname, name); + + inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); + outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); + + if (!inbuf || !outbuf) { + + DEBUG(0, ("Could not allocate memory for inbuf or outbuf while changing time on: %s\n", fname)); + return False; + + } + + memset(outbuf, 0, smb_size); + set_message(outbuf, 8, 4 + strlen(fname), True); + CVAL(outbuf, smb_com) = SMBsetatr; + SSVAL(outbuf, smb_tid, cnum); + cli_setup_pkt(outbuf); + + SSVAL(outbuf, smb_vwv0, 0); + put_dos_date3(outbuf, smb_vwv1, mtime); + + p = smb_buf(outbuf); + *p++ = 4; + strcpy(p, fname); + p+= (strlen(fname)+1); + + *p++ = 4; + *p++ = 0; + + send_smb(Client, outbuf); + client_receive_smb(Client, inbuf, CLIENT_TIMEOUT); + + if (CVAL(inbuf,smb_rcls) != 0) + { + DEBUG(0,("%s setting attributes on file %s\n", + smb_errstr(inbuf), fname)); + free(inbuf);free(outbuf); + return(False); + } + + free(inbuf);free(outbuf); + return(True); + +} + /**************************************************************************** Set DOS file attributes ***************************************************************************/ @@ -499,7 +581,7 @@ static int do_setrattr(char *fname, int attr, int setit) cli_setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,attr); - + p = smb_buf(outbuf); *p++ = 4; strcpy(p,fname); @@ -531,7 +613,7 @@ static BOOL smbcreat(file_info finfo, int *fnum, char *inbuf, char *outbuf) char *p; /* *must* be called with buffer ready malloc'ed */ /* open remote file */ - + memset(outbuf,0,smb_size); set_message(outbuf,3,2 + strlen(finfo.name),True); CVAL(outbuf,smb_com) = SMBcreate; @@ -704,6 +786,8 @@ static BOOL ensurepath(char *fname, char *inbuf, char *outbuf) pstring partpath, ffname; char *p=fname, *basehack; + DEBUG(5, ( "Ensurepath called with: %s\n", fname)); + *partpath = 0; /* fname copied to ffname so can strtok */ @@ -766,7 +850,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1) { int fnum; uint32 nread=0; - char *p; + char *p, ftype; char *inbuf,*outbuf; file_info finfo; BOOL close_done = False; @@ -778,6 +862,8 @@ static void do_atar(char *rname,char *lname,file_info *finfo1) struct timeval tp_start; GetTimeOfDay(&tp_start); + ftype = '0'; /* An ordinary file ... */ + if (finfo1) finfo = *finfo1; else @@ -893,7 +979,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1) lname)); /* write a tar header, don't bother with mode - just set to 100644 */ - writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0"); + writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype); while (nread < finfo.size && !close_done) { @@ -1174,7 +1260,7 @@ static void do_tar(file_info *finfo) { pstring rname; - if (strequal(finfo->name,".") || strequal(finfo->name,"..")) + if (strequal(finfo->name,"..")) return; /* Is it on the exclude list ? */ @@ -1213,14 +1299,16 @@ static void do_tar(file_info *finfo) strcat(cur_dir,finfo->name); strcat(cur_dir,"\\"); + DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir)); + /* write a tar directory, don't bother with mode - just set it to * 40755 */ - writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0"); + writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5'); + ntarf++; /* Make sure we have a file on there */ strcpy(mtar_mask,cur_dir); strcat(mtar_mask,"*"); - - do_dir((char *)inbuf,(char *)outbuf,mtar_mask,attribute,do_tar,recurse); - strcpy(cur_dir,saved_curdir); + /* do_dir((char *)inbuf,(char *)outbuf,mtar_mask,attribute,do_tar,recurse,True); */ + strcpy(cur_dir,saved_curdir); free(inbuf);free(outbuf); } else @@ -1265,11 +1353,25 @@ static void unfixtarname(char *tptr, char *fp, int l) } } +/**************************************************************************** +Move to the next block in the buffer, which may mean read in another set of +blocks. +****************************************************************************/ +int next_block(char *tarbuf, char *bufferp, int bufsiz) +{ + int bufread, total = 0; + + for (bufread = read(tarhandle, tarbuf, bufsiz); total += bufread; total < bufsiz) { + + } + +} + static void do_tarput() { file_info finfo; int nread=0, bufread; - char *inbuf,*outbuf; + char *inbuf,*outbuf, *longname = NULL; int fsize=0; int fnum; struct timeval tp_start; @@ -1332,26 +1434,93 @@ static void do_tarput() do { if (!fsize) { - switch (readtarheader((union hblock *) bufferp, &finfo, cur_dir)) - { - case -2: /* something dodgy but not fatal about this */ - DEBUG(0, ("skipping %s...\n", finfo.name)); - bufferp+=TBLOCK; /* header - like a link */ - continue; - case -1: - DEBUG(0, ("abandoning restore\n")); - free(inbuf); free(outbuf); - return; - case 0: /* chksum is zero - we assume that one all zero - *header block will do for eof */ - DEBUG(0, - ("total of %d tar files restored to share\n", ntarf)); - free(inbuf); free(outbuf); - return; - default: - break; - } + int next_header = 1; /* Want at least one header */ + while (next_header) + { + if (bufferp >= endofbuffer) { + + bufread = read(tarhandle, tarbuf, tbufsiz); + bufferp = tarbuf; + + } + next_header = 0; /* Don't want the next one ... */ + switch (readtarheader((union hblock *) bufferp, &finfo, cur_dir)) + { + case -2: /* something dodgy but not fatal about this */ + DEBUG(0, ("skipping %s...\n", finfo.name)); + bufferp+=TBLOCK; /* header - like a link */ + continue; + case -1: + DEBUG(0, ("abandoning restore, -1 from readtarheader\n")); + free(inbuf); free(outbuf); + return; + case 0: /* chksum is zero - we assume that one all zero + *header block will do for eof */ + DEBUG(0, + ("total of %d tar files restored to share\n", ntarf)); + free(inbuf); free(outbuf); + return; + default: + break; + } + + /* If we have a longname left from the last time through, + copy it into finfo.name and free it. + + The size of a pstring is the limiting factor on filenames + and directory names now. The total pathname length must be + less than sizeof(pstring) - 1, which is currently 1023. */ + + if (longname != NULL) { + + strncpy(finfo.name, longname, sizeof(pstring) - 1); + free(longname); + longname = NULL; + + } + + /* Check if a long-link. We do this before the clip checking + because clip-checking should clip on real name - RJS */ + + if (((union hblock *)bufferp) -> dbuf.linkflag == 'L') { + + /* Skip this header, but pick up length, get the name and + fix the name and skip the name. Hmmm, what about end of + buffer??? */ + + longname = malloc(finfo.size + strlen(cur_dir) + 1); + if (longname == NULL) { + + DEBUG(0, ("could not allocate buffer of size %d for longname\n", + finfo.size + strlen(cur_dir) + 1) + ); + free(inbuf); free(outbuf); + return; + } + + bufferp += TBLOCK; /* Skip that longlink header */ + /* This needs restructuring ... */ + + if (bufferp >= endofbuffer) { + + bufread = read(tarhandle, tarbuf, tbufsiz); + + bufferp = tarbuf; + + } + + strncpy(longname, cur_dir, strlen(cur_dir)); + unfixtarname(longname+strlen(cur_dir), bufferp, finfo.size); + + /* Next rounds up to next TBLOCK and takes care of us being right + on a TBLOCK boundary */ + + bufferp += (((finfo.size - 1)/TBLOCK)+1)*TBLOCK; + next_header = 1; /* Force read of next header */ + + } + } tskip=clipn && (clipfind(cliplist, clipn, finfo.name) ^ tar_excl); if (tskip) { @@ -1371,17 +1540,32 @@ static void do_tarput() } } + DEBUG(5, ("do_tarput: File is: %s\n", finfo.name)); + if (finfo.mode & aDIR) { - if (!smbchkpath(finfo.name, inbuf, outbuf) - && !smbmkdir(finfo.name, inbuf, outbuf)) + if (!ensurepath(finfo.name, inbuf, outbuf)) +/* if (!smbchkpath(finfo.name, inbuf, outbuf) + && !smbmkdir(finfo.name, inbuf, outbuf))*/ { - DEBUG(0, ("abandoning restore\n")); + DEBUG(0, ("abandoning restore, problems ensuring path\n")); free(inbuf); free(outbuf); return; } else { + /* Now we update the creation date ... */ + + DEBUG(5, ("Updating creation date on %s\n", finfo.name)); + + if (!do_setrtime(finfo.name, finfo.mtime)) { + + DEBUG(0, ("Could not set time on file: %s\n", finfo.name)); + return; + + } + + ntarf++; bufferp+=TBLOCK; continue; } @@ -1397,9 +1581,17 @@ static void do_tarput() return; } - DEBUG(0,("restore tar file %s of size %d bytes\n", + DEBUG(0 ,("restore tar file %s of size %d bytes\n", finfo.name,finfo.size)); + if (!finfo.size) { + if (!smbshut(finfo, fnum, inbuf, outbuf)){ + DEBUG(0, ("Error closing remote file of length 0: %s\n", finfo.name)); + free(inbuf);free(outbuf); + return; + } + } + nread=0; if ((bufferp+=TBLOCK) >= endofbuffer) break; } /* if (!fsize) */ @@ -1430,7 +1622,7 @@ static void do_tarput() bufferp+=minichunk; nread+=minichunk; chunk-=minichunk; } - + if (nread>=fsize) { if (!smbshut(finfo, fnum, inbuf, outbuf)) @@ -1641,19 +1833,19 @@ int process_tar(char *inbuf, char *outbuf) strcpy(cur_dir, tarmac); *(strrchr(cur_dir, '\\')+1)='\0'; - do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse); + do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True); strcpy(cur_dir,saved_dir); } else { strcpy(tarmac, cur_dir); strcat(tarmac, cliplist[i]); - do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse); + do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True); } } } else { pstring mask; strcpy(mask,cur_dir); strcat(mask,"\\*"); - do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse); + do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse, True); } if (ntarf) dotareof(tarhandle); @@ -1774,8 +1966,38 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind) tar_excl=tar_clipfl!='X'; if (Optind+1=argc || !strcmp(argv[Optind], "-")) { /* Sets tar handle to either 0 or 1, as appropriate */ -- cgit