Merge from HEAD for Amanda group.
[kai/samba.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_list(exclaim, cliplist, clipn, 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         /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1060          * header call. */
1061         int namesize = finfo.size + strlen(cur_dir) + 2;
1062         char *longname = malloc(namesize);
1063         int offset = 0, left = finfo.size;
1064         BOOL first = True;
1065
1066         DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1067         DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1068
1069         if (longname == NULL) {
1070                 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1071                 return(NULL);
1072         }
1073
1074         /* First, add cur_dir to the long file name */
1075
1076         if (strlen(cur_dir) > 0) {
1077                 strncpy(longname, cur_dir, namesize);
1078                 offset = strlen(cur_dir);
1079         }
1080
1081         /* Loop through the blocks picking up the name */
1082
1083         while (left > 0) {
1084                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1085                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1086                         return(NULL);
1087                 }
1088
1089                 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1090                 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1091
1092                 offset += TBLOCK;
1093                 left -= TBLOCK;
1094         }
1095
1096         return(longname);
1097 }
1098
1099 static void do_tarput(void)
1100 {
1101         file_info2 finfo;
1102         struct timeval tp_start;
1103         char *longfilename = NULL, linkflag;
1104         int skip = False;
1105
1106         GetTimeOfDay(&tp_start);
1107         DEBUG(5, ("RJS do_tarput called ...\n"));
1108
1109         buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1110
1111         /* Now read through those files ... */
1112         while (True) {
1113                 /* Get us to the next block, or the first block first time around */
1114                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1115                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1116                         return;
1117                 }
1118
1119                 DEBUG(5, ("Reading the next header ...\n"));
1120
1121                 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1122                         case -2:    /* Hmm, not good, but not fatal */
1123                                 DEBUG(0, ("Skipping %s...\n", finfo.name));
1124                                 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1125                                         DEBUG(0, ("Short file, bailing out...\n"));
1126                                         return;
1127                                 }
1128                                 break;
1129
1130                         case -1:
1131                                 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1132                                 return;
1133
1134                         case 0: /* chksum is zero - looks like an EOF */
1135                                 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1136                                 return;        /* Hmmm, bad here ... */
1137
1138                         default: 
1139                                 /* No action */
1140                                 break;
1141                 }
1142
1143                 /* Now, do we have a long file name? */
1144                 if (longfilename != NULL) {
1145                         SAFE_FREE(finfo.name);   /* Free the space already allocated */
1146                         finfo.name = longfilename;
1147                         longfilename = NULL;
1148                 }
1149
1150                 /* Well, now we have a header, process the file ...            */
1151                 /* Should we skip the file? We have the long name as well here */
1152                 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1153 #ifdef HAVE_REGEX_H
1154                                         (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1155 #else
1156                                         (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1157 #endif
1158
1159                 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1160                 if (skip) {
1161                         skip_file(finfo.size);
1162                         continue;
1163                 }
1164
1165                 /* We only get this far if we should process the file */
1166                 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1167                 switch (linkflag) {
1168                         case '0':  /* Should use symbolic names--FIXME */
1169                                 /* 
1170                                  * Skip to the next block first, so we can get the file, FIXME, should
1171                                  * be in get_file ...
1172                                  * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1173                                  * Fixes bug where file size in tarfile is zero.
1174                                  */
1175                                 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1176                                         DEBUG(0, ("Short file, bailing out...\n"));
1177                                         return;
1178                                 }
1179                                 if (!get_file(finfo)) {
1180                                         DEBUG(0, ("Abandoning restore\n"));
1181                                         return;
1182                                 }
1183                                 break;
1184                         case '5':
1185                                 if (!get_dir(finfo)) {
1186                                         DEBUG(0, ("Abandoning restore \n"));
1187                                         return;
1188                                 }
1189                                 break;
1190                         case 'L':
1191                                 longfilename = get_longfilename(finfo);
1192                                 if (!longfilename) {
1193                                         DEBUG(0, ("abandoning restore\n"));
1194                                         return;
1195                                 }
1196                                 DEBUG(5, ("Long file name: %s\n", longfilename));
1197                                 break;
1198
1199                         default:
1200                                 skip_file(finfo.size);  /* Don't handle these yet */
1201                                 break;
1202                 }
1203         }
1204 }
1205
1206 /*
1207  * samba interactive commands
1208  */
1209
1210 /****************************************************************************
1211 Blocksize command
1212 ***************************************************************************/
1213
1214 int cmd_block(void)
1215 {
1216         fstring buf;
1217         int block;
1218
1219         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1220                 DEBUG(0, ("blocksize <n>\n"));
1221                 return 1;
1222         }
1223
1224         block=atoi(buf);
1225         if (block < 0 || block > 65535) {
1226                 DEBUG(0, ("blocksize out of range"));
1227                 return 1;
1228         }
1229
1230         blocksize=block;
1231         DEBUG(2,("blocksize is now %d\n", blocksize));
1232
1233         return 0;
1234 }
1235
1236 /****************************************************************************
1237 command to set incremental / reset mode
1238 ***************************************************************************/
1239
1240 int cmd_tarmode(void)
1241 {
1242         fstring buf;
1243
1244         while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1245                 if (strequal(buf, "full"))
1246                         tar_inc=False;
1247                 else if (strequal(buf, "inc"))
1248                         tar_inc=True;
1249                 else if (strequal(buf, "reset"))
1250                         tar_reset=True;
1251                 else if (strequal(buf, "noreset"))
1252                         tar_reset=False;
1253                 else if (strequal(buf, "system"))
1254                         tar_system=True;
1255                 else if (strequal(buf, "nosystem"))
1256                         tar_system=False;
1257                 else if (strequal(buf, "hidden"))
1258                         tar_hidden=True;
1259                 else if (strequal(buf, "nohidden"))
1260                         tar_hidden=False;
1261                 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1262                         tar_noisy=True;
1263                 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1264                         tar_noisy=False;
1265                 else
1266                         DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1267         }
1268
1269         DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1270                         tar_inc ? "incremental" : "full",
1271                         tar_system ? "system" : "nosystem",
1272                         tar_hidden ? "hidden" : "nohidden",
1273                         tar_reset ? "reset" : "noreset",
1274                         tar_noisy ? "verbose" : "quiet"));
1275         return 0;
1276 }
1277
1278 /****************************************************************************
1279 Feeble attrib command
1280 ***************************************************************************/
1281
1282 int cmd_setmode(void)
1283 {
1284         char *q;
1285         fstring buf;
1286         pstring fname;
1287         uint16 attra[2];
1288         int direct=1;
1289
1290         attra[0] = attra[1] = 0;
1291
1292         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1293                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1294                 return 1;
1295         }
1296
1297         pstrcpy(fname, cur_dir);
1298         pstrcat(fname, buf);
1299
1300         while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1301                 q=buf;
1302
1303                 while(*q) {
1304                         switch (*q++) {
1305                                 case '+':
1306                                         direct=1;
1307                                         break;
1308                                 case '-':
1309                                         direct=0;
1310                                         break;
1311                                 case 'r':
1312                                         attra[direct]|=aRONLY;
1313                                         break;
1314                                 case 'h':
1315                                         attra[direct]|=aHIDDEN;
1316                                         break;
1317                                 case 's':
1318                                         attra[direct]|=aSYSTEM;
1319                                         break;
1320                                 case 'a':
1321                                         attra[direct]|=aARCH;
1322                                         break;
1323                                 default:
1324                                         DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1325                                         return 1;
1326                         }
1327                 }
1328         }
1329
1330         if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1331                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1332                 return 1;
1333         }
1334
1335         DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1336         do_setrattr(fname, attra[ATTRSET], ATTRSET);
1337         do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1338         return 0;
1339 }
1340
1341 /****************************************************************************
1342 Principal command for creating / extracting
1343 ***************************************************************************/
1344
1345 int cmd_tar(void)
1346 {
1347         fstring buf;
1348         char **argl;
1349         int argcl;
1350
1351         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1352                 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1353                 return 1;
1354         }
1355
1356         argl=toktocliplist(&argcl, NULL);
1357         if (!tar_parseargs(argcl, argl, buf, 0))
1358                 return 1;
1359
1360         process_tar();
1361         SAFE_FREE(argl);
1362         return 0;
1363 }
1364
1365 /****************************************************************************
1366 Command line (option) version
1367 ***************************************************************************/
1368
1369 int process_tar(void)
1370 {
1371         initarbuf();
1372         switch(tar_type) {
1373                 case 'x':
1374
1375 #if 0
1376                         do_tarput2();
1377 #else
1378                         do_tarput();
1379 #endif
1380                         SAFE_FREE(tarbuf);
1381                         close(tarhandle);
1382                         break;
1383                 case 'r':
1384                 case 'c':
1385                         if (clipn && tar_excl) {
1386                                 int i;
1387                                 pstring tarmac;
1388
1389                                 for (i=0; i<clipn; i++) {
1390                                         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1391
1392                                         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1393                                                 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1394                                         }
1395         
1396                                         if (strrchr_m(cliplist[i], '\\')) {
1397                                                 pstring saved_dir;
1398           
1399                                                 pstrcpy(saved_dir, cur_dir);
1400           
1401                                                 if (*cliplist[i]=='\\') {
1402                                                         pstrcpy(tarmac, cliplist[i]);
1403                                                 } else {
1404                                                         pstrcpy(tarmac, cur_dir);
1405                                                         pstrcat(tarmac, cliplist[i]);
1406                                                 }
1407                                                 pstrcpy(cur_dir, tarmac);
1408                                                 *(strrchr_m(cur_dir, '\\')+1)='\0';
1409
1410                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1411                                                 do_list(tarmac,attribute,do_tar, False, True);
1412                                                 pstrcpy(cur_dir,saved_dir);
1413                                         } else {
1414                                                 pstrcpy(tarmac, cur_dir);
1415                                                 pstrcat(tarmac, cliplist[i]);
1416                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1417                                                 do_list(tarmac,attribute,do_tar, False, True);
1418                                         }
1419                                 }
1420                         } else {
1421                                 pstring mask;
1422                                 pstrcpy(mask,cur_dir);
1423                                 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1424                                 pstrcat(mask,"\\*");
1425                                 do_list(mask,attribute,do_tar,False, True);
1426                         }
1427     
1428                         if (ntarf)
1429                                 dotareof(tarhandle);
1430                         close(tarhandle);
1431                         SAFE_FREE(tarbuf);
1432     
1433                         DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1434                         DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1435                         break;
1436         }
1437
1438         if (must_free_cliplist) {
1439                 int i;
1440                 for (i = 0; i < clipn; ++i) {
1441                         SAFE_FREE(cliplist[i]);
1442                 }
1443                 SAFE_FREE(cliplist);
1444                 cliplist = NULL;
1445                 clipn = 0;
1446                 must_free_cliplist = False;
1447         }
1448         return(0);
1449 }
1450
1451 /****************************************************************************
1452 Find a token (filename) in a clip list
1453 ***************************************************************************/
1454
1455 static int clipfind(char **aret, int ret, char *tok)
1456 {
1457         if (aret==NULL)
1458                 return 0;
1459
1460         /* ignore leading slashes or dots in token */
1461         while(strchr_m("/\\.", *tok))
1462                 tok++;
1463
1464         while(ret--) {
1465                 char *pkey=*aret++;
1466
1467                 /* ignore leading slashes or dots in list */
1468                 while(strchr_m("/\\.", *pkey))
1469                         pkey++;
1470
1471                 if (!strslashcmp(pkey, tok))
1472                         return 1;
1473         }
1474         return 0;
1475 }
1476
1477 /****************************************************************************
1478 Read list of files to include from the file and initialize cliplist
1479 accordingly.
1480 ***************************************************************************/
1481
1482 static int read_inclusion_file(char *filename)
1483 {
1484         XFILE *inclusion = NULL;
1485         char buf[PATH_MAX + 1];
1486         char *inclusion_buffer = NULL;
1487         int inclusion_buffer_size = 0;
1488         int inclusion_buffer_sofar = 0;
1489         char *p;
1490         char *tmpstr;
1491         int i;
1492         int error = 0;
1493
1494         clipn = 0;
1495         buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1496         if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1497                 /* XXX It would be better to include a reason for failure, but without
1498                  * autoconf, it's hard to use strerror, sys_errlist, etc.
1499                  */
1500                 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1501                 return 0;
1502         }
1503
1504         while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1505                 if (inclusion_buffer == NULL) {
1506                         inclusion_buffer_size = 1024;
1507                         if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1508                                 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1509                                 error = 1;
1510                                 break;
1511                         }
1512                 }
1513     
1514                 if (buf[strlen(buf)-1] == '\n') {
1515                         buf[strlen(buf)-1] = '\0';
1516                 }
1517     
1518                 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1519                         char *ib;
1520                         inclusion_buffer_size *= 2;
1521                         ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1522                         if (! ib) {
1523                                 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1524                                                 inclusion_buffer_size));
1525                                 error = 1;
1526                                 break;
1527                         } else {
1528                                 inclusion_buffer = ib;
1529                         }
1530                 }
1531     
1532                 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1533                 inclusion_buffer_sofar += strlen(buf) + 1;
1534                 clipn++;
1535         }
1536         x_fclose(inclusion);
1537
1538         if (! error) {
1539                 /* Allocate an array of clipn + 1 char*'s for cliplist */
1540                 cliplist = malloc((clipn + 1) * sizeof(char *));
1541                 if (cliplist == NULL) {
1542                         DEBUG(0,("failure allocating memory for cliplist\n"));
1543                         error = 1;
1544                 } else {
1545                         cliplist[clipn] = NULL;
1546                         p = inclusion_buffer;
1547                         for (i = 0; (! error) && (i < clipn); i++) {
1548                                 /* set current item to NULL so array will be null-terminated even if
1549                                                 * malloc fails below. */
1550                                 cliplist[i] = NULL;
1551                                 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1552                                         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1553                                         error = 1;
1554                                 } else {
1555                                         unfixtarname(tmpstr, p, strlen(p) + 1, True);
1556                                         cliplist[i] = tmpstr;
1557                                         if ((p = strchr_m(p, '\000')) == NULL) {
1558                                                 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1559                                                 abort();
1560                                         }
1561                                 }
1562                                 ++p;
1563                         }
1564                         must_free_cliplist = True;
1565                 }
1566         }
1567
1568         SAFE_FREE(inclusion_buffer);
1569         if (error) {
1570                 if (cliplist) {
1571                         char **pp;
1572                         /* We know cliplist is always null-terminated */
1573                         for (pp = cliplist; *pp; ++pp) {
1574                                 SAFE_FREE(*pp);
1575                         }
1576                         SAFE_FREE(cliplist);
1577                         cliplist = NULL;
1578                         must_free_cliplist = False;
1579                 }
1580                 return 0;
1581         }
1582   
1583         /* cliplist and its elements are freed at the end of process_tar. */
1584         return 1;
1585 }
1586
1587 /****************************************************************************
1588 Parse tar arguments. Sets tar_type, tar_excl, etc.
1589 ***************************************************************************/
1590
1591 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1592 {
1593         int newOptind = Optind;
1594         char tar_clipfl='\0';
1595
1596         /* Reset back to defaults - could be from interactive version 
1597          * reset mode and archive mode left as they are though
1598          */
1599         tar_type='\0';
1600         tar_excl=True;
1601         dry_run=False;
1602
1603         while (*Optarg) {
1604                 switch(*Optarg++) {
1605                         case 'c':
1606                                 tar_type='c';
1607                                 break;
1608                         case 'x':
1609                                 if (tar_type=='c') {
1610                                         printf("Tar must be followed by only one of c or x.\n");
1611                                         return 0;
1612                                 }
1613                                 tar_type='x';
1614                                 break;
1615                         case 'b':
1616                                 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1617                                         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1618                                         return 0;
1619                                 } else {
1620                                         Optind++;
1621                                         newOptind++;
1622                                 }
1623                                 break;
1624                         case 'g':
1625                                 tar_inc=True;
1626                                 break;
1627                         case 'N':
1628                                 if (Optind>=argc) {
1629                                         DEBUG(0,("Option N must be followed by valid file name\n"));
1630                                         return 0;
1631                                 } else {
1632                                         SMB_STRUCT_STAT stbuf;
1633                                         extern time_t newer_than;
1634         
1635                                         if (sys_stat(argv[Optind], &stbuf) == 0) {
1636                                                 newer_than = stbuf.st_mtime;
1637                                                 DEBUG(1,("Getting files newer than %s",
1638                                                         asctime(LocalTime(&newer_than))));
1639                                                 newOptind++;
1640                                                 Optind++;
1641                                         } else {
1642                                                 DEBUG(0,("Error setting newer-than time\n"));
1643                                                 return 0;
1644                                         }
1645                                 }
1646                                 break;
1647                         case 'a':
1648                                 tar_reset=True;
1649                                 break;
1650                         case 'q':
1651                                 tar_noisy=False;
1652                                 break;
1653                         case 'I':
1654                                 if (tar_clipfl) {
1655                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1656                                         return 0;
1657                                 }
1658                                 tar_clipfl='I';
1659                                 break;
1660                         case 'X':
1661                                 if (tar_clipfl) {
1662                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1663                                         return 0;
1664                                 }
1665                                 tar_clipfl='X';
1666                                 break;
1667                         case 'F':
1668                                 if (tar_clipfl) {
1669                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1670                                         return 0;
1671                                 }
1672                                 tar_clipfl='F';
1673                                 break;
1674                         case 'r':
1675                                 DEBUG(0, ("tar_re_search set\n"));
1676                                 tar_re_search = True;
1677                                 break;
1678                         case 'n':
1679                                 if (tar_type == 'c') {
1680                                         DEBUG(0, ("dry_run set\n"));
1681                                         dry_run = True;
1682                                 } else {
1683                                         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1684                                         return 0;
1685                                 }
1686                                 break;
1687                         default:
1688                                 DEBUG(0,("Unknown tar option\n"));
1689                                 return 0;
1690                 }
1691         }
1692
1693         if (!tar_type) {
1694                 printf("Option T must be followed by one of c or x.\n");
1695                 return 0;
1696         }
1697
1698         /* tar_excl is true if cliplist lists files to be included.
1699          * Both 'I' and 'F' mean include. */
1700         tar_excl=tar_clipfl!='X';
1701
1702         if (tar_clipfl=='F') {
1703                 if (argc-Optind-1 != 1) {
1704                         DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1705                         return 0;
1706                 }
1707                 newOptind++;
1708                 Optind++;
1709                 if (! read_inclusion_file(argv[Optind])) {
1710                         return 0;
1711                 }
1712         } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1713                 char *tmpstr;
1714                 char **tmplist;
1715                 int clipcount;
1716
1717                 cliplist=argv+Optind+1;
1718                 clipn=argc-Optind-1;
1719                 clipcount = clipn;
1720
1721                 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1722                         DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1723                         return 0;
1724                 }
1725
1726                 for (clipcount = 0; clipcount < clipn; clipcount++) {
1727
1728                         DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1729
1730                         if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1731                                 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1732                                 return 0;
1733                         }
1734
1735                         unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1736                         tmplist[clipcount] = tmpstr;
1737                         DEBUG(5, ("Processed an item, %s\n", tmpstr));
1738
1739                         DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1740                 }
1741
1742                 cliplist = tmplist;
1743                 must_free_cliplist = True;
1744
1745                 newOptind += clipn;
1746         }
1747
1748         if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
1749 #ifdef HAVE_REGEX_H
1750                 int errcode;
1751
1752                 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1753
1754                         DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1755                         return;
1756                 }
1757
1758                 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1759                         char errstr[1024];
1760                         size_t errlen;
1761
1762                         errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1763                         DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1764                         return;
1765                 }
1766 #endif
1767
1768                 clipn=argc-Optind-1;
1769                 cliplist=argv+Optind+1;
1770                 newOptind += clipn;
1771         }
1772
1773         if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1774                 /* Sets tar handle to either 0 or 1, as appropriate */
1775                 tarhandle=(tar_type=='c');
1776                 /*
1777                  * Make sure that dbf points to stderr if we are using stdout for 
1778                  * tar output
1779                  */
1780                 if (tarhandle == 1)  {
1781                         dbf = x_stderr;
1782                 }
1783                 if (!argv[Optind]) {
1784                         DEBUG(0,("Must specify tar filename\n"));
1785                         return 0;
1786                 }
1787                 if (!strcmp(argv[Optind], "-")) {
1788                         newOptind++;
1789                 }
1790
1791         } else {
1792                 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0)) {
1793                         if (!dry_run) {
1794                                 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1795                                 dry_run = True;
1796                         }
1797                         tarhandle=-1;
1798                 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1799                                         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1800                         DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1801                         return(0);
1802                 }
1803                 newOptind++;
1804         }
1805
1806         return newOptind;
1807 }