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