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