converted smbclient to use clientgen.c rather than clientutil.c
[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   int size;
49   int 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 int 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, int attr, int set)
600 {
601         int oldattr;
602         time_t t;
603
604         if (!cli_getatr(cli, name, &oldattr, NULL, &t)) return;
605
606         if (set == ATTRSET) {
607                 attr |= oldattr;
608         } else {
609                 attr = oldattr & ~attr;
610         }
611
612         if (!cli_setatr(cli, name, attr, t)) {
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 *p, 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               p=NULL;
722               
723               DEBUG(3,("nread=%d\n",nread));
724               
725               datalen = cli_read(cli, fnum, data, nread, read_size);
726               
727               if (datalen == -1) {
728                       DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
729                       break;
730               }
731               
732               /* add received bits of file to buffer - dotarbuf will
733                * write out in 512 byte intervals */
734               if (dotarbuf(tarhandle,data,datalen) != datalen) {
735                       DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
736                       break;
737               }
738               
739               nread += datalen;
740               if (datalen == 0) {
741                       DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
742                       break;
743               }
744
745               datalen=0;
746       }
747
748       /* pad tar file with zero's if we couldn't get entire file */
749       if (nread < finfo.size) {
750               DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
751               if (padit(data, sizeof(data), finfo.size - nread))
752                       DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
753       }
754
755       /* round tar file to nearest block */
756       if (finfo.size % TBLOCK)
757         dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
758       
759       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
760       ntarf++;
761     }
762   
763   cli_close(cli, fnum);
764
765   if (shallitime)
766     {
767       struct timeval tp_end;
768       int this_time;
769
770       /* if shallitime is true then we didn't skip */
771       if (tar_reset && !dry_run)
772         (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
773       
774       GetTimeOfDay(&tp_end);
775       this_time = 
776         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
777           (tp_end.tv_usec - tp_start.tv_usec)/1000;
778       get_total_time_ms += this_time;
779       get_total_size += finfo.size;
780
781       if (tar_noisy)
782         {
783           DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
784                finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
785                finfo.name));
786         }
787
788       /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
789       DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
790                finfo.size / MAX(0.001, (1.024*this_time)),
791                get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
792     }
793 }
794
795 /****************************************************************************
796 Append single file to tar file (or not)
797 ***************************************************************************/
798 static void do_tar(file_info *finfo)
799 {
800   pstring rname;
801
802   if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
803     return;
804
805   /* Is it on the exclude list ? */
806   if (!tar_excl && clipn) {
807     pstring exclaim;
808
809     DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir)));
810
811     safe_strcpy(exclaim, cur_dir, sizeof(pstring));
812     *(exclaim+strlen(exclaim)-1)='\0';
813
814     safe_strcat(exclaim, "\\", sizeof(pstring));
815     safe_strcat(exclaim, finfo->name, sizeof(exclaim));
816
817     DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
818
819     if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
820 #ifdef HAVE_REGEX_H
821         (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
822 #else
823         (tar_re_search && mask_match(exclaim, cliplist[0], True, False))) {
824 #endif
825       DEBUG(3,("Skipping file %s\n", exclaim));
826       return;
827     }
828   }
829
830   if (finfo->mode & aDIR)
831     {
832       pstring saved_curdir;
833       pstring mtar_mask;
834
835       safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
836
837       DEBUG(5, ("Sizeof(cur_dir)=%i, strlen(cur_dir)=%i, strlen(finfo->name)=%i\nname=%s,cur_dir=%s\n", sizeof(cur_dir), strlen(cur_dir), strlen(finfo->name), finfo->name, cur_dir));
838
839       safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
840       safe_strcat(cur_dir,"\\", sizeof(cur_dir));
841
842       DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
843
844       /* write a tar directory, don't bother with mode - just set it to
845        * 40755 */
846       writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
847       if (tar_noisy) {
848           DEBUG(0,("                directory %s\n", cur_dir));
849       }
850       ntarf++;  /* Make sure we have a file on there */
851       safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
852       safe_strcat(mtar_mask,"*.*", sizeof(pstring));
853       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, 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   int 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> <perm=[+|-]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> <perm=[+|-]rsha>\n"));
1390       return;
1391     }
1392
1393   DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1394   (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
1395   (void) 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           do_list(tarmac,attribute,do_tar, False, True);
1467           safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1468         } else {
1469           safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1470           safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1471           do_list(tarmac,attribute,do_tar, False, True);
1472         }
1473       }
1474     } else {
1475       pstring mask;
1476       safe_strcpy(mask,cur_dir, sizeof(pstring));
1477       safe_strcat(mask,"\\*.*", sizeof(pstring));
1478       do_list(mask,attribute,do_tar,False, True);
1479     }
1480     
1481     if (ntarf) dotareof(tarhandle);
1482     close(tarhandle);
1483     free(tarbuf);
1484     
1485     DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1486     DEBUG(0, ("Total bytes written: %d\n", ttarf));
1487     break;
1488   }
1489
1490   if (must_free_cliplist) {
1491     int i;
1492     for (i = 0; i < clipn; ++i) {
1493       free(cliplist[i]);
1494     }
1495     free(cliplist);
1496     cliplist = NULL;
1497     clipn = 0;
1498     must_free_cliplist = False;
1499   }
1500
1501   return(0);
1502 }
1503
1504 /****************************************************************************
1505 Find a token (filename) in a clip list
1506 ***************************************************************************/
1507 static int clipfind(char **aret, int ret, char *tok)
1508 {
1509   if (aret==NULL) return 0;
1510
1511   /* ignore leading slashes or dots in token */
1512   while(strchr("/\\.", *tok)) tok++;
1513
1514   while(ret--) {
1515     char *pkey=*aret++;
1516
1517     /* ignore leading slashes or dots in list */
1518     while(strchr("/\\.", *pkey)) pkey++;
1519
1520     if (!strslashcmp(pkey, tok)) return 1;
1521   }
1522
1523   return 0;
1524 }
1525
1526 /****************************************************************************
1527 Read list of files to include from the file and initialize cliplist
1528 accordingly.
1529 ***************************************************************************/
1530 static int read_inclusion_file(char *filename)
1531 {
1532   FILE *inclusion = NULL;
1533   char buf[MAXPATHLEN + 1];
1534   char *inclusion_buffer = NULL;
1535   int inclusion_buffer_size = 0;
1536   int inclusion_buffer_sofar = 0;
1537   char *p;
1538   char *tmpstr;
1539   int i;
1540   int error = 0;
1541
1542   clipn = 0;
1543   buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1544   if ((inclusion = fopen(filename, "r")) == NULL) {
1545     /* XXX It would be better to include a reason for failure, but without
1546      * autoconf, it's hard to use strerror, sys_errlist, etc.
1547      */
1548     DEBUG(0,("Unable to open inclusion file %s\n", filename));
1549     return 0;
1550   }
1551
1552   while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1553     if (inclusion_buffer == NULL) {
1554       inclusion_buffer_size = 1024;
1555       if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1556         DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1557         error = 1;
1558         break;
1559       }
1560     }
1561     
1562     if (buf[strlen(buf)-1] == '\n') {
1563       buf[strlen(buf)-1] = '\0';
1564     }
1565     
1566     if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1567       inclusion_buffer_size *= 2;
1568       inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
1569       if (! inclusion_buffer) {
1570         DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1571                  inclusion_buffer_size));
1572         error = 1;
1573         break;
1574       }
1575     }
1576     
1577     safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1578     inclusion_buffer_sofar += strlen(buf) + 1;
1579     clipn++;
1580   }
1581   fclose(inclusion);
1582
1583   if (! error) {
1584     /* Allocate an array of clipn + 1 char*'s for cliplist */
1585     cliplist = malloc((clipn + 1) * sizeof(char *));
1586     if (cliplist == NULL) {
1587       DEBUG(0,("failure allocating memory for cliplist\n"));
1588       error = 1;
1589     } else {
1590       cliplist[clipn] = NULL;
1591       p = inclusion_buffer;
1592       for (i = 0; (! error) && (i < clipn); i++) {
1593         /* set current item to NULL so array will be null-terminated even if
1594          * malloc fails below. */
1595         cliplist[i] = NULL;
1596         if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1597           DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1598           error = 1;
1599         } else {
1600           unfixtarname(tmpstr, p, strlen(p) + 1, True);
1601           cliplist[i] = tmpstr;
1602           if ((p = strchr(p, '\000')) == NULL) {
1603             DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1604             abort();
1605           }
1606         }
1607         ++p;
1608       }
1609       must_free_cliplist = True;
1610     }
1611   }
1612
1613   if (inclusion_buffer) {
1614     free(inclusion_buffer);
1615   }
1616   if (error) {
1617     if (cliplist) {
1618       char **pp;
1619       /* We know cliplist is always null-terminated */
1620       for (pp = cliplist; *pp; ++pp) {
1621         free(*pp);
1622       }
1623       free(cliplist);
1624       cliplist = NULL;
1625       must_free_cliplist = False;
1626     }
1627     return 0;
1628   }
1629   
1630   /* cliplist and its elements are freed at the end of process_tar. */
1631   return 1;
1632 }
1633
1634 /****************************************************************************
1635 Parse tar arguments. Sets tar_type, tar_excl, etc.
1636 ***************************************************************************/
1637 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1638 {
1639   char tar_clipfl='\0';
1640
1641   /* Reset back to defaults - could be from interactive version 
1642    * reset mode and archive mode left as they are though
1643    */
1644   tar_type='\0';
1645   tar_excl=True;
1646   dry_run=False;
1647
1648   while (*Optarg) 
1649     switch(*Optarg++) {
1650     case 'c':
1651       tar_type='c';
1652       break;
1653     case 'x':
1654       if (tar_type=='c') {
1655         printf("Tar must be followed by only one of c or x.\n");
1656         return 0;
1657       }
1658       tar_type='x';
1659       break;
1660     case 'b':
1661       if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1662         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1663         return 0;
1664       } else {
1665         Optind++;
1666       }
1667       break;
1668     case 'g':
1669       tar_inc=True;
1670       break;
1671     case 'N':
1672       if (Optind>=argc) {
1673         DEBUG(0,("Option N must be followed by valid file name\n"));
1674         return 0;
1675       } else {
1676         SMB_STRUCT_STAT stbuf;
1677         extern time_t newer_than;
1678         
1679         if (dos_stat(argv[Optind], &stbuf) == 0) {
1680           newer_than = stbuf.st_mtime;
1681           DEBUG(1,("Getting files newer than %s",
1682                    asctime(LocalTime(&newer_than))));
1683           Optind++;
1684         } else {
1685           DEBUG(0,("Error setting newer-than time\n"));
1686           return 0;
1687         }
1688       }
1689       break;
1690     case 'a':
1691       tar_reset=True;
1692       break;
1693     case 'q':
1694       tar_noisy=False;
1695       break;
1696     case 'I':
1697       if (tar_clipfl) {
1698         DEBUG(0,("Only one of I,X,F must be specified\n"));
1699         return 0;
1700       }
1701       tar_clipfl='I';
1702       break;
1703     case 'X':
1704       if (tar_clipfl) {
1705         DEBUG(0,("Only one of I,X,F must be specified\n"));
1706         return 0;
1707       }
1708       tar_clipfl='X';
1709       break;
1710     case 'F':
1711       if (tar_clipfl) {
1712         DEBUG(0,("Only one of I,X,F must be specified\n"));
1713         return 0;
1714       }
1715       tar_clipfl='F';
1716       break;
1717     case 'r':
1718       DEBUG(0, ("tar_re_search set\n"));
1719       tar_re_search = True;
1720       break;
1721     case 'n':
1722       if (tar_type == 'c') {
1723         DEBUG(0, ("dry_run set\n"));
1724         dry_run = True;
1725       } else {
1726         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1727         return 0;
1728       }
1729       break;
1730     default:
1731       DEBUG(0,("Unknown tar option\n"));
1732       return 0;
1733     }
1734
1735   if (!tar_type) {
1736     printf("Option T must be followed by one of c or x.\n");
1737     return 0;
1738   }
1739
1740   /* tar_excl is true if cliplist lists files to be included.
1741    * Both 'I' and 'F' mean include. */
1742   tar_excl=tar_clipfl!='X';
1743
1744   if (tar_clipfl=='F') {
1745     if (argc-Optind-1 != 1) {
1746       DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1747       return 0;
1748     }
1749     if (! read_inclusion_file(argv[Optind+1])) {
1750       return 0;
1751     }
1752   } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1753     char *tmpstr;
1754     char **tmplist;
1755     int clipcount;
1756
1757     cliplist=argv+Optind+1;
1758     clipn=argc-Optind-1;
1759     clipcount = clipn;
1760
1761     if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1762       DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
1763                clipn)
1764            );
1765       return 0;
1766     }
1767
1768     for (clipcount = 0; clipcount < clipn; clipcount++) {
1769
1770       DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1771
1772       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1773         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1774                  clipcount)
1775              );
1776         return 0;
1777       }
1778       unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1779       tmplist[clipcount] = tmpstr;
1780       DEBUG(5, ("Processed an item, %s\n", tmpstr));
1781
1782       DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1783     }
1784     cliplist = tmplist;
1785     must_free_cliplist = True;
1786   }
1787
1788   if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
1789 #ifdef HAVE_REGEX_H
1790     int errcode;
1791
1792     if ((preg = (regex_t *)malloc(65536)) == NULL) {
1793
1794       DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1795       return;
1796
1797     }
1798
1799     if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1800       char errstr[1024];
1801       size_t errlen;
1802
1803       errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1804       
1805       DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1806       return;
1807
1808     }
1809 #endif
1810
1811     clipn=argc-Optind-1;
1812     cliplist=argv+Optind+1;
1813
1814   }
1815
1816   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1817     /* Sets tar handle to either 0 or 1, as appropriate */
1818     tarhandle=(tar_type=='c');
1819   } else {
1820     if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1821       {
1822         if (!dry_run) {
1823           DEBUG(0,("Output is /dev/null, assuming dry_run"));
1824           dry_run = True;
1825         }
1826         tarhandle=-1;
1827       } else
1828     if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
1829         || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
1830       {
1831         DEBUG(0,("Error opening local file %s - %s\n",
1832                  argv[Optind], strerror(errno)));
1833         return(0);
1834       }
1835   }
1836
1837   return 1;
1838 }