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