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