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