client/clitar.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    Tar Extensions
00004    Copyright (C) Ricky Poulten 1995-1998
00005    Copyright (C) Richard Sharpe 1998
00006    
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011    
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016    
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 */
00021 /* The following changes developed by Richard Sharpe for Canon Information
00022    Systems Research Australia (CISRA)
00023 
00024    1. Restore can now restore files with long file names
00025    2. Save now saves directory information so that we can restore 
00026       directory creation times
00027    3. tar now accepts both UNIX path names and DOS path names. I prefer
00028       those lovely /'s to those UGLY \'s :-)
00029    4. the files to exclude can be specified as a regular expression by adding
00030       an r flag to the other tar flags. Eg:
00031 
00032          -TcrX file.tar "*.(obj|exe)"
00033 
00034       will skip all .obj and .exe files
00035 */
00036 
00037 
00038 #include "includes.h"
00039 #include "clitar.h"
00040 #include "client/client_proto.h"
00041 
00042 static int clipfind(char **aret, int ret, char *tok);
00043 
00044 typedef struct file_info_struct file_info2;
00045 
00046 struct file_info_struct {
00047         SMB_OFF_T size;
00048         uint16 mode;
00049         uid_t uid;
00050         gid_t gid;
00051         /* These times are normally kept in GMT */
00052         struct timespec mtime_ts;
00053         struct timespec atime_ts;
00054         struct timespec ctime_ts;
00055         char *name;     /* This is dynamically allocate */
00056 
00057         file_info2 *next, *prev;  /* Used in the stack ... */
00058 };
00059 
00060 typedef struct {
00061         file_info2 *top;
00062         int items;
00063 } stack;
00064 
00065 #define SEPARATORS " \t\n\r"
00066 extern time_t newer_than;
00067 extern struct cli_state *cli;
00068 
00069 /* These defines are for the do_setrattr routine, to indicate
00070  * setting and reseting of file attributes in the function call */
00071 #define ATTRSET 1
00072 #define ATTRRESET 0
00073 
00074 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
00075 
00076 #ifndef CLIENT_TIMEOUT
00077 #define CLIENT_TIMEOUT (30*1000)
00078 #endif
00079 
00080 static char *tarbuf, *buffer_p;
00081 static int tp, ntarf, tbufsiz;
00082 static double ttarf;
00083 /* Incremental mode */
00084 static BOOL tar_inc=False;
00085 /* Reset archive bit */
00086 static BOOL tar_reset=False;
00087 /* Include / exclude mode (true=include, false=exclude) */
00088 static BOOL tar_excl=True;
00089 /* use regular expressions for search on file names */
00090 static BOOL tar_re_search=False;
00091 /* Do not dump anything, just calculate sizes */
00092 static BOOL dry_run=False;
00093 /* Dump files with System attribute */
00094 static BOOL tar_system=True;
00095 /* Dump files with Hidden attribute */
00096 static BOOL tar_hidden=True;
00097 /* Be noisy - make a catalogue */
00098 static BOOL tar_noisy=True;
00099 static BOOL tar_real_noisy=False;  /* Don't want to be really noisy by default */
00100 
00101 char tar_type='\0';
00102 static char **cliplist=NULL;
00103 static int clipn=0;
00104 static BOOL must_free_cliplist = False;
00105 
00106 extern file_info def_finfo;
00107 extern BOOL lowercase;
00108 extern uint16 cnum;
00109 extern BOOL readbraw_supported;
00110 extern int max_xmit;
00111 extern pstring cur_dir;
00112 extern int get_total_time_ms;
00113 extern int get_total_size;
00114 
00115 static int blocksize=20;
00116 static int tarhandle;
00117 
00118 static void writetarheader(int f,  const char *aname, SMB_BIG_UINT size, time_t mtime,
00119                            const char *amode, unsigned char ftype);
00120 static void do_atar(char *rname,char *lname,file_info *finfo1);
00121 static void do_tar(file_info *finfo);
00122 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
00123 static void fixtarname(char *tptr, const char *fp, size_t l);
00124 static int dotarbuf(int f, char *b, int n);
00125 static void dozerobuf(int f, int n);
00126 static void dotareof(int f);
00127 static void initarbuf(void);
00128 
00129 /* restore functions */
00130 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
00131 static long unoct(char *p, int ndgs);
00132 static void do_tarput(void);
00133 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
00134 
00135 /*
00136  * tar specific utitlities
00137  */
00138 
00139 /*******************************************************************
00140 Create  a string of size size+1 (for the null)
00141 *******************************************************************/
00142 
00143 static char *string_create_s(int size)
00144 {
00145         char *tmp;
00146 
00147         tmp = (char *)SMB_MALLOC(size+1);
00148 
00149         if (tmp == NULL) {
00150                 DEBUG(0, ("Out of memory in string_create_s\n"));
00151         }
00152 
00153         return(tmp);
00154 }
00155 
00156 /****************************************************************************
00157 Write a tar header to buffer
00158 ****************************************************************************/
00159 
00160 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
00161                            const char *amode, unsigned char ftype)
00162 {
00163         union hblock hb;
00164         int i, chk, l;
00165         char *jp;
00166 
00167         DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
00168 
00169         memset(hb.dummy, 0, sizeof(hb.dummy));
00170   
00171         l=strlen(aname);
00172         /* We will be prepending a '.' in fixtarheader so use +2 to
00173          * take care of the . and terminating zero. JRA.
00174          */
00175         if (l+2 >= NAMSIZ) {
00176                 /* write a GNU tar style long header */
00177                 char *b;
00178                 b = (char *)SMB_MALLOC(l+TBLOCK+100);
00179                 if (!b) {
00180                         DEBUG(0,("out of memory\n"));
00181                         exit(1);
00182                 }
00183                 writetarheader(f, "/./@LongLink", l+2, 0, "     0 \0", 'L');
00184                 memset(b, 0, l+TBLOCK+100);
00185                 fixtarname(b, aname, l+2);
00186                 i = strlen(b)+1;
00187                 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
00188                 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
00189                 SAFE_FREE(b);
00190         }
00191 
00192         fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
00193 
00194         if (lowercase)
00195                 strlower_m(hb.dbuf.name);
00196 
00197         /* write out a "standard" tar format header */
00198 
00199         hb.dbuf.name[NAMSIZ-1]='\0';
00200         safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
00201         oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
00202         oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
00203         oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
00204 #ifdef HAVE_LONGLONG
00205         if (size > (SMB_BIG_UINT)077777777777LL) {    
00206 #else
00207         if (size > (SMB_BIG_UINT)077777777777) {    
00208 #endif
00209 
00210                 /* This is a non-POSIX compatible extention to store files
00211                         greater than 8GB. */
00212 
00213                 memset(hb.dbuf.size, 0, 4);
00214                 hb.dbuf.size[0]=128;
00215                 for (i = 8, jp=(char*)&size; i; i--)
00216                         hb.dbuf.size[i+3] = *(jp++);
00217         }
00218         oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
00219         memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
00220         memset(hb.dbuf.linkname, 0, NAMSIZ);
00221         hb.dbuf.linkflag=ftype;
00222   
00223         for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
00224                 chk+=(0xFF & *jp++);
00225 
00226         oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
00227         hb.dbuf.chksum[6] = '\0';
00228 
00229         (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
00230 }
00231 
00232 /****************************************************************************
00233 Read a tar header into a hblock structure, and validate
00234 ***************************************************************************/
00235 
00236 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
00237 {
00238         long chk, fchk;
00239         int i;
00240         char *jp;
00241 
00242         /*
00243          * read in a "standard" tar format header - we're not that interested
00244          * in that many fields, though
00245          */
00246 
00247         /* check the checksum */
00248         for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
00249                 chk+=(0xFF & *jp++);
00250 
00251         if (chk == 0)
00252                 return chk;
00253 
00254         /* compensate for blanks in chksum header */
00255         for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
00256                 chk-=(0xFF & *jp++);
00257 
00258         chk += ' ' * sizeof(hb->dbuf.chksum);
00259 
00260         fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
00261 
00262         DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
00263                         chk, fchk, hb->dbuf.chksum));
00264 
00265         if (fchk != chk) {
00266                 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
00267                 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
00268                 return -1;
00269         }
00270 
00271         if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
00272                 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
00273                 return(-1);
00274         }
00275 
00276         safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
00277 
00278         /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
00279         unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
00280                 strlen(hb->dbuf.name) + 1, True);
00281 
00282         /* can't handle some links at present */
00283         if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
00284                 if (hb->dbuf.linkflag == 0) {
00285                         DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
00286                                 finfo->name));
00287                 } else { 
00288                         if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
00289                                 /* Do nothing here at the moment. do_tarput will handle this
00290                                         as long as the longlink gets back to it, as it has to advance 
00291                                         the buffer pointer, etc */
00292                         } else {
00293                                 DEBUG(0, ("this tar file appears to contain some kind \
00294 of link other than a GNUtar Longlink - ignoring\n"));
00295                                 return -2;
00296                         }
00297                 }
00298         }
00299     
00300         if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
00301                                 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
00302                 finfo->mode=aDIR;
00303         } else {
00304                 finfo->mode=0; /* we don't care about mode at the moment, we'll
00305                                 * just make it a regular file */
00306         }
00307 
00308         /*
00309          * Bug fix by richard@sj.co.uk
00310          *
00311          * REC: restore times correctly (as does tar)
00312          * We only get the modification time of the file; set the creation time
00313          * from the mod. time, and the access time to current time
00314          */
00315         finfo->mtime_ts = finfo->ctime_ts =
00316                 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
00317         finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
00318         finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
00319 
00320         return True;
00321 }
00322 
00323 /****************************************************************************
00324 Write out the tar buffer to tape or wherever
00325 ****************************************************************************/
00326 
00327 static int dotarbuf(int f, char *b, int n)
00328 {
00329         int fail=1, writ=n;
00330 
00331         if (dry_run) {
00332                 return writ;
00333         }
00334         /* This routine and the next one should be the only ones that do write()s */
00335         if (tp + n >= tbufsiz) {
00336                 int diff;
00337 
00338                 diff=tbufsiz-tp;
00339                 memcpy(tarbuf + tp, b, diff);
00340                 fail=fail && (1+write(f, tarbuf, tbufsiz));
00341                 n-=diff;
00342                 b+=diff;
00343                 tp=0;
00344 
00345                 while (n >= tbufsiz) {
00346                         fail=fail && (1 + write(f, b, tbufsiz));
00347                         n-=tbufsiz;
00348                         b+=tbufsiz;
00349                 }
00350         }
00351 
00352         if (n>0) {
00353                 memcpy(tarbuf+tp, b, n);
00354                 tp+=n;
00355         }
00356 
00357         return(fail ? writ : 0);
00358 }
00359 
00360 /****************************************************************************
00361 Write zeros to buffer / tape
00362 ****************************************************************************/
00363 
00364 static void dozerobuf(int f, int n)
00365 {
00366         /* short routine just to write out n zeros to buffer -
00367          * used to round files to nearest block
00368          * and to do tar EOFs */
00369 
00370         if (dry_run)
00371                 return;
00372   
00373         if (n+tp >= tbufsiz) {
00374                 memset(tarbuf+tp, 0, tbufsiz-tp);
00375                 write(f, tarbuf, tbufsiz);
00376                 memset(tarbuf, 0, (tp+=n-tbufsiz));
00377         } else {
00378                 memset(tarbuf+tp, 0, n);
00379                 tp+=n;
00380         }
00381 }
00382 
00383 /****************************************************************************
00384 Malloc tape buffer
00385 ****************************************************************************/
00386 
00387 static void initarbuf(void)
00388 {
00389         /* initialize tar buffer */
00390         tbufsiz=blocksize*TBLOCK;
00391         tarbuf=(char *)SMB_MALLOC(tbufsiz);      /* FIXME: We might not get the buffer */
00392 
00393         /* reset tar buffer pointer and tar file counter and total dumped */
00394         tp=0; ntarf=0; ttarf=0;
00395 }
00396 
00397 /****************************************************************************
00398 Write two zero blocks at end of file
00399 ****************************************************************************/
00400 
00401 static void dotareof(int f)
00402 {
00403         SMB_STRUCT_STAT stbuf;
00404         /* Two zero blocks at end of file, write out full buffer */
00405 
00406         if (dry_run)
00407                 return;
00408 
00409         (void) dozerobuf(f, TBLOCK);
00410         (void) dozerobuf(f, TBLOCK);
00411 
00412         if (sys_fstat(f, &stbuf) == -1) {
00413                 DEBUG(0, ("Couldn't stat file handle\n"));
00414                 return;
00415         }
00416 
00417         /* Could be a pipe, in which case S_ISREG should fail,
00418                 * and we should write out at full size */
00419         if (tp > 0)
00420                 write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
00421 }
00422 
00423 /****************************************************************************
00424 (Un)mangle DOS pathname, make nonabsolute
00425 ****************************************************************************/
00426 
00427 static void fixtarname(char *tptr, const char *fp, size_t l)
00428 {
00429         /* add a '.' to start of file name, convert from ugly dos \'s in path
00430          * to lovely unix /'s :-} */
00431         *tptr++='.';
00432         l--;
00433 
00434         StrnCpy(tptr, fp, l-1);
00435         string_replace(tptr, '\\', '/');
00436 }
00437 
00438 /****************************************************************************
00439 Convert from decimal to octal string
00440 ****************************************************************************/
00441 
00442 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
00443 {
00444         /* Converts long to octal string, pads with leading zeros */
00445 
00446         /* skip final null, but do final space */
00447         --ndgs;
00448         p[--ndgs] = ' ';
00449  
00450         /* Loop does at least one digit */
00451         do {
00452                 p[--ndgs] = '0' + (char) (value & 7);
00453                 value >>= 3;
00454         } while (ndgs > 0 && value != 0);
00455  
00456         /* Do leading zeros */
00457         while (ndgs > 0)
00458                 p[--ndgs] = '0';
00459 }
00460 
00461 /****************************************************************************
00462 Convert from octal string to long
00463 ***************************************************************************/
00464 
00465 static long unoct(char *p, int ndgs)
00466 {
00467         long value=0;
00468         /* Converts octal string to long, ignoring any non-digit */
00469 
00470         while (--ndgs) {
00471                 if (isdigit((int)*p))
00472                         value = (value << 3) | (long) (*p - '0');
00473 
00474                 p++;
00475         }
00476 
00477         return value;
00478 }
00479 
00480 /****************************************************************************
00481 Compare two strings in a slash insensitive way, allowing s1 to match s2 
00482 if s1 is an "initial" string (up to directory marker).  Thus, if s2 is 
00483 a file in any subdirectory of s1, declare a match.
00484 ***************************************************************************/
00485 
00486 static int strslashcmp(char *s1, char *s2)
00487 {
00488         char *s1_0=s1;
00489 
00490         while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
00491                                 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
00492                 s1++; s2++;
00493         }
00494 
00495         /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" 
00496                 string of s2.
00497         */
00498         if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
00499                 return 0;
00500 
00501         /* ignore trailing slash on s1 */
00502         if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
00503                 return 0;
00504 
00505         /* check for s1 is an "initial" string of s2 */
00506         if ((*s2 == '/' || *s2 == '\\') && !*s1)
00507                 return 0;
00508 
00509         return *s1-*s2;
00510 }
00511 
00512 /****************************************************************************
00513 Ensure a remote path exists (make if necessary)
00514 ***************************************************************************/
00515 
00516 static BOOL ensurepath(char *fname)
00517 {
00518         /* *must* be called with buffer ready malloc'ed */
00519         /* ensures path exists */
00520 
00521         char *partpath, *ffname;
00522         char *p=fname, *basehack;
00523 
00524         DEBUG(5, ( "Ensurepath called with: %s\n", fname));
00525 
00526         partpath = string_create_s(strlen(fname));
00527         ffname = string_create_s(strlen(fname));
00528 
00529         if ((partpath == NULL) || (ffname == NULL)){
00530                 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
00531                 SAFE_FREE(partpath);
00532                 SAFE_FREE(ffname);
00533                 return(False);
00534         }
00535 
00536         *partpath = 0;
00537 
00538         /* fname copied to ffname so can strtok */
00539 
00540         safe_strcpy(ffname, fname, strlen(fname));
00541 
00542         /* do a `basename' on ffname, so don't try and make file name directory */
00543         if ((basehack=strrchr_m(ffname, '\\')) == NULL)
00544                 return True;
00545         else
00546                 *basehack='\0';
00547 
00548         p=strtok(ffname, "\\");
00549 
00550         while (p) {
00551                 safe_strcat(partpath, p, strlen(fname) + 1);
00552 
00553                 if (!cli_chkpath(cli, partpath)) {
00554                         if (!cli_mkdir(cli, partpath)) {
00555                                 DEBUG(0, ("Error mkdirhiering\n"));
00556                                 return False;
00557                         } else {
00558                                 DEBUG(3, ("mkdirhiering %s\n", partpath));
00559                         }
00560                 }
00561 
00562                 safe_strcat(partpath, "\\", strlen(fname) + 1);
00563                 p = strtok(NULL,"/\\");
00564         }
00565 
00566         return True;
00567 }
00568 
00569 static int padit(char *buf, SMB_BIG_UINT bufsize, SMB_BIG_UINT padsize)
00570 {
00571         int berr= 0;
00572         int bytestowrite;
00573   
00574         DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
00575         memset(buf, 0, (size_t)bufsize);
00576         while( !berr && padsize > 0 ) {
00577                 bytestowrite= (int)MIN(bufsize, padsize);
00578                 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
00579                 padsize -= bytestowrite;
00580         }
00581   
00582         return berr;
00583 }
00584 
00585 static void do_setrattr(char *name, uint16 attr, int set)
00586 {
00587         uint16 oldattr;
00588 
00589         if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
00590 
00591         if (set == ATTRSET) {
00592                 attr |= oldattr;
00593         } else {
00594                 attr = oldattr & ~attr;
00595         }
00596 
00597         if (!cli_setatr(cli, name, attr, 0)) {
00598                 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
00599         }
00600 }
00601 
00602 /****************************************************************************
00603 append one remote file to the tar file
00604 ***************************************************************************/
00605 
00606 static void do_atar(char *rname,char *lname,file_info *finfo1)
00607 {
00608         int fnum;
00609         SMB_BIG_UINT nread=0;
00610         char ftype;
00611         file_info2 finfo;
00612         BOOL shallitime=True;
00613         char data[65520];
00614         int read_size = 65520;
00615         int datalen=0;
00616 
00617         struct timeval tp_start;
00618 
00619         GetTimeOfDay(&tp_start);
00620 
00621         ftype = '0'; /* An ordinary file ... */
00622 
00623         if (finfo1) {
00624                 finfo.size  = finfo1 -> size;
00625                 finfo.mode  = finfo1 -> mode;
00626                 finfo.uid   = finfo1 -> uid;
00627                 finfo.gid   = finfo1 -> gid;
00628                 finfo.mtime_ts = finfo1 -> mtime_ts;
00629                 finfo.atime_ts = finfo1 -> atime_ts;
00630                 finfo.ctime_ts = finfo1 -> ctime_ts;
00631                 finfo.name  = finfo1 -> name;
00632         } else {
00633                 finfo.size  = def_finfo.size;
00634                 finfo.mode  = def_finfo.mode;
00635                 finfo.uid   = def_finfo.uid;
00636                 finfo.gid   = def_finfo.gid;
00637                 finfo.mtime_ts = def_finfo.mtime_ts;
00638                 finfo.atime_ts = def_finfo.atime_ts;
00639                 finfo.ctime_ts = def_finfo.ctime_ts;
00640                 finfo.name  = def_finfo.name;
00641         }
00642 
00643         if (dry_run) {
00644                 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
00645                                 (double)finfo.size));
00646                 shallitime=0;
00647                 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
00648                 ntarf++;
00649                 return;
00650         }
00651 
00652         fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
00653 
00654         clean_name(rname);
00655 
00656         if (fnum == -1) {
00657                 DEBUG(0,("%s opening remote file %s (%s)\n",
00658                                 cli_errstr(cli),rname, cur_dir));
00659                 return;
00660         }
00661 
00662         finfo.name = string_create_s(strlen(rname));
00663         if (finfo.name == NULL) {
00664                 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
00665                 return;
00666         }
00667 
00668         safe_strcpy(finfo.name,rname, strlen(rname));
00669         if (!finfo1) {
00670                 time_t atime, mtime;
00671                 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &atime, &mtime)) {
00672                         DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
00673                         return;
00674                 }
00675                 finfo.atime_ts = convert_time_t_to_timespec(atime);
00676                 finfo.mtime_ts = convert_time_t_to_timespec(mtime);
00677                 finfo.ctime_ts = finfo.mtime_ts;
00678         }
00679 
00680         DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
00681 
00682         if (tar_inc && !(finfo.mode & aARCH)) {
00683                 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
00684                 shallitime=0;
00685         } else if (!tar_system && (finfo.mode & aSYSTEM)) {
00686                 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
00687                 shallitime=0;
00688         } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
00689                 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
00690                 shallitime=0;
00691         } else {
00692                 BOOL wrote_tar_header = False;
00693 
00694                 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
00695                         finfo.name, (double)finfo.size, lname));
00696       
00697                 do {
00698               
00699                         DEBUG(3,("nread=%.0f\n",(double)nread));
00700               
00701                         datalen = cli_read(cli, fnum, data, nread, read_size);
00702               
00703                         if (datalen == -1) {
00704                                 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
00705                                 break;
00706                         }
00707               
00708                         nread += datalen;
00709 
00710                         /* Only if the first read succeeds, write out the tar header. */
00711                         if (!wrote_tar_header) {
00712                                 /* write a tar header, don't bother with mode - just set to 100644 */
00713                                 writetarheader(tarhandle, rname, finfo.size,
00714                                         finfo.mtime_ts.tv_sec, "100644 \0", ftype);
00715                                 wrote_tar_header = True;
00716                         }
00717 
00718                         /* if file size has increased since we made file size query, truncate
00719                                 read so tar header for this file will be correct.
00720                         */
00721 
00722                         if (nread > finfo.size) {
00723                                 datalen -= nread - finfo.size;
00724                                 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
00725                                                         finfo.name, (double)finfo.size));
00726                         }
00727 
00728                         /* add received bits of file to buffer - dotarbuf will
00729                         * write out in 512 byte intervals */
00730 
00731                         if (dotarbuf(tarhandle,data,datalen) != datalen) {
00732                                 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
00733                                 break;
00734                         }
00735               
00736                         if ( (datalen == 0) && (finfo.size != 0) ) {
00737                                 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
00738                                 break;
00739                         }
00740 
00741                         datalen=0;
00742                 } while ( nread < finfo.size );
00743 
00744                 if (wrote_tar_header) {
00745                         /* pad tar file with zero's if we couldn't get entire file */
00746                         if (nread < finfo.size) {
00747                                 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
00748                                                         (double)finfo.size, (int)nread));
00749                                 if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
00750                                         DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
00751                         }
00752 
00753                         /* round tar file to nearest block */
00754                         if (finfo.size % TBLOCK)
00755                                 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
00756       
00757                         ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
00758                         ntarf++;
00759                 } else {
00760                         DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
00761                         shallitime=0;
00762                 }
00763         }
00764   
00765         cli_close(cli, fnum);
00766 
00767         if (shallitime) {
00768                 struct timeval tp_end;
00769                 int this_time;
00770 
00771                 /* if shallitime is true then we didn't skip */
00772                 if (tar_reset && !dry_run)
00773                         (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
00774       
00775                 GetTimeOfDay(&tp_end);
00776                 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
00777                 get_total_time_ms += this_time;
00778                 get_total_size += finfo.size;
00779 
00780                 if (tar_noisy) {
00781                         DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
00782                                 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
00783                                 finfo.name));
00784                 }
00785 
00786                 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
00787                 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
00788                                 finfo.size / MAX(0.001, (1.024*this_time)),
00789                                 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
00790         }
00791 }
00792 
00793 /****************************************************************************
00794 Append single file to tar file (or not)
00795 ***************************************************************************/
00796 
00797 static void do_tar(file_info *finfo)
00798 {
00799         pstring rname;
00800 
00801         if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
00802                 return;
00803 
00804         /* Is it on the exclude list ? */
00805         if (!tar_excl && clipn) {
00806                 pstring exclaim;
00807 
00808                 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
00809 
00810                 pstrcpy(exclaim, cur_dir);
00811                 *(exclaim+strlen(exclaim)-1)='\0';
00812 
00813                 pstrcat(exclaim, "\\");
00814                 pstrcat(exclaim, finfo->name);
00815 
00816                 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
00817 
00818                 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
00819                                 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
00820                         DEBUG(3,("Skipping file %s\n", exclaim));
00821                         return;
00822                 }
00823         }
00824 
00825         if (finfo->mode & aDIR) {
00826                 pstring saved_curdir;
00827                 pstring mtar_mask;
00828 
00829                 pstrcpy(saved_curdir, cur_dir);
00830 
00831                 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
00832 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
00833                         (int)sizeof(cur_dir), (int)strlen(cur_dir),
00834                         (int)strlen(finfo->name), finfo->name, cur_dir));
00835 
00836                 pstrcat(cur_dir,finfo->name);
00837                 pstrcat(cur_dir,"\\");
00838 
00839                 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
00840 
00841                 /* write a tar directory, don't bother with mode - just set it to
00842                         * 40755 */
00843                 writetarheader(tarhandle, cur_dir, 0, finfo->mtime_ts.tv_sec, "040755 \0", '5');
00844                 if (tar_noisy) {
00845                         DEBUG(0,("                directory %s\n", cur_dir));
00846                 }
00847                 ntarf++;  /* Make sure we have a file on there */
00848                 pstrcpy(mtar_mask,cur_dir);
00849                 pstrcat(mtar_mask,"*");
00850                 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
00851                 do_list(mtar_mask, attribute, do_tar, False, True);
00852                 pstrcpy(cur_dir,saved_curdir);
00853         } else {
00854                 pstrcpy(rname,cur_dir);
00855                 pstrcat(rname,finfo->name);
00856                 do_atar(rname,finfo->name,finfo);
00857         }
00858 }
00859 
00860 /****************************************************************************
00861 Convert from UNIX to DOS file names
00862 ***************************************************************************/
00863 
00864 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
00865 {
00866         /* remove '.' from start of file name, convert from unix /'s to
00867          * dos \'s in path. Kill any absolute path names. But only if first!
00868          */
00869 
00870         DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
00871 
00872         if (first) {
00873                 if (*fp == '.') {
00874                         fp++;
00875                         l--;
00876                 }
00877                 if (*fp == '\\' || *fp == '/') {
00878                         fp++;
00879                         l--;
00880                 }
00881         }
00882 
00883         safe_strcpy(tptr, fp, l);
00884         string_replace(tptr, '/', '\\');
00885 }
00886 
00887 /****************************************************************************
00888 Move to the next block in the buffer, which may mean read in another set of
00889 blocks. FIXME, we should allow more than one block to be skipped.
00890 ****************************************************************************/
00891 
00892 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
00893 {
00894         int bufread, total = 0;
00895 
00896         DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
00897         *bufferp += TBLOCK;
00898         total = TBLOCK;
00899 
00900         if (*bufferp >= (ltarbuf + bufsiz)) {
00901 
00902                 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
00903 
00904                 /*
00905                  * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
00906                  * Fixes bug where read can return short if coming from
00907                  * a pipe.
00908                  */
00909 
00910                 bufread = read(tarhandle, ltarbuf, bufsiz);
00911                 total = bufread;
00912 
00913                 while (total < bufsiz) {
00914                         if (bufread < 0) { /* An error, return false */
00915                                 return (total > 0 ? -2 : bufread);
00916                         }
00917                         if (bufread == 0) {
00918                                 if (total <= 0) {
00919                                         return -2;
00920                                 }
00921                                 break;
00922                         }
00923                         bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
00924                         total += bufread;
00925                 }
00926 
00927                 DEBUG(5, ("Total bytes read ... %i\n", total));
00928 
00929                 *bufferp = ltarbuf;
00930         }
00931 
00932         return(total);
00933 }
00934 
00935 /* Skip a file, even if it includes a long file name? */
00936 static int skip_file(int skipsize)
00937 {
00938         int dsize = skipsize;
00939 
00940         DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
00941 
00942         /* FIXME, we should skip more than one block at a time */
00943 
00944         while (dsize > 0) {
00945                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
00946                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
00947                         return(False);
00948                 }
00949                 dsize -= TBLOCK;
00950         }
00951 
00952         return(True);
00953 }
00954 
00955 /*************************************************************
00956  Get a file from the tar file and store it.
00957  When this is called, tarbuf already contains the first
00958  file block. This is a bit broken & needs fixing.
00959 **************************************************************/
00960 
00961 static int get_file(file_info2 finfo)
00962 {
00963         int fnum = -1, pos = 0, dsize = 0, bpos = 0;
00964         SMB_BIG_UINT rsize = 0;
00965 
00966         DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
00967 
00968         if (ensurepath(finfo.name) && 
00969                         (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
00970                 DEBUG(0, ("abandoning restore\n"));
00971                 return(False);
00972         }
00973 
00974         /* read the blocks from the tar file and write to the remote file */
00975 
00976         rsize = finfo.size;  /* This is how much to write */
00977 
00978         while (rsize > 0) {
00979 
00980                 /* We can only write up to the end of the buffer */
00981                 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
00982                 dsize = MIN(dsize, rsize);  /* Should be only what is left */
00983                 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
00984 
00985                 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
00986                         DEBUG(0, ("Error writing remote file\n"));
00987                         return 0;
00988                 }
00989 
00990                 rsize -= dsize;
00991                 pos += dsize;
00992 
00993                 /* Now figure out how much to move in the buffer */
00994 
00995                 /* FIXME, we should skip more than one block at a time */
00996 
00997                 /* First, skip any initial part of the part written that is left over */
00998                 /* from the end of the first TBLOCK                                   */
00999 
01000                 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
01001                         dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
01002                         bpos = 0;
01003 
01004                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
01005                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
01006                                 return False;
01007                         }
01008                 }
01009 
01010                 /*
01011                  * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
01012                  * If the file being extracted is an exact multiple of
01013                  * TBLOCK bytes then we don't want to extract the next
01014                  * block from the tarfile here, as it will be done in
01015                  * the caller of get_file().
01016                  */
01017 
01018                 while (((rsize != 0) && (dsize >= TBLOCK)) ||
01019                                 ((rsize == 0) && (dsize > TBLOCK))) {
01020 
01021                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
01022                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
01023                                 return False;
01024                         }
01025 
01026                         dsize -= TBLOCK;
01027                 }
01028                 bpos = dsize;
01029         }
01030 
01031         /* Now close the file ... */
01032 
01033         if (!cli_close(cli, fnum)) {
01034                 DEBUG(0, ("Error closing remote file\n"));
01035                 return(False);
01036         }
01037 
01038         /* Now we update the creation date ... */
01039         DEBUG(5, ("Updating creation date on %s\n", finfo.name));
01040 
01041         if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec)) {
01042                 if (tar_real_noisy) {
01043                         DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
01044                         /*return(False); */ /* Ignore, as Win95 does not allow changes */
01045                 }
01046         }
01047 
01048         ntarf++;
01049         DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
01050         return(True);
01051 }
01052 
01053 /* Create a directory.  We just ensure that the path exists and return as there
01054    is no file associated with a directory 
01055 */
01056 static int get_dir(file_info2 finfo)
01057 {
01058         DEBUG(0, ("restore directory %s\n", finfo.name));
01059 
01060         if (!ensurepath(finfo.name)) {
01061                 DEBUG(0, ("Problems creating directory\n"));
01062                 return(False);
01063         }
01064         ntarf++;
01065         return(True);
01066 }
01067 
01068 /* Get a file with a long file name ... first file has file name, next file 
01069    has the data. We only want the long file name, as the loop in do_tarput
01070    will deal with the rest.
01071 */
01072 static char *get_longfilename(file_info2 finfo)
01073 {
01074         /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
01075          * header call. */
01076         int namesize = finfo.size + strlen(cur_dir) + 2;
01077         char *longname = (char *)SMB_MALLOC(namesize);
01078         int offset = 0, left = finfo.size;
01079         BOOL first = True;
01080 
01081         DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
01082         DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
01083 
01084         if (longname == NULL) {
01085                 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
01086                 return(NULL);
01087         }
01088 
01089         /* First, add cur_dir to the long file name */
01090 
01091         if (strlen(cur_dir) > 0) {
01092                 strncpy(longname, cur_dir, namesize);
01093                 offset = strlen(cur_dir);
01094         }
01095 
01096         /* Loop through the blocks picking up the name */
01097 
01098         while (left > 0) {
01099                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
01100                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
01101                         SAFE_FREE(longname);
01102                         return(NULL);
01103                 }
01104 
01105                 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
01106                 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
01107 
01108                 offset += TBLOCK;
01109                 left -= TBLOCK;
01110         }
01111 
01112         return(longname);
01113 }
01114 
01115 static void do_tarput(void)
01116 {
01117         file_info2 finfo;
01118         struct timeval tp_start;
01119         char *longfilename = NULL, linkflag;
01120         int skip = False;
01121 
01122         ZERO_STRUCT(finfo);
01123 
01124         GetTimeOfDay(&tp_start);
01125         DEBUG(5, ("RJS do_tarput called ...\n"));
01126 
01127         buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
01128 
01129         /* Now read through those files ... */
01130         while (True) {
01131                 /* Get us to the next block, or the first block first time around */
01132                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
01133                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
01134                         SAFE_FREE(longfilename);
01135                         return;
01136                 }
01137 
01138                 DEBUG(5, ("Reading the next header ...\n"));
01139 
01140                 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
01141                         case -2:    /* Hmm, not good, but not fatal */
01142                                 DEBUG(0, ("Skipping %s...\n", finfo.name));
01143                                 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
01144                                         DEBUG(0, ("Short file, bailing out...\n"));
01145                                         return;
01146                                 }
01147                                 break;
01148 
01149                         case -1:
01150                                 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
01151                                 return;
01152 
01153                         case 0: /* chksum is zero - looks like an EOF */
01154                                 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
01155                                 return;        /* Hmmm, bad here ... */
01156 
01157                         default: 
01158                                 /* No action */
01159                                 break;
01160                 }
01161 
01162                 /* Now, do we have a long file name? */
01163                 if (longfilename != NULL) {
01164                         SAFE_FREE(finfo.name);   /* Free the space already allocated */
01165                         finfo.name = longfilename;
01166                         longfilename = NULL;
01167                 }
01168 
01169                 /* Well, now we have a header, process the file ...            */
01170                 /* Should we skip the file? We have the long name as well here */
01171                 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
01172                                         (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
01173 
01174                 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
01175                 if (skip) {
01176                         skip_file(finfo.size);
01177                         continue;
01178                 }
01179 
01180                 /* We only get this far if we should process the file */
01181                 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
01182                 switch (linkflag) {
01183                         case '0':  /* Should use symbolic names--FIXME */
01184                                 /* 
01185                                  * Skip to the next block first, so we can get the file, FIXME, should
01186                                  * be in get_file ...
01187                                  * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
01188                                  * Fixes bug where file size in tarfile is zero.
01189                                  */
01190                                 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
01191                                         DEBUG(0, ("Short file, bailing out...\n"));
01192                                         return;
01193                                 }
01194                                 if (!get_file(finfo)) {
01195                                         DEBUG(0, ("Abandoning restore\n"));
01196                                         return;
01197                                 }
01198                                 break;
01199                         case '5':
01200                                 if (!get_dir(finfo)) {
01201                                         DEBUG(0, ("Abandoning restore \n"));
01202                                         return;
01203                                 }
01204                                 break;
01205                         case 'L':
01206                                 SAFE_FREE(longfilename);
01207                                 longfilename = get_longfilename(finfo);
01208                                 if (!longfilename) {
01209                                         DEBUG(0, ("abandoning restore\n"));
01210                                         return;
01211                                 }
01212                                 DEBUG(5, ("Long file name: %s\n", longfilename));
01213                                 break;
01214 
01215                         default:
01216                                 skip_file(finfo.size);  /* Don't handle these yet */
01217                                 break;
01218                 }
01219         }
01220 }
01221 
01222 /*
01223  * samba interactive commands
01224  */
01225 
01226 /****************************************************************************
01227 Blocksize command
01228 ***************************************************************************/
01229 
01230 int cmd_block(void)
01231 {
01232         fstring buf;
01233         int block;
01234 
01235         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
01236                 DEBUG(0, ("blocksize <n>\n"));
01237                 return 1;
01238         }
01239 
01240         block=atoi(buf);
01241         if (block < 0 || block > 65535) {
01242                 DEBUG(0, ("blocksize out of range"));
01243                 return 1;
01244         }
01245 
01246         blocksize=block;
01247         DEBUG(2,("blocksize is now %d\n", blocksize));
01248 
01249         return 0;
01250 }
01251 
01252 /****************************************************************************
01253 command to set incremental / reset mode
01254 ***************************************************************************/
01255 
01256 int cmd_tarmode(void)
01257 {
01258         fstring buf;
01259 
01260         while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
01261                 if (strequal(buf, "full"))
01262                         tar_inc=False;
01263                 else if (strequal(buf, "inc"))
01264                         tar_inc=True;
01265                 else if (strequal(buf, "reset"))
01266                         tar_reset=True;
01267                 else if (strequal(buf, "noreset"))
01268                         tar_reset=False;
01269                 else if (strequal(buf, "system"))
01270                         tar_system=True;
01271                 else if (strequal(buf, "nosystem"))
01272                         tar_system=False;
01273                 else if (strequal(buf, "hidden"))
01274                         tar_hidden=True;
01275                 else if (strequal(buf, "nohidden"))
01276                         tar_hidden=False;
01277                 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
01278                         tar_noisy=True;
01279                 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
01280                         tar_noisy=False;
01281                 else
01282                         DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
01283         }
01284 
01285         DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
01286                         tar_inc ? "incremental" : "full",
01287                         tar_system ? "system" : "nosystem",
01288                         tar_hidden ? "hidden" : "nohidden",
01289                         tar_reset ? "reset" : "noreset",
01290                         tar_noisy ? "verbose" : "quiet"));
01291         return 0;
01292 }
01293 
01294 /****************************************************************************
01295 Feeble attrib command
01296 ***************************************************************************/
01297 
01298 int cmd_setmode(void)
01299 {
01300         char *q;
01301         fstring buf;
01302         pstring fname;
01303         uint16 attra[2];
01304         int direct=1;
01305 
01306         attra[0] = attra[1] = 0;
01307 
01308         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
01309                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
01310                 return 1;
01311         }
01312 
01313         pstrcpy(fname, cur_dir);
01314         pstrcat(fname, buf);
01315 
01316         while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
01317                 q=buf;
01318 
01319                 while(*q) {
01320                         switch (*q++) {
01321                                 case '+':
01322                                         direct=1;
01323                                         break;
01324                                 case '-':
01325                                         direct=0;
01326                                         break;
01327                                 case 'r':
01328                                         attra[direct]|=aRONLY;
01329                                         break;
01330                                 case 'h':
01331                                         attra[direct]|=aHIDDEN;
01332                                         break;
01333                                 case 's':
01334                                         attra[direct]|=aSYSTEM;
01335                                         break;
01336                                 case 'a':
01337                                         attra[direct]|=aARCH;
01338                                         break;
01339                                 default:
01340                                         DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
01341                                         return 1;
01342                         }
01343                 }
01344         }
01345 
01346         if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
01347                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
01348                 return 1;
01349         }
01350 
01351         DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
01352         do_setrattr(fname, attra[ATTRSET], ATTRSET);
01353         do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
01354         return 0;
01355 }
01356 
01357 /****************************************************************************
01358 Principal command for creating / extracting
01359 ***************************************************************************/
01360 
01361 int cmd_tar(void)
01362 {
01363         fstring buf;
01364         char **argl = NULL;
01365         int argcl = 0;
01366         int ret;
01367 
01368         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
01369                 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
01370                 return 1;
01371         }
01372 
01373         argl=toktocliplist(&argcl, NULL);
01374         if (!tar_parseargs(argcl, argl, buf, 0))
01375                 return 1;
01376 
01377         ret = process_tar();
01378         SAFE_FREE(argl);
01379         return ret;
01380 }
01381 
01382 /****************************************************************************
01383 Command line (option) version
01384 ***************************************************************************/
01385 
01386 int process_tar(void)
01387 {
01388         int rc = 0;
01389         initarbuf();
01390         switch(tar_type) {
01391                 case 'x':
01392 
01393 #if 0
01394                         do_tarput2();
01395 #else
01396                         do_tarput();
01397 #endif
01398                         SAFE_FREE(tarbuf);
01399                         close(tarhandle);
01400                         break;
01401                 case 'r':
01402                 case 'c':
01403                         if (clipn && tar_excl) {
01404                                 int i;
01405                                 pstring tarmac;
01406 
01407                                 for (i=0; i<clipn; i++) {
01408                                         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
01409 
01410                                         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
01411                                                 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
01412                                         }
01413         
01414                                         if (strrchr_m(cliplist[i], '\\')) {
01415                                                 pstring saved_dir;
01416           
01417                                                 pstrcpy(saved_dir, cur_dir);
01418           
01419                                                 if (*cliplist[i]=='\\') {
01420                                                         pstrcpy(tarmac, cliplist[i]);
01421                                                 } else {
01422                                                         pstrcpy(tarmac, cur_dir);
01423                                                         pstrcat(tarmac, cliplist[i]);
01424                                                 }
01425                                                 pstrcpy(cur_dir, tarmac);
01426                                                 *(strrchr_m(cur_dir, '\\')+1)='\0';
01427 
01428                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
01429                                                 do_list(tarmac,attribute,do_tar, False, True);
01430                                                 pstrcpy(cur_dir,saved_dir);
01431                                         } else {
01432                                                 pstrcpy(tarmac, cur_dir);
01433                                                 pstrcat(tarmac, cliplist[i]);
01434                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
01435                                                 do_list(tarmac,attribute,do_tar, False, True);
01436                                         }
01437                                 }
01438                         } else {
01439                                 pstring mask;
01440                                 pstrcpy(mask,cur_dir);
01441                                 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
01442                                 pstrcat(mask,"\\*");
01443                                 do_list(mask,attribute,do_tar,False, True);
01444                         }
01445     
01446                         if (ntarf)
01447                                 dotareof(tarhandle);
01448                         close(tarhandle);
01449                         SAFE_FREE(tarbuf);
01450     
01451                         DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
01452                         DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
01453                         break;
01454         }
01455 
01456         if (must_free_cliplist) {
01457                 int i;
01458                 for (i = 0; i < clipn; ++i) {
01459                         SAFE_FREE(cliplist[i]);
01460                 }
01461                 SAFE_FREE(cliplist);
01462                 cliplist = NULL;
01463                 clipn = 0;
01464                 must_free_cliplist = False;
01465         }
01466         return rc;
01467 }
01468 
01469 /****************************************************************************
01470 Find a token (filename) in a clip list
01471 ***************************************************************************/
01472 
01473 static int clipfind(char **aret, int ret, char *tok)
01474 {
01475         if (aret==NULL)
01476                 return 0;
01477 
01478         /* ignore leading slashes or dots in token */
01479         while(strchr_m("/\\.", *tok))
01480                 tok++;
01481 
01482         while(ret--) {
01483                 char *pkey=*aret++;
01484 
01485                 /* ignore leading slashes or dots in list */
01486                 while(strchr_m("/\\.", *pkey))
01487                         pkey++;
01488 
01489                 if (!strslashcmp(pkey, tok))
01490                         return 1;
01491         }
01492         return 0;
01493 }
01494 
01495 /****************************************************************************
01496 Read list of files to include from the file and initialize cliplist
01497 accordingly.
01498 ***************************************************************************/
01499 
01500 static int read_inclusion_file(char *filename)
01501 {
01502         XFILE *inclusion = NULL;
01503         char buf[PATH_MAX + 1];
01504         char *inclusion_buffer = NULL;
01505         int inclusion_buffer_size = 0;
01506         int inclusion_buffer_sofar = 0;
01507         char *p;
01508         char *tmpstr;
01509         int i;
01510         int error = 0;
01511 
01512         clipn = 0;
01513         buf[PATH_MAX] = '\0'; /* guarantee null-termination */
01514         if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
01515                 /* XXX It would be better to include a reason for failure, but without
01516                  * autoconf, it's hard to use strerror, sys_errlist, etc.
01517                  */
01518                 DEBUG(0,("Unable to open inclusion file %s\n", filename));
01519                 return 0;
01520         }
01521 
01522         while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
01523                 if (inclusion_buffer == NULL) {
01524                         inclusion_buffer_size = 1024;
01525                         if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
01526                                 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
01527                                 error = 1;
01528                                 break;
01529                         }
01530                 }
01531     
01532                 if (buf[strlen(buf)-1] == '\n') {
01533                         buf[strlen(buf)-1] = '\0';
01534                 }
01535     
01536                 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
01537                         inclusion_buffer_size *= 2;
01538                         inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
01539                         if (!inclusion_buffer) {
01540                                 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
01541                                                 inclusion_buffer_size));
01542                                 error = 1;
01543                                 break;
01544                         }
01545                 }
01546     
01547                 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
01548                 inclusion_buffer_sofar += strlen(buf) + 1;
01549                 clipn++;
01550         }
01551         x_fclose(inclusion);
01552 
01553         if (! error) {
01554                 /* Allocate an array of clipn + 1 char*'s for cliplist */
01555                 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
01556                 if (cliplist == NULL) {
01557                         DEBUG(0,("failure allocating memory for cliplist\n"));
01558                         error = 1;
01559                 } else {
01560                         cliplist[clipn] = NULL;
01561                         p = inclusion_buffer;
01562                         for (i = 0; (! error) && (i < clipn); i++) {
01563                                 /* set current item to NULL so array will be null-terminated even if
01564                                                 * malloc fails below. */
01565                                 cliplist[i] = NULL;
01566                                 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
01567                                         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
01568                                         error = 1;
01569                                 } else {
01570                                         unfixtarname(tmpstr, p, strlen(p) + 1, True);
01571                                         cliplist[i] = tmpstr;
01572                                         if ((p = strchr_m(p, '\000')) == NULL) {
01573                                                 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
01574                                                 abort();
01575                                         }
01576                                 }
01577                                 ++p;
01578                         }
01579                         must_free_cliplist = True;
01580                 }
01581         }
01582 
01583         SAFE_FREE(inclusion_buffer);
01584         if (error) {
01585                 if (cliplist) {
01586                         char **pp;
01587                         /* We know cliplist is always null-terminated */
01588                         for (pp = cliplist; *pp; ++pp) {
01589                                 SAFE_FREE(*pp);
01590                         }
01591                         SAFE_FREE(cliplist);
01592                         cliplist = NULL;
01593                         must_free_cliplist = False;
01594                 }
01595                 return 0;
01596         }
01597   
01598         /* cliplist and its elements are freed at the end of process_tar. */
01599         return 1;
01600 }
01601 
01602 /****************************************************************************
01603 Parse tar arguments. Sets tar_type, tar_excl, etc.
01604 ***************************************************************************/
01605 
01606 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
01607 {
01608         int newOptind = Optind;
01609         char tar_clipfl='\0';
01610 
01611         /* Reset back to defaults - could be from interactive version 
01612          * reset mode and archive mode left as they are though
01613          */
01614         tar_type='\0';
01615         tar_excl=True;
01616         dry_run=False;
01617 
01618         while (*Optarg) {
01619                 switch(*Optarg++) {
01620                         case 'c':
01621                                 tar_type='c';
01622                                 break;
01623                         case 'x':
01624                                 if (tar_type=='c') {
01625                                         printf("Tar must be followed by only one of c or x.\n");
01626                                         return 0;
01627                                 }
01628                                 tar_type='x';
01629                                 break;
01630                         case 'b':
01631                                 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
01632                                         DEBUG(0,("Option b must be followed by valid blocksize\n"));
01633                                         return 0;
01634                                 } else {
01635                                         Optind++;
01636                                         newOptind++;
01637                                 }
01638                                 break;
01639                         case 'g':
01640                                 tar_inc=True;
01641                                 break;
01642                         case 'N':
01643                                 if (Optind>=argc) {
01644                                         DEBUG(0,("Option N must be followed by valid file name\n"));
01645                                         return 0;
01646                                 } else {
01647                                         SMB_STRUCT_STAT stbuf;
01648         
01649                                         if (sys_stat(argv[Optind], &stbuf) == 0) {
01650                                                 newer_than = stbuf.st_mtime;
01651                                                 DEBUG(1,("Getting files newer than %s",
01652                                                         time_to_asc(newer_than)));
01653                                                 newOptind++;
01654                                                 Optind++;
01655                                         } else {
01656                                                 DEBUG(0,("Error setting newer-than time\n"));
01657                                                 return 0;
01658                                         }
01659                                 }
01660                                 break;
01661                         case 'a':
01662                                 tar_reset=True;
01663                                 break;
01664                         case 'q':
01665                                 tar_noisy=False;
01666                                 break;
01667                         case 'I':
01668                                 if (tar_clipfl) {
01669                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
01670                                         return 0;
01671                                 }
01672                                 tar_clipfl='I';
01673                                 break;
01674                         case 'X':
01675                                 if (tar_clipfl) {
01676                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
01677                                         return 0;
01678                                 }
01679                                 tar_clipfl='X';
01680                                 break;
01681                         case 'F':
01682                                 if (tar_clipfl) {
01683                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
01684                                         return 0;
01685                                 }
01686                                 tar_clipfl='F';
01687                                 break;
01688                         case 'r':
01689                                 DEBUG(0, ("tar_re_search set\n"));
01690                                 tar_re_search = True;
01691                                 break;
01692                         case 'n':
01693                                 if (tar_type == 'c') {
01694                                         DEBUG(0, ("dry_run set\n"));
01695                                         dry_run = True;
01696                                 } else {
01697                                         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
01698                                         return 0;
01699                                 }
01700                                 break;
01701                         default:
01702                                 DEBUG(0,("Unknown tar option\n"));
01703                                 return 0;
01704                 }
01705         }
01706 
01707         if (!tar_type) {
01708                 printf("Option T must be followed by one of c or x.\n");
01709                 return 0;
01710         }
01711 
01712         /* tar_excl is true if cliplist lists files to be included.
01713          * Both 'I' and 'F' mean include. */
01714         tar_excl=tar_clipfl!='X';
01715 
01716         if (tar_clipfl=='F') {
01717                 if (argc-Optind-1 != 1) {
01718                         DEBUG(0,("Option F must be followed by exactly one filename.\n"));
01719                         return 0;
01720                 }
01721                 newOptind++;
01722                 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
01723                 if (! read_inclusion_file(argv[Optind+1])) {
01724                         return 0;
01725                 }
01726         } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
01727                 char *tmpstr;
01728                 char **tmplist;
01729                 int clipcount;
01730 
01731                 cliplist=argv+Optind+1;
01732                 clipn=argc-Optind-1;
01733                 clipcount = clipn;
01734 
01735                 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
01736                         DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
01737                         return 0;
01738                 }
01739 
01740                 for (clipcount = 0; clipcount < clipn; clipcount++) {
01741 
01742                         DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
01743 
01744                         if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
01745                                 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
01746                                 SAFE_FREE(tmplist);
01747                                 return 0;
01748                         }
01749 
01750                         unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
01751                         tmplist[clipcount] = tmpstr;
01752                         DEBUG(5, ("Processed an item, %s\n", tmpstr));
01753 
01754                         DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
01755                 }
01756 
01757                 cliplist = tmplist;
01758                 must_free_cliplist = True;
01759 
01760                 newOptind += clipn;
01761         }
01762 
01763         if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
01764                 /* Doing regular expression seaches not from an inclusion file. */
01765                 clipn=argc-Optind-1;
01766                 cliplist=argv+Optind+1;
01767                 newOptind += clipn;
01768         }
01769 
01770         if (Optind>=argc || !strcmp(argv[Optind], "-")) {
01771                 /* Sets tar handle to either 0 or 1, as appropriate */
01772                 tarhandle=(tar_type=='c');
01773                 /*
01774                  * Make sure that dbf points to stderr if we are using stdout for 
01775                  * tar output
01776                  */
01777                 if (tarhandle == 1)  {
01778                         dbf = x_stderr;
01779                 }
01780                 if (!argv[Optind]) {
01781                         DEBUG(0,("Must specify tar filename\n"));
01782                         return 0;
01783                 }
01784                 if (!strcmp(argv[Optind], "-")) {
01785                         newOptind++;
01786                 }
01787 
01788         } else {
01789                 if (tar_type=='c' && dry_run) {
01790                         tarhandle=-1;
01791                 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
01792                                         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
01793                         DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
01794                         return(0);
01795                 }
01796                 newOptind++;
01797         }
01798 
01799         return newOptind;
01800 }

Sambaに対してSat Aug 29 21:22:53 2009に生成されました。  doxygen 1.4.7