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