64b035a89ec97c66cd51ee6f0a5e554a1c0b0908
[kai/samba.git] / source3 / client / clitar.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Tar Extensions
5    Copyright (C) Ricky Poulten 1995-1998
6    Copyright (C) Richard Sharpe 1998
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 /* The following changes developed by Richard Sharpe for Canon Information
23    Systems Research Australia (CISRA)
24
25    1. Restore can now restore files with long file names
26    2. Save now saves directory information so that we can restore 
27       directory creation times
28    3. tar now accepts both UNIX path names and DOS path names. I prefer
29       those lovely /'s to those UGLY \'s :-)
30    4. the files to exclude can be specified as a regular expression by adding
31       an r flag to the other tar flags. Eg:
32
33          -TcrX file.tar "*.(obj|exe)"
34
35       will skip all .obj and .exe files
36 */
37
38
39 #include "includes.h"
40 #include "clitar.h"
41
42 static int clipfind(char **aret, int ret, char *tok);
43
44 typedef struct file_info_struct file_info2;
45
46 struct file_info_struct
47 {
48   size_t size;
49   uint16 mode;
50   int uid;
51   int gid;
52   /* These times are normally kept in GMT */
53   time_t mtime;
54   time_t atime;
55   time_t ctime;
56   char *name;     /* This is dynamically allocate */
57
58   file_info2 *next, *prev;  /* Used in the stack ... */
59
60 };
61
62 typedef struct
63 {
64   file_info2 *top;
65   int items;
66
67 } stack;
68
69 stack dir_stack = {NULL, 0}; /* Want an empty stack */
70
71 #define SEPARATORS " \t\n\r"
72 extern 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 int 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 1;
1289     }
1290
1291   block=atoi(buf);
1292   if (block < 0 || block > 65535)
1293     {
1294       DEBUG(0, ("blocksize out of range"));
1295       return 1;
1296     }
1297
1298   blocksize=block;
1299   DEBUG(2,("blocksize is now %d\n", blocksize));
1300
1301   return 0;
1302 }
1303
1304 /****************************************************************************
1305 command to set incremental / reset mode
1306 ***************************************************************************/
1307 int cmd_tarmode(void)
1308 {
1309   fstring buf;
1310
1311   while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1312     if (strequal(buf, "full"))
1313       tar_inc=False;
1314     else if (strequal(buf, "inc"))
1315       tar_inc=True;
1316     else if (strequal(buf, "reset"))
1317       tar_reset=True;
1318     else if (strequal(buf, "noreset"))
1319       tar_reset=False;
1320     else if (strequal(buf, "system"))
1321       tar_system=True;
1322     else if (strequal(buf, "nosystem"))
1323       tar_system=False;
1324     else if (strequal(buf, "hidden"))
1325       tar_hidden=True;
1326     else if (strequal(buf, "nohidden"))
1327       tar_hidden=False;
1328     else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1329       tar_noisy=True;
1330     else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1331       tar_noisy=False;
1332     else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1333   }
1334
1335   DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1336             tar_inc ? "incremental" : "full",
1337             tar_system ? "system" : "nosystem",
1338             tar_hidden ? "hidden" : "nohidden",
1339             tar_reset ? "reset" : "noreset",
1340             tar_noisy ? "verbose" : "quiet"));
1341
1342   return 0;
1343 }
1344
1345 /****************************************************************************
1346 Feeble attrib command
1347 ***************************************************************************/
1348 int cmd_setmode(void)
1349 {
1350   char *q;
1351   fstring buf;
1352   pstring fname;
1353   uint16 attra[2];
1354   int direct=1;
1355
1356   attra[0] = attra[1] = 0;
1357
1358   if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1359     {
1360       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1361       return 1;
1362     }
1363
1364   safe_strcpy(fname, cur_dir, sizeof(pstring));
1365   safe_strcat(fname, buf, sizeof(pstring));
1366
1367   while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1368     q=buf;
1369
1370     while(*q)
1371       switch (*q++) {
1372       case '+': direct=1;
1373         break;
1374       case '-': direct=0;
1375         break;
1376       case 'r': attra[direct]|=aRONLY;
1377         break;
1378       case 'h': attra[direct]|=aHIDDEN;
1379         break;
1380       case 's': attra[direct]|=aSYSTEM;
1381         break;
1382       case 'a': attra[direct]|=aARCH;
1383         break;
1384       default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1385         return 1;
1386       }
1387   }
1388
1389   if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1390     {
1391       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1392       return 1;
1393     }
1394
1395   DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1396   do_setrattr(fname, attra[ATTRSET], ATTRSET);
1397   do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1398
1399   return 0;
1400 }
1401
1402 /****************************************************************************
1403 Principal command for creating / extracting
1404 ***************************************************************************/
1405 int cmd_tar(void)
1406 {
1407   fstring buf;
1408   char **argl;
1409   int argcl;
1410
1411   if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1412     {
1413       DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1414       return 1;
1415     }
1416
1417   argl=toktocliplist(&argcl, NULL);
1418   if (!tar_parseargs(argcl, argl, buf, 0))
1419     return 1;
1420
1421   process_tar();
1422
1423   SAFE_FREE(argl);
1424
1425   return 0;
1426 }
1427
1428 /****************************************************************************
1429 Command line (option) version
1430 ***************************************************************************/
1431 int process_tar(void)
1432 {
1433   initarbuf();
1434   switch(tar_type) {
1435   case 'x':
1436
1437 #if 0
1438     do_tarput2();
1439 #else
1440     do_tarput();
1441 #endif
1442     SAFE_FREE(tarbuf);
1443     close(tarhandle);
1444     break;
1445   case 'r':
1446   case 'c':
1447     if (clipn && tar_excl) {
1448       int i;
1449       pstring tarmac;
1450
1451       for (i=0; i<clipn; i++) {
1452         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1453
1454         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1455           *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1456         }
1457         
1458         if (strrchr_m(cliplist[i], '\\')) {
1459           pstring saved_dir;
1460           
1461           safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1462           
1463           if (*cliplist[i]=='\\') {
1464             safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1465           } else {
1466             safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1467             safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1468           }
1469           safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1470           *(strrchr_m(cur_dir, '\\')+1)='\0';
1471
1472           DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1473           do_list(tarmac,attribute,do_tar, False, True);
1474           safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1475         } else {
1476           safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1477           safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1478           DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1479           do_list(tarmac,attribute,do_tar, False, True);
1480         }
1481       }
1482     } else {
1483       pstring mask;
1484       safe_strcpy(mask,cur_dir, sizeof(pstring));
1485       DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1486       safe_strcat(mask,"\\*", sizeof(pstring));
1487       do_list(mask,attribute,do_tar,False, True);
1488     }
1489     
1490     if (ntarf) dotareof(tarhandle);
1491     close(tarhandle);
1492     SAFE_FREE(tarbuf);
1493     
1494     DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1495     DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1496     break;
1497   }
1498
1499   if (must_free_cliplist) {
1500     int i;
1501     for (i = 0; i < clipn; ++i) {
1502       SAFE_FREE(cliplist[i]);
1503     }
1504     SAFE_FREE(cliplist);
1505     cliplist = NULL;
1506     clipn = 0;
1507     must_free_cliplist = False;
1508   }
1509
1510   return(0);
1511 }
1512
1513 /****************************************************************************
1514 Find a token (filename) in a clip list
1515 ***************************************************************************/
1516 static int clipfind(char **aret, int ret, char *tok)
1517 {
1518   if (aret==NULL) return 0;
1519
1520   /* ignore leading slashes or dots in token */
1521   while(strchr_m("/\\.", *tok)) tok++;
1522
1523   while(ret--) {
1524     char *pkey=*aret++;
1525
1526     /* ignore leading slashes or dots in list */
1527     while(strchr_m("/\\.", *pkey)) pkey++;
1528
1529     if (!strslashcmp(pkey, tok)) return 1;
1530   }
1531
1532   return 0;
1533 }
1534
1535 /****************************************************************************
1536 Read list of files to include from the file and initialize cliplist
1537 accordingly.
1538 ***************************************************************************/
1539 static int read_inclusion_file(char *filename)
1540 {
1541   XFILE *inclusion = NULL;
1542   char buf[MAXPATHLEN + 1];
1543   char *inclusion_buffer = NULL;
1544   int inclusion_buffer_size = 0;
1545   int inclusion_buffer_sofar = 0;
1546   char *p;
1547   char *tmpstr;
1548   int i;
1549   int error = 0;
1550
1551   clipn = 0;
1552   buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1553   if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1554     /* XXX It would be better to include a reason for failure, but without
1555      * autoconf, it's hard to use strerror, sys_errlist, etc.
1556      */
1557     DEBUG(0,("Unable to open inclusion file %s\n", filename));
1558     return 0;
1559   }
1560
1561   while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1562     if (inclusion_buffer == NULL) {
1563       inclusion_buffer_size = 1024;
1564       if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1565         DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1566         error = 1;
1567         break;
1568       }
1569     }
1570     
1571     if (buf[strlen(buf)-1] == '\n') {
1572       buf[strlen(buf)-1] = '\0';
1573     }
1574     
1575     if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1576       char *ib;
1577       inclusion_buffer_size *= 2;
1578       ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1579       if (! ib) {
1580         DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1581                  inclusion_buffer_size));
1582         error = 1;
1583         break;
1584       }
1585       else inclusion_buffer = ib;
1586     }
1587     
1588     safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1589     inclusion_buffer_sofar += strlen(buf) + 1;
1590     clipn++;
1591   }
1592   x_fclose(inclusion);
1593
1594   if (! error) {
1595     /* Allocate an array of clipn + 1 char*'s for cliplist */
1596     cliplist = malloc((clipn + 1) * sizeof(char *));
1597     if (cliplist == NULL) {
1598       DEBUG(0,("failure allocating memory for cliplist\n"));
1599       error = 1;
1600     } else {
1601       cliplist[clipn] = NULL;
1602       p = inclusion_buffer;
1603       for (i = 0; (! error) && (i < clipn); i++) {
1604         /* set current item to NULL so array will be null-terminated even if
1605          * malloc fails below. */
1606         cliplist[i] = NULL;
1607         if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1608           DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1609           error = 1;
1610         } else {
1611           unfixtarname(tmpstr, p, strlen(p) + 1, True);
1612           cliplist[i] = tmpstr;
1613           if ((p = strchr_m(p, '\000')) == NULL) {
1614             DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1615             abort();
1616           }
1617         }
1618         ++p;
1619       }
1620       must_free_cliplist = True;
1621     }
1622   }
1623
1624   SAFE_FREE(inclusion_buffer);
1625   if (error) {
1626     if (cliplist) {
1627       char **pp;
1628       /* We know cliplist is always null-terminated */
1629       for (pp = cliplist; *pp; ++pp) {
1630         SAFE_FREE(*pp);
1631       }
1632       SAFE_FREE(cliplist);
1633       cliplist = NULL;
1634       must_free_cliplist = False;
1635     }
1636     return 0;
1637   }
1638   
1639   /* cliplist and its elements are freed at the end of process_tar. */
1640   return 1;
1641 }
1642
1643 /****************************************************************************
1644 Parse tar arguments. Sets tar_type, tar_excl, etc.
1645 ***************************************************************************/
1646 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1647 {
1648   char tar_clipfl='\0';
1649
1650   /* Reset back to defaults - could be from interactive version 
1651    * reset mode and archive mode left as they are though
1652    */
1653   tar_type='\0';
1654   tar_excl=True;
1655   dry_run=False;
1656
1657   while (*Optarg) 
1658     switch(*Optarg++) {
1659     case 'c':
1660       tar_type='c';
1661       break;
1662     case 'x':
1663       if (tar_type=='c') {
1664         printf("Tar must be followed by only one of c or x.\n");
1665         return 0;
1666       }
1667       tar_type='x';
1668       break;
1669     case 'b':
1670       if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1671         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1672         return 0;
1673       } else {
1674         Optind++;
1675       }
1676       break;
1677     case 'g':
1678       tar_inc=True;
1679       break;
1680     case 'N':
1681       if (Optind>=argc) {
1682         DEBUG(0,("Option N must be followed by valid file name\n"));
1683         return 0;
1684       } else {
1685         SMB_STRUCT_STAT stbuf;
1686         extern time_t newer_than;
1687         
1688         if (sys_stat(argv[Optind], &stbuf) == 0) {
1689           newer_than = stbuf.st_mtime;
1690           DEBUG(1,("Getting files newer than %s",
1691                    asctime(LocalTime(&newer_than))));
1692           Optind++;
1693         } else {
1694           DEBUG(0,("Error setting newer-than time\n"));
1695           return 0;
1696         }
1697       }
1698       break;
1699     case 'a':
1700       tar_reset=True;
1701       break;
1702     case 'q':
1703       tar_noisy=False;
1704       break;
1705     case 'I':
1706       if (tar_clipfl) {
1707         DEBUG(0,("Only one of I,X,F must be specified\n"));
1708         return 0;
1709       }
1710       tar_clipfl='I';
1711       break;
1712     case 'X':
1713       if (tar_clipfl) {
1714         DEBUG(0,("Only one of I,X,F must be specified\n"));
1715         return 0;
1716       }
1717       tar_clipfl='X';
1718       break;
1719     case 'F':
1720       if (tar_clipfl) {
1721         DEBUG(0,("Only one of I,X,F must be specified\n"));
1722         return 0;
1723       }
1724       tar_clipfl='F';
1725       break;
1726     case 'r':
1727       DEBUG(0, ("tar_re_search set\n"));
1728       tar_re_search = True;
1729       break;
1730     case 'n':
1731       if (tar_type == 'c') {
1732         DEBUG(0, ("dry_run set\n"));
1733         dry_run = True;
1734       } else {
1735         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1736         return 0;
1737       }
1738       break;
1739     default:
1740       DEBUG(0,("Unknown tar option\n"));
1741       return 0;
1742     }
1743
1744   if (!tar_type) {
1745     printf("Option T must be followed by one of c or x.\n");
1746     return 0;
1747   }
1748
1749   /* tar_excl is true if cliplist lists files to be included.
1750    * Both 'I' and 'F' mean include. */
1751   tar_excl=tar_clipfl!='X';
1752
1753   if (tar_clipfl=='F') {
1754     if (argc-Optind-1 != 1) {
1755       DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1756       return 0;
1757     }
1758     if (! read_inclusion_file(argv[Optind+1])) {
1759       return 0;
1760     }
1761   } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1762     char *tmpstr;
1763     char **tmplist;
1764     int clipcount;
1765
1766     cliplist=argv+Optind+1;
1767     clipn=argc-Optind-1;
1768     clipcount = clipn;
1769
1770     if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1771       DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
1772                clipn)
1773            );
1774       return 0;
1775     }
1776
1777     for (clipcount = 0; clipcount < clipn; clipcount++) {
1778
1779       DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1780
1781       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1782         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1783                  clipcount)
1784              );
1785         return 0;
1786       }
1787       unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1788       tmplist[clipcount] = tmpstr;
1789       DEBUG(5, ("Processed an item, %s\n", tmpstr));
1790
1791       DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1792     }
1793     cliplist = tmplist;
1794     must_free_cliplist = True;
1795   }
1796
1797   if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
1798 #ifdef HAVE_REGEX_H
1799     int errcode;
1800
1801     if ((preg = (regex_t *)malloc(65536)) == NULL) {
1802
1803       DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1804       return;
1805
1806     }
1807
1808     if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1809       char errstr[1024];
1810       size_t errlen;
1811
1812       errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1813       
1814       DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1815       return;
1816
1817     }
1818 #endif
1819
1820     clipn=argc-Optind-1;
1821     cliplist=argv+Optind+1;
1822
1823   }
1824
1825   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1826     /* Sets tar handle to either 0 or 1, as appropriate */
1827     tarhandle=(tar_type=='c');
1828     /*
1829      * Make sure that dbf points to stderr if we are using stdout for 
1830      * tar output
1831     */
1832     if (tarhandle == 1) 
1833       dbf = x_stderr;
1834   } else {
1835     if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1836       {
1837         if (!dry_run) {
1838           DEBUG(0,("Output is /dev/null, assuming dry_run"));
1839           dry_run = True;
1840         }
1841         tarhandle=-1;
1842       } else
1843     if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1844         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1845       {
1846         DEBUG(0,("Error opening local file %s - %s\n",
1847                  argv[Optind], strerror(errno)));
1848         return(0);
1849       }
1850   }
1851
1852   return 1;
1853 }