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