r14128: Remove warning generated by coverity scan tool (missing SAFE_FREE in error...
[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_ascii(*s1) == tolower_ascii(*s2) ||
486                                 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
487                 s1++; s2++;
488         }
489
490         /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" 
491                 string of s2.
492         */
493         if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
494                 return 0;
495
496         /* ignore trailing slash on s1 */
497         if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
498                 return 0;
499
500         /* check for s1 is an "initial" string of s2 */
501         if ((*s2 == '/' || *s2 == '\\') && !*s1)
502                 return 0;
503
504         return *s1-*s2;
505 }
506
507 /****************************************************************************
508 Ensure a remote path exists (make if necessary)
509 ***************************************************************************/
510
511 static BOOL ensurepath(char *fname)
512 {
513         /* *must* be called with buffer ready malloc'ed */
514         /* ensures path exists */
515
516         char *partpath, *ffname;
517         char *p=fname, *basehack;
518
519         DEBUG(5, ( "Ensurepath called with: %s\n", fname));
520
521         partpath = string_create_s(strlen(fname));
522         ffname = string_create_s(strlen(fname));
523
524         if ((partpath == NULL) || (ffname == NULL)){
525                 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
526                 return(False);
527         }
528
529         *partpath = 0;
530
531         /* fname copied to ffname so can strtok */
532
533         safe_strcpy(ffname, fname, strlen(fname));
534
535         /* do a `basename' on ffname, so don't try and make file name directory */
536         if ((basehack=strrchr_m(ffname, '\\')) == NULL)
537                 return True;
538         else
539                 *basehack='\0';
540
541         p=strtok(ffname, "\\");
542
543         while (p) {
544                 safe_strcat(partpath, p, strlen(fname) + 1);
545
546                 if (!cli_chkpath(cli, partpath)) {
547                         if (!cli_mkdir(cli, partpath)) {
548                                 DEBUG(0, ("Error mkdirhiering\n"));
549                                 return False;
550                         } else {
551                                 DEBUG(3, ("mkdirhiering %s\n", partpath));
552                         }
553                 }
554
555                 safe_strcat(partpath, "\\", strlen(fname) + 1);
556                 p = strtok(NULL,"/\\");
557         }
558
559         return True;
560 }
561
562 static int padit(char *buf, int bufsize, int padsize)
563 {
564         int berr= 0;
565         int bytestowrite;
566   
567         DEBUG(5, ("Padding with %d zeros\n", padsize));
568         memset(buf, 0, bufsize);
569         while( !berr && padsize > 0 ) {
570                 bytestowrite= MIN(bufsize, padsize);
571                 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
572                 padsize -= bytestowrite;
573         }
574   
575         return berr;
576 }
577
578 static void do_setrattr(char *name, uint16 attr, int set)
579 {
580         uint16 oldattr;
581
582         if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
583
584         if (set == ATTRSET) {
585                 attr |= oldattr;
586         } else {
587                 attr = oldattr & ~attr;
588         }
589
590         if (!cli_setatr(cli, name, attr, 0)) {
591                 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
592         }
593 }
594
595 /****************************************************************************
596 append one remote file to the tar file
597 ***************************************************************************/
598
599 static void do_atar(char *rname,char *lname,file_info *finfo1)
600 {
601         int fnum;
602         SMB_BIG_UINT nread=0;
603         char ftype;
604         file_info2 finfo;
605         BOOL close_done = False;
606         BOOL shallitime=True;
607         char data[65520];
608         int read_size = 65520;
609         int datalen=0;
610
611         struct timeval tp_start;
612
613         GetTimeOfDay(&tp_start);
614
615         ftype = '0'; /* An ordinary file ... */
616
617         if (finfo1) {
618                 finfo.size  = finfo1 -> size;
619                 finfo.mode  = finfo1 -> mode;
620                 finfo.uid   = finfo1 -> uid;
621                 finfo.gid   = finfo1 -> gid;
622                 finfo.mtime = finfo1 -> mtime;
623                 finfo.atime = finfo1 -> atime;
624                 finfo.ctime = finfo1 -> ctime;
625                 finfo.name  = finfo1 -> name;
626         } else {
627                 finfo.size  = def_finfo.size;
628                 finfo.mode  = def_finfo.mode;
629                 finfo.uid   = def_finfo.uid;
630                 finfo.gid   = def_finfo.gid;
631                 finfo.mtime = def_finfo.mtime;
632                 finfo.atime = def_finfo.atime;
633                 finfo.ctime = def_finfo.ctime;
634                 finfo.name  = def_finfo.name;
635         }
636
637         if (dry_run) {
638                 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
639                                 (double)finfo.size));
640                 shallitime=0;
641                 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
642                 ntarf++;
643                 return;
644         }
645
646         fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
647
648         dos_clean_name(rname);
649
650         if (fnum == -1) {
651                 DEBUG(0,("%s opening remote file %s (%s)\n",
652                                 cli_errstr(cli),rname, cur_dir));
653                 return;
654         }
655
656         finfo.name = string_create_s(strlen(rname));
657         if (finfo.name == NULL) {
658                 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
659                 return;
660         }
661
662         safe_strcpy(finfo.name,rname, strlen(rname));
663         if (!finfo1) {
664                 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
665                         DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
666                         return;
667                 }
668                 finfo.ctime = finfo.mtime;
669         }
670
671         DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
672
673         if (tar_inc && !(finfo.mode & aARCH)) {
674                 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
675                 shallitime=0;
676         } else if (!tar_system && (finfo.mode & aSYSTEM)) {
677                 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
678                 shallitime=0;
679         } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
680                 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
681                 shallitime=0;
682         } else {
683                 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
684                         finfo.name, (double)finfo.size, lname));
685       
686                 /* write a tar header, don't bother with mode - just set to 100644 */
687                 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
688
689                 while (nread < finfo.size && !close_done) {
690               
691                         DEBUG(3,("nread=%.0f\n",(double)nread));
692               
693                         datalen = cli_read(cli, fnum, data, nread, read_size);
694               
695                         if (datalen == -1) {
696                                 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
697                                 break;
698                         }
699               
700                         nread += datalen;
701
702                         /* if file size has increased since we made file size query, truncate
703                                 read so tar header for this file will be correct.
704                         */
705
706                         if (nread > finfo.size) {
707                                 datalen -= nread - finfo.size;
708                                 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
709                                                         finfo.name, (double)finfo.size));
710                         }
711
712                         /* add received bits of file to buffer - dotarbuf will
713                         * write out in 512 byte intervals */
714
715                         if (dotarbuf(tarhandle,data,datalen) != datalen) {
716                                 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
717                                 break;
718                         }
719               
720                         if (datalen == 0) {
721                                 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
722                                 break;
723                         }
724
725                         datalen=0;
726                 }
727
728                 /* pad tar file with zero's if we couldn't get entire file */
729                 if (nread < finfo.size) {
730                         DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
731                                                 (double)finfo.size, (int)nread));
732                         if (padit(data, sizeof(data), finfo.size - nread))
733                                 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
734                 }
735
736                 /* round tar file to nearest block */
737                 if (finfo.size % TBLOCK)
738                         dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
739       
740                 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
741                 ntarf++;
742         }
743   
744         cli_close(cli, fnum);
745
746         if (shallitime) {
747                 struct timeval tp_end;
748                 int this_time;
749
750                 /* if shallitime is true then we didn't skip */
751                 if (tar_reset && !dry_run)
752                         (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
753       
754                 GetTimeOfDay(&tp_end);
755                 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
756                 get_total_time_ms += this_time;
757                 get_total_size += finfo.size;
758
759                 if (tar_noisy) {
760                         DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
761                                 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
762                                 finfo.name));
763                 }
764
765                 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
766                 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
767                                 finfo.size / MAX(0.001, (1.024*this_time)),
768                                 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
769         }
770 }
771
772 /****************************************************************************
773 Append single file to tar file (or not)
774 ***************************************************************************/
775
776 static void do_tar(file_info *finfo)
777 {
778         pstring rname;
779
780         if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
781                 return;
782
783         /* Is it on the exclude list ? */
784         if (!tar_excl && clipn) {
785                 pstring exclaim;
786
787                 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
788
789                 pstrcpy(exclaim, cur_dir);
790                 *(exclaim+strlen(exclaim)-1)='\0';
791
792                 pstrcat(exclaim, "\\");
793                 pstrcat(exclaim, finfo->name);
794
795                 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
796
797                 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
798                                 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
799                         DEBUG(3,("Skipping file %s\n", exclaim));
800                         return;
801                 }
802         }
803
804         if (finfo->mode & aDIR) {
805                 pstring saved_curdir;
806                 pstring mtar_mask;
807
808                 pstrcpy(saved_curdir, cur_dir);
809
810                 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
811 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
812                         (int)sizeof(cur_dir), (int)strlen(cur_dir),
813                         (int)strlen(finfo->name), finfo->name, cur_dir));
814
815                 pstrcat(cur_dir,finfo->name);
816                 pstrcat(cur_dir,"\\");
817
818                 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
819
820                 /* write a tar directory, don't bother with mode - just set it to
821                         * 40755 */
822                 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
823                 if (tar_noisy) {
824                         DEBUG(0,("                directory %s\n", cur_dir));
825                 }
826                 ntarf++;  /* Make sure we have a file on there */
827                 pstrcpy(mtar_mask,cur_dir);
828                 pstrcat(mtar_mask,"*");
829                 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
830                 do_list(mtar_mask, attribute, do_tar, False, True);
831                 pstrcpy(cur_dir,saved_curdir);
832         } else {
833                 pstrcpy(rname,cur_dir);
834                 pstrcat(rname,finfo->name);
835                 do_atar(rname,finfo->name,finfo);
836         }
837 }
838
839 /****************************************************************************
840 Convert from UNIX to DOS file names
841 ***************************************************************************/
842
843 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
844 {
845         /* remove '.' from start of file name, convert from unix /'s to
846          * dos \'s in path. Kill any absolute path names. But only if first!
847          */
848
849         DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
850
851         if (first) {
852                 if (*fp == '.') {
853                         fp++;
854                         l--;
855                 }
856                 if (*fp == '\\' || *fp == '/') {
857                         fp++;
858                         l--;
859                 }
860         }
861
862         safe_strcpy(tptr, fp, l);
863         string_replace(tptr, '/', '\\');
864 }
865
866 /****************************************************************************
867 Move to the next block in the buffer, which may mean read in another set of
868 blocks. FIXME, we should allow more than one block to be skipped.
869 ****************************************************************************/
870
871 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
872 {
873         int bufread, total = 0;
874
875         DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
876         *bufferp += TBLOCK;
877         total = TBLOCK;
878
879         if (*bufferp >= (ltarbuf + bufsiz)) {
880
881                 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
882
883                 /*
884                  * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
885                  * Fixes bug where read can return short if coming from
886                  * a pipe.
887                  */
888
889                 bufread = read(tarhandle, ltarbuf, bufsiz);
890                 total = bufread;
891
892                 while (total < bufsiz) {
893                         if (bufread < 0) { /* An error, return false */
894                                 return (total > 0 ? -2 : bufread);
895                         }
896                         if (bufread == 0) {
897                                 if (total <= 0) {
898                                         return -2;
899                                 }
900                                 break;
901                         }
902                         bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
903                         total += bufread;
904                 }
905
906                 DEBUG(5, ("Total bytes read ... %i\n", total));
907
908                 *bufferp = ltarbuf;
909         }
910
911         return(total);
912 }
913
914 /* Skip a file, even if it includes a long file name? */
915 static int skip_file(int skipsize)
916 {
917         int dsize = skipsize;
918
919         DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
920
921         /* FIXME, we should skip more than one block at a time */
922
923         while (dsize > 0) {
924                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
925                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
926                         return(False);
927                 }
928                 dsize -= TBLOCK;
929         }
930
931         return(True);
932 }
933
934 /*************************************************************
935  Get a file from the tar file and store it.
936  When this is called, tarbuf already contains the first
937  file block. This is a bit broken & needs fixing.
938 **************************************************************/
939
940 static int get_file(file_info2 finfo)
941 {
942         int fnum = -1, pos = 0, dsize = 0, bpos = 0;
943         SMB_BIG_UINT rsize = 0;
944
945         DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
946
947         if (ensurepath(finfo.name) && 
948                         (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
949                 DEBUG(0, ("abandoning restore\n"));
950                 return(False);
951         }
952
953         /* read the blocks from the tar file and write to the remote file */
954
955         rsize = finfo.size;  /* This is how much to write */
956
957         while (rsize > 0) {
958
959                 /* We can only write up to the end of the buffer */
960                 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
961                 dsize = MIN(dsize, rsize);  /* Should be only what is left */
962                 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
963
964                 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
965                         DEBUG(0, ("Error writing remote file\n"));
966                         return 0;
967                 }
968
969                 rsize -= dsize;
970                 pos += dsize;
971
972                 /* Now figure out how much to move in the buffer */
973
974                 /* FIXME, we should skip more than one block at a time */
975
976                 /* First, skip any initial part of the part written that is left over */
977                 /* from the end of the first TBLOCK                                   */
978
979                 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
980                         dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
981                         bpos = 0;
982
983                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
984                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
985                                 return False;
986                         }
987                 }
988
989                 /*
990                  * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
991                  * If the file being extracted is an exact multiple of
992                  * TBLOCK bytes then we don't want to extract the next
993                  * block from the tarfile here, as it will be done in
994                  * the caller of get_file().
995                  */
996
997                 while (((rsize != 0) && (dsize >= TBLOCK)) ||
998                                 ((rsize == 0) && (dsize > TBLOCK))) {
999
1000                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1001                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1002                                 return False;
1003                         }
1004
1005                         dsize -= TBLOCK;
1006                 }
1007                 bpos = dsize;
1008         }
1009
1010         /* Now close the file ... */
1011
1012         if (!cli_close(cli, fnum)) {
1013                 DEBUG(0, ("Error closing remote file\n"));
1014                 return(False);
1015         }
1016
1017         /* Now we update the creation date ... */
1018         DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1019
1020         if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1021                 if (tar_real_noisy) {
1022                         DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1023                         /*return(False); */ /* Ignore, as Win95 does not allow changes */
1024                 }
1025         }
1026
1027         ntarf++;
1028         DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1029         return(True);
1030 }
1031
1032 /* Create a directory.  We just ensure that the path exists and return as there
1033    is no file associated with a directory 
1034 */
1035 static int get_dir(file_info2 finfo)
1036 {
1037         DEBUG(0, ("restore directory %s\n", finfo.name));
1038
1039         if (!ensurepath(finfo.name)) {
1040                 DEBUG(0, ("Problems creating directory\n"));
1041                 return(False);
1042         }
1043         ntarf++;
1044         return(True);
1045 }
1046
1047 /* Get a file with a long file name ... first file has file name, next file 
1048    has the data. We only want the long file name, as the loop in do_tarput
1049    will deal with the rest.
1050 */
1051 static char *get_longfilename(file_info2 finfo)
1052 {
1053         /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1054          * header call. */
1055         int namesize = finfo.size + strlen(cur_dir) + 2;
1056         char *longname = SMB_MALLOC(namesize);
1057         int offset = 0, left = finfo.size;
1058         BOOL first = True;
1059
1060         DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1061         DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1062
1063         if (longname == NULL) {
1064                 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1065                 return(NULL);
1066         }
1067
1068         /* First, add cur_dir to the long file name */
1069
1070         if (strlen(cur_dir) > 0) {
1071                 strncpy(longname, cur_dir, namesize);
1072                 offset = strlen(cur_dir);
1073         }
1074
1075         /* Loop through the blocks picking up the name */
1076
1077         while (left > 0) {
1078                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1079                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1080                         SAFE_FREE(longname);
1081                         return(NULL);
1082                 }
1083
1084                 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1085                 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1086
1087                 offset += TBLOCK;
1088                 left -= TBLOCK;
1089         }
1090
1091         return(longname);
1092 }
1093
1094 static void do_tarput(void)
1095 {
1096         file_info2 finfo;
1097         struct timeval tp_start;
1098         char *longfilename = NULL, linkflag;
1099         int skip = False;
1100
1101         ZERO_STRUCT(finfo);
1102
1103         GetTimeOfDay(&tp_start);
1104         DEBUG(5, ("RJS do_tarput called ...\n"));
1105
1106         buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1107
1108         /* Now read through those files ... */
1109         while (True) {
1110                 /* Get us to the next block, or the first block first time around */
1111                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1112                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1113                         return;
1114                 }
1115
1116                 DEBUG(5, ("Reading the next header ...\n"));
1117
1118                 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1119                         case -2:    /* Hmm, not good, but not fatal */
1120                                 DEBUG(0, ("Skipping %s...\n", finfo.name));
1121                                 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1122                                         DEBUG(0, ("Short file, bailing out...\n"));
1123                                         return;
1124                                 }
1125                                 break;
1126
1127                         case -1:
1128                                 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1129                                 return;
1130
1131                         case 0: /* chksum is zero - looks like an EOF */
1132                                 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1133                                 return;        /* Hmmm, bad here ... */
1134
1135                         default: 
1136                                 /* No action */
1137                                 break;
1138                 }
1139
1140                 /* Now, do we have a long file name? */
1141                 if (longfilename != NULL) {
1142                         SAFE_FREE(finfo.name);   /* Free the space already allocated */
1143                         finfo.name = longfilename;
1144                         longfilename = NULL;
1145                 }
1146
1147                 /* Well, now we have a header, process the file ...            */
1148                 /* Should we skip the file? We have the long name as well here */
1149                 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1150                                         (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1151
1152                 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1153                 if (skip) {
1154                         skip_file(finfo.size);
1155                         continue;
1156                 }
1157
1158                 /* We only get this far if we should process the file */
1159                 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1160                 switch (linkflag) {
1161                         case '0':  /* Should use symbolic names--FIXME */
1162                                 /* 
1163                                  * Skip to the next block first, so we can get the file, FIXME, should
1164                                  * be in get_file ...
1165                                  * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1166                                  * Fixes bug where file size in tarfile is zero.
1167                                  */
1168                                 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1169                                         DEBUG(0, ("Short file, bailing out...\n"));
1170                                         return;
1171                                 }
1172                                 if (!get_file(finfo)) {
1173                                         DEBUG(0, ("Abandoning restore\n"));
1174                                         return;
1175                                 }
1176                                 break;
1177                         case '5':
1178                                 if (!get_dir(finfo)) {
1179                                         DEBUG(0, ("Abandoning restore \n"));
1180                                         return;
1181                                 }
1182                                 break;
1183                         case 'L':
1184                                 longfilename = get_longfilename(finfo);
1185                                 if (!longfilename) {
1186                                         DEBUG(0, ("abandoning restore\n"));
1187                                         return;
1188                                 }
1189                                 DEBUG(5, ("Long file name: %s\n", longfilename));
1190                                 break;
1191
1192                         default:
1193                                 skip_file(finfo.size);  /* Don't handle these yet */
1194                                 break;
1195                 }
1196         }
1197 }
1198
1199 /*
1200  * samba interactive commands
1201  */
1202
1203 /****************************************************************************
1204 Blocksize command
1205 ***************************************************************************/
1206
1207 int cmd_block(void)
1208 {
1209         fstring buf;
1210         int block;
1211
1212         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1213                 DEBUG(0, ("blocksize <n>\n"));
1214                 return 1;
1215         }
1216
1217         block=atoi(buf);
1218         if (block < 0 || block > 65535) {
1219                 DEBUG(0, ("blocksize out of range"));
1220                 return 1;
1221         }
1222
1223         blocksize=block;
1224         DEBUG(2,("blocksize is now %d\n", blocksize));
1225
1226         return 0;
1227 }
1228
1229 /****************************************************************************
1230 command to set incremental / reset mode
1231 ***************************************************************************/
1232
1233 int cmd_tarmode(void)
1234 {
1235         fstring buf;
1236
1237         while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1238                 if (strequal(buf, "full"))
1239                         tar_inc=False;
1240                 else if (strequal(buf, "inc"))
1241                         tar_inc=True;
1242                 else if (strequal(buf, "reset"))
1243                         tar_reset=True;
1244                 else if (strequal(buf, "noreset"))
1245                         tar_reset=False;
1246                 else if (strequal(buf, "system"))
1247                         tar_system=True;
1248                 else if (strequal(buf, "nosystem"))
1249                         tar_system=False;
1250                 else if (strequal(buf, "hidden"))
1251                         tar_hidden=True;
1252                 else if (strequal(buf, "nohidden"))
1253                         tar_hidden=False;
1254                 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1255                         tar_noisy=True;
1256                 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1257                         tar_noisy=False;
1258                 else
1259                         DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1260         }
1261
1262         DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1263                         tar_inc ? "incremental" : "full",
1264                         tar_system ? "system" : "nosystem",
1265                         tar_hidden ? "hidden" : "nohidden",
1266                         tar_reset ? "reset" : "noreset",
1267                         tar_noisy ? "verbose" : "quiet"));
1268         return 0;
1269 }
1270
1271 /****************************************************************************
1272 Feeble attrib command
1273 ***************************************************************************/
1274
1275 int cmd_setmode(void)
1276 {
1277         char *q;
1278         fstring buf;
1279         pstring fname;
1280         uint16 attra[2];
1281         int direct=1;
1282
1283         attra[0] = attra[1] = 0;
1284
1285         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1286                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1287                 return 1;
1288         }
1289
1290         pstrcpy(fname, cur_dir);
1291         pstrcat(fname, buf);
1292
1293         while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1294                 q=buf;
1295
1296                 while(*q) {
1297                         switch (*q++) {
1298                                 case '+':
1299                                         direct=1;
1300                                         break;
1301                                 case '-':
1302                                         direct=0;
1303                                         break;
1304                                 case 'r':
1305                                         attra[direct]|=aRONLY;
1306                                         break;
1307                                 case 'h':
1308                                         attra[direct]|=aHIDDEN;
1309                                         break;
1310                                 case 's':
1311                                         attra[direct]|=aSYSTEM;
1312                                         break;
1313                                 case 'a':
1314                                         attra[direct]|=aARCH;
1315                                         break;
1316                                 default:
1317                                         DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1318                                         return 1;
1319                         }
1320                 }
1321         }
1322
1323         if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1324                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1325                 return 1;
1326         }
1327
1328         DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1329         do_setrattr(fname, attra[ATTRSET], ATTRSET);
1330         do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1331         return 0;
1332 }
1333
1334 /****************************************************************************
1335 Principal command for creating / extracting
1336 ***************************************************************************/
1337
1338 int cmd_tar(void)
1339 {
1340         fstring buf;
1341         char **argl = NULL;
1342         int argcl = 0;
1343         int ret;
1344
1345         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1346                 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1347                 return 1;
1348         }
1349
1350         argl=toktocliplist(&argcl, NULL);
1351         if (!tar_parseargs(argcl, argl, buf, 0))
1352                 return 1;
1353
1354         ret = process_tar();
1355         SAFE_FREE(argl);
1356         return ret;
1357 }
1358
1359 /****************************************************************************
1360 Command line (option) version
1361 ***************************************************************************/
1362
1363 int process_tar(void)
1364 {
1365         int rc = 0;
1366         initarbuf();
1367         switch(tar_type) {
1368                 case 'x':
1369
1370 #if 0
1371                         do_tarput2();
1372 #else
1373                         do_tarput();
1374 #endif
1375                         SAFE_FREE(tarbuf);
1376                         close(tarhandle);
1377                         break;
1378                 case 'r':
1379                 case 'c':
1380                         if (clipn && tar_excl) {
1381                                 int i;
1382                                 pstring tarmac;
1383
1384                                 for (i=0; i<clipn; i++) {
1385                                         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1386
1387                                         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1388                                                 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1389                                         }
1390         
1391                                         if (strrchr_m(cliplist[i], '\\')) {
1392                                                 pstring saved_dir;
1393           
1394                                                 pstrcpy(saved_dir, cur_dir);
1395           
1396                                                 if (*cliplist[i]=='\\') {
1397                                                         pstrcpy(tarmac, cliplist[i]);
1398                                                 } else {
1399                                                         pstrcpy(tarmac, cur_dir);
1400                                                         pstrcat(tarmac, cliplist[i]);
1401                                                 }
1402                                                 pstrcpy(cur_dir, tarmac);
1403                                                 *(strrchr_m(cur_dir, '\\')+1)='\0';
1404
1405                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1406                                                 do_list(tarmac,attribute,do_tar, False, True);
1407                                                 pstrcpy(cur_dir,saved_dir);
1408                                         } else {
1409                                                 pstrcpy(tarmac, cur_dir);
1410                                                 pstrcat(tarmac, cliplist[i]);
1411                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1412                                                 do_list(tarmac,attribute,do_tar, False, True);
1413                                         }
1414                                 }
1415                         } else {
1416                                 pstring mask;
1417                                 pstrcpy(mask,cur_dir);
1418                                 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1419                                 pstrcat(mask,"\\*");
1420                                 do_list(mask,attribute,do_tar,False, True);
1421                         }
1422     
1423                         if (ntarf)
1424                                 dotareof(tarhandle);
1425                         close(tarhandle);
1426                         SAFE_FREE(tarbuf);
1427     
1428                         DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1429                         DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1430                         break;
1431         }
1432
1433         if (must_free_cliplist) {
1434                 int i;
1435                 for (i = 0; i < clipn; ++i) {
1436                         SAFE_FREE(cliplist[i]);
1437                 }
1438                 SAFE_FREE(cliplist);
1439                 cliplist = NULL;
1440                 clipn = 0;
1441                 must_free_cliplist = False;
1442         }
1443         return rc;
1444 }
1445
1446 /****************************************************************************
1447 Find a token (filename) in a clip list
1448 ***************************************************************************/
1449
1450 static int clipfind(char **aret, int ret, char *tok)
1451 {
1452         if (aret==NULL)
1453                 return 0;
1454
1455         /* ignore leading slashes or dots in token */
1456         while(strchr_m("/\\.", *tok))
1457                 tok++;
1458
1459         while(ret--) {
1460                 char *pkey=*aret++;
1461
1462                 /* ignore leading slashes or dots in list */
1463                 while(strchr_m("/\\.", *pkey))
1464                         pkey++;
1465
1466                 if (!strslashcmp(pkey, tok))
1467                         return 1;
1468         }
1469         return 0;
1470 }
1471
1472 /****************************************************************************
1473 Read list of files to include from the file and initialize cliplist
1474 accordingly.
1475 ***************************************************************************/
1476
1477 static int read_inclusion_file(char *filename)
1478 {
1479         XFILE *inclusion = NULL;
1480         char buf[PATH_MAX + 1];
1481         char *inclusion_buffer = NULL;
1482         int inclusion_buffer_size = 0;
1483         int inclusion_buffer_sofar = 0;
1484         char *p;
1485         char *tmpstr;
1486         int i;
1487         int error = 0;
1488
1489         clipn = 0;
1490         buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1491         if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1492                 /* XXX It would be better to include a reason for failure, but without
1493                  * autoconf, it's hard to use strerror, sys_errlist, etc.
1494                  */
1495                 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1496                 return 0;
1497         }
1498
1499         while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1500                 if (inclusion_buffer == NULL) {
1501                         inclusion_buffer_size = 1024;
1502                         if ((inclusion_buffer = SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1503                                 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1504                                 error = 1;
1505                                 break;
1506                         }
1507                 }
1508     
1509                 if (buf[strlen(buf)-1] == '\n') {
1510                         buf[strlen(buf)-1] = '\0';
1511                 }
1512     
1513                 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1514                         inclusion_buffer_size *= 2;
1515                         inclusion_buffer = SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1516                         if (!inclusion_buffer) {
1517                                 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1518                                                 inclusion_buffer_size));
1519                                 error = 1;
1520                                 break;
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 points at the tar output file, Optind+1 at the inclusion file. */
1700                 if (! read_inclusion_file(argv[Optind+1])) {
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 && tar_clipfl != 'F') {
1740                 /* Doing regular expression seaches not from an inclusion file. */
1741                 clipn=argc-Optind-1;
1742                 cliplist=argv+Optind+1;
1743                 newOptind += clipn;
1744         }
1745
1746         if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1747                 /* Sets tar handle to either 0 or 1, as appropriate */
1748                 tarhandle=(tar_type=='c');
1749                 /*
1750                  * Make sure that dbf points to stderr if we are using stdout for 
1751                  * tar output
1752                  */
1753                 if (tarhandle == 1)  {
1754                         dbf = x_stderr;
1755                 }
1756                 if (!argv[Optind]) {
1757                         DEBUG(0,("Must specify tar filename\n"));
1758                         return 0;
1759                 }
1760                 if (!strcmp(argv[Optind], "-")) {
1761                         newOptind++;
1762                 }
1763
1764         } else {
1765                 if (tar_type=='c' && dry_run) {
1766                         tarhandle=-1;
1767                 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1768                                         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1769                         DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1770                         return(0);
1771                 }
1772                 newOptind++;
1773         }
1774
1775         return newOptind;
1776 }