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