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