r3323: more warning reductions
[bbaumbach/samba-autobuild/.git] / source4 / client / clitar.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Tar Extensions
4    Copyright (C) Ricky Poulten 1995-1998
5    Copyright (C) Richard Sharpe 1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 /* The following changes developed by Richard Sharpe for Canon Information
22    Systems Research Australia (CISRA)
23
24    1. Restore can now restore files with long file names
25    2. Save now saves directory information so that we can restore 
26       directory creation times
27    3. tar now accepts both UNIX path names and DOS path names. I prefer
28       those lovely /'s to those UGLY \'s :-)
29    4. the files to exclude can be specified as a regular expression by adding
30       an r flag to the other tar flags. Eg:
31
32          -TcrX file.tar "*.(obj|exe)"
33
34       will skip all .obj and .exe files
35 */
36
37
38 #include "includes.h"
39 #include "clitar.h"
40
41 /**
42  Convert list of tokens to array; dependent on above routine.
43 **/
44 static char **toktocliplist(char *ptr, int *ctok, const char *sep)
45 {
46         char *s = ptr;
47         int ictok=0;
48         char **ret, **iret;
49
50         if (!sep)
51                 sep = " \t\n\r";
52
53         while(*s && strchr_m(sep,*s))
54                 s++;
55
56         /* nothing left? */
57         if (!*s)
58                 return(NULL);
59
60         do {
61                 ictok++;
62                 while(*s && (!strchr_m(sep,*s)))
63                         s++;
64                 while(*s && strchr_m(sep,*s))
65                         *s++=0;
66         } while(*s);
67         
68         *ctok=ictok;
69         s = ptr;
70         
71         if (!(ret=iret=malloc(ictok*sizeof(char *))))
72                 return NULL;
73         
74         while(ictok--) {    
75                 *iret++=s;
76                 while(*s++)
77                         ;
78                 while(!*s)
79                         s++;
80         }
81
82         return ret;
83 }
84
85 static int clipfind(char **aret, int ret, char *tok);
86 void dos_clean_name(char *s);
87
88 typedef struct file_info_struct file_info2;
89
90 struct file_info_struct
91 {
92   uint64_t size;
93   uint16_t mode;
94   uid_t uid;
95   gid_t gid;
96   /* These times are normally kept in GMT */
97   time_t mtime;
98   time_t atime;
99   time_t ctime;
100   char *name;     /* This is dynamically allocate */
101
102   file_info2 *next, *prev;  /* Used in the stack ... */
103
104 };
105
106 typedef struct
107 {
108   file_info2 *top;
109   int items;
110
111 } stack;
112
113 #define SEPARATORS " \t\n\r"
114 extern struct smbcli_state *cli;
115
116 /* These defines are for the do_setrattr routine, to indicate
117  * setting and reseting of file attributes in the function call */
118 #define ATTRSET 1
119 #define ATTRRESET 0
120
121 static uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
122
123 #ifndef CLIENT_TIMEOUT
124 #define CLIENT_TIMEOUT (30*1000)
125 #endif
126
127 static char *tarbuf, *buffer_p;
128 static int tp, ntarf, tbufsiz;
129 static double ttarf;
130 /* Incremental mode */
131 static BOOL tar_inc=False;
132 /* Reset archive bit */
133 static BOOL tar_reset=False;
134 /* Include / exclude mode (true=include, false=exclude) */
135 static BOOL tar_excl=True;
136 /* use regular expressions for search on file names */
137 static BOOL tar_re_search=False;
138 #ifdef HAVE_REGEX_H
139 regex_t *preg;
140 #endif
141 /* Do not dump anything, just calculate sizes */
142 static BOOL dry_run=False;
143 /* Dump files with System attribute */
144 static BOOL tar_system=True;
145 /* Dump files with Hidden attribute */
146 static BOOL tar_hidden=True;
147 /* Be noisy - make a catalogue */
148 static BOOL tar_noisy=True;
149 static BOOL tar_real_noisy=False;  /* Don't want to be really noisy by default */
150
151 char tar_type='\0';
152 static char **cliplist=NULL;
153 static int clipn=0;
154 static BOOL must_free_cliplist = False;
155
156 extern BOOL lowercase;
157 extern uint16_t cnum;
158 extern BOOL readbraw_supported;
159 extern int max_xmit;
160 extern pstring cur_dir;
161 extern int get_total_time_ms;
162 extern int get_total_size;
163
164 static int blocksize=20;
165 static int tarhandle;
166
167 static void writetarheader(int f,  const char *aname, uint64_t size, time_t mtime,
168                            const char *amode, uint8_t ftype);
169 static void do_atar(char *rname,const char *lname,file_info *finfo1);
170 static void do_tar(file_info *finfo);
171 static void oct_it(uint64_t value, int ndgs, char *p);
172 static void fixtarname(char *tptr, const char *fp, int l);
173 static int dotarbuf(int f, char *b, int n);
174 static void dozerobuf(int f, int n);
175 static void dotareof(int f);
176 static void initarbuf(void);
177
178 /* restore functions */
179 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
180 static long unoct(char *p, int ndgs);
181 static void do_tarput(void);
182 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
183
184 /*
185  * tar specific utitlities
186  */
187
188 /*******************************************************************
189 Create  a string of size size+1 (for the null)
190 *******************************************************************/
191 static char *string_create_s(int size)
192 {
193   char *tmp;
194
195   tmp = (char *)malloc(size+1);
196
197   if (tmp == NULL) {
198
199     DEBUG(0, ("Out of memory in string_create_s\n"));
200
201   }
202
203   return(tmp);
204
205 }
206
207 /****************************************************************************
208 Write a tar header to buffer
209 ****************************************************************************/
210 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
211                            const char *amode, uint8_t ftype)
212 {
213   union hblock hb;
214   int i, chk, l;
215   char *jp;
216
217   DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
218
219   memset(hb.dummy, 0, sizeof(hb.dummy));
220   
221   l=strlen(aname);
222   if (l >= NAMSIZ - 1) {
223           /* write a GNU tar style long header */
224           char *b;
225           b = (char *)malloc(l+TBLOCK+100);
226           if (!b) {
227                   DEBUG(0,("out of memory\n"));
228                   exit(1);
229           }
230           writetarheader(f, "/./@LongLink", l+2, 0, "     0 \0", 'L');
231           memset(b, 0, l+TBLOCK+100);
232           fixtarname(b, aname, l);
233           i = strlen(b)+1;
234           DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
235           dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
236           SAFE_FREE(b);
237   }
238
239   /* use l + 1 to do the null too */
240   fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
241
242   if (lowercase)
243     strlower(hb.dbuf.name);
244
245   /* write out a "standard" tar format header */
246
247   hb.dbuf.name[NAMSIZ-1]='\0';
248   safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
249   oct_it((uint64_t)0, 8, hb.dbuf.uid);
250   oct_it((uint64_t)0, 8, hb.dbuf.gid);
251   oct_it((uint64_t) size, 13, hb.dbuf.size);
252   oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
253   memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
254   memset(hb.dbuf.linkname, 0, NAMSIZ);
255   hb.dbuf.linkflag=ftype;
256   
257   for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
258
259   oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
260   hb.dbuf.chksum[6] = '\0';
261
262   (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
263 }
264
265 /****************************************************************************
266 Read a tar header into a hblock structure, and validate
267 ***************************************************************************/
268 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
269 {
270   long chk, fchk;
271   int i;
272   char *jp;
273
274   /*
275    * read in a "standard" tar format header - we're not that interested
276    * in that many fields, though
277    */
278
279   /* check the checksum */
280   for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
281
282   if (chk == 0)
283     return chk;
284
285   /* compensate for blanks in chksum header */
286   for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
287     chk-=(0xFF & *jp++);
288
289   chk += ' ' * sizeof(hb->dbuf.chksum);
290
291   fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
292
293   DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
294             chk, fchk, hb->dbuf.chksum));
295
296   if (fchk != chk)
297     {
298       DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
299       dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
300       return -1;
301     }
302
303   if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
304
305     DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
306     return(-1);
307
308   }
309
310   safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
311
312   /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
313   unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
314                strlen(hb->dbuf.name) + 1, True);
315
316   /* can't handle some links at present */
317   if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
318     if (hb->dbuf.linkflag == 0) {
319       DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
320                 finfo->name));
321     } else { 
322       if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
323          /* Do nothing here at the moment. do_tarput will handle this
324             as long as the longlink gets back to it, as it has to advance 
325             the buffer pointer, etc */
326
327       } else {
328         DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
329         return -2;
330       }
331     }
332   }
333     
334   if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
335     || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
336     {
337       finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
338     }
339   else
340     finfo->mode=0; /* we don't care about mode at the moment, we'll
341                     * just make it a regular file */
342   /*
343    * Bug fix by richard@sj.co.uk
344    *
345    * REC: restore times correctly (as does tar)
346    * We only get the modification time of the file; set the creation time
347    * from the mod. time, and the access time to current time
348    */
349   finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
350   finfo->atime = time(NULL);
351   finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
352
353   return True;
354 }
355
356 /****************************************************************************
357 Write out the tar buffer to tape or wherever
358 ****************************************************************************/
359 static int dotarbuf(int f, char *b, int n)
360 {
361   int fail=1, writ=n;
362
363   if (dry_run) {
364     return writ;
365   }
366   /* This routine and the next one should be the only ones that do write()s */
367   if (tp + n >= tbufsiz)
368     {
369       int diff;
370
371       diff=tbufsiz-tp;
372       memcpy(tarbuf + tp, b, diff);
373       fail=fail && (1+write(f, tarbuf, tbufsiz));
374       n-=diff;
375       b+=diff;
376       tp=0;
377
378       while (n >= tbufsiz)
379         {
380           fail=fail && (1 + write(f, b, tbufsiz));
381           n-=tbufsiz;
382           b+=tbufsiz;
383         }
384     }
385   if (n>0) {
386     memcpy(tarbuf+tp, b, n);
387     tp+=n;
388   }
389
390   return(fail ? writ : 0);
391 }
392
393 /****************************************************************************
394 Write zeros to buffer / tape
395 ****************************************************************************/
396 static void dozerobuf(int f, int n)
397 {
398   /* short routine just to write out n zeros to buffer -
399    * used to round files to nearest block
400    * and to do tar EOFs */
401
402   if (dry_run)
403     return;
404   
405   if (n+tp >= tbufsiz)
406     {
407       memset(tarbuf+tp, 0, tbufsiz-tp);
408
409       write(f, tarbuf, tbufsiz);
410       memset(tarbuf, 0, (tp+=n-tbufsiz));
411     }
412   else
413     {
414       memset(tarbuf+tp, 0, n);
415       tp+=n;
416     }
417 }
418
419 /****************************************************************************
420 Malloc tape buffer
421 ****************************************************************************/
422 static void initarbuf(void)
423 {
424   /* initialize tar buffer */
425   tbufsiz=blocksize*TBLOCK;
426   tarbuf=malloc(tbufsiz);      /* FIXME: We might not get the buffer */
427
428   /* reset tar buffer pointer and tar file counter and total dumped */
429   tp=0; ntarf=0; ttarf=0;
430 }
431
432 /****************************************************************************
433 Write two zero blocks at end of file
434 ****************************************************************************/
435 static void dotareof(int f)
436 {
437   SMB_STRUCT_STAT stbuf;
438   /* Two zero blocks at end of file, write out full buffer */
439
440   if (dry_run)
441     return;
442
443   (void) dozerobuf(f, TBLOCK);
444   (void) dozerobuf(f, TBLOCK);
445
446   if (sys_fstat(f, &stbuf) == -1)
447     {
448       DEBUG(0, ("Couldn't stat file handle\n"));
449       return;
450     }
451
452   /* Could be a pipe, in which case S_ISREG should fail,
453    * and we should write out at full size */
454   if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
455 }
456
457 /****************************************************************************
458 (Un)mangle DOS pathname, make nonabsolute
459 ****************************************************************************/
460 static void fixtarname(char *tptr, const char *fp, int l)
461 {
462         /* add a '.' to start of file name, convert from ugly dos \'s in path
463          * to lovely unix /'s :-} */
464         *tptr++='.';
465
466         safe_strcpy(tptr, fp, l);
467         string_replace(tptr, '\\', '/');
468 }
469
470 /****************************************************************************
471 Convert from decimal to octal string
472 ****************************************************************************/
473 static void oct_it (uint64_t value, int ndgs, char *p)
474 {
475   /* Converts long to octal string, pads with leading zeros */
476
477   /* skip final null, but do final space */
478   --ndgs;
479   p[--ndgs] = ' ';
480  
481   /* Loop does at least one digit */
482   do {
483       p[--ndgs] = '0' + (char) (value & 7);
484       value >>= 3;
485     }
486   while (ndgs > 0 && value != 0);
487  
488   /* Do leading zeros */
489   while (ndgs > 0)
490     p[--ndgs] = '0';
491 }
492
493 /****************************************************************************
494 Convert from octal string to long
495 ***************************************************************************/
496 static long unoct(char *p, int ndgs)
497 {
498   long value=0;
499   /* Converts octal string to long, ignoring any non-digit */
500
501   while (--ndgs)
502     {
503       if (isdigit((int)*p))
504         value = (value << 3) | (long) (*p - '0');
505
506       p++;
507     }
508
509   return value;
510 }
511
512 /****************************************************************************
513 Compare two strings in a slash insensitive way, allowing s1 to match s2 
514 if s1 is an "initial" string (up to directory marker).  Thus, if s2 is 
515 a file in any subdirectory of s1, declare a match.
516 ***************************************************************************/
517 static int strslashcmp(char *s1, char *s2)
518 {
519   char *s1_0=s1;
520
521   while(*s1 && *s2 &&
522         (*s1 == *s2
523          || tolower(*s1) == tolower(*s2)
524          || (*s1 == '\\' && *s2=='/')
525          || (*s1 == '/' && *s2=='\\'))) {
526           s1++; s2++;
527   }
528
529   /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" 
530      string of s2.
531    */
532   if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
533
534   /* ignore trailing slash on s1 */
535   if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
536
537   /* check for s1 is an "initial" string of s2 */
538   if ((*s2 == '/' || *s2 == '\\') && !*s1) return 0;
539
540   return *s1-*s2;
541 }
542
543
544 /****************************************************************************
545 Ensure a remote path exists (make if necessary)
546 ***************************************************************************/
547 static BOOL ensurepath(char *fname)
548 {
549   /* *must* be called with buffer ready malloc'ed */
550   /* ensures path exists */
551
552   char *partpath, *ffname;
553   char *p=fname, *basehack;
554
555   DEBUG(5, ( "Ensurepath called with: %s\n", fname));
556
557   partpath = string_create_s(strlen(fname));
558   ffname = string_create_s(strlen(fname));
559
560   if ((partpath == NULL) || (ffname == NULL)){
561
562     DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
563     return(False);
564
565   }
566
567   *partpath = 0;
568
569   /* fname copied to ffname so can strtok */
570
571   safe_strcpy(ffname, fname, strlen(fname));
572
573   /* do a `basename' on ffname, so don't try and make file name directory */
574   if ((basehack=strrchr_m(ffname, '\\')) == NULL)
575     return True;
576   else
577     *basehack='\0';
578
579   p=strtok(ffname, "\\");
580
581   while (p)
582     {
583       safe_strcat(partpath, p, strlen(fname) + 1);
584
585       if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, partpath))) {
586         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, partpath)))
587           {
588             DEBUG(0, ("Error mkdirhiering\n"));
589             return False;
590           }
591         else
592           DEBUG(3, ("mkdirhiering %s\n", partpath));
593
594       }
595
596       safe_strcat(partpath, "\\", strlen(fname) + 1);
597       p = strtok(NULL,"/\\");
598     }
599
600     return True;
601 }
602
603 static int padit(char *buf, int bufsize, int padsize)
604 {
605         int berr= 0;
606         int bytestowrite;
607   
608         DEBUG(5, ("Padding with %d zeros\n", padsize));
609         memset(buf, 0, bufsize);
610         while( !berr && padsize > 0 ) {
611                 bytestowrite= MIN(bufsize, padsize);
612                 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
613                 padsize -= bytestowrite;
614         }
615   
616         return berr;
617 }
618
619
620 static void do_setrattr(char *name, uint16_t attr, int set)
621 {
622         uint16_t oldattr;
623
624         if (NT_STATUS_IS_ERR(smbcli_getatr(cli->tree, name, &oldattr, NULL, NULL)))
625                 return;
626
627         if (set == ATTRSET) {
628                 attr |= oldattr;
629         } else {
630                 attr = oldattr & ~attr;
631         }
632
633         if (NT_STATUS_IS_ERR(smbcli_setatr(cli->tree, name, attr, 0))) {
634                 DEBUG(1,("setatr failed: %s\n", smbcli_errstr(cli->tree)));
635         }
636 }
637
638
639 /****************************************************************************
640 append one remote file to the tar file
641 ***************************************************************************/
642 static void do_atar(char *rname,const char *lname,file_info *finfo1)
643 {
644   int fnum;
645   uint64_t nread=0;
646   char ftype;
647   file_info2 finfo;
648   BOOL close_done = False;
649   BOOL shallitime=True;
650   char data[65520];
651   int read_size = 65520;
652   int datalen=0;
653
654   struct timeval tp_start;
655   GetTimeOfDay(&tp_start);
656
657   ftype = '0'; /* An ordinary file ... */
658
659   if (finfo1) {
660     finfo.size  = finfo1 -> size;
661     finfo.mode  = finfo1 -> mode;
662     finfo.uid   = finfo1 -> uid;
663     finfo.gid   = finfo1 -> gid;
664     finfo.mtime = finfo1 -> mtime;
665     finfo.atime = finfo1 -> atime;
666     finfo.ctime = finfo1 -> ctime;
667     finfo.name  = discard_const_p(char, finfo1 -> name);
668   }
669   else {
670           ZERO_STRUCT(finfo);
671   }
672
673   if (dry_run)
674     {
675       DEBUG(3,("skipping file %s of size %12.0f bytes\n",
676                finfo.name,
677                (double)finfo.size));
678       shallitime=0;
679       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
680       ntarf++;
681       return;
682     }
683
684   fnum = smbcli_open(cli->tree, rname, O_RDONLY, DENY_NONE);
685
686   dos_clean_name(rname);
687
688   if (fnum == -1) {
689           DEBUG(0,("%s opening remote file %s (%s)\n",
690                    smbcli_errstr(cli->tree),rname, cur_dir));
691           return;
692   }
693
694   finfo.name = string_create_s(strlen(rname));
695   if (finfo.name == NULL) {
696           DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
697           return;
698   }
699
700   safe_strcpy(finfo.name,rname, strlen(rname));
701   if (!finfo1) {
702           size_t size;
703           if (NT_STATUS_IS_ERR(smbcli_getattrE(cli->tree, fnum, &finfo.mode, &size, NULL, &finfo.atime, &finfo.mtime))) {
704                   DEBUG(0, ("getattrE: %s\n", smbcli_errstr(cli->tree)));
705                   return;
706           }
707           finfo.size = size;
708           finfo.ctime = finfo.mtime;
709   }
710
711   DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
712
713   if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE))
714     {
715       DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
716       shallitime=0;
717     }
718   else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM))
719     {
720       DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
721       shallitime=0;
722     }
723   else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN))
724     {
725       DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
726       shallitime=0;
727     }
728   else
729     {
730       DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
731                finfo.name,
732                (double)finfo.size,
733                lname));
734       
735       /* write a tar header, don't bother with mode - just set to 100644 */
736       writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
737
738       while (nread < finfo.size && !close_done) {
739               
740               DEBUG(3,("nread=%.0f\n",(double)nread));
741               
742               datalen = smbcli_read(cli->tree, fnum, data, nread, read_size);
743               
744               if (datalen == -1) {
745                       DEBUG(0,("Error reading file %s : %s\n", rname, smbcli_errstr(cli->tree)));
746                       break;
747               }
748               
749                   nread += datalen;
750
751                   /* if file size has increased since we made file size query, truncate
752                         read so tar header for this file will be correct.
753                    */
754
755                   if (nread > finfo.size) {
756                         datalen -= nread - finfo.size;
757                         DEBUG(0,("File size change - truncating %s to %.0f bytes\n", finfo.name, (double)finfo.size));
758                   }
759
760               /* add received bits of file to buffer - dotarbuf will
761                * write out in 512 byte intervals */
762               if (dotarbuf(tarhandle,data,datalen) != datalen) {
763                       DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
764                       break;
765               }
766               
767               if (datalen == 0) {
768                       DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
769                       break;
770               }
771
772               datalen=0;
773       }
774
775       /* pad tar file with zero's if we couldn't get entire file */
776       if (nread < finfo.size) {
777               DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n", (double)finfo.size, (int)nread));
778               if (padit(data, sizeof(data), finfo.size - nread))
779                       DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
780       }
781
782       /* round tar file to nearest block */
783       if (finfo.size % TBLOCK)
784         dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
785       
786       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
787       ntarf++;
788     }
789   
790   smbcli_close(cli->tree, fnum);
791
792   if (shallitime)
793     {
794       struct timeval tp_end;
795       int this_time;
796
797       /* if shallitime is true then we didn't skip */
798       if (tar_reset && !dry_run)
799         (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
800       
801       GetTimeOfDay(&tp_end);
802       this_time = 
803         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
804           (tp_end.tv_usec - tp_start.tv_usec)/1000;
805       get_total_time_ms += this_time;
806       get_total_size += finfo.size;
807
808       if (tar_noisy)
809         {
810           DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
811                (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
812                finfo.name));
813         }
814
815       /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
816       DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
817                finfo.size / MAX(0.001, (1.024*this_time)),
818                get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
819     }
820 }
821
822 /****************************************************************************
823 Append single file to tar file (or not)
824 ***************************************************************************/
825 static void do_tar(file_info *finfo)
826 {
827   pstring rname;
828
829   if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
830     return;
831
832   /* Is it on the exclude list ? */
833   if (!tar_excl && clipn) {
834     pstring exclaim;
835
836     DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
837
838     safe_strcpy(exclaim, cur_dir, sizeof(pstring));
839     *(exclaim+strlen(exclaim)-1)='\0';
840
841     safe_strcat(exclaim, "\\", sizeof(pstring));
842     safe_strcat(exclaim, finfo->name, sizeof(exclaim));
843
844     DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
845
846     if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
847 #ifdef HAVE_REGEX_H
848         (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
849 #else
850         (tar_re_search && mask_match(cli, exclaim, cliplist[0], True))) {
851 #endif
852       DEBUG(3,("Skipping file %s\n", exclaim));
853       return;
854     }
855   }
856
857   if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY)
858     {
859       pstring saved_curdir;
860       pstring mtar_mask;
861
862       safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
863
864       DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", (int)sizeof(cur_dir), (int)strlen(cur_dir), (int)strlen(finfo->name), finfo->name, cur_dir));
865
866       safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
867       safe_strcat(cur_dir,"\\", sizeof(cur_dir));
868
869       DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
870
871       /* write a tar directory, don't bother with mode - just set it to
872        * 40755 */
873       writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
874       if (tar_noisy) {
875           DEBUG(0,("                directory %s\n", cur_dir));
876       }
877       ntarf++;  /* Make sure we have a file on there */
878       safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
879       safe_strcat(mtar_mask,"*", sizeof(pstring));
880       DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
881       do_list(mtar_mask, attribute, do_tar, False, True);
882       safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
883     }
884   else
885     {
886       safe_strcpy(rname,cur_dir, sizeof(pstring));
887       safe_strcat(rname,finfo->name, sizeof(pstring));
888       do_atar(rname,finfo->name,finfo);
889     }
890 }
891
892 /****************************************************************************
893 Convert from UNIX to DOS file names
894 ***************************************************************************/
895 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
896 {
897         /* remove '.' from start of file name, convert from unix /'s to
898          * dos \'s in path. Kill any absolute path names. But only if first!
899          */
900
901         DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
902
903         if (first) {
904                 if (*fp == '.') {
905                         fp++;
906                         l--;
907                 }
908                 if (*fp == '\\' || *fp == '/') {
909                         fp++;
910                         l--;
911                 }
912         }
913
914         safe_strcpy(tptr, fp, l);
915         string_replace(tptr, '/', '\\');
916 }
917
918
919 /****************************************************************************
920 Move to the next block in the buffer, which may mean read in another set of
921 blocks. FIXME, we should allow more than one block to be skipped.
922 ****************************************************************************/
923 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
924 {
925   int bufread, total = 0;
926
927   DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
928   *bufferp += TBLOCK;
929   total = TBLOCK;
930
931   if (*bufferp >= (ltarbuf + bufsiz)) {
932
933     DEBUG(5, ("Reading more data into ltarbuf ...\n"));
934
935     /*
936      * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
937      * Fixes bug where read can return short if coming from
938      * a pipe.
939      */
940
941     bufread = read(tarhandle, ltarbuf, bufsiz);
942     total = bufread;
943
944     while (total < bufsiz) {
945       if (bufread < 0) { /* An error, return false */
946         return (total > 0 ? -2 : bufread);
947       }
948       if (bufread == 0) {
949         if (total <= 0) {
950             return -2;
951         }
952         break;
953       }
954       bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
955       total += bufread;
956     }
957
958     DEBUG(5, ("Total bytes read ... %i\n", total));
959
960     *bufferp = ltarbuf;
961
962   }
963
964   return(total);
965
966 }
967
968 /* Skip a file, even if it includes a long file name? */
969 static int skip_file(int skipsize)
970 {
971   int dsize = skipsize;
972
973   DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
974
975   /* FIXME, we should skip more than one block at a time */
976
977   while (dsize > 0) {
978
979     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
980
981         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
982         return(False);
983
984     }
985
986     dsize -= TBLOCK;
987
988   }
989
990   return(True);
991 }
992
993 /*************************************************************
994  Get a file from the tar file and store it.
995  When this is called, tarbuf already contains the first
996  file block. This is a bit broken & needs fixing.
997 **************************************************************/
998
999 static int get_file(file_info2 finfo)
1000 {
1001   int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
1002
1003   DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
1004
1005   if (ensurepath(finfo.name) && 
1006       (fnum=smbcli_open(cli->tree, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
1007       DEBUG(0, ("abandoning restore\n"));
1008       return(False);
1009   }
1010
1011   /* read the blocks from the tar file and write to the remote file */
1012
1013   rsize = finfo.size;  /* This is how much to write */
1014
1015   while (rsize > 0) {
1016
1017     /* We can only write up to the end of the buffer */
1018
1019     dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1020     dsize = MIN(dsize, rsize);  /* Should be only what is left */
1021     DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1022
1023     if (smbcli_write(cli->tree, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1024             DEBUG(0, ("Error writing remote file\n"));
1025             return 0;
1026     }
1027
1028     rsize -= dsize;
1029     pos += dsize;
1030
1031     /* Now figure out how much to move in the buffer */
1032
1033     /* FIXME, we should skip more than one block at a time */
1034
1035     /* First, skip any initial part of the part written that is left over */
1036     /* from the end of the first TBLOCK                                   */
1037
1038     if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1039
1040       dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
1041       bpos = 0;
1042
1043       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
1044         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1045         return False;
1046
1047       }
1048
1049     }
1050
1051     /*
1052      * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1053      * If the file being extracted is an exact multiple of
1054      * TBLOCK bytes then we don't want to extract the next
1055      * block from the tarfile here, as it will be done in
1056      * the caller of get_file().
1057      */
1058
1059     while (((rsize != 0) && (dsize >= TBLOCK)) ||
1060          ((rsize == 0) && (dsize > TBLOCK))) {
1061
1062       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1063         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1064         return False;
1065       }
1066
1067       dsize -= TBLOCK;
1068     }
1069
1070     bpos = dsize;
1071
1072   }
1073
1074   /* Now close the file ... */
1075
1076   if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
1077           DEBUG(0, ("Error closing remote file\n"));
1078           return(False);
1079   }
1080
1081   /* Now we update the creation date ... */
1082
1083   DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1084
1085   if (NT_STATUS_IS_ERR(smbcli_setatr(cli->tree, finfo.name, finfo.mode, finfo.mtime))) {
1086           if (tar_real_noisy) {
1087                   DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1088                   /*return(False); */ /* Ignore, as Win95 does not allow changes */
1089           }
1090   }
1091
1092   ntarf++;
1093
1094   DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1095   
1096   return(True);
1097 }
1098
1099 /* Create a directory.  We just ensure that the path exists and return as there
1100    is no file associated with a directory 
1101 */
1102 static int get_dir(file_info2 finfo)
1103 {
1104
1105   DEBUG(0, ("restore directory %s\n", finfo.name));
1106
1107   if (!ensurepath(finfo.name)) {
1108
1109     DEBUG(0, ("Problems creating directory\n"));
1110     return(False);
1111
1112   }
1113
1114   ntarf++;
1115   return(True);
1116
1117 }
1118 /* Get a file with a long file name ... first file has file name, next file 
1119    has the data. We only want the long file name, as the loop in do_tarput
1120    will deal with the rest.
1121 */
1122 static char * get_longfilename(file_info2 finfo)
1123 {
1124   int namesize = finfo.size + strlen(cur_dir) + 2;
1125   char *longname = malloc(namesize);
1126   int offset = 0, left = finfo.size;
1127   BOOL first = True;
1128
1129   DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1130   DEBUG(5, ("Len = %d\n", (int)finfo.size));
1131
1132   if (longname == NULL) {
1133
1134     DEBUG(0, ("could not allocate buffer of size %d for longname\n", 
1135               (int)(finfo.size + strlen(cur_dir) + 2)));
1136     return(NULL);
1137   }
1138
1139   /* First, add cur_dir to the long file name */
1140
1141   if (strlen(cur_dir) > 0) {
1142     strncpy(longname, cur_dir, namesize);
1143     offset = strlen(cur_dir);
1144   }
1145
1146   /* Loop through the blocks picking up the name */
1147
1148   while (left > 0) {
1149
1150     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1151
1152       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1153       return(NULL);
1154
1155     }
1156
1157     unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1158     DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1159
1160     offset += TBLOCK;
1161     left -= TBLOCK;
1162
1163   }
1164
1165   return(longname);
1166
1167 }
1168
1169 static void do_tarput(void)
1170 {
1171   file_info2 finfo;
1172   struct timeval tp_start;
1173   char *longfilename = NULL, linkflag;
1174   int skip = False;
1175
1176   GetTimeOfDay(&tp_start);
1177
1178   DEBUG(5, ("RJS do_tarput called ...\n"));
1179
1180   buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1181
1182   /* Now read through those files ... */
1183
1184   while (True) {
1185
1186     /* Get us to the next block, or the first block first time around */
1187
1188     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1189
1190       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1191
1192       return;
1193
1194     }
1195
1196     DEBUG(5, ("Reading the next header ...\n"));
1197
1198     switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1199
1200     case -2:    /* Hmm, not good, but not fatal */
1201       DEBUG(0, ("Skipping %s...\n", finfo.name));
1202       if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1203           !skip_file(finfo.size)) {
1204
1205         DEBUG(0, ("Short file, bailing out...\n"));
1206         return;
1207
1208       }
1209
1210       break;
1211
1212     case -1:
1213       DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1214       return;
1215
1216     case 0: /* chksum is zero - looks like an EOF */
1217       DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1218       return;        /* Hmmm, bad here ... */
1219
1220     default: 
1221       /* No action */
1222
1223       break;
1224
1225     }
1226
1227     /* Now, do we have a long file name? */
1228
1229     if (longfilename != NULL) {
1230
1231       SAFE_FREE(finfo.name);   /* Free the space already allocated */
1232       finfo.name = longfilename;
1233       longfilename = NULL;
1234
1235     }
1236
1237     /* Well, now we have a header, process the file ...            */
1238
1239     /* Should we skip the file? We have the long name as well here */
1240
1241     skip = clipn &&
1242       ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1243 #ifdef HAVE_REGEX_H
1244       || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1245 #else
1246       || (tar_re_search && mask_match(cli, finfo.name, cliplist[0], True)));
1247 #endif
1248
1249   DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1250
1251   if (skip) {
1252
1253     skip_file(finfo.size);
1254     continue;
1255
1256   }
1257
1258     /* We only get this far if we should process the file */
1259   linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1260
1261     switch (linkflag) {
1262
1263     case '0':  /* Should use symbolic names--FIXME */
1264
1265       /* 
1266        * Skip to the next block first, so we can get the file, FIXME, should
1267        * be in get_file ...
1268        * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1269        * Fixes bug where file size in tarfile is zero.
1270        */
1271
1272       if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1273         DEBUG(0, ("Short file, bailing out...\n"));
1274         return;
1275       }
1276       if (!get_file(finfo)) {
1277         DEBUG(0, ("Abandoning restore\n"));
1278         return;
1279
1280       }
1281       break;
1282
1283     case '5':
1284       if (!get_dir(finfo)) {
1285         DEBUG(0, ("Abandoning restore \n"));
1286         return;
1287       }
1288       break;
1289
1290     case 'L':
1291       longfilename = get_longfilename(finfo);
1292       if (!longfilename) {
1293         DEBUG(0, ("abandoning restore\n"));
1294         return;
1295
1296       }
1297       DEBUG(5, ("Long file name: %s\n", longfilename));
1298       break;
1299
1300     default:
1301       skip_file(finfo.size);  /* Don't handle these yet */
1302       break;
1303
1304     }
1305
1306   }
1307
1308
1309 }
1310
1311
1312 /*
1313  * samba interactive commands
1314  */
1315
1316 /****************************************************************************
1317 Blocksize command
1318 ***************************************************************************/
1319 int cmd_block(const char **cmd_ptr)
1320 {
1321   fstring buf;
1322   int block;
1323
1324   if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)))
1325     {
1326       DEBUG(0, ("blocksize <n>\n"));
1327       return 1;
1328     }
1329
1330   block=atoi(buf);
1331   if (block < 0 || block > 65535)
1332     {
1333       DEBUG(0, ("blocksize out of range"));
1334       return 1;
1335     }
1336
1337   blocksize=block;
1338   DEBUG(2,("blocksize is now %d\n", blocksize));
1339
1340   return 0;
1341 }
1342
1343 /****************************************************************************
1344 command to set incremental / reset mode
1345 ***************************************************************************/
1346 int cmd_tarmode(const char **cmd_ptr)
1347 {
1348   fstring buf;
1349
1350   while (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1351     if (strequal(buf, "full"))
1352       tar_inc=False;
1353     else if (strequal(buf, "inc"))
1354       tar_inc=True;
1355     else if (strequal(buf, "reset"))
1356       tar_reset=True;
1357     else if (strequal(buf, "noreset"))
1358       tar_reset=False;
1359     else if (strequal(buf, "system"))
1360       tar_system=True;
1361     else if (strequal(buf, "nosystem"))
1362       tar_system=False;
1363     else if (strequal(buf, "hidden"))
1364       tar_hidden=True;
1365     else if (strequal(buf, "nohidden"))
1366       tar_hidden=False;
1367     else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1368       tar_noisy=True;
1369     else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1370       tar_noisy=False;
1371     else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1372   }
1373
1374   DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1375             tar_inc ? "incremental" : "full",
1376             tar_system ? "system" : "nosystem",
1377             tar_hidden ? "hidden" : "nohidden",
1378             tar_reset ? "reset" : "noreset",
1379             tar_noisy ? "verbose" : "quiet"));
1380
1381   return 0;
1382 }
1383
1384 /****************************************************************************
1385 Feeble attrib command
1386 ***************************************************************************/
1387 int cmd_setmode(const char **cmd_ptr)
1388 {
1389   char *q;
1390   fstring buf;
1391   pstring fname;
1392   uint16_t attra[2];
1393   int direct=1;
1394
1395   attra[0] = attra[1] = 0;
1396
1397   if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)))
1398     {
1399       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1400       return 1;
1401     }
1402
1403   safe_strcpy(fname, cur_dir, sizeof(pstring));
1404   safe_strcat(fname, buf, sizeof(pstring));
1405
1406   while (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1407     q=buf;
1408
1409     while(*q)
1410       switch (*q++) {
1411       case '+': direct=1;
1412         break;
1413       case '-': direct=0;
1414         break;
1415       case 'r': attra[direct]|=FILE_ATTRIBUTE_READONLY;
1416         break;
1417       case 'h': attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1418         break;
1419       case 's': attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1420         break;
1421       case 'a': attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1422         break;
1423       default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1424         return 1;
1425       }
1426   }
1427
1428   if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1429     {
1430       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1431       return 1;
1432     }
1433
1434   DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1435   do_setrattr(fname, attra[ATTRSET], ATTRSET);
1436   do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1437
1438   return 0;
1439 }
1440
1441 /****************************************************************************
1442 Principal command for creating / extracting
1443 ***************************************************************************/
1444 int cmd_tar(char **cmd_ptr)
1445 {
1446   fstring buf;
1447   char **argl;
1448   int argcl;
1449
1450   if (!next_token((const char **)cmd_ptr,buf,NULL,sizeof(buf)))
1451     {
1452       DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1453       return 1;
1454     }
1455
1456   argl=toktocliplist(*cmd_ptr, &argcl, NULL);
1457   if (!tar_parseargs(argcl, argl, buf, 0))
1458     return 1;
1459
1460   process_tar();
1461
1462   SAFE_FREE(argl);
1463
1464   return 0;
1465 }
1466
1467 /****************************************************************************
1468 Command line (option) version
1469 ***************************************************************************/
1470 int process_tar(void)
1471 {
1472   initarbuf();
1473   switch(tar_type) {
1474   case 'x':
1475
1476 #if 0
1477     do_tarput2();
1478 #else
1479     do_tarput();
1480 #endif
1481     SAFE_FREE(tarbuf);
1482     close(tarhandle);
1483     break;
1484   case 'r':
1485   case 'c':
1486     if (clipn && tar_excl) {
1487       int i;
1488       pstring tarmac;
1489
1490       for (i=0; i<clipn; i++) {
1491         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1492
1493         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1494           *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1495         }
1496         
1497         if (strrchr_m(cliplist[i], '\\')) {
1498           pstring saved_dir;
1499           
1500           safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1501           
1502           if (*cliplist[i]=='\\') {
1503             safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1504           } else {
1505             safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1506             safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1507           }
1508           safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1509           *(strrchr_m(cur_dir, '\\')+1)='\0';
1510
1511           DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1512           do_list(tarmac,attribute,do_tar, False, True);
1513           safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1514         } else {
1515           safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1516           safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1517           DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1518           do_list(tarmac,attribute,do_tar, False, True);
1519         }
1520       }
1521     } else {
1522       pstring mask;
1523       safe_strcpy(mask,cur_dir, sizeof(pstring));
1524       DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1525       safe_strcat(mask,"\\*", sizeof(pstring));
1526       do_list(mask,attribute,do_tar,False, True);
1527     }
1528     
1529     if (ntarf) dotareof(tarhandle);
1530     close(tarhandle);
1531     SAFE_FREE(tarbuf);
1532     
1533     DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1534     DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1535     break;
1536   }
1537
1538   if (must_free_cliplist) {
1539     int i;
1540     for (i = 0; i < clipn; ++i) {
1541       SAFE_FREE(cliplist[i]);
1542     }
1543     SAFE_FREE(cliplist);
1544     cliplist = NULL;
1545     clipn = 0;
1546     must_free_cliplist = False;
1547   }
1548
1549   return(0);
1550 }
1551
1552 /****************************************************************************
1553 Find a token (filename) in a clip list
1554 ***************************************************************************/
1555 static int clipfind(char **aret, int ret, char *tok)
1556 {
1557   if (aret==NULL) return 0;
1558
1559   /* ignore leading slashes or dots in token */
1560   while(strchr_m("/\\.", *tok)) tok++;
1561
1562   while(ret--) {
1563     char *pkey=*aret++;
1564
1565     /* ignore leading slashes or dots in list */
1566     while(strchr_m("/\\.", *pkey)) pkey++;
1567
1568     if (!strslashcmp(pkey, tok)) return 1;
1569   }
1570
1571   return 0;
1572 }
1573
1574 /****************************************************************************
1575 Read list of files to include from the file and initialize cliplist
1576 accordingly.
1577 ***************************************************************************/
1578 static int read_inclusion_file(char *filename)
1579 {
1580   XFILE *inclusion = NULL;
1581   char buf[MAXPATHLEN + 1];
1582   char *inclusion_buffer = NULL;
1583   int inclusion_buffer_size = 0;
1584   int inclusion_buffer_sofar = 0;
1585   char *p;
1586   char *tmpstr;
1587   int i;
1588   int error = 0;
1589
1590   clipn = 0;
1591   buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1592   if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1593     /* XXX It would be better to include a reason for failure, but without
1594      * autoconf, it's hard to use strerror, sys_errlist, etc.
1595      */
1596     DEBUG(0,("Unable to open inclusion file %s\n", filename));
1597     return 0;
1598   }
1599
1600   while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1601     if (inclusion_buffer == NULL) {
1602       inclusion_buffer_size = 1024;
1603       if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1604         DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1605         error = 1;
1606         break;
1607       }
1608     }
1609     
1610     if (buf[strlen(buf)-1] == '\n') {
1611       buf[strlen(buf)-1] = '\0';
1612     }
1613     
1614     if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1615       char *ib;
1616       inclusion_buffer_size *= 2;
1617       ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1618       if (! ib) {
1619         DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1620                  inclusion_buffer_size));
1621         error = 1;
1622         break;
1623       }
1624       else inclusion_buffer = ib;
1625     }
1626     
1627     safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1628     inclusion_buffer_sofar += strlen(buf) + 1;
1629     clipn++;
1630   }
1631   x_fclose(inclusion);
1632
1633   if (! error) {
1634     /* Allocate an array of clipn + 1 char*'s for cliplist */
1635     cliplist = malloc((clipn + 1) * sizeof(char *));
1636     if (cliplist == NULL) {
1637       DEBUG(0,("failure allocating memory for cliplist\n"));
1638       error = 1;
1639     } else {
1640       cliplist[clipn] = NULL;
1641       p = inclusion_buffer;
1642       for (i = 0; (! error) && (i < clipn); i++) {
1643         /* set current item to NULL so array will be null-terminated even if
1644          * malloc fails below. */
1645         cliplist[i] = NULL;
1646         if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1647           DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1648           error = 1;
1649         } else {
1650           unfixtarname(tmpstr, p, strlen(p) + 1, True);
1651           cliplist[i] = tmpstr;
1652           if ((p = strchr_m(p, '\000')) == NULL) {
1653             DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1654             abort();
1655           }
1656         }
1657         ++p;
1658       }
1659       must_free_cliplist = True;
1660     }
1661   }
1662
1663   SAFE_FREE(inclusion_buffer);
1664   if (error) {
1665     if (cliplist) {
1666       char **pp;
1667       /* We know cliplist is always null-terminated */
1668       for (pp = cliplist; *pp; ++pp) {
1669         SAFE_FREE(*pp);
1670       }
1671       SAFE_FREE(cliplist);
1672       cliplist = NULL;
1673       must_free_cliplist = False;
1674     }
1675     return 0;
1676   }
1677   
1678   /* cliplist and its elements are freed at the end of process_tar. */
1679   return 1;
1680 }
1681
1682 /****************************************************************************
1683 Parse tar arguments. Sets tar_type, tar_excl, etc.
1684 ***************************************************************************/
1685 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1686 {
1687   char tar_clipfl='\0';
1688
1689   /* Reset back to defaults - could be from interactive version 
1690    * reset mode and archive mode left as they are though
1691    */
1692   tar_type='\0';
1693   tar_excl=True;
1694   dry_run=False;
1695
1696   while (*Optarg) 
1697     switch(*Optarg++) {
1698     case 'c':
1699       tar_type='c';
1700       break;
1701     case 'x':
1702       if (tar_type=='c') {
1703         printf("Tar must be followed by only one of c or x.\n");
1704         return 0;
1705       }
1706       tar_type='x';
1707       break;
1708     case 'b':
1709       if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1710         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1711         return 0;
1712       } else {
1713         Optind++;
1714       }
1715       break;
1716     case 'g':
1717       tar_inc=True;
1718       break;
1719     case 'N':
1720       if (Optind>=argc) {
1721         DEBUG(0,("Option N must be followed by valid file name\n"));
1722         return 0;
1723       } else {
1724         SMB_STRUCT_STAT stbuf;
1725         extern time_t newer_than;
1726         
1727         if (sys_stat(argv[Optind], &stbuf) == 0) {
1728           newer_than = stbuf.st_mtime;
1729           DEBUG(1,("Getting files newer than %s",
1730                    asctime(localtime(&newer_than))));
1731           Optind++;
1732         } else {
1733           DEBUG(0,("Error setting newer-than time\n"));
1734           return 0;
1735         }
1736       }
1737       break;
1738     case 'a':
1739       tar_reset=True;
1740       break;
1741     case 'q':
1742       tar_noisy=False;
1743       break;
1744     case 'I':
1745       if (tar_clipfl) {
1746         DEBUG(0,("Only one of I,X,F must be specified\n"));
1747         return 0;
1748       }
1749       tar_clipfl='I';
1750       break;
1751     case 'X':
1752       if (tar_clipfl) {
1753         DEBUG(0,("Only one of I,X,F must be specified\n"));
1754         return 0;
1755       }
1756       tar_clipfl='X';
1757       break;
1758     case 'F':
1759       if (tar_clipfl) {
1760         DEBUG(0,("Only one of I,X,F must be specified\n"));
1761         return 0;
1762       }
1763       tar_clipfl='F';
1764       break;
1765     case 'r':
1766       DEBUG(0, ("tar_re_search set\n"));
1767       tar_re_search = True;
1768       break;
1769     case 'n':
1770       if (tar_type == 'c') {
1771         DEBUG(0, ("dry_run set\n"));
1772         dry_run = True;
1773       } else {
1774         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1775         return 0;
1776       }
1777       break;
1778     default:
1779       DEBUG(0,("Unknown tar option\n"));
1780       return 0;
1781     }
1782
1783   if (!tar_type) {
1784     printf("Option T must be followed by one of c or x.\n");
1785     return 0;
1786   }
1787
1788   /* tar_excl is true if cliplist lists files to be included.
1789    * Both 'I' and 'F' mean include. */
1790   tar_excl=tar_clipfl!='X';
1791
1792   if (tar_clipfl=='F') {
1793     if (argc-Optind-1 != 1) {
1794       DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1795       return 0;
1796     }
1797     if (! read_inclusion_file(argv[Optind+1])) {
1798       return 0;
1799     }
1800   } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1801     char *tmpstr;
1802     char **tmplist;
1803     int clipcount;
1804
1805     cliplist=argv+Optind+1;
1806     clipn=argc-Optind-1;
1807     clipcount = clipn;
1808
1809     if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1810       DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
1811                clipn)
1812            );
1813       return 0;
1814     }
1815
1816     for (clipcount = 0; clipcount < clipn; clipcount++) {
1817
1818       DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1819
1820       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1821         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1822                  clipcount)
1823              );
1824         return 0;
1825       }
1826       unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1827       tmplist[clipcount] = tmpstr;
1828       DEBUG(5, ("Processed an item, %s\n", tmpstr));
1829
1830       DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1831     }
1832     cliplist = tmplist;
1833     must_free_cliplist = True;
1834   }
1835
1836   if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
1837 #ifdef HAVE_REGEX_H
1838     int errcode;
1839
1840     if ((preg = (regex_t *)malloc(65536)) == NULL) {
1841
1842       DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1843       return;
1844
1845     }
1846
1847     if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1848       char errstr[1024];
1849       size_t errlen;
1850
1851       errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1852       
1853       DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1854       return;
1855
1856     }
1857 #endif
1858
1859     clipn=argc-Optind-1;
1860     cliplist=argv+Optind+1;
1861
1862   }
1863
1864   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1865     /* Sets tar handle to either 0 or 1, as appropriate */
1866     tarhandle=(tar_type=='c');
1867     /*
1868      * Make sure that dbf points to stderr if we are using stdout for 
1869      * tar output
1870     */
1871     if (tarhandle == 1) 
1872             setup_logging("clitar", DEBUG_STDERR);
1873   } else {
1874     if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1875       {
1876         if (!dry_run) {
1877           DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1878           dry_run = True;
1879         }
1880         tarhandle=-1;
1881       } else
1882     if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1883         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1884       {
1885         DEBUG(0,("Error opening local file %s - %s\n",
1886                  argv[Optind], strerror(errno)));
1887         return(0);
1888       }
1889   }
1890
1891   return 1;
1892 }