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