first public release of samba4 code
[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 "clitar.h"
40 #include "../client/client_proto.h"
41
42 static int clipfind(char **aret, int ret, char *tok);
43 void dos_clean_name(char *s);
44
45 typedef struct file_info_struct file_info2;
46
47 struct file_info_struct
48 {
49   SMB_BIG_UINT size;
50   uint16 mode;
51   uid_t uid;
52   gid_t gid;
53   /* These times are normally kept in GMT */
54   time_t mtime;
55   time_t atime;
56   time_t ctime;
57   char *name;     /* This is dynamically allocate */
58
59   file_info2 *next, *prev;  /* Used in the stack ... */
60
61 };
62
63 typedef struct
64 {
65   file_info2 *top;
66   int items;
67
68 } stack;
69
70 #define SEPARATORS " \t\n\r"
71 extern struct cli_state *cli;
72
73 /* These defines are for the do_setrattr routine, to indicate
74  * setting and reseting of file attributes in the function call */
75 #define ATTRSET 1
76 #define ATTRRESET 0
77
78 static uint16 attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
79
80 #ifndef CLIENT_TIMEOUT
81 #define CLIENT_TIMEOUT (30*1000)
82 #endif
83
84 static char *tarbuf, *buffer_p;
85 static int tp, ntarf, tbufsiz;
86 static double ttarf;
87 /* Incremental mode */
88 static BOOL tar_inc=False;
89 /* Reset archive bit */
90 static BOOL tar_reset=False;
91 /* Include / exclude mode (true=include, false=exclude) */
92 static BOOL tar_excl=True;
93 /* use regular expressions for search on file names */
94 static BOOL tar_re_search=False;
95 #ifdef HAVE_REGEX_H
96 regex_t *preg;
97 #endif
98 /* Do not dump anything, just calculate sizes */
99 static BOOL dry_run=False;
100 /* Dump files with System attribute */
101 static BOOL tar_system=True;
102 /* Dump files with Hidden attribute */
103 static BOOL tar_hidden=True;
104 /* Be noisy - make a catalogue */
105 static BOOL tar_noisy=True;
106 static BOOL tar_real_noisy=False;  /* Don't want to be really noisy by default */
107
108 char tar_type='\0';
109 static char **cliplist=NULL;
110 static int clipn=0;
111 static BOOL must_free_cliplist = False;
112
113 extern file_info def_finfo;
114 extern BOOL lowercase;
115 extern uint16 cnum;
116 extern BOOL readbraw_supported;
117 extern int max_xmit;
118 extern pstring cur_dir;
119 extern int get_total_time_ms;
120 extern int get_total_size;
121
122 static int blocksize=20;
123 static int tarhandle;
124
125 static void writetarheader(int f,  const char *aname, SMB_BIG_UINT size, time_t mtime,
126                            const char *amode, unsigned char ftype);
127 static void do_atar(char *rname,char *lname,file_info *finfo1);
128 static void do_tar(file_info *finfo);
129 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
130 static void fixtarname(char *tptr, const char *fp, int l);
131 static int dotarbuf(int f, char *b, int n);
132 static void dozerobuf(int f, int n);
133 static void dotareof(int f);
134 static void initarbuf(void);
135
136 /* restore functions */
137 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
138 static long unoct(char *p, int ndgs);
139 static void do_tarput(void);
140 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
141
142 /*
143  * tar specific utitlities
144  */
145
146 /*******************************************************************
147 Create  a string of size size+1 (for the null)
148 *******************************************************************/
149 static char *string_create_s(int size)
150 {
151   char *tmp;
152
153   tmp = (char *)malloc(size+1);
154
155   if (tmp == NULL) {
156
157     DEBUG(0, ("Out of memory in string_create_s\n"));
158
159   }
160
161   return(tmp);
162
163 }
164
165 /****************************************************************************
166 Write a tar header to buffer
167 ****************************************************************************/
168 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
169                            const char *amode, unsigned char ftype)
170 {
171   union hblock hb;
172   int i, chk, l;
173   char *jp;
174
175   DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
176
177   memset(hb.dummy, 0, sizeof(hb.dummy));
178   
179   l=strlen(aname);
180   if (l >= NAMSIZ - 1) {
181           /* write a GNU tar style long header */
182           char *b;
183           b = (char *)malloc(l+TBLOCK+100);
184           if (!b) {
185                   DEBUG(0,("out of memory\n"));
186                   exit(1);
187           }
188           writetarheader(f, "/./@LongLink", l+2, 0, "     0 \0", 'L');
189           memset(b, 0, l+TBLOCK+100);
190           fixtarname(b, aname, l);
191           i = strlen(b)+1;
192           DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
193           dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
194           SAFE_FREE(b);
195   }
196
197   /* use l + 1 to do the null too */
198   fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
199
200   if (lowercase)
201     strlower(hb.dbuf.name);
202
203   /* write out a "standard" tar format header */
204
205   hb.dbuf.name[NAMSIZ-1]='\0';
206   safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
207   oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
208   oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
209   oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
210   oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
211   memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
212   memset(hb.dbuf.linkname, 0, NAMSIZ);
213   hb.dbuf.linkflag=ftype;
214   
215   for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
216
217   oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
218   hb.dbuf.chksum[6] = '\0';
219
220   (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
221 }
222
223 /****************************************************************************
224 Read a tar header into a hblock structure, and validate
225 ***************************************************************************/
226 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
227 {
228   long chk, fchk;
229   int i;
230   char *jp;
231
232   /*
233    * read in a "standard" tar format header - we're not that interested
234    * in that many fields, though
235    */
236
237   /* check the checksum */
238   for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
239
240   if (chk == 0)
241     return chk;
242
243   /* compensate for blanks in chksum header */
244   for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
245     chk-=(0xFF & *jp++);
246
247   chk += ' ' * sizeof(hb->dbuf.chksum);
248
249   fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
250
251   DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
252             chk, fchk, hb->dbuf.chksum));
253
254   if (fchk != chk)
255     {
256       DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
257       dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
258       return -1;
259     }
260
261   if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
262
263     DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
264     return(-1);
265
266   }
267
268   safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
269
270   /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
271   unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
272                strlen(hb->dbuf.name) + 1, True);
273
274   /* can't handle some links at present */
275   if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
276     if (hb->dbuf.linkflag == 0) {
277       DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
278                 finfo->name));
279     } else { 
280       if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
281          /* Do nothing here at the moment. do_tarput will handle this
282             as long as the longlink gets back to it, as it has to advance 
283             the buffer pointer, etc */
284
285       } else {
286         DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
287         return -2;
288       }
289     }
290   }
291     
292   if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
293     || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
294     {
295       finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
296     }
297   else
298     finfo->mode=0; /* we don't care about mode at the moment, we'll
299                     * just make it a regular file */
300   /*
301    * Bug fix by richard@sj.co.uk
302    *
303    * REC: restore times correctly (as does tar)
304    * We only get the modification time of the file; set the creation time
305    * from the mod. time, and the access time to current time
306    */
307   finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
308   finfo->atime = time(NULL);
309   finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
310
311   return True;
312 }
313
314 /****************************************************************************
315 Write out the tar buffer to tape or wherever
316 ****************************************************************************/
317 static int dotarbuf(int f, char *b, int n)
318 {
319   int fail=1, writ=n;
320
321   if (dry_run) {
322     return writ;
323   }
324   /* This routine and the next one should be the only ones that do write()s */
325   if (tp + n >= tbufsiz)
326     {
327       int diff;
328
329       diff=tbufsiz-tp;
330       memcpy(tarbuf + tp, b, diff);
331       fail=fail && (1+write(f, tarbuf, tbufsiz));
332       n-=diff;
333       b+=diff;
334       tp=0;
335
336       while (n >= tbufsiz)
337         {
338           fail=fail && (1 + write(f, b, tbufsiz));
339           n-=tbufsiz;
340           b+=tbufsiz;
341         }
342     }
343   if (n>0) {
344     memcpy(tarbuf+tp, b, n);
345     tp+=n;
346   }
347
348   return(fail ? writ : 0);
349 }
350
351 /****************************************************************************
352 Write zeros to buffer / tape
353 ****************************************************************************/
354 static void dozerobuf(int f, int n)
355 {
356   /* short routine just to write out n zeros to buffer -
357    * used to round files to nearest block
358    * and to do tar EOFs */
359
360   if (dry_run)
361     return;
362   
363   if (n+tp >= tbufsiz)
364     {
365       memset(tarbuf+tp, 0, tbufsiz-tp);
366
367       write(f, tarbuf, tbufsiz);
368       memset(tarbuf, 0, (tp+=n-tbufsiz));
369     }
370   else
371     {
372       memset(tarbuf+tp, 0, n);
373       tp+=n;
374     }
375 }
376
377 /****************************************************************************
378 Malloc tape buffer
379 ****************************************************************************/
380 static void initarbuf(void)
381 {
382   /* initialize tar buffer */
383   tbufsiz=blocksize*TBLOCK;
384   tarbuf=malloc(tbufsiz);      /* FIXME: We might not get the buffer */
385
386   /* reset tar buffer pointer and tar file counter and total dumped */
387   tp=0; ntarf=0; ttarf=0;
388 }
389
390 /****************************************************************************
391 Write two zero blocks at end of file
392 ****************************************************************************/
393 static void dotareof(int f)
394 {
395   SMB_STRUCT_STAT stbuf;
396   /* Two zero blocks at end of file, write out full buffer */
397
398   if (dry_run)
399     return;
400
401   (void) dozerobuf(f, TBLOCK);
402   (void) dozerobuf(f, TBLOCK);
403
404   if (sys_fstat(f, &stbuf) == -1)
405     {
406       DEBUG(0, ("Couldn't stat file handle\n"));
407       return;
408     }
409
410   /* Could be a pipe, in which case S_ISREG should fail,
411    * and we should write out at full size */
412   if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
413 }
414
415 /****************************************************************************
416 (Un)mangle DOS pathname, make nonabsolute
417 ****************************************************************************/
418 static void fixtarname(char *tptr, const char *fp, int l)
419 {
420         /* add a '.' to start of file name, convert from ugly dos \'s in path
421          * to lovely unix /'s :-} */
422         *tptr++='.';
423
424         safe_strcpy(tptr, fp, l);
425         string_replace(tptr, '\\', '/');
426 }
427
428 /****************************************************************************
429 Convert from decimal to octal string
430 ****************************************************************************/
431 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
432 {
433   /* Converts long to octal string, pads with leading zeros */
434
435   /* skip final null, but do final space */
436   --ndgs;
437   p[--ndgs] = ' ';
438  
439   /* Loop does at least one digit */
440   do {
441       p[--ndgs] = '0' + (char) (value & 7);
442       value >>= 3;
443     }
444   while (ndgs > 0 && value != 0);
445  
446   /* Do leading zeros */
447   while (ndgs > 0)
448     p[--ndgs] = '0';
449 }
450
451 /****************************************************************************
452 Convert from octal string to long
453 ***************************************************************************/
454 static long unoct(char *p, int ndgs)
455 {
456   long value=0;
457   /* Converts octal string to long, ignoring any non-digit */
458
459   while (--ndgs)
460     {
461       if (isdigit((int)*p))
462         value = (value << 3) | (long) (*p - '0');
463
464       p++;
465     }
466
467   return value;
468 }
469
470 /****************************************************************************
471 Compare two strings in a slash insensitive way, allowing s1 to match s2 
472 if s1 is an "initial" string (up to directory marker).  Thus, if s2 is 
473 a file in any subdirectory of s1, declare a match.
474 ***************************************************************************/
475 static int strslashcmp(char *s1, char *s2)
476 {
477   char *s1_0=s1;
478
479   while(*s1 && *s2 &&
480         (*s1 == *s2
481          || tolower(*s1) == tolower(*s2)
482          || (*s1 == '\\' && *s2=='/')
483          || (*s1 == '/' && *s2=='\\'))) {
484           s1++; s2++;
485   }
486
487   /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" 
488      string of s2.
489    */
490   if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
491
492   /* ignore trailing slash on s1 */
493   if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
494
495   /* check for s1 is an "initial" string of s2 */
496   if ((*s2 == '/' || *s2 == '\\') && !*s1) return 0;
497
498   return *s1-*s2;
499 }
500
501
502 /****************************************************************************
503 Ensure a remote path exists (make if necessary)
504 ***************************************************************************/
505 static BOOL ensurepath(char *fname)
506 {
507   /* *must* be called with buffer ready malloc'ed */
508   /* ensures path exists */
509
510   char *partpath, *ffname;
511   char *p=fname, *basehack;
512
513   DEBUG(5, ( "Ensurepath called with: %s\n", fname));
514
515   partpath = string_create_s(strlen(fname));
516   ffname = string_create_s(strlen(fname));
517
518   if ((partpath == NULL) || (ffname == NULL)){
519
520     DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
521     return(False);
522
523   }
524
525   *partpath = 0;
526
527   /* fname copied to ffname so can strtok */
528
529   safe_strcpy(ffname, fname, strlen(fname));
530
531   /* do a `basename' on ffname, so don't try and make file name directory */
532   if ((basehack=strrchr_m(ffname, '\\')) == NULL)
533     return True;
534   else
535     *basehack='\0';
536
537   p=strtok(ffname, "\\");
538
539   while (p)
540     {
541       safe_strcat(partpath, p, strlen(fname) + 1);
542
543       if (!cli_chkpath(cli, partpath)) {
544         if (!cli_mkdir(cli, partpath))
545           {
546             DEBUG(0, ("Error mkdirhiering\n"));
547             return False;
548           }
549         else
550           DEBUG(3, ("mkdirhiering %s\n", partpath));
551
552       }
553
554       safe_strcat(partpath, "\\", strlen(fname) + 1);
555       p = strtok(NULL,"/\\");
556     }
557
558     return True;
559 }
560
561 static int padit(char *buf, int bufsize, int padsize)
562 {
563         int berr= 0;
564         int bytestowrite;
565   
566         DEBUG(5, ("Padding with %d zeros\n", padsize));
567         memset(buf, 0, bufsize);
568         while( !berr && padsize > 0 ) {
569                 bytestowrite= MIN(bufsize, padsize);
570                 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
571                 padsize -= bytestowrite;
572         }
573   
574         return berr;
575 }
576
577
578 static void do_setrattr(char *name, uint16 attr, int set)
579 {
580         uint16 oldattr;
581
582         if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
583
584         if (set == ATTRSET) {
585                 attr |= oldattr;
586         } else {
587                 attr = oldattr & ~attr;
588         }
589
590         if (!cli_setatr(cli, name, attr, 0)) {
591                 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
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, 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),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 (!cli_getattrE(cli, fnum, &finfo.mode, &size, NULL, &finfo.atime, &finfo.mtime)) {
668                   DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
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, fnum, data, nread, read_size);
707               
708               if (datalen == -1) {
709                       DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
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, 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, 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, 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 (!cli_close(cli, 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 (!cli_setatr(cli, 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 }