b4d6273f7bb695c8dd12c6e50aa78ea7202abff1
[tprouty/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_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 = NULL;
1349         int argcl = 0;
1350         int ret;
1351
1352         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1353                 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1354                 return 1;
1355         }
1356
1357         argl=toktocliplist(&argcl, NULL);
1358         if (!tar_parseargs(argcl, argl, buf, 0))
1359                 return 1;
1360
1361         ret = process_tar();
1362         SAFE_FREE(argl);
1363         return ret;
1364 }
1365
1366 /****************************************************************************
1367 Command line (option) version
1368 ***************************************************************************/
1369
1370 int process_tar(void)
1371 {
1372         int rc = 0;
1373         initarbuf();
1374         switch(tar_type) {
1375                 case 'x':
1376
1377 #if 0
1378                         do_tarput2();
1379 #else
1380                         do_tarput();
1381 #endif
1382                         SAFE_FREE(tarbuf);
1383                         close(tarhandle);
1384                         break;
1385                 case 'r':
1386                 case 'c':
1387                         if (clipn && tar_excl) {
1388                                 int i;
1389                                 pstring tarmac;
1390
1391                                 for (i=0; i<clipn; i++) {
1392                                         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1393
1394                                         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1395                                                 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1396                                         }
1397         
1398                                         if (strrchr_m(cliplist[i], '\\')) {
1399                                                 pstring saved_dir;
1400           
1401                                                 pstrcpy(saved_dir, cur_dir);
1402           
1403                                                 if (*cliplist[i]=='\\') {
1404                                                         pstrcpy(tarmac, cliplist[i]);
1405                                                 } else {
1406                                                         pstrcpy(tarmac, cur_dir);
1407                                                         pstrcat(tarmac, cliplist[i]);
1408                                                 }
1409                                                 pstrcpy(cur_dir, tarmac);
1410                                                 *(strrchr_m(cur_dir, '\\')+1)='\0';
1411
1412                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1413                                                 do_list(tarmac,attribute,do_tar, False, True);
1414                                                 pstrcpy(cur_dir,saved_dir);
1415                                         } else {
1416                                                 pstrcpy(tarmac, cur_dir);
1417                                                 pstrcat(tarmac, cliplist[i]);
1418                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1419                                                 do_list(tarmac,attribute,do_tar, False, True);
1420                                         }
1421                                 }
1422                         } else {
1423                                 pstring mask;
1424                                 pstrcpy(mask,cur_dir);
1425                                 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1426                                 pstrcat(mask,"\\*");
1427                                 do_list(mask,attribute,do_tar,False, True);
1428                         }
1429     
1430                         if (ntarf)
1431                                 dotareof(tarhandle);
1432                         close(tarhandle);
1433                         SAFE_FREE(tarbuf);
1434     
1435                         DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1436                         DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1437                         break;
1438         }
1439
1440         if (must_free_cliplist) {
1441                 int i;
1442                 for (i = 0; i < clipn; ++i) {
1443                         SAFE_FREE(cliplist[i]);
1444                 }
1445                 SAFE_FREE(cliplist);
1446                 cliplist = NULL;
1447                 clipn = 0;
1448                 must_free_cliplist = False;
1449         }
1450         return rc;
1451 }
1452
1453 /****************************************************************************
1454 Find a token (filename) in a clip list
1455 ***************************************************************************/
1456
1457 static int clipfind(char **aret, int ret, char *tok)
1458 {
1459         if (aret==NULL)
1460                 return 0;
1461
1462         /* ignore leading slashes or dots in token */
1463         while(strchr_m("/\\.", *tok))
1464                 tok++;
1465
1466         while(ret--) {
1467                 char *pkey=*aret++;
1468
1469                 /* ignore leading slashes or dots in list */
1470                 while(strchr_m("/\\.", *pkey))
1471                         pkey++;
1472
1473                 if (!strslashcmp(pkey, tok))
1474                         return 1;
1475         }
1476         return 0;
1477 }
1478
1479 /****************************************************************************
1480 Read list of files to include from the file and initialize cliplist
1481 accordingly.
1482 ***************************************************************************/
1483
1484 static int read_inclusion_file(char *filename)
1485 {
1486         XFILE *inclusion = NULL;
1487         char buf[PATH_MAX + 1];
1488         char *inclusion_buffer = NULL;
1489         int inclusion_buffer_size = 0;
1490         int inclusion_buffer_sofar = 0;
1491         char *p;
1492         char *tmpstr;
1493         int i;
1494         int error = 0;
1495
1496         clipn = 0;
1497         buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1498         if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1499                 /* XXX It would be better to include a reason for failure, but without
1500                  * autoconf, it's hard to use strerror, sys_errlist, etc.
1501                  */
1502                 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1503                 return 0;
1504         }
1505
1506         while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1507                 if (inclusion_buffer == NULL) {
1508                         inclusion_buffer_size = 1024;
1509                         if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1510                                 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1511                                 error = 1;
1512                                 break;
1513                         }
1514                 }
1515     
1516                 if (buf[strlen(buf)-1] == '\n') {
1517                         buf[strlen(buf)-1] = '\0';
1518                 }
1519     
1520                 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1521                         char *ib;
1522                         inclusion_buffer_size *= 2;
1523                         ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1524                         if (! ib) {
1525                                 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1526                                                 inclusion_buffer_size));
1527                                 error = 1;
1528                                 break;
1529                         } else {
1530                                 inclusion_buffer = ib;
1531                         }
1532                 }
1533     
1534                 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1535                 inclusion_buffer_sofar += strlen(buf) + 1;
1536                 clipn++;
1537         }
1538         x_fclose(inclusion);
1539
1540         if (! error) {
1541                 /* Allocate an array of clipn + 1 char*'s for cliplist */
1542                 cliplist = malloc((clipn + 1) * sizeof(char *));
1543                 if (cliplist == NULL) {
1544                         DEBUG(0,("failure allocating memory for cliplist\n"));
1545                         error = 1;
1546                 } else {
1547                         cliplist[clipn] = NULL;
1548                         p = inclusion_buffer;
1549                         for (i = 0; (! error) && (i < clipn); i++) {
1550                                 /* set current item to NULL so array will be null-terminated even if
1551                                                 * malloc fails below. */
1552                                 cliplist[i] = NULL;
1553                                 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1554                                         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1555                                         error = 1;
1556                                 } else {
1557                                         unfixtarname(tmpstr, p, strlen(p) + 1, True);
1558                                         cliplist[i] = tmpstr;
1559                                         if ((p = strchr_m(p, '\000')) == NULL) {
1560                                                 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1561                                                 abort();
1562                                         }
1563                                 }
1564                                 ++p;
1565                         }
1566                         must_free_cliplist = True;
1567                 }
1568         }
1569
1570         SAFE_FREE(inclusion_buffer);
1571         if (error) {
1572                 if (cliplist) {
1573                         char **pp;
1574                         /* We know cliplist is always null-terminated */
1575                         for (pp = cliplist; *pp; ++pp) {
1576                                 SAFE_FREE(*pp);
1577                         }
1578                         SAFE_FREE(cliplist);
1579                         cliplist = NULL;
1580                         must_free_cliplist = False;
1581                 }
1582                 return 0;
1583         }
1584   
1585         /* cliplist and its elements are freed at the end of process_tar. */
1586         return 1;
1587 }
1588
1589 /****************************************************************************
1590 Parse tar arguments. Sets tar_type, tar_excl, etc.
1591 ***************************************************************************/
1592
1593 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1594 {
1595         int newOptind = Optind;
1596         char tar_clipfl='\0';
1597
1598         /* Reset back to defaults - could be from interactive version 
1599          * reset mode and archive mode left as they are though
1600          */
1601         tar_type='\0';
1602         tar_excl=True;
1603         dry_run=False;
1604
1605         while (*Optarg) {
1606                 switch(*Optarg++) {
1607                         case 'c':
1608                                 tar_type='c';
1609                                 break;
1610                         case 'x':
1611                                 if (tar_type=='c') {
1612                                         printf("Tar must be followed by only one of c or x.\n");
1613                                         return 0;
1614                                 }
1615                                 tar_type='x';
1616                                 break;
1617                         case 'b':
1618                                 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1619                                         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1620                                         return 0;
1621                                 } else {
1622                                         Optind++;
1623                                         newOptind++;
1624                                 }
1625                                 break;
1626                         case 'g':
1627                                 tar_inc=True;
1628                                 break;
1629                         case 'N':
1630                                 if (Optind>=argc) {
1631                                         DEBUG(0,("Option N must be followed by valid file name\n"));
1632                                         return 0;
1633                                 } else {
1634                                         SMB_STRUCT_STAT stbuf;
1635                                         extern time_t newer_than;
1636         
1637                                         if (sys_stat(argv[Optind], &stbuf) == 0) {
1638                                                 newer_than = stbuf.st_mtime;
1639                                                 DEBUG(1,("Getting files newer than %s",
1640                                                         asctime(LocalTime(&newer_than))));
1641                                                 newOptind++;
1642                                                 Optind++;
1643                                         } else {
1644                                                 DEBUG(0,("Error setting newer-than time\n"));
1645                                                 return 0;
1646                                         }
1647                                 }
1648                                 break;
1649                         case 'a':
1650                                 tar_reset=True;
1651                                 break;
1652                         case 'q':
1653                                 tar_noisy=False;
1654                                 break;
1655                         case 'I':
1656                                 if (tar_clipfl) {
1657                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1658                                         return 0;
1659                                 }
1660                                 tar_clipfl='I';
1661                                 break;
1662                         case 'X':
1663                                 if (tar_clipfl) {
1664                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1665                                         return 0;
1666                                 }
1667                                 tar_clipfl='X';
1668                                 break;
1669                         case 'F':
1670                                 if (tar_clipfl) {
1671                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1672                                         return 0;
1673                                 }
1674                                 tar_clipfl='F';
1675                                 break;
1676                         case 'r':
1677                                 DEBUG(0, ("tar_re_search set\n"));
1678                                 tar_re_search = True;
1679                                 break;
1680                         case 'n':
1681                                 if (tar_type == 'c') {
1682                                         DEBUG(0, ("dry_run set\n"));
1683                                         dry_run = True;
1684                                 } else {
1685                                         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1686                                         return 0;
1687                                 }
1688                                 break;
1689                         default:
1690                                 DEBUG(0,("Unknown tar option\n"));
1691                                 return 0;
1692                 }
1693         }
1694
1695         if (!tar_type) {
1696                 printf("Option T must be followed by one of c or x.\n");
1697                 return 0;
1698         }
1699
1700         /* tar_excl is true if cliplist lists files to be included.
1701          * Both 'I' and 'F' mean include. */
1702         tar_excl=tar_clipfl!='X';
1703
1704         if (tar_clipfl=='F') {
1705                 if (argc-Optind-1 != 1) {
1706                         DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1707                         return 0;
1708                 }
1709                 newOptind++;
1710                 Optind++;
1711                 if (! read_inclusion_file(argv[Optind])) {
1712                         return 0;
1713                 }
1714         } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1715                 char *tmpstr;
1716                 char **tmplist;
1717                 int clipcount;
1718
1719                 cliplist=argv+Optind+1;
1720                 clipn=argc-Optind-1;
1721                 clipcount = clipn;
1722
1723                 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1724                         DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1725                         return 0;
1726                 }
1727
1728                 for (clipcount = 0; clipcount < clipn; clipcount++) {
1729
1730                         DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1731
1732                         if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1733                                 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1734                                 return 0;
1735                         }
1736
1737                         unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1738                         tmplist[clipcount] = tmpstr;
1739                         DEBUG(5, ("Processed an item, %s\n", tmpstr));
1740
1741                         DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1742                 }
1743
1744                 cliplist = tmplist;
1745                 must_free_cliplist = True;
1746
1747                 newOptind += clipn;
1748         }
1749
1750         if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
1751 #ifdef HAVE_REGEX_H
1752                 int errcode;
1753
1754                 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1755
1756                         DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1757                         return;
1758                 }
1759
1760                 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1761                         char errstr[1024];
1762                         size_t errlen;
1763
1764                         errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1765                         DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1766                         return;
1767                 }
1768 #endif
1769
1770                 clipn=argc-Optind-1;
1771                 cliplist=argv+Optind+1;
1772                 newOptind += clipn;
1773         }
1774
1775         if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1776                 /* Sets tar handle to either 0 or 1, as appropriate */
1777                 tarhandle=(tar_type=='c');
1778                 /*
1779                  * Make sure that dbf points to stderr if we are using stdout for 
1780                  * tar output
1781                  */
1782                 if (tarhandle == 1)  {
1783                         dbf = x_stderr;
1784                 }
1785                 if (!argv[Optind]) {
1786                         DEBUG(0,("Must specify tar filename\n"));
1787                         return 0;
1788                 }
1789                 if (!strcmp(argv[Optind], "-")) {
1790                         newOptind++;
1791                 }
1792
1793         } else {
1794                 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0)) {
1795                         if (!dry_run) {
1796                                 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1797                                 dry_run = True;
1798                         }
1799                         tarhandle=-1;
1800                 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1801                                         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1802                         DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1803                         return(0);
1804                 }
1805                 newOptind++;
1806         }
1807
1808         return newOptind;
1809 }