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