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