Added some debugging to clitar ...
[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       DEBUG(5, ("Doing list with mtar_mask: %s\n, mtar_mask));
852       do_list(mtar_mask, attribute, do_tar, False, True);
853       safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
854     }
855   else
856     {
857       safe_strcpy(rname,cur_dir, sizeof(pstring));
858       safe_strcat(rname,finfo->name, sizeof(pstring));
859       do_atar(rname,finfo->name,finfo);
860     }
861 }
862
863 /****************************************************************************
864 Convert from UNIX to DOS file names
865 ***************************************************************************/
866 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
867 {
868   /* remove '.' from start of file name, convert from unix /'s to
869    * dos \'s in path. Kill any absolute path names. But only if first!
870    */
871
872   DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
873
874   if (first) {
875     if (*fp == '.') {
876       fp++;
877       l--;
878     }
879     if (*fp == '\\' || *fp == '/') {
880       fp++;
881       l--;
882     }
883   }
884
885   while (l > 0) {
886     int skip;
887     if(( skip = skip_multibyte_char( *fp )) != 0) {
888       if (skip == 2) {
889         *tptr++ = *fp++;
890         *tptr++ = *fp++;
891         l -= 2;
892       } else if (skip == 1) {
893         *tptr++ = *fp++;
894         l--;
895       }
896     } else if (*fp == '/') {
897       *tptr++ = '\\';
898       fp++;
899       l--;
900     } else {
901       *tptr++ = *fp++;
902       l--;
903     }
904   }
905 }
906
907
908 /****************************************************************************
909 Move to the next block in the buffer, which may mean read in another set of
910 blocks. FIXME, we should allow more than one block to be skipped.
911 ****************************************************************************/
912 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
913 {
914   int bufread, total = 0;
915
916   DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
917   *bufferp += TBLOCK;
918   total = TBLOCK;
919
920   if (*bufferp >= (ltarbuf + bufsiz)) {
921
922     DEBUG(5, ("Reading more data into ltarbuf ...\n"));
923
924     total = 0;
925
926     for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
927
928       if (bufread <= 0) { /* An error, return false */
929         return (total > 0 ? -2 : bufread);
930       }
931
932     }
933
934     DEBUG(5, ("Total bytes read ... %i\n", total));
935
936     *bufferp = ltarbuf;
937
938   }
939
940   return(total);
941
942 }
943
944 /* Skip a file, even if it includes a long file name? */
945 static int skip_file(int skipsize)
946 {
947   int dsize = skipsize;
948
949   DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
950
951   /* FIXME, we should skip more than one block at a time */
952
953   while (dsize > 0) {
954
955     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
956
957         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
958         return(False);
959
960     }
961
962     dsize -= TBLOCK;
963
964   }
965
966   return(True);
967 }
968
969 /* We get a file from the tar file and store it */
970 static int get_file(file_info2 finfo)
971 {
972   int fsize = finfo.size;
973   int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
974
975   DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
976
977   if (ensurepath(finfo.name) && 
978       (fnum=cli_open(cli, finfo.name, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE)) == -1)
979     {
980       DEBUG(0, ("abandoning restore\n"));
981       return(False);
982     }
983
984   /* read the blocks from the tar file and write to the remote file */
985
986   rsize = fsize;  /* This is how much to write */
987
988   while (rsize > 0) {
989
990     /* We can only write up to the end of the buffer */
991
992     dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
993     dsize = MIN(dsize, rsize);  /* Should be only what is left */
994     DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
995
996     if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
997             DEBUG(0, ("Error writing remote file\n"));
998             return 0;
999     }
1000
1001     rsize -= dsize;
1002     pos += dsize;
1003
1004     /* Now figure out how much to move in the buffer */
1005
1006     /* FIXME, we should skip more than one block at a time */
1007
1008     /* First, skip any initial part of the part written that is left over */
1009     /* from the end of the first TBLOCK                                   */
1010
1011     if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1012
1013       dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
1014       bpos = 0;
1015
1016       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
1017         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1018         return False;
1019
1020       }
1021
1022     }
1023
1024     while (dsize >= TBLOCK) {
1025
1026       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1027
1028         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1029         return False;
1030
1031       }
1032
1033       dsize -= TBLOCK;
1034
1035     }
1036
1037     bpos = dsize;
1038
1039   }
1040
1041   /* Now close the file ... */
1042
1043   if (!cli_close(cli, fnum)) {
1044           DEBUG(0, ("Error closing remote file\n"));
1045           return(False);
1046   }
1047
1048   /* Now we update the creation date ... */
1049
1050   DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1051
1052   if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1053           if (tar_real_noisy) {
1054                   DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1055                   /*return(False); */ /* Ignore, as Win95 does not allow changes */
1056           }
1057   }
1058
1059   ntarf++;
1060
1061   DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
1062   
1063   return(True);
1064 }
1065
1066 /* Create a directory.  We just ensure that the path exists and return as there
1067    is no file associated with a directory 
1068 */
1069 static int get_dir(file_info2 finfo)
1070 {
1071
1072   DEBUG(5, ("Creating directory: %s\n", finfo.name));
1073
1074   if (!ensurepath(finfo.name)) {
1075
1076     DEBUG(0, ("Problems creating directory\n"));
1077     return(False);
1078
1079   }
1080   return(True);
1081
1082 }
1083 /* Get a file with a long file name ... first file has file name, next file 
1084    has the data. We only want the long file name, as the loop in do_tarput
1085    will deal with the rest.
1086 */
1087 static char * get_longfilename(file_info2 finfo)
1088 {
1089   int namesize = finfo.size + strlen(cur_dir) + 2;
1090   char *longname = malloc(namesize);
1091   int offset = 0, left = finfo.size;
1092   BOOL first = True;
1093
1094   DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1095   DEBUG(5, ("Len = %i\n", finfo.size));
1096
1097   if (longname == NULL) {
1098
1099     DEBUG(0, ("could not allocate buffer of size %d for longname\n", 
1100               finfo.size + strlen(cur_dir) + 2));
1101     return(NULL);
1102   }
1103
1104   /* First, add cur_dir to the long file name */
1105
1106   if (strlen(cur_dir) > 0) {
1107     strncpy(longname, cur_dir, namesize);
1108     offset = strlen(cur_dir);
1109   }
1110
1111   /* Loop through the blocks picking up the name */
1112
1113   while (left > 0) {
1114
1115     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1116
1117       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1118       return(NULL);
1119
1120     }
1121
1122     unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1123     DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1124
1125     offset += TBLOCK;
1126     left -= TBLOCK;
1127
1128   }
1129
1130   return(longname);
1131
1132 }
1133
1134 static void do_tarput(void)
1135 {
1136   file_info2 finfo;
1137   struct timeval tp_start;
1138   char *longfilename = NULL, linkflag;
1139   int skip = False;
1140
1141   GetTimeOfDay(&tp_start);
1142
1143   DEBUG(5, ("RJS do_tarput called ...\n"));
1144
1145   buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1146
1147   /* Now read through those files ... */
1148
1149   while (True) {
1150
1151     /* Get us to the next block, or the first block first time around */
1152
1153     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1154
1155       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1156
1157       return;
1158
1159     }
1160
1161     DEBUG(5, ("Reading the next header ...\n"));
1162
1163     switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1164
1165     case -2:    /* Hmm, not good, but not fatal */
1166       DEBUG(0, ("Skipping %s...\n", finfo.name));
1167       if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1168           !skip_file(finfo.size)) {
1169
1170         DEBUG(0, ("Short file, bailing out...\n"));
1171         return;
1172
1173       }
1174
1175       break;
1176
1177     case -1:
1178       DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1179       return;
1180
1181     case 0: /* chksum is zero - looks like an EOF */
1182       DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
1183       return;        /* Hmmm, bad here ... */
1184
1185     default: 
1186       /* No action */
1187
1188       break;
1189
1190     }
1191
1192     /* Now, do we have a long file name? */
1193
1194     if (longfilename != NULL) {
1195
1196       free(finfo.name);   /* Free the space already allocated */
1197       finfo.name = longfilename;
1198       longfilename = NULL;
1199
1200     }
1201
1202     /* Well, now we have a header, process the file ...            */
1203
1204     /* Should we skip the file? We have the long name as well here */
1205
1206     skip = clipn &&
1207       ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1208 #ifdef HAVE_REGEX_H
1209       || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1210 #else
1211       || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
1212 #endif
1213
1214   DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1215
1216   if (skip) {
1217
1218     skip_file(finfo.size);
1219     continue;
1220
1221   }
1222
1223     /* We only get this far if we should process the file */
1224   linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1225
1226     switch (linkflag) {
1227
1228     case '0':  /* Should use symbolic names--FIXME */
1229
1230       /* Skip to the next block first, so we can get the file, FIXME, should
1231          be in get_file ... */
1232
1233       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1234         DEBUG(0, ("Short file, bailing out...\n"));
1235         return;
1236       }
1237       if (!get_file(finfo)) {
1238         DEBUG(0, ("Abandoning restore\n"));
1239         return;
1240
1241       }
1242       break;
1243
1244     case '5':
1245       if (!get_dir(finfo)) {
1246         DEBUG(0, ("Abandoning restore \n"));
1247         return;
1248       }
1249       break;
1250
1251     case 'L':
1252       longfilename = get_longfilename(finfo);
1253       if (!longfilename) {
1254         DEBUG(0, ("abandoning restore\n"));
1255         return;
1256
1257       }
1258       DEBUG(5, ("Long file name: %s\n", longfilename));
1259       break;
1260
1261     default:
1262       skip_file(finfo.size);  /* Don't handle these yet */
1263       break;
1264
1265     }
1266
1267   }
1268
1269
1270 }
1271
1272
1273 /*
1274  * samba interactive commands
1275  */
1276
1277 /****************************************************************************
1278 Blocksize command
1279 ***************************************************************************/
1280 void cmd_block(void)
1281 {
1282   fstring buf;
1283   int block;
1284
1285   if (!next_token(NULL,buf,NULL,sizeof(buf)))
1286     {
1287       DEBUG(0, ("blocksize <n>\n"));
1288       return;
1289     }
1290
1291   block=atoi(buf);
1292   if (block < 0 || block > 65535)
1293     {
1294       DEBUG(0, ("blocksize out of range"));
1295       return;
1296     }
1297
1298   blocksize=block;
1299   DEBUG(2,("blocksize is now %d\n", blocksize));
1300 }
1301
1302 /****************************************************************************
1303 command to set incremental / reset mode
1304 ***************************************************************************/
1305 void cmd_tarmode(void)
1306 {
1307   fstring buf;
1308
1309   while (next_token(NULL,buf,NULL,sizeof(buf))) {
1310     if (strequal(buf, "full"))
1311       tar_inc=False;
1312     else if (strequal(buf, "inc"))
1313       tar_inc=True;
1314     else if (strequal(buf, "reset"))
1315       tar_reset=True;
1316     else if (strequal(buf, "noreset"))
1317       tar_reset=False;
1318     else if (strequal(buf, "system"))
1319       tar_system=True;
1320     else if (strequal(buf, "nosystem"))
1321       tar_system=False;
1322     else if (strequal(buf, "hidden"))
1323       tar_hidden=True;
1324     else if (strequal(buf, "nohidden"))
1325       tar_hidden=False;
1326     else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1327       tar_noisy=True;
1328     else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1329       tar_noisy=False;
1330     else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1331   }
1332
1333   DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1334             tar_inc ? "incremental" : "full",
1335             tar_system ? "system" : "nosystem",
1336             tar_hidden ? "hidden" : "nohidden",
1337             tar_reset ? "reset" : "noreset",
1338             tar_noisy ? "verbose" : "quiet"));
1339
1340 }
1341
1342 /****************************************************************************
1343 Feeble attrib command
1344 ***************************************************************************/
1345 void cmd_setmode(void)
1346 {
1347   char *q;
1348   fstring buf;
1349   pstring fname;
1350   uint16 attra[2];
1351   int direct=1;
1352
1353   attra[0] = attra[1] = 0;
1354
1355   if (!next_token(NULL,buf,NULL,sizeof(buf)))
1356     {
1357       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1358       return;
1359     }
1360
1361   safe_strcpy(fname, cur_dir, sizeof(pstring));
1362   safe_strcat(fname, buf, sizeof(pstring));
1363
1364   while (next_token(NULL,buf,NULL,sizeof(buf))) {
1365     q=buf;
1366
1367     while(*q)
1368       switch (*q++) {
1369       case '+': direct=1;
1370         break;
1371       case '-': direct=0;
1372         break;
1373       case 'r': attra[direct]|=aRONLY;
1374         break;
1375       case 'h': attra[direct]|=aHIDDEN;
1376         break;
1377       case 's': attra[direct]|=aSYSTEM;
1378         break;
1379       case 'a': attra[direct]|=aARCH;
1380         break;
1381       default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1382         return;
1383       }
1384   }
1385
1386   if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1387     {
1388       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1389       return;
1390     }
1391
1392   DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1393   do_setrattr(fname, attra[ATTRSET], ATTRSET);
1394   do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1395 }
1396
1397 /****************************************************************************
1398 Principal command for creating / extracting
1399 ***************************************************************************/
1400 void cmd_tar(void)
1401 {
1402   fstring buf;
1403   char **argl;
1404   int argcl;
1405
1406   if (!next_token(NULL,buf,NULL,sizeof(buf)))
1407     {
1408       DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1409       return;
1410     }
1411
1412   argl=toktocliplist(&argcl, NULL);
1413   if (!tar_parseargs(argcl, argl, buf, 0))
1414     return;
1415
1416   process_tar();
1417
1418   free(argl);
1419 }
1420
1421 /****************************************************************************
1422 Command line (option) version
1423 ***************************************************************************/
1424 int process_tar(void)
1425 {
1426   initarbuf();
1427   switch(tar_type) {
1428   case 'x':
1429
1430 #if 0
1431     do_tarput2();
1432 #else
1433     do_tarput();
1434 #endif
1435     free(tarbuf);
1436     close(tarhandle);
1437     break;
1438   case 'r':
1439   case 'c':
1440     if (clipn && tar_excl) {
1441       int i;
1442       pstring tarmac;
1443
1444       for (i=0; i<clipn; i++) {
1445         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1446
1447         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1448           *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1449         }
1450         
1451         if (strrchr(cliplist[i], '\\')) {
1452           pstring saved_dir;
1453           
1454           safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1455           
1456           if (*cliplist[i]=='\\') {
1457             safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1458           } else {
1459             safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1460             safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1461           }
1462           safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1463           *(strrchr(cur_dir, '\\')+1)='\0';
1464
1465           DEBUG(5, "process_tar, do_list with tarmac: %s\n", tarmac);
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           DEBUG(5, "process_tar, do_list with tarmac: %s\n", tarmac);
1472           do_list(tarmac,attribute,do_tar, False, True);
1473         }
1474       }
1475     } else {
1476       pstring mask;
1477       safe_strcpy(mask,cur_dir, sizeof(pstring));
1478       DEBUG(5, process_tar, do_list with mask: $s\n", mask);
1479       safe_strcat(mask,"\\*", sizeof(pstring));
1480       do_list(mask,attribute,do_tar,False, True);
1481     }
1482     
1483     if (ntarf) dotareof(tarhandle);
1484     close(tarhandle);
1485     free(tarbuf);
1486     
1487     DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1488     DEBUG(0, ("Total bytes written: %d\n", ttarf));
1489     break;
1490   }
1491
1492   if (must_free_cliplist) {
1493     int i;
1494     for (i = 0; i < clipn; ++i) {
1495       free(cliplist[i]);
1496     }
1497     free(cliplist);
1498     cliplist = NULL;
1499     clipn = 0;
1500     must_free_cliplist = False;
1501   }
1502
1503   return(0);
1504 }
1505
1506 /****************************************************************************
1507 Find a token (filename) in a clip list
1508 ***************************************************************************/
1509 static int clipfind(char **aret, int ret, char *tok)
1510 {
1511   if (aret==NULL) return 0;
1512
1513   /* ignore leading slashes or dots in token */
1514   while(strchr("/\\.", *tok)) tok++;
1515
1516   while(ret--) {
1517     char *pkey=*aret++;
1518
1519     /* ignore leading slashes or dots in list */
1520     while(strchr("/\\.", *pkey)) pkey++;
1521
1522     if (!strslashcmp(pkey, tok)) return 1;
1523   }
1524
1525   return 0;
1526 }
1527
1528 /****************************************************************************
1529 Read list of files to include from the file and initialize cliplist
1530 accordingly.
1531 ***************************************************************************/
1532 static int read_inclusion_file(char *filename)
1533 {
1534   FILE *inclusion = NULL;
1535   char buf[MAXPATHLEN + 1];
1536   char *inclusion_buffer = NULL;
1537   int inclusion_buffer_size = 0;
1538   int inclusion_buffer_sofar = 0;
1539   char *p;
1540   char *tmpstr;
1541   int i;
1542   int error = 0;
1543
1544   clipn = 0;
1545   buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1546   if ((inclusion = sys_fopen(filename, "r")) == NULL) {
1547     /* XXX It would be better to include a reason for failure, but without
1548      * autoconf, it's hard to use strerror, sys_errlist, etc.
1549      */
1550     DEBUG(0,("Unable to open inclusion file %s\n", filename));
1551     return 0;
1552   }
1553
1554   while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1555     if (inclusion_buffer == NULL) {
1556       inclusion_buffer_size = 1024;
1557       if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1558         DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1559         error = 1;
1560         break;
1561       }
1562     }
1563     
1564     if (buf[strlen(buf)-1] == '\n') {
1565       buf[strlen(buf)-1] = '\0';
1566     }
1567     
1568     if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1569       inclusion_buffer_size *= 2;
1570       inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
1571       if (! inclusion_buffer) {
1572         DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1573                  inclusion_buffer_size));
1574         error = 1;
1575         break;
1576       }
1577     }
1578     
1579     safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1580     inclusion_buffer_sofar += strlen(buf) + 1;
1581     clipn++;
1582   }
1583   fclose(inclusion);
1584
1585   if (! error) {
1586     /* Allocate an array of clipn + 1 char*'s for cliplist */
1587     cliplist = malloc((clipn + 1) * sizeof(char *));
1588     if (cliplist == NULL) {
1589       DEBUG(0,("failure allocating memory for cliplist\n"));
1590       error = 1;
1591     } else {
1592       cliplist[clipn] = NULL;
1593       p = inclusion_buffer;
1594       for (i = 0; (! error) && (i < clipn); i++) {
1595         /* set current item to NULL so array will be null-terminated even if
1596          * malloc fails below. */
1597         cliplist[i] = NULL;
1598         if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1599           DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1600           error = 1;
1601         } else {
1602           unfixtarname(tmpstr, p, strlen(p) + 1, True);
1603           cliplist[i] = tmpstr;
1604           if ((p = strchr(p, '\000')) == NULL) {
1605             DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1606             abort();
1607           }
1608         }
1609         ++p;
1610       }
1611       must_free_cliplist = True;
1612     }
1613   }
1614
1615   if (inclusion_buffer) {
1616     free(inclusion_buffer);
1617   }
1618   if (error) {
1619     if (cliplist) {
1620       char **pp;
1621       /* We know cliplist is always null-terminated */
1622       for (pp = cliplist; *pp; ++pp) {
1623         free(*pp);
1624       }
1625       free(cliplist);
1626       cliplist = NULL;
1627       must_free_cliplist = False;
1628     }
1629     return 0;
1630   }
1631   
1632   /* cliplist and its elements are freed at the end of process_tar. */
1633   return 1;
1634 }
1635
1636 /****************************************************************************
1637 Parse tar arguments. Sets tar_type, tar_excl, etc.
1638 ***************************************************************************/
1639 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1640 {
1641   char tar_clipfl='\0';
1642
1643   /* Reset back to defaults - could be from interactive version 
1644    * reset mode and archive mode left as they are though
1645    */
1646   tar_type='\0';
1647   tar_excl=True;
1648   dry_run=False;
1649
1650   while (*Optarg) 
1651     switch(*Optarg++) {
1652     case 'c':
1653       tar_type='c';
1654       break;
1655     case 'x':
1656       if (tar_type=='c') {
1657         printf("Tar must be followed by only one of c or x.\n");
1658         return 0;
1659       }
1660       tar_type='x';
1661       break;
1662     case 'b':
1663       if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1664         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1665         return 0;
1666       } else {
1667         Optind++;
1668       }
1669       break;
1670     case 'g':
1671       tar_inc=True;
1672       break;
1673     case 'N':
1674       if (Optind>=argc) {
1675         DEBUG(0,("Option N must be followed by valid file name\n"));
1676         return 0;
1677       } else {
1678         SMB_STRUCT_STAT stbuf;
1679         extern time_t newer_than;
1680         
1681         if (dos_stat(argv[Optind], &stbuf) == 0) {
1682           newer_than = stbuf.st_mtime;
1683           DEBUG(1,("Getting files newer than %s",
1684                    asctime(LocalTime(&newer_than))));
1685           Optind++;
1686         } else {
1687           DEBUG(0,("Error setting newer-than time\n"));
1688           return 0;
1689         }
1690       }
1691       break;
1692     case 'a':
1693       tar_reset=True;
1694       break;
1695     case 'q':
1696       tar_noisy=False;
1697       break;
1698     case 'I':
1699       if (tar_clipfl) {
1700         DEBUG(0,("Only one of I,X,F must be specified\n"));
1701         return 0;
1702       }
1703       tar_clipfl='I';
1704       break;
1705     case 'X':
1706       if (tar_clipfl) {
1707         DEBUG(0,("Only one of I,X,F must be specified\n"));
1708         return 0;
1709       }
1710       tar_clipfl='X';
1711       break;
1712     case 'F':
1713       if (tar_clipfl) {
1714         DEBUG(0,("Only one of I,X,F must be specified\n"));
1715         return 0;
1716       }
1717       tar_clipfl='F';
1718       break;
1719     case 'r':
1720       DEBUG(0, ("tar_re_search set\n"));
1721       tar_re_search = True;
1722       break;
1723     case 'n':
1724       if (tar_type == 'c') {
1725         DEBUG(0, ("dry_run set\n"));
1726         dry_run = True;
1727       } else {
1728         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1729         return 0;
1730       }
1731       break;
1732     default:
1733       DEBUG(0,("Unknown tar option\n"));
1734       return 0;
1735     }
1736
1737   if (!tar_type) {
1738     printf("Option T must be followed by one of c or x.\n");
1739     return 0;
1740   }
1741
1742   /* tar_excl is true if cliplist lists files to be included.
1743    * Both 'I' and 'F' mean include. */
1744   tar_excl=tar_clipfl!='X';
1745
1746   if (tar_clipfl=='F') {
1747     if (argc-Optind-1 != 1) {
1748       DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1749       return 0;
1750     }
1751     if (! read_inclusion_file(argv[Optind+1])) {
1752       return 0;
1753     }
1754   } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1755     char *tmpstr;
1756     char **tmplist;
1757     int clipcount;
1758
1759     cliplist=argv+Optind+1;
1760     clipn=argc-Optind-1;
1761     clipcount = clipn;
1762
1763     if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1764       DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
1765                clipn)
1766            );
1767       return 0;
1768     }
1769
1770     for (clipcount = 0; clipcount < clipn; clipcount++) {
1771
1772       DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1773
1774       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1775         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1776                  clipcount)
1777              );
1778         return 0;
1779       }
1780       unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1781       tmplist[clipcount] = tmpstr;
1782       DEBUG(5, ("Processed an item, %s\n", tmpstr));
1783
1784       DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1785     }
1786     cliplist = tmplist;
1787     must_free_cliplist = True;
1788   }
1789
1790   if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
1791 #ifdef HAVE_REGEX_H
1792     int errcode;
1793
1794     if ((preg = (regex_t *)malloc(65536)) == NULL) {
1795
1796       DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1797       return;
1798
1799     }
1800
1801     if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1802       char errstr[1024];
1803       size_t errlen;
1804
1805       errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1806       
1807       DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1808       return;
1809
1810     }
1811 #endif
1812
1813     clipn=argc-Optind-1;
1814     cliplist=argv+Optind+1;
1815
1816   }
1817
1818   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1819     /* Sets tar handle to either 0 or 1, as appropriate */
1820     tarhandle=(tar_type=='c');
1821   } else {
1822     if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1823       {
1824         if (!dry_run) {
1825           DEBUG(0,("Output is /dev/null, assuming dry_run"));
1826           dry_run = True;
1827         }
1828         tarhandle=-1;
1829       } else
1830     if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1831         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1832       {
1833         DEBUG(0,("Error opening local file %s - %s\n",
1834                  argv[Optind], strerror(errno)));
1835         return(0);
1836       }
1837   }
1838
1839   return 1;
1840 }