0b7cf6f54d535dcd1ef89e855332b709b4217ec7
[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 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) {
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+1, 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=%i, \n", b, 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
427   *tptr++='.';
428
429   while (l > 0) {
430     int skip;
431     if((skip = skip_multibyte_char( *fp)) != 0) {
432       if (skip == 2) {
433         *tptr++ = *fp++;
434         *tptr++ = *fp++;
435         l -= 2;
436       } else if (skip == 1) {
437         *tptr++ = *fp++;
438         l--;
439       }
440     } else if (*fp == '\\') {
441       *tptr++ = '/';
442       fp++;
443       l--;
444     } else {
445       *tptr++ = *fp++;
446       l--;
447     }
448   }
449 }
450
451 /****************************************************************************
452 Convert from decimal to octal string
453 ****************************************************************************/
454 static void oct_it (long value, int ndgs, char *p)
455 {
456   /* Converts long to octal string, pads with leading zeros */
457
458   /* skip final null, but do final space */
459   --ndgs;
460   p[--ndgs] = ' ';
461  
462   /* Loop does at least one digit */
463   do {
464       p[--ndgs] = '0' + (char) (value & 7);
465       value >>= 3;
466     }
467   while (ndgs > 0 && value != 0);
468  
469   /* Do leading zeros */
470   while (ndgs > 0)
471     p[--ndgs] = '0';
472 }
473
474 /****************************************************************************
475 Convert from octal string to long
476 ***************************************************************************/
477 static long unoct(char *p, int ndgs)
478 {
479   long value=0;
480   /* Converts octal string to long, ignoring any non-digit */
481
482   while (--ndgs)
483     {
484       if (isdigit((int)*p))
485         value = (value << 3) | (long) (*p - '0');
486
487       p++;
488     }
489
490   return value;
491 }
492
493 /****************************************************************************
494 Compare two strings in a slash insensitive way, allowing s1 to match s2 
495 if s1 is an "initial" string (up to directory marker).  Thus, if s2 is 
496 a file in any subdirectory of s1, declare a match.
497 ***************************************************************************/
498 static int strslashcmp(char *s1, char *s2)
499 {
500   char *s1_0=s1;
501
502   while(*s1 && *s2 &&
503         (*s1 == *s2
504          || tolower(*s1) == tolower(*s2)
505          || (*s1 == '\\' && *s2=='/')
506          || (*s1 == '/' && *s2=='\\'))) {
507           s1++; s2++;
508   }
509
510   /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" 
511      string of s2.
512    */
513   if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
514
515   /* ignore trailing slash on s1 */
516   if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
517
518   /* check for s1 is an "initial" string of s2 */
519   if (*s2 == '/' || *s2 == '\\') return 0;
520
521   return *s1-*s2;
522 }
523
524
525 /****************************************************************************
526 Ensure a remote path exists (make if necessary)
527 ***************************************************************************/
528 static BOOL ensurepath(char *fname)
529 {
530   /* *must* be called with buffer ready malloc'ed */
531   /* ensures path exists */
532
533   char *partpath, *ffname;
534   char *p=fname, *basehack;
535
536   DEBUG(5, ( "Ensurepath called with: %s\n", fname));
537
538   partpath = string_create_s(strlen(fname));
539   ffname = string_create_s(strlen(fname));
540
541   if ((partpath == NULL) || (ffname == NULL)){
542
543     DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
544     return(False);
545
546   }
547
548   *partpath = 0;
549
550   /* fname copied to ffname so can strtok */
551
552   safe_strcpy(ffname, fname, strlen(fname));
553
554   /* do a `basename' on ffname, so don't try and make file name directory */
555   if ((basehack=strrchr(ffname, '\\')) == NULL)
556     return True;
557   else
558     *basehack='\0';
559
560   p=strtok(ffname, "\\");
561
562   while (p)
563     {
564       safe_strcat(partpath, p, strlen(fname) + 1);
565
566       if (!cli_chkpath(cli, partpath)) {
567         if (!cli_mkdir(cli, partpath))
568           {
569             DEBUG(0, ("Error mkdirhiering\n"));
570             return False;
571           }
572         else
573           DEBUG(3, ("mkdirhiering %s\n", partpath));
574
575       }
576
577       safe_strcat(partpath, "\\", strlen(fname) + 1);
578       p = strtok(NULL,"/\\");
579     }
580
581     return True;
582 }
583
584 static int padit(char *buf, int bufsize, int padsize)
585 {
586         int berr= 0;
587         int bytestowrite;
588   
589         DEBUG(5, ("Padding with %d zeros\n", padsize));
590         memset(buf, 0, bufsize);
591         while( !berr && padsize > 0 ) {
592                 bytestowrite= MIN(bufsize, padsize);
593                 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
594                 padsize -= bytestowrite;
595         }
596   
597         return berr;
598 }
599
600
601 static void do_setrattr(char *name, uint16 attr, int set)
602 {
603         uint16 oldattr;
604
605         if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
606
607         if (set == ATTRSET) {
608                 attr |= oldattr;
609         } else {
610                 attr = oldattr & ~attr;
611         }
612
613         if (!cli_setatr(cli, name, attr, 0)) {
614                 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
615         }
616 }
617
618
619 /****************************************************************************
620 append one remote file to the tar file
621 ***************************************************************************/
622 static void do_atar(char *rname,char *lname,file_info *finfo1)
623 {
624   int fnum;
625   uint32 nread=0;
626   char ftype;
627   file_info2 finfo;
628   BOOL close_done = False;
629   BOOL shallitime=True;
630   char data[65520];
631   int read_size = 65520;
632   int datalen=0;
633
634   struct timeval tp_start;
635   GetTimeOfDay(&tp_start);
636
637   ftype = '0'; /* An ordinary file ... */
638
639   if (finfo1) {
640     finfo.size  = finfo1 -> size;
641     finfo.mode  = finfo1 -> mode;
642     finfo.uid   = finfo1 -> uid;
643     finfo.gid   = finfo1 -> gid;
644     finfo.mtime = finfo1 -> mtime;
645     finfo.atime = finfo1 -> atime;
646     finfo.ctime = finfo1 -> ctime;
647   }
648   else {
649     finfo.size  = def_finfo.size;
650     finfo.mode  = def_finfo.mode;
651     finfo.uid   = def_finfo.uid;
652     finfo.gid   = def_finfo.gid;
653     finfo.mtime = def_finfo.mtime;
654     finfo.atime = def_finfo.atime;
655     finfo.ctime = def_finfo.ctime;
656   }
657
658   if (dry_run)
659     {
660       DEBUG(3,("skipping file %s of size %d bytes\n",
661                finfo.name,
662                finfo.size));
663       shallitime=0;
664       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
665       ntarf++;
666       return;
667     }
668
669   fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
670
671   dos_clean_name(rname);
672
673   if (fnum == -1) {
674           DEBUG(0,("%s opening remote file %s (%s)\n",
675                    cli_errstr(cli),rname, cur_dir));
676           return;
677   }
678
679   finfo.name = string_create_s(strlen(rname));
680   if (finfo.name == NULL) {
681           DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
682           return;
683   }
684
685   safe_strcpy(finfo.name,rname, strlen(rname));
686   if (!finfo1) {
687           if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
688                   DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
689                   return;
690           }
691           finfo.ctime = finfo.mtime;
692   }
693
694   DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
695
696   if (tar_inc && !(finfo.mode & aARCH))
697     {
698       DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
699       shallitime=0;
700     }
701   else if (!tar_system && (finfo.mode & aSYSTEM))
702     {
703       DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
704       shallitime=0;
705     }
706   else if (!tar_hidden && (finfo.mode & aHIDDEN))
707     {
708       DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
709       shallitime=0;
710     }
711   else
712     {
713       DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
714                finfo.name,
715                finfo.size,
716                lname));
717       
718       /* write a tar header, don't bother with mode - just set to 100644 */
719       writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
720
721       while (nread < finfo.size && !close_done) {
722               
723               DEBUG(3,("nread=%d\n",nread));
724               
725               datalen = cli_read(cli, fnum, data, nread, read_size);
726               
727               if (datalen == -1) {
728                       DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
729                       break;
730               }
731               
732               /* add received bits of file to buffer - dotarbuf will
733                * write out in 512 byte intervals */
734               if (dotarbuf(tarhandle,data,datalen) != datalen) {
735                       DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
736                       break;
737               }
738               
739               nread += datalen;
740               if (datalen == 0) {
741                       DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
742                       break;
743               }
744
745               datalen=0;
746       }
747
748       /* pad tar file with zero's if we couldn't get entire file */
749       if (nread < finfo.size) {
750               DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
751               if (padit(data, sizeof(data), finfo.size - nread))
752                       DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
753       }
754
755       /* round tar file to nearest block */
756       if (finfo.size % TBLOCK)
757         dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
758       
759       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
760       ntarf++;
761     }
762   
763   cli_close(cli, fnum);
764
765   if (shallitime)
766     {
767       struct timeval tp_end;
768       int this_time;
769
770       /* if shallitime is true then we didn't skip */
771       if (tar_reset && !dry_run)
772         (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
773       
774       GetTimeOfDay(&tp_end);
775       this_time = 
776         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
777           (tp_end.tv_usec - tp_start.tv_usec)/1000;
778       get_total_time_ms += this_time;
779       get_total_size += finfo.size;
780
781       if (tar_noisy)
782         {
783           DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
784                finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
785                finfo.name));
786         }
787
788       /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
789       DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
790                finfo.size / MAX(0.001, (1.024*this_time)),
791                get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
792     }
793 }
794
795 /****************************************************************************
796 Append single file to tar file (or not)
797 ***************************************************************************/
798 static void do_tar(file_info *finfo)
799 {
800   pstring rname;
801
802   if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
803     return;
804
805   /* Is it on the exclude list ? */
806   if (!tar_excl && clipn) {
807     pstring exclaim;
808
809     DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir)));
810
811     safe_strcpy(exclaim, cur_dir, sizeof(pstring));
812     *(exclaim+strlen(exclaim)-1)='\0';
813
814     safe_strcat(exclaim, "\\", sizeof(pstring));
815     safe_strcat(exclaim, finfo->name, sizeof(exclaim));
816
817     DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
818
819     if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
820 #ifdef HAVE_REGEX_H
821         (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
822 #else
823         (tar_re_search && mask_match(exclaim, cliplist[0], True, False))) {
824 #endif
825       DEBUG(3,("Skipping file %s\n", exclaim));
826       return;
827     }
828   }
829
830   if (finfo->mode & aDIR)
831     {
832       pstring saved_curdir;
833       pstring mtar_mask;
834
835       safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
836
837       DEBUG(5, ("Sizeof(cur_dir)=%i, strlen(cur_dir)=%i, strlen(finfo->name)=%i\nname=%s,cur_dir=%s\n", sizeof(cur_dir), strlen(cur_dir), strlen(finfo->name), finfo->name, cur_dir));
838
839       safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
840       safe_strcat(cur_dir,"\\", sizeof(cur_dir));
841
842       DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
843
844       /* write a tar directory, don't bother with mode - just set it to
845        * 40755 */
846       writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
847       if (tar_noisy) {
848           DEBUG(0,("                directory %s\n", cur_dir));
849       }
850       ntarf++;  /* Make sure we have a file on there */
851       safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
852       safe_strcat(mtar_mask,"*", sizeof(pstring));
853       DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
854       do_list(mtar_mask, attribute, do_tar, False, True);
855       safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
856     }
857   else
858     {
859       safe_strcpy(rname,cur_dir, sizeof(pstring));
860       safe_strcat(rname,finfo->name, sizeof(pstring));
861       do_atar(rname,finfo->name,finfo);
862     }
863 }
864
865 /****************************************************************************
866 Convert from UNIX to DOS file names
867 ***************************************************************************/
868 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
869 {
870   /* remove '.' from start of file name, convert from unix /'s to
871    * dos \'s in path. Kill any absolute path names. But only if first!
872    */
873
874   DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
875
876   if (first) {
877     if (*fp == '.') {
878       fp++;
879       l--;
880     }
881     if (*fp == '\\' || *fp == '/') {
882       fp++;
883       l--;
884     }
885   }
886
887   while (l > 0) {
888     int skip;
889     if(( skip = skip_multibyte_char( *fp )) != 0) {
890       if (skip == 2) {
891         *tptr++ = *fp++;
892         *tptr++ = *fp++;
893         l -= 2;
894       } else if (skip == 1) {
895         *tptr++ = *fp++;
896         l--;
897       }
898     } else if (*fp == '/') {
899       *tptr++ = '\\';
900       fp++;
901       l--;
902     } else {
903       *tptr++ = *fp++;
904       l--;
905     }
906   }
907 }
908
909
910 /****************************************************************************
911 Move to the next block in the buffer, which may mean read in another set of
912 blocks. FIXME, we should allow more than one block to be skipped.
913 ****************************************************************************/
914 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
915 {
916   int bufread, total = 0;
917
918   DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
919   *bufferp += TBLOCK;
920   total = TBLOCK;
921
922   if (*bufferp >= (ltarbuf + bufsiz)) {
923
924     DEBUG(5, ("Reading more data into ltarbuf ...\n"));
925
926     total = 0;
927
928     for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
929
930       if (bufread <= 0) { /* An error, return false */
931         return (total > 0 ? -2 : bufread);
932       }
933
934     }
935
936     DEBUG(5, ("Total bytes read ... %i\n", total));
937
938     *bufferp = ltarbuf;
939
940   }
941
942   return(total);
943
944 }
945
946 /* Skip a file, even if it includes a long file name? */
947 static int skip_file(int skipsize)
948 {
949   int dsize = skipsize;
950
951   DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
952
953   /* FIXME, we should skip more than one block at a time */
954
955   while (dsize > 0) {
956
957     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
958
959         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
960         return(False);
961
962     }
963
964     dsize -= TBLOCK;
965
966   }
967
968   return(True);
969 }
970
971 /* We get a file from the tar file and store it */
972 static int get_file(file_info2 finfo)
973 {
974   int fsize = finfo.size;
975   int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
976
977   DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
978
979   if (ensurepath(finfo.name) && 
980       (fnum=cli_open(cli, finfo.name, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE)) == -1)
981     {
982       DEBUG(0, ("abandoning restore\n"));
983       return(False);
984     }
985
986   /* read the blocks from the tar file and write to the remote file */
987
988   rsize = fsize;  /* This is how much to write */
989
990   while (rsize > 0) {
991
992     /* We can only write up to the end of the buffer */
993
994     dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
995     dsize = MIN(dsize, rsize);  /* Should be only what is left */
996     DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
997
998     if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
999             DEBUG(0, ("Error writing remote file\n"));
1000             return 0;
1001     }
1002
1003     rsize -= dsize;
1004     pos += dsize;
1005
1006     /* Now figure out how much to move in the buffer */
1007
1008     /* FIXME, we should skip more than one block at a time */
1009
1010     /* First, skip any initial part of the part written that is left over */
1011     /* from the end of the first TBLOCK                                   */
1012
1013     if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1014
1015       dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
1016       bpos = 0;
1017
1018       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
1019         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1020         return False;
1021
1022       }
1023
1024     }
1025
1026     while (dsize >= TBLOCK) {
1027
1028       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1029
1030         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1031         return False;
1032
1033       }
1034
1035       dsize -= TBLOCK;
1036
1037     }
1038
1039     bpos = dsize;
1040
1041   }
1042
1043   /* Now close the file ... */
1044
1045   if (!cli_close(cli, fnum)) {
1046           DEBUG(0, ("Error closing remote file\n"));
1047           return(False);
1048   }
1049
1050   /* Now we update the creation date ... */
1051
1052   DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1053
1054   if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1055           if (tar_real_noisy) {
1056                   DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1057                   /*return(False); */ /* Ignore, as Win95 does not allow changes */
1058           }
1059   }
1060
1061   ntarf++;
1062
1063   DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
1064   
1065   return(True);
1066 }
1067
1068 /* Create a directory.  We just ensure that the path exists and return as there
1069    is no file associated with a directory 
1070 */
1071 static int get_dir(file_info2 finfo)
1072 {
1073
1074   DEBUG(5, ("Creating directory: %s\n", finfo.name));
1075
1076   if (!ensurepath(finfo.name)) {
1077
1078     DEBUG(0, ("Problems creating directory\n"));
1079     return(False);
1080
1081   }
1082   return(True);
1083
1084 }
1085 /* Get a file with a long file name ... first file has file name, next file 
1086    has the data. We only want the long file name, as the loop in do_tarput
1087    will deal with the rest.
1088 */
1089 static char * get_longfilename(file_info2 finfo)
1090 {
1091   int namesize = finfo.size + strlen(cur_dir) + 2;
1092   char *longname = malloc(namesize);
1093   int offset = 0, left = finfo.size;
1094   BOOL first = True;
1095
1096   DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1097   DEBUG(5, ("Len = %i\n", finfo.size));
1098
1099   if (longname == NULL) {
1100
1101     DEBUG(0, ("could not allocate buffer of size %d for longname\n", 
1102               finfo.size + strlen(cur_dir) + 2));
1103     return(NULL);
1104   }
1105
1106   /* First, add cur_dir to the long file name */
1107
1108   if (strlen(cur_dir) > 0) {
1109     strncpy(longname, cur_dir, namesize);
1110     offset = strlen(cur_dir);
1111   }
1112
1113   /* Loop through the blocks picking up the name */
1114
1115   while (left > 0) {
1116
1117     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1118
1119       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1120       return(NULL);
1121
1122     }
1123
1124     unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1125     DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1126
1127     offset += TBLOCK;
1128     left -= TBLOCK;
1129
1130   }
1131
1132   return(longname);
1133
1134 }
1135
1136 static void do_tarput(void)
1137 {
1138   file_info2 finfo;
1139   struct timeval tp_start;
1140   char *longfilename = NULL, linkflag;
1141   int skip = False;
1142
1143   GetTimeOfDay(&tp_start);
1144
1145   DEBUG(5, ("RJS do_tarput called ...\n"));
1146
1147   buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1148
1149   /* Now read through those files ... */
1150
1151   while (True) {
1152
1153     /* Get us to the next block, or the first block first time around */
1154
1155     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1156
1157       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1158
1159       return;
1160
1161     }
1162
1163     DEBUG(5, ("Reading the next header ...\n"));
1164
1165     switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1166
1167     case -2:    /* Hmm, not good, but not fatal */
1168       DEBUG(0, ("Skipping %s...\n", finfo.name));
1169       if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1170           !skip_file(finfo.size)) {
1171
1172         DEBUG(0, ("Short file, bailing out...\n"));
1173         return;
1174
1175       }
1176
1177       break;
1178
1179     case -1:
1180       DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1181       return;
1182
1183     case 0: /* chksum is zero - looks like an EOF */
1184       DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
1185       return;        /* Hmmm, bad here ... */
1186
1187     default: 
1188       /* No action */
1189
1190       break;
1191
1192     }
1193
1194     /* Now, do we have a long file name? */
1195
1196     if (longfilename != NULL) {
1197
1198       free(finfo.name);   /* Free the space already allocated */
1199       finfo.name = longfilename;
1200       longfilename = NULL;
1201
1202     }
1203
1204     /* Well, now we have a header, process the file ...            */
1205
1206     /* Should we skip the file? We have the long name as well here */
1207
1208     skip = clipn &&
1209       ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1210 #ifdef HAVE_REGEX_H
1211       || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1212 #else
1213       || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
1214 #endif
1215
1216   DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1217
1218   if (skip) {
1219
1220     skip_file(finfo.size);
1221     continue;
1222
1223   }
1224
1225     /* We only get this far if we should process the file */
1226   linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1227
1228     switch (linkflag) {
1229
1230     case '0':  /* Should use symbolic names--FIXME */
1231
1232       /* Skip to the next block first, so we can get the file, FIXME, should
1233          be in get_file ... */
1234
1235       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1236         DEBUG(0, ("Short file, bailing out...\n"));
1237         return;
1238       }
1239       if (!get_file(finfo)) {
1240         DEBUG(0, ("Abandoning restore\n"));
1241         return;
1242
1243       }
1244       break;
1245
1246     case '5':
1247       if (!get_dir(finfo)) {
1248         DEBUG(0, ("Abandoning restore \n"));
1249         return;
1250       }
1251       break;
1252
1253     case 'L':
1254       longfilename = get_longfilename(finfo);
1255       if (!longfilename) {
1256         DEBUG(0, ("abandoning restore\n"));
1257         return;
1258
1259       }
1260       DEBUG(5, ("Long file name: %s\n", longfilename));
1261       break;
1262
1263     default:
1264       skip_file(finfo.size);  /* Don't handle these yet */
1265       break;
1266
1267     }
1268
1269   }
1270
1271
1272 }
1273
1274
1275 /*
1276  * samba interactive commands
1277  */
1278
1279 /****************************************************************************
1280 Blocksize command
1281 ***************************************************************************/
1282 void cmd_block(void)
1283 {
1284   fstring buf;
1285   int block;
1286
1287   if (!next_token(NULL,buf,NULL,sizeof(buf)))
1288     {
1289       DEBUG(0, ("blocksize <n>\n"));
1290       return;
1291     }
1292
1293   block=atoi(buf);
1294   if (block < 0 || block > 65535)
1295     {
1296       DEBUG(0, ("blocksize out of range"));
1297       return;
1298     }
1299
1300   blocksize=block;
1301   DEBUG(2,("blocksize is now %d\n", blocksize));
1302 }
1303
1304 /****************************************************************************
1305 command to set incremental / reset mode
1306 ***************************************************************************/
1307 void cmd_tarmode(void)
1308 {
1309   fstring buf;
1310
1311   while (next_token(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 }
1343
1344 /****************************************************************************
1345 Feeble attrib command
1346 ***************************************************************************/
1347 void cmd_setmode(void)
1348 {
1349   char *q;
1350   fstring buf;
1351   pstring fname;
1352   uint16 attra[2];
1353   int direct=1;
1354
1355   attra[0] = attra[1] = 0;
1356
1357   if (!next_token(NULL,buf,NULL,sizeof(buf)))
1358     {
1359       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1360       return;
1361     }
1362
1363   safe_strcpy(fname, cur_dir, sizeof(pstring));
1364   safe_strcat(fname, buf, sizeof(pstring));
1365
1366   while (next_token(NULL,buf,NULL,sizeof(buf))) {
1367     q=buf;
1368
1369     while(*q)
1370       switch (*q++) {
1371       case '+': direct=1;
1372         break;
1373       case '-': direct=0;
1374         break;
1375       case 'r': attra[direct]|=aRONLY;
1376         break;
1377       case 'h': attra[direct]|=aHIDDEN;
1378         break;
1379       case 's': attra[direct]|=aSYSTEM;
1380         break;
1381       case 'a': attra[direct]|=aARCH;
1382         break;
1383       default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1384         return;
1385       }
1386   }
1387
1388   if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1389     {
1390       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1391       return;
1392     }
1393
1394   DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1395   do_setrattr(fname, attra[ATTRSET], ATTRSET);
1396   do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1397 }
1398
1399 /****************************************************************************
1400 Principal command for creating / extracting
1401 ***************************************************************************/
1402 void cmd_tar(void)
1403 {
1404   fstring buf;
1405   char **argl;
1406   int argcl;
1407
1408   if (!next_token(NULL,buf,NULL,sizeof(buf)))
1409     {
1410       DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1411       return;
1412     }
1413
1414   argl=toktocliplist(&argcl, NULL);
1415   if (!tar_parseargs(argcl, argl, buf, 0))
1416     return;
1417
1418   process_tar();
1419
1420   free(argl);
1421 }
1422
1423 /****************************************************************************
1424 Command line (option) version
1425 ***************************************************************************/
1426 int process_tar(void)
1427 {
1428   initarbuf();
1429   switch(tar_type) {
1430   case 'x':
1431
1432 #if 0
1433     do_tarput2();
1434 #else
1435     do_tarput();
1436 #endif
1437     free(tarbuf);
1438     close(tarhandle);
1439     break;
1440   case 'r':
1441   case 'c':
1442     if (clipn && tar_excl) {
1443       int i;
1444       pstring tarmac;
1445
1446       for (i=0; i<clipn; i++) {
1447         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1448
1449         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1450           *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1451         }
1452         
1453         if (strrchr(cliplist[i], '\\')) {
1454           pstring saved_dir;
1455           
1456           safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1457           
1458           if (*cliplist[i]=='\\') {
1459             safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1460           } else {
1461             safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1462             safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1463           }
1464           safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1465           *(strrchr(cur_dir, '\\')+1)='\0';
1466
1467           DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1468           do_list(tarmac,attribute,do_tar, False, True);
1469           safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1470         } else {
1471           safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1472           safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1473           DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1474           do_list(tarmac,attribute,do_tar, False, True);
1475         }
1476       }
1477     } else {
1478       pstring mask;
1479       safe_strcpy(mask,cur_dir, sizeof(pstring));
1480       DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1481       safe_strcat(mask,"\\*", sizeof(pstring));
1482       do_list(mask,attribute,do_tar,False, True);
1483     }
1484     
1485     if (ntarf) dotareof(tarhandle);
1486     close(tarhandle);
1487     free(tarbuf);
1488     
1489     DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1490     DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1491     break;
1492   }
1493
1494   if (must_free_cliplist) {
1495     int i;
1496     for (i = 0; i < clipn; ++i) {
1497       free(cliplist[i]);
1498     }
1499     free(cliplist);
1500     cliplist = NULL;
1501     clipn = 0;
1502     must_free_cliplist = False;
1503   }
1504
1505   return(0);
1506 }
1507
1508 /****************************************************************************
1509 Find a token (filename) in a clip list
1510 ***************************************************************************/
1511 static int clipfind(char **aret, int ret, char *tok)
1512 {
1513   if (aret==NULL) return 0;
1514
1515   /* ignore leading slashes or dots in token */
1516   while(strchr("/\\.", *tok)) tok++;
1517
1518   while(ret--) {
1519     char *pkey=*aret++;
1520
1521     /* ignore leading slashes or dots in list */
1522     while(strchr("/\\.", *pkey)) pkey++;
1523
1524     if (!strslashcmp(pkey, tok)) return 1;
1525   }
1526
1527   return 0;
1528 }
1529
1530 /****************************************************************************
1531 Read list of files to include from the file and initialize cliplist
1532 accordingly.
1533 ***************************************************************************/
1534 static int read_inclusion_file(char *filename)
1535 {
1536   FILE *inclusion = NULL;
1537   char buf[MAXPATHLEN + 1];
1538   char *inclusion_buffer = NULL;
1539   int inclusion_buffer_size = 0;
1540   int inclusion_buffer_sofar = 0;
1541   char *p;
1542   char *tmpstr;
1543   int i;
1544   int error = 0;
1545
1546   clipn = 0;
1547   buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1548   if ((inclusion = sys_fopen(filename, "r")) == NULL) {
1549     /* XXX It would be better to include a reason for failure, but without
1550      * autoconf, it's hard to use strerror, sys_errlist, etc.
1551      */
1552     DEBUG(0,("Unable to open inclusion file %s\n", filename));
1553     return 0;
1554   }
1555
1556   while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1557     if (inclusion_buffer == NULL) {
1558       inclusion_buffer_size = 1024;
1559       if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1560         DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1561         error = 1;
1562         break;
1563       }
1564     }
1565     
1566     if (buf[strlen(buf)-1] == '\n') {
1567       buf[strlen(buf)-1] = '\0';
1568     }
1569     
1570     if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1571       inclusion_buffer_size *= 2;
1572       inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
1573       if (! inclusion_buffer) {
1574         DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1575                  inclusion_buffer_size));
1576         error = 1;
1577         break;
1578       }
1579     }
1580     
1581     safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1582     inclusion_buffer_sofar += strlen(buf) + 1;
1583     clipn++;
1584   }
1585   fclose(inclusion);
1586
1587   if (! error) {
1588     /* Allocate an array of clipn + 1 char*'s for cliplist */
1589     cliplist = malloc((clipn + 1) * sizeof(char *));
1590     if (cliplist == NULL) {
1591       DEBUG(0,("failure allocating memory for cliplist\n"));
1592       error = 1;
1593     } else {
1594       cliplist[clipn] = NULL;
1595       p = inclusion_buffer;
1596       for (i = 0; (! error) && (i < clipn); i++) {
1597         /* set current item to NULL so array will be null-terminated even if
1598          * malloc fails below. */
1599         cliplist[i] = NULL;
1600         if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1601           DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1602           error = 1;
1603         } else {
1604           unfixtarname(tmpstr, p, strlen(p) + 1, True);
1605           cliplist[i] = tmpstr;
1606           if ((p = strchr(p, '\000')) == NULL) {
1607             DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1608             abort();
1609           }
1610         }
1611         ++p;
1612       }
1613       must_free_cliplist = True;
1614     }
1615   }
1616
1617   if (inclusion_buffer) {
1618     free(inclusion_buffer);
1619   }
1620   if (error) {
1621     if (cliplist) {
1622       char **pp;
1623       /* We know cliplist is always null-terminated */
1624       for (pp = cliplist; *pp; ++pp) {
1625         free(*pp);
1626       }
1627       free(cliplist);
1628       cliplist = NULL;
1629       must_free_cliplist = False;
1630     }
1631     return 0;
1632   }
1633   
1634   /* cliplist and its elements are freed at the end of process_tar. */
1635   return 1;
1636 }
1637
1638 /****************************************************************************
1639 Parse tar arguments. Sets tar_type, tar_excl, etc.
1640 ***************************************************************************/
1641 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1642 {
1643   char tar_clipfl='\0';
1644
1645   /* Reset back to defaults - could be from interactive version 
1646    * reset mode and archive mode left as they are though
1647    */
1648   tar_type='\0';
1649   tar_excl=True;
1650   dry_run=False;
1651
1652   while (*Optarg) 
1653     switch(*Optarg++) {
1654     case 'c':
1655       tar_type='c';
1656       break;
1657     case 'x':
1658       if (tar_type=='c') {
1659         printf("Tar must be followed by only one of c or x.\n");
1660         return 0;
1661       }
1662       tar_type='x';
1663       break;
1664     case 'b':
1665       if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1666         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1667         return 0;
1668       } else {
1669         Optind++;
1670       }
1671       break;
1672     case 'g':
1673       tar_inc=True;
1674       break;
1675     case 'N':
1676       if (Optind>=argc) {
1677         DEBUG(0,("Option N must be followed by valid file name\n"));
1678         return 0;
1679       } else {
1680         SMB_STRUCT_STAT stbuf;
1681         extern time_t newer_than;
1682         
1683         if (dos_stat(argv[Optind], &stbuf) == 0) {
1684           newer_than = stbuf.st_mtime;
1685           DEBUG(1,("Getting files newer than %s",
1686                    asctime(LocalTime(&newer_than))));
1687           Optind++;
1688         } else {
1689           DEBUG(0,("Error setting newer-than time\n"));
1690           return 0;
1691         }
1692       }
1693       break;
1694     case 'a':
1695       tar_reset=True;
1696       break;
1697     case 'q':
1698       tar_noisy=False;
1699       break;
1700     case 'I':
1701       if (tar_clipfl) {
1702         DEBUG(0,("Only one of I,X,F must be specified\n"));
1703         return 0;
1704       }
1705       tar_clipfl='I';
1706       break;
1707     case 'X':
1708       if (tar_clipfl) {
1709         DEBUG(0,("Only one of I,X,F must be specified\n"));
1710         return 0;
1711       }
1712       tar_clipfl='X';
1713       break;
1714     case 'F':
1715       if (tar_clipfl) {
1716         DEBUG(0,("Only one of I,X,F must be specified\n"));
1717         return 0;
1718       }
1719       tar_clipfl='F';
1720       break;
1721     case 'r':
1722       DEBUG(0, ("tar_re_search set\n"));
1723       tar_re_search = True;
1724       break;
1725     case 'n':
1726       if (tar_type == 'c') {
1727         DEBUG(0, ("dry_run set\n"));
1728         dry_run = True;
1729       } else {
1730         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1731         return 0;
1732       }
1733       break;
1734     default:
1735       DEBUG(0,("Unknown tar option\n"));
1736       return 0;
1737     }
1738
1739   if (!tar_type) {
1740     printf("Option T must be followed by one of c or x.\n");
1741     return 0;
1742   }
1743
1744   /* tar_excl is true if cliplist lists files to be included.
1745    * Both 'I' and 'F' mean include. */
1746   tar_excl=tar_clipfl!='X';
1747
1748   if (tar_clipfl=='F') {
1749     if (argc-Optind-1 != 1) {
1750       DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1751       return 0;
1752     }
1753     if (! read_inclusion_file(argv[Optind+1])) {
1754       return 0;
1755     }
1756   } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1757     char *tmpstr;
1758     char **tmplist;
1759     int clipcount;
1760
1761     cliplist=argv+Optind+1;
1762     clipn=argc-Optind-1;
1763     clipcount = clipn;
1764
1765     if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1766       DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
1767                clipn)
1768            );
1769       return 0;
1770     }
1771
1772     for (clipcount = 0; clipcount < clipn; clipcount++) {
1773
1774       DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1775
1776       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1777         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1778                  clipcount)
1779              );
1780         return 0;
1781       }
1782       unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1783       tmplist[clipcount] = tmpstr;
1784       DEBUG(5, ("Processed an item, %s\n", tmpstr));
1785
1786       DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1787     }
1788     cliplist = tmplist;
1789     must_free_cliplist = True;
1790   }
1791
1792   if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
1793 #ifdef HAVE_REGEX_H
1794     int errcode;
1795
1796     if ((preg = (regex_t *)malloc(65536)) == NULL) {
1797
1798       DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1799       return;
1800
1801     }
1802
1803     if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1804       char errstr[1024];
1805       size_t errlen;
1806
1807       errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1808       
1809       DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1810       return;
1811
1812     }
1813 #endif
1814
1815     clipn=argc-Optind-1;
1816     cliplist=argv+Optind+1;
1817
1818   }
1819
1820   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1821     /* Sets tar handle to either 0 or 1, as appropriate */
1822     tarhandle=(tar_type=='c');
1823     /*
1824      * Make sure that dbf points to stderr if we are using stdout for 
1825      * tar output
1826     */
1827     if (tarhandle == 1) 
1828       dbf = stderr;
1829   } else {
1830     if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1831       {
1832         if (!dry_run) {
1833           DEBUG(0,("Output is /dev/null, assuming dry_run"));
1834           dry_run = True;
1835         }
1836         tarhandle=-1;
1837       } else
1838     if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1839         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1840       {
1841         DEBUG(0,("Error opening local file %s - %s\n",
1842                  argv[Optind], strerror(errno)));
1843         return(0);
1844       }
1845   }
1846
1847   return 1;
1848 }