da91ba4bebb9b98dbe5826041e572283c8d7874c
[samba.git] / source / 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
41 static int clipfind(char **aret, int ret, char *tok);
42 void dos_clean_name(char *s);
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 = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
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, strlen(amode));
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=FILE_ATTRIBUTE_DIRECTORY;
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 (NT_STATUS_IS_ERR(cli_chkpath(cli->tree, partpath))) {
543         if (NT_STATUS_IS_ERR(cli_mkdir(cli->tree, 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 (NT_STATUS_IS_ERR(cli_getatr(cli->tree, name, &oldattr, NULL, NULL)))
582                 return;
583
584         if (set == ATTRSET) {
585                 attr |= oldattr;
586         } else {
587                 attr = oldattr & ~attr;
588         }
589
590         if (NT_STATUS_IS_ERR(cli_setatr(cli->tree, name, attr, 0))) {
591                 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli->tree)));
592         }
593 }
594
595
596 /****************************************************************************
597 append one remote file to the tar file
598 ***************************************************************************/
599 static void do_atar(char *rname,char *lname,file_info *finfo1)
600 {
601   int fnum;
602   SMB_BIG_UINT nread=0;
603   char ftype;
604   file_info2 finfo;
605   BOOL close_done = False;
606   BOOL shallitime=True;
607   char data[65520];
608   int read_size = 65520;
609   int datalen=0;
610
611   struct timeval tp_start;
612   GetTimeOfDay(&tp_start);
613
614   ftype = '0'; /* An ordinary file ... */
615
616   if (finfo1) {
617     finfo.size  = finfo1 -> size;
618     finfo.mode  = finfo1 -> mode;
619     finfo.uid   = finfo1 -> uid;
620     finfo.gid   = finfo1 -> gid;
621     finfo.mtime = finfo1 -> mtime;
622     finfo.atime = finfo1 -> atime;
623     finfo.ctime = finfo1 -> ctime;
624     finfo.name  = finfo1 -> name;
625   }
626   else {
627     finfo.size  = def_finfo.size;
628     finfo.mode  = def_finfo.mode;
629     finfo.uid   = def_finfo.uid;
630     finfo.gid   = def_finfo.gid;
631     finfo.mtime = def_finfo.mtime;
632     finfo.atime = def_finfo.atime;
633     finfo.ctime = def_finfo.ctime;
634     finfo.name  = def_finfo.name;
635   }
636
637   if (dry_run)
638     {
639       DEBUG(3,("skipping file %s of size %12.0f bytes\n",
640                finfo.name,
641                (double)finfo.size));
642       shallitime=0;
643       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
644       ntarf++;
645       return;
646     }
647
648   fnum = cli_open(cli->tree, rname, O_RDONLY, DENY_NONE);
649
650   dos_clean_name(rname);
651
652   if (fnum == -1) {
653           DEBUG(0,("%s opening remote file %s (%s)\n",
654                    cli_errstr(cli->tree),rname, cur_dir));
655           return;
656   }
657
658   finfo.name = string_create_s(strlen(rname));
659   if (finfo.name == NULL) {
660           DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
661           return;
662   }
663
664   safe_strcpy(finfo.name,rname, strlen(rname));
665   if (!finfo1) {
666           size_t size;
667           if (NT_STATUS_IS_ERR(cli_getattrE(cli->tree, fnum, &finfo.mode, &size, NULL, &finfo.atime, &finfo.mtime))) {
668                   DEBUG(0, ("getattrE: %s\n", cli_errstr(cli->tree)));
669                   return;
670           }
671           finfo.size = size;
672           finfo.ctime = finfo.mtime;
673   }
674
675   DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
676
677   if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE))
678     {
679       DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
680       shallitime=0;
681     }
682   else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM))
683     {
684       DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
685       shallitime=0;
686     }
687   else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN))
688     {
689       DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
690       shallitime=0;
691     }
692   else
693     {
694       DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
695                finfo.name,
696                (double)finfo.size,
697                lname));
698       
699       /* write a tar header, don't bother with mode - just set to 100644 */
700       writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
701
702       while (nread < finfo.size && !close_done) {
703               
704               DEBUG(3,("nread=%.0f\n",(double)nread));
705               
706               datalen = cli_read(cli->tree, fnum, data, nread, read_size);
707               
708               if (datalen == -1) {
709                       DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli->tree)));
710                       break;
711               }
712               
713                   nread += datalen;
714
715                   /* if file size has increased since we made file size query, truncate
716                         read so tar header for this file will be correct.
717                    */
718
719                   if (nread > finfo.size) {
720                         datalen -= nread - finfo.size;
721                         DEBUG(0,("File size change - truncating %s to %.0f bytes\n", finfo.name, (double)finfo.size));
722                   }
723
724               /* add received bits of file to buffer - dotarbuf will
725                * write out in 512 byte intervals */
726               if (dotarbuf(tarhandle,data,datalen) != datalen) {
727                       DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
728                       break;
729               }
730               
731               if (datalen == 0) {
732                       DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
733                       break;
734               }
735
736               datalen=0;
737       }
738
739       /* pad tar file with zero's if we couldn't get entire file */
740       if (nread < finfo.size) {
741               DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n", (double)finfo.size, (int)nread));
742               if (padit(data, sizeof(data), finfo.size - nread))
743                       DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
744       }
745
746       /* round tar file to nearest block */
747       if (finfo.size % TBLOCK)
748         dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
749       
750       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
751       ntarf++;
752     }
753   
754   cli_close(cli->tree, fnum);
755
756   if (shallitime)
757     {
758       struct timeval tp_end;
759       int this_time;
760
761       /* if shallitime is true then we didn't skip */
762       if (tar_reset && !dry_run)
763         (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
764       
765       GetTimeOfDay(&tp_end);
766       this_time = 
767         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
768           (tp_end.tv_usec - tp_start.tv_usec)/1000;
769       get_total_time_ms += this_time;
770       get_total_size += finfo.size;
771
772       if (tar_noisy)
773         {
774           DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
775                (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
776                finfo.name));
777         }
778
779       /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
780       DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
781                finfo.size / MAX(0.001, (1.024*this_time)),
782                get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
783     }
784 }
785
786 /****************************************************************************
787 Append single file to tar file (or not)
788 ***************************************************************************/
789 static void do_tar(file_info *finfo)
790 {
791   pstring rname;
792
793   if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
794     return;
795
796   /* Is it on the exclude list ? */
797   if (!tar_excl && clipn) {
798     pstring exclaim;
799
800     DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
801
802     safe_strcpy(exclaim, cur_dir, sizeof(pstring));
803     *(exclaim+strlen(exclaim)-1)='\0';
804
805     safe_strcat(exclaim, "\\", sizeof(pstring));
806     safe_strcat(exclaim, finfo->name, sizeof(exclaim));
807
808     DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
809
810     if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
811 #ifdef HAVE_REGEX_H
812         (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
813 #else
814         (tar_re_search && mask_match(cli, exclaim, cliplist[0], True))) {
815 #endif
816       DEBUG(3,("Skipping file %s\n", exclaim));
817       return;
818     }
819   }
820
821   if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY)
822     {
823       pstring saved_curdir;
824       pstring mtar_mask;
825
826       safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
827
828       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));
829
830       safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
831       safe_strcat(cur_dir,"\\", sizeof(cur_dir));
832
833       DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
834
835       /* write a tar directory, don't bother with mode - just set it to
836        * 40755 */
837       writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
838       if (tar_noisy) {
839           DEBUG(0,("                directory %s\n", cur_dir));
840       }
841       ntarf++;  /* Make sure we have a file on there */
842       safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
843       safe_strcat(mtar_mask,"*", sizeof(pstring));
844       DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
845       do_list(mtar_mask, attribute, do_tar, False, True);
846       safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
847     }
848   else
849     {
850       safe_strcpy(rname,cur_dir, sizeof(pstring));
851       safe_strcat(rname,finfo->name, sizeof(pstring));
852       do_atar(rname,finfo->name,finfo);
853     }
854 }
855
856 /****************************************************************************
857 Convert from UNIX to DOS file names
858 ***************************************************************************/
859 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
860 {
861         /* remove '.' from start of file name, convert from unix /'s to
862          * dos \'s in path. Kill any absolute path names. But only if first!
863          */
864
865         DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
866
867         if (first) {
868                 if (*fp == '.') {
869                         fp++;
870                         l--;
871                 }
872                 if (*fp == '\\' || *fp == '/') {
873                         fp++;
874                         l--;
875                 }
876         }
877
878         safe_strcpy(tptr, fp, l);
879         string_replace(tptr, '/', '\\');
880 }
881
882
883 /****************************************************************************
884 Move to the next block in the buffer, which may mean read in another set of
885 blocks. FIXME, we should allow more than one block to be skipped.
886 ****************************************************************************/
887 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
888 {
889   int bufread, total = 0;
890
891   DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
892   *bufferp += TBLOCK;
893   total = TBLOCK;
894
895   if (*bufferp >= (ltarbuf + bufsiz)) {
896
897     DEBUG(5, ("Reading more data into ltarbuf ...\n"));
898
899     /*
900      * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
901      * Fixes bug where read can return short if coming from
902      * a pipe.
903      */
904
905     bufread = read(tarhandle, ltarbuf, bufsiz);
906     total = bufread;
907
908     while (total < bufsiz) {
909       if (bufread < 0) { /* An error, return false */
910         return (total > 0 ? -2 : bufread);
911       }
912       if (bufread == 0) {
913         if (total <= 0) {
914             return -2;
915         }
916         break;
917       }
918       bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
919       total += bufread;
920     }
921
922     DEBUG(5, ("Total bytes read ... %i\n", total));
923
924     *bufferp = ltarbuf;
925
926   }
927
928   return(total);
929
930 }
931
932 /* Skip a file, even if it includes a long file name? */
933 static int skip_file(int skipsize)
934 {
935   int dsize = skipsize;
936
937   DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
938
939   /* FIXME, we should skip more than one block at a time */
940
941   while (dsize > 0) {
942
943     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
944
945         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
946         return(False);
947
948     }
949
950     dsize -= TBLOCK;
951
952   }
953
954   return(True);
955 }
956
957 /*************************************************************
958  Get a file from the tar file and store it.
959  When this is called, tarbuf already contains the first
960  file block. This is a bit broken & needs fixing.
961 **************************************************************/
962
963 static int get_file(file_info2 finfo)
964 {
965   int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
966
967   DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
968
969   if (ensurepath(finfo.name) && 
970       (fnum=cli_open(cli->tree, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
971       DEBUG(0, ("abandoning restore\n"));
972       return(False);
973   }
974
975   /* read the blocks from the tar file and write to the remote file */
976
977   rsize = finfo.size;  /* This is how much to write */
978
979   while (rsize > 0) {
980
981     /* We can only write up to the end of the buffer */
982
983     dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
984     dsize = MIN(dsize, rsize);  /* Should be only what is left */
985     DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
986
987     if (cli_write(cli->tree, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
988             DEBUG(0, ("Error writing remote file\n"));
989             return 0;
990     }
991
992     rsize -= dsize;
993     pos += dsize;
994
995     /* Now figure out how much to move in the buffer */
996
997     /* FIXME, we should skip more than one block at a time */
998
999     /* First, skip any initial part of the part written that is left over */
1000     /* from the end of the first TBLOCK                                   */
1001
1002     if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1003
1004       dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
1005       bpos = 0;
1006
1007       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
1008         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1009         return False;
1010
1011       }
1012
1013     }
1014
1015     /*
1016      * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1017      * If the file being extracted is an exact multiple of
1018      * TBLOCK bytes then we don't want to extract the next
1019      * block from the tarfile here, as it will be done in
1020      * the caller of get_file().
1021      */
1022
1023     while (((rsize != 0) && (dsize >= TBLOCK)) ||
1024          ((rsize == 0) && (dsize > TBLOCK))) {
1025
1026       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1027         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1028         return False;
1029       }
1030
1031       dsize -= TBLOCK;
1032     }
1033
1034     bpos = dsize;
1035
1036   }
1037
1038   /* Now close the file ... */
1039
1040   if (NT_STATUS_IS_ERR(cli_close(cli->tree, fnum))) {
1041           DEBUG(0, ("Error closing remote file\n"));
1042           return(False);
1043   }
1044
1045   /* Now we update the creation date ... */
1046
1047   DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1048
1049   if (NT_STATUS_IS_ERR(cli_setatr(cli->tree, finfo.name, finfo.mode, finfo.mtime))) {
1050           if (tar_real_noisy) {
1051                   DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1052                   /*return(False); */ /* Ignore, as Win95 does not allow changes */
1053           }
1054   }
1055
1056   ntarf++;
1057
1058   DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1059   
1060   return(True);
1061 }
1062
1063 /* Create a directory.  We just ensure that the path exists and return as there
1064    is no file associated with a directory 
1065 */
1066 static int get_dir(file_info2 finfo)
1067 {
1068
1069   DEBUG(0, ("restore directory %s\n", finfo.name));
1070
1071   if (!ensurepath(finfo.name)) {
1072
1073     DEBUG(0, ("Problems creating directory\n"));
1074     return(False);
1075
1076   }
1077
1078   ntarf++;
1079   return(True);
1080
1081 }
1082 /* Get a file with a long file name ... first file has file name, next file 
1083    has the data. We only want the long file name, as the loop in do_tarput
1084    will deal with the rest.
1085 */
1086 static char * get_longfilename(file_info2 finfo)
1087 {
1088   int namesize = finfo.size + strlen(cur_dir) + 2;
1089   char *longname = malloc(namesize);
1090   int offset = 0, left = finfo.size;
1091   BOOL first = True;
1092
1093   DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1094   DEBUG(5, ("Len = %d\n", (int)finfo.size));
1095
1096   if (longname == NULL) {
1097
1098     DEBUG(0, ("could not allocate buffer of size %d for longname\n", 
1099               (int)(finfo.size + strlen(cur_dir) + 2)));
1100     return(NULL);
1101   }
1102
1103   /* First, add cur_dir to the long file name */
1104
1105   if (strlen(cur_dir) > 0) {
1106     strncpy(longname, cur_dir, namesize);
1107     offset = strlen(cur_dir);
1108   }
1109
1110   /* Loop through the blocks picking up the name */
1111
1112   while (left > 0) {
1113
1114     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1115
1116       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1117       return(NULL);
1118
1119     }
1120
1121     unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1122     DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1123
1124     offset += TBLOCK;
1125     left -= TBLOCK;
1126
1127   }
1128
1129   return(longname);
1130
1131 }
1132
1133 static void do_tarput(void)
1134 {
1135   file_info2 finfo;
1136   struct timeval tp_start;
1137   char *longfilename = NULL, linkflag;
1138   int skip = False;
1139
1140   GetTimeOfDay(&tp_start);
1141
1142   DEBUG(5, ("RJS do_tarput called ...\n"));
1143
1144   buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1145
1146   /* Now read through those files ... */
1147
1148   while (True) {
1149
1150     /* Get us to the next block, or the first block first time around */
1151
1152     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1153
1154       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1155
1156       return;
1157
1158     }
1159
1160     DEBUG(5, ("Reading the next header ...\n"));
1161
1162     switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1163
1164     case -2:    /* Hmm, not good, but not fatal */
1165       DEBUG(0, ("Skipping %s...\n", finfo.name));
1166       if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1167           !skip_file(finfo.size)) {
1168
1169         DEBUG(0, ("Short file, bailing out...\n"));
1170         return;
1171
1172       }
1173
1174       break;
1175
1176     case -1:
1177       DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1178       return;
1179
1180     case 0: /* chksum is zero - looks like an EOF */
1181       DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1182       return;        /* Hmmm, bad here ... */
1183
1184     default: 
1185       /* No action */
1186
1187       break;
1188
1189     }
1190
1191     /* Now, do we have a long file name? */
1192
1193     if (longfilename != NULL) {
1194
1195       SAFE_FREE(finfo.name);   /* Free the space already allocated */
1196       finfo.name = longfilename;
1197       longfilename = NULL;
1198
1199     }
1200
1201     /* Well, now we have a header, process the file ...            */
1202
1203     /* Should we skip the file? We have the long name as well here */
1204
1205     skip = clipn &&
1206       ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1207 #ifdef HAVE_REGEX_H
1208       || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1209 #else
1210       || (tar_re_search && mask_match(cli, finfo.name, cliplist[0], True)));
1211 #endif
1212
1213   DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1214
1215   if (skip) {
1216
1217     skip_file(finfo.size);
1218     continue;
1219
1220   }
1221
1222     /* We only get this far if we should process the file */
1223   linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1224
1225     switch (linkflag) {
1226
1227     case '0':  /* Should use symbolic names--FIXME */
1228
1229       /* 
1230        * Skip to the next block first, so we can get the file, FIXME, should
1231        * be in get_file ...
1232        * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1233        * Fixes bug where file size in tarfile is zero.
1234        */
1235
1236       if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1237         DEBUG(0, ("Short file, bailing out...\n"));
1238         return;
1239       }
1240       if (!get_file(finfo)) {
1241         DEBUG(0, ("Abandoning restore\n"));
1242         return;
1243
1244       }
1245       break;
1246
1247     case '5':
1248       if (!get_dir(finfo)) {
1249         DEBUG(0, ("Abandoning restore \n"));
1250         return;
1251       }
1252       break;
1253
1254     case 'L':
1255       longfilename = get_longfilename(finfo);
1256       if (!longfilename) {
1257         DEBUG(0, ("abandoning restore\n"));
1258         return;
1259
1260       }
1261       DEBUG(5, ("Long file name: %s\n", longfilename));
1262       break;
1263
1264     default:
1265       skip_file(finfo.size);  /* Don't handle these yet */
1266       break;
1267
1268     }
1269
1270   }
1271
1272
1273 }
1274
1275
1276 /*
1277  * samba interactive commands
1278  */
1279
1280 /****************************************************************************
1281 Blocksize command
1282 ***************************************************************************/
1283 int cmd_block(void)
1284 {
1285   fstring buf;
1286   int block;
1287
1288   if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1289     {
1290       DEBUG(0, ("blocksize <n>\n"));
1291       return 1;
1292     }
1293
1294   block=atoi(buf);
1295   if (block < 0 || block > 65535)
1296     {
1297       DEBUG(0, ("blocksize out of range"));
1298       return 1;
1299     }
1300
1301   blocksize=block;
1302   DEBUG(2,("blocksize is now %d\n", blocksize));
1303
1304   return 0;
1305 }
1306
1307 /****************************************************************************
1308 command to set incremental / reset mode
1309 ***************************************************************************/
1310 int cmd_tarmode(void)
1311 {
1312   fstring buf;
1313
1314   while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1315     if (strequal(buf, "full"))
1316       tar_inc=False;
1317     else if (strequal(buf, "inc"))
1318       tar_inc=True;
1319     else if (strequal(buf, "reset"))
1320       tar_reset=True;
1321     else if (strequal(buf, "noreset"))
1322       tar_reset=False;
1323     else if (strequal(buf, "system"))
1324       tar_system=True;
1325     else if (strequal(buf, "nosystem"))
1326       tar_system=False;
1327     else if (strequal(buf, "hidden"))
1328       tar_hidden=True;
1329     else if (strequal(buf, "nohidden"))
1330       tar_hidden=False;
1331     else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1332       tar_noisy=True;
1333     else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1334       tar_noisy=False;
1335     else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1336   }
1337
1338   DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1339             tar_inc ? "incremental" : "full",
1340             tar_system ? "system" : "nosystem",
1341             tar_hidden ? "hidden" : "nohidden",
1342             tar_reset ? "reset" : "noreset",
1343             tar_noisy ? "verbose" : "quiet"));
1344
1345   return 0;
1346 }
1347
1348 /****************************************************************************
1349 Feeble attrib command
1350 ***************************************************************************/
1351 int cmd_setmode(void)
1352 {
1353   char *q;
1354   fstring buf;
1355   pstring fname;
1356   uint16 attra[2];
1357   int direct=1;
1358
1359   attra[0] = attra[1] = 0;
1360
1361   if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1362     {
1363       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1364       return 1;
1365     }
1366
1367   safe_strcpy(fname, cur_dir, sizeof(pstring));
1368   safe_strcat(fname, buf, sizeof(pstring));
1369
1370   while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1371     q=buf;
1372
1373     while(*q)
1374       switch (*q++) {
1375       case '+': direct=1;
1376         break;
1377       case '-': direct=0;
1378         break;
1379       case 'r': attra[direct]|=FILE_ATTRIBUTE_READONLY;
1380         break;
1381       case 'h': attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1382         break;
1383       case 's': attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1384         break;
1385       case 'a': attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1386         break;
1387       default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1388         return 1;
1389       }
1390   }
1391
1392   if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1393     {
1394       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1395       return 1;
1396     }
1397
1398   DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1399   do_setrattr(fname, attra[ATTRSET], ATTRSET);
1400   do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1401
1402   return 0;
1403 }
1404
1405 /****************************************************************************
1406 Principal command for creating / extracting
1407 ***************************************************************************/
1408 int cmd_tar(void)
1409 {
1410   fstring buf;
1411   char **argl;
1412   int argcl;
1413
1414   if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1415     {
1416       DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1417       return 1;
1418     }
1419
1420   argl=toktocliplist(&argcl, NULL);
1421   if (!tar_parseargs(argcl, argl, buf, 0))
1422     return 1;
1423
1424   process_tar();
1425
1426   SAFE_FREE(argl);
1427
1428   return 0;
1429 }
1430
1431 /****************************************************************************
1432 Command line (option) version
1433 ***************************************************************************/
1434 int process_tar(void)
1435 {
1436   initarbuf();
1437   switch(tar_type) {
1438   case 'x':
1439
1440 #if 0
1441     do_tarput2();
1442 #else
1443     do_tarput();
1444 #endif
1445     SAFE_FREE(tarbuf);
1446     close(tarhandle);
1447     break;
1448   case 'r':
1449   case 'c':
1450     if (clipn && tar_excl) {
1451       int i;
1452       pstring tarmac;
1453
1454       for (i=0; i<clipn; i++) {
1455         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1456
1457         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1458           *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1459         }
1460         
1461         if (strrchr_m(cliplist[i], '\\')) {
1462           pstring saved_dir;
1463           
1464           safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1465           
1466           if (*cliplist[i]=='\\') {
1467             safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1468           } else {
1469             safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1470             safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1471           }
1472           safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1473           *(strrchr_m(cur_dir, '\\')+1)='\0';
1474
1475           DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1476           do_list(tarmac,attribute,do_tar, False, True);
1477           safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1478         } else {
1479           safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1480           safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1481           DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1482           do_list(tarmac,attribute,do_tar, False, True);
1483         }
1484       }
1485     } else {
1486       pstring mask;
1487       safe_strcpy(mask,cur_dir, sizeof(pstring));
1488       DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1489       safe_strcat(mask,"\\*", sizeof(pstring));
1490       do_list(mask,attribute,do_tar,False, True);
1491     }
1492     
1493     if (ntarf) dotareof(tarhandle);
1494     close(tarhandle);
1495     SAFE_FREE(tarbuf);
1496     
1497     DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1498     DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1499     break;
1500   }
1501
1502   if (must_free_cliplist) {
1503     int i;
1504     for (i = 0; i < clipn; ++i) {
1505       SAFE_FREE(cliplist[i]);
1506     }
1507     SAFE_FREE(cliplist);
1508     cliplist = NULL;
1509     clipn = 0;
1510     must_free_cliplist = False;
1511   }
1512
1513   return(0);
1514 }
1515
1516 /****************************************************************************
1517 Find a token (filename) in a clip list
1518 ***************************************************************************/
1519 static int clipfind(char **aret, int ret, char *tok)
1520 {
1521   if (aret==NULL) return 0;
1522
1523   /* ignore leading slashes or dots in token */
1524   while(strchr_m("/\\.", *tok)) tok++;
1525
1526   while(ret--) {
1527     char *pkey=*aret++;
1528
1529     /* ignore leading slashes or dots in list */
1530     while(strchr_m("/\\.", *pkey)) pkey++;
1531
1532     if (!strslashcmp(pkey, tok)) return 1;
1533   }
1534
1535   return 0;
1536 }
1537
1538 /****************************************************************************
1539 Read list of files to include from the file and initialize cliplist
1540 accordingly.
1541 ***************************************************************************/
1542 static int read_inclusion_file(char *filename)
1543 {
1544   XFILE *inclusion = NULL;
1545   char buf[MAXPATHLEN + 1];
1546   char *inclusion_buffer = NULL;
1547   int inclusion_buffer_size = 0;
1548   int inclusion_buffer_sofar = 0;
1549   char *p;
1550   char *tmpstr;
1551   int i;
1552   int error = 0;
1553
1554   clipn = 0;
1555   buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1556   if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1557     /* XXX It would be better to include a reason for failure, but without
1558      * autoconf, it's hard to use strerror, sys_errlist, etc.
1559      */
1560     DEBUG(0,("Unable to open inclusion file %s\n", filename));
1561     return 0;
1562   }
1563
1564   while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1565     if (inclusion_buffer == NULL) {
1566       inclusion_buffer_size = 1024;
1567       if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1568         DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1569         error = 1;
1570         break;
1571       }
1572     }
1573     
1574     if (buf[strlen(buf)-1] == '\n') {
1575       buf[strlen(buf)-1] = '\0';
1576     }
1577     
1578     if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1579       char *ib;
1580       inclusion_buffer_size *= 2;
1581       ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1582       if (! ib) {
1583         DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1584                  inclusion_buffer_size));
1585         error = 1;
1586         break;
1587       }
1588       else inclusion_buffer = ib;
1589     }
1590     
1591     safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1592     inclusion_buffer_sofar += strlen(buf) + 1;
1593     clipn++;
1594   }
1595   x_fclose(inclusion);
1596
1597   if (! error) {
1598     /* Allocate an array of clipn + 1 char*'s for cliplist */
1599     cliplist = malloc((clipn + 1) * sizeof(char *));
1600     if (cliplist == NULL) {
1601       DEBUG(0,("failure allocating memory for cliplist\n"));
1602       error = 1;
1603     } else {
1604       cliplist[clipn] = NULL;
1605       p = inclusion_buffer;
1606       for (i = 0; (! error) && (i < clipn); i++) {
1607         /* set current item to NULL so array will be null-terminated even if
1608          * malloc fails below. */
1609         cliplist[i] = NULL;
1610         if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1611           DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1612           error = 1;
1613         } else {
1614           unfixtarname(tmpstr, p, strlen(p) + 1, True);
1615           cliplist[i] = tmpstr;
1616           if ((p = strchr_m(p, '\000')) == NULL) {
1617             DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1618             abort();
1619           }
1620         }
1621         ++p;
1622       }
1623       must_free_cliplist = True;
1624     }
1625   }
1626
1627   SAFE_FREE(inclusion_buffer);
1628   if (error) {
1629     if (cliplist) {
1630       char **pp;
1631       /* We know cliplist is always null-terminated */
1632       for (pp = cliplist; *pp; ++pp) {
1633         SAFE_FREE(*pp);
1634       }
1635       SAFE_FREE(cliplist);
1636       cliplist = NULL;
1637       must_free_cliplist = False;
1638     }
1639     return 0;
1640   }
1641   
1642   /* cliplist and its elements are freed at the end of process_tar. */
1643   return 1;
1644 }
1645
1646 /****************************************************************************
1647 Parse tar arguments. Sets tar_type, tar_excl, etc.
1648 ***************************************************************************/
1649 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1650 {
1651   char tar_clipfl='\0';
1652
1653   /* Reset back to defaults - could be from interactive version 
1654    * reset mode and archive mode left as they are though
1655    */
1656   tar_type='\0';
1657   tar_excl=True;
1658   dry_run=False;
1659
1660   while (*Optarg) 
1661     switch(*Optarg++) {
1662     case 'c':
1663       tar_type='c';
1664       break;
1665     case 'x':
1666       if (tar_type=='c') {
1667         printf("Tar must be followed by only one of c or x.\n");
1668         return 0;
1669       }
1670       tar_type='x';
1671       break;
1672     case 'b':
1673       if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1674         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1675         return 0;
1676       } else {
1677         Optind++;
1678       }
1679       break;
1680     case 'g':
1681       tar_inc=True;
1682       break;
1683     case 'N':
1684       if (Optind>=argc) {
1685         DEBUG(0,("Option N must be followed by valid file name\n"));
1686         return 0;
1687       } else {
1688         SMB_STRUCT_STAT stbuf;
1689         extern time_t newer_than;
1690         
1691         if (sys_stat(argv[Optind], &stbuf) == 0) {
1692           newer_than = stbuf.st_mtime;
1693           DEBUG(1,("Getting files newer than %s",
1694                    asctime(LocalTime(&newer_than))));
1695           Optind++;
1696         } else {
1697           DEBUG(0,("Error setting newer-than time\n"));
1698           return 0;
1699         }
1700       }
1701       break;
1702     case 'a':
1703       tar_reset=True;
1704       break;
1705     case 'q':
1706       tar_noisy=False;
1707       break;
1708     case 'I':
1709       if (tar_clipfl) {
1710         DEBUG(0,("Only one of I,X,F must be specified\n"));
1711         return 0;
1712       }
1713       tar_clipfl='I';
1714       break;
1715     case 'X':
1716       if (tar_clipfl) {
1717         DEBUG(0,("Only one of I,X,F must be specified\n"));
1718         return 0;
1719       }
1720       tar_clipfl='X';
1721       break;
1722     case 'F':
1723       if (tar_clipfl) {
1724         DEBUG(0,("Only one of I,X,F must be specified\n"));
1725         return 0;
1726       }
1727       tar_clipfl='F';
1728       break;
1729     case 'r':
1730       DEBUG(0, ("tar_re_search set\n"));
1731       tar_re_search = True;
1732       break;
1733     case 'n':
1734       if (tar_type == 'c') {
1735         DEBUG(0, ("dry_run set\n"));
1736         dry_run = True;
1737       } else {
1738         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1739         return 0;
1740       }
1741       break;
1742     default:
1743       DEBUG(0,("Unknown tar option\n"));
1744       return 0;
1745     }
1746
1747   if (!tar_type) {
1748     printf("Option T must be followed by one of c or x.\n");
1749     return 0;
1750   }
1751
1752   /* tar_excl is true if cliplist lists files to be included.
1753    * Both 'I' and 'F' mean include. */
1754   tar_excl=tar_clipfl!='X';
1755
1756   if (tar_clipfl=='F') {
1757     if (argc-Optind-1 != 1) {
1758       DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1759       return 0;
1760     }
1761     if (! read_inclusion_file(argv[Optind+1])) {
1762       return 0;
1763     }
1764   } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1765     char *tmpstr;
1766     char **tmplist;
1767     int clipcount;
1768
1769     cliplist=argv+Optind+1;
1770     clipn=argc-Optind-1;
1771     clipcount = clipn;
1772
1773     if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1774       DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
1775                clipn)
1776            );
1777       return 0;
1778     }
1779
1780     for (clipcount = 0; clipcount < clipn; clipcount++) {
1781
1782       DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1783
1784       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1785         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1786                  clipcount)
1787              );
1788         return 0;
1789       }
1790       unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1791       tmplist[clipcount] = tmpstr;
1792       DEBUG(5, ("Processed an item, %s\n", tmpstr));
1793
1794       DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1795     }
1796     cliplist = tmplist;
1797     must_free_cliplist = True;
1798   }
1799
1800   if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
1801 #ifdef HAVE_REGEX_H
1802     int errcode;
1803
1804     if ((preg = (regex_t *)malloc(65536)) == NULL) {
1805
1806       DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1807       return;
1808
1809     }
1810
1811     if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1812       char errstr[1024];
1813       size_t errlen;
1814
1815       errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1816       
1817       DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1818       return;
1819
1820     }
1821 #endif
1822
1823     clipn=argc-Optind-1;
1824     cliplist=argv+Optind+1;
1825
1826   }
1827
1828   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1829     /* Sets tar handle to either 0 or 1, as appropriate */
1830     tarhandle=(tar_type=='c');
1831     /*
1832      * Make sure that dbf points to stderr if we are using stdout for 
1833      * tar output
1834     */
1835     if (tarhandle == 1) 
1836             setup_logging("clitar", DEBUG_STDERR);
1837   } else {
1838     if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1839       {
1840         if (!dry_run) {
1841           DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1842           dry_run = True;
1843         }
1844         tarhandle=-1;
1845       } else
1846     if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1847         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1848       {
1849         DEBUG(0,("Error opening local file %s - %s\n",
1850                  argv[Optind], strerror(errno)));
1851         return(0);
1852       }
1853   }
1854
1855   return 1;
1856 }