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