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