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