b82a59953db6c519b456fc242e1e9ca4e2a8f2ed
[nivanova/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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20 /* The following changes developed by Richard Sharpe for Canon Information
21    Systems Research Australia (CISRA)
22
23    1. Restore can now restore files with long file names
24    2. Save now saves directory information so that we can restore 
25       directory creation times
26    3. tar now accepts both UNIX path names and DOS path names. I prefer
27       those lovely /'s to those UGLY \'s :-)
28    4. the files to exclude can be specified as a regular expression by adding
29       an r flag to the other tar flags. Eg:
30
31          -TcrX file.tar "*.(obj|exe)"
32
33       will skip all .obj and .exe files
34 */
35
36
37 #include "includes.h"
38 #include "clitar.h"
39 #include "client/client_proto.h"
40
41 static int clipfind(char **aret, int ret, char *tok);
42
43 typedef struct file_info_struct file_info2;
44
45 struct file_info_struct {
46         SMB_OFF_T size;
47         uint16 mode;
48         uid_t uid;
49         gid_t gid;
50         /* These times are normally kept in GMT */
51         struct timespec mtime_ts;
52         struct timespec atime_ts;
53         struct timespec ctime_ts;
54         char *name;     /* This is dynamically allocate */
55
56         file_info2 *next, *prev;  /* Used in the stack ... */
57 };
58
59 typedef struct {
60         file_info2 *top;
61         int items;
62 } stack;
63
64 #define SEPARATORS " \t\n\r"
65 extern time_t newer_than;
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 #ifdef HAVE_LONGLONG
204         if (size > (SMB_BIG_UINT)077777777777LL) {    
205 #else
206         if (size > (SMB_BIG_UINT)077777777777) {    
207 #endif
208
209                 /* This is a non-POSIX compatible extention to store files
210                         greater than 8GB. */
211
212                 memset(hb.dbuf.size, 0, 4);
213                 hb.dbuf.size[0]=128;
214                 for (i = 8, jp=(char*)&size; i; i--)
215                         hb.dbuf.size[i+3] = *(jp++);
216         }
217         oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
218         memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
219         memset(hb.dbuf.linkname, 0, NAMSIZ);
220         hb.dbuf.linkflag=ftype;
221   
222         for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
223                 chk+=(0xFF & *jp++);
224
225         oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
226         hb.dbuf.chksum[6] = '\0';
227
228         (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
229 }
230
231 /****************************************************************************
232 Read a tar header into a hblock structure, and validate
233 ***************************************************************************/
234
235 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
236 {
237         long chk, fchk;
238         int i;
239         char *jp;
240
241         /*
242          * read in a "standard" tar format header - we're not that interested
243          * in that many fields, though
244          */
245
246         /* check the checksum */
247         for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
248                 chk+=(0xFF & *jp++);
249
250         if (chk == 0)
251                 return chk;
252
253         /* compensate for blanks in chksum header */
254         for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
255                 chk-=(0xFF & *jp++);
256
257         chk += ' ' * sizeof(hb->dbuf.chksum);
258
259         fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
260
261         DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
262                         chk, fchk, hb->dbuf.chksum));
263
264         if (fchk != chk) {
265                 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
266                 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
267                 return -1;
268         }
269
270         if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
271                 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
272                 return(-1);
273         }
274
275         safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
276
277         /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
278         unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
279                 strlen(hb->dbuf.name) + 1, True);
280
281         /* can't handle some links at present */
282         if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
283                 if (hb->dbuf.linkflag == 0) {
284                         DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
285                                 finfo->name));
286                 } else { 
287                         if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
288                                 /* Do nothing here at the moment. do_tarput will handle this
289                                         as long as the longlink gets back to it, as it has to advance 
290                                         the buffer pointer, etc */
291                         } else {
292                                 DEBUG(0, ("this tar file appears to contain some kind \
293 of link other than a GNUtar Longlink - ignoring\n"));
294                                 return -2;
295                         }
296                 }
297         }
298     
299         if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
300                                 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
301                 finfo->mode=aDIR;
302         } else {
303                 finfo->mode=0; /* we don't care about mode at the moment, we'll
304                                 * just make it a regular file */
305         }
306
307         /*
308          * Bug fix by richard@sj.co.uk
309          *
310          * REC: restore times correctly (as does tar)
311          * We only get the modification time of the file; set the creation time
312          * from the mod. time, and the access time to current time
313          */
314         finfo->mtime_ts = finfo->ctime_ts =
315                 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
316         finfo->atime_ts = convert_time_t_to_timespec(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=(char *)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_ts = finfo1 -> mtime_ts;
629                 finfo.atime_ts = finfo1 -> atime_ts;
630                 finfo.ctime_ts = finfo1 -> ctime_ts;
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_ts = def_finfo.mtime_ts;
638                 finfo.atime_ts = def_finfo.atime_ts;
639                 finfo.ctime_ts = def_finfo.ctime_ts;
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         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                 time_t atime, mtime;
671                 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &atime, &mtime)) {
672                         DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
673                         return;
674                 }
675                 finfo.atime_ts = convert_time_t_to_timespec(atime);
676                 finfo.mtime_ts = convert_time_t_to_timespec(mtime);
677                 finfo.ctime_ts = finfo.mtime_ts;
678         }
679
680         DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
681
682         if (tar_inc && !(finfo.mode & aARCH)) {
683                 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
684                 shallitime=0;
685         } else if (!tar_system && (finfo.mode & aSYSTEM)) {
686                 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
687                 shallitime=0;
688         } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
689                 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
690                 shallitime=0;
691         } else {
692                 BOOL wrote_tar_header = False;
693
694                 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
695                         finfo.name, (double)finfo.size, lname));
696       
697                 while (nread < finfo.size && !close_done) {
698               
699                         DEBUG(3,("nread=%.0f\n",(double)nread));
700               
701                         datalen = cli_read(cli, fnum, data, nread, read_size);
702               
703                         if (datalen == -1) {
704                                 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
705                                 break;
706                         }
707               
708                         nread += datalen;
709
710                         /* Only if the first read succeeds, write out the tar header. */
711                         if (!wrote_tar_header) {
712                                 /* write a tar header, don't bother with mode - just set to 100644 */
713                                 writetarheader(tarhandle, rname, finfo.size,
714                                         finfo.mtime_ts.tv_sec, "100644 \0", ftype);
715                                 wrote_tar_header = True;
716                         }
717
718                         /* if file size has increased since we made file size query, truncate
719                                 read so tar header for this file will be correct.
720                         */
721
722                         if (nread > finfo.size) {
723                                 datalen -= nread - finfo.size;
724                                 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
725                                                         finfo.name, (double)finfo.size));
726                         }
727
728                         /* add received bits of file to buffer - dotarbuf will
729                         * write out in 512 byte intervals */
730
731                         if (dotarbuf(tarhandle,data,datalen) != datalen) {
732                                 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
733                                 break;
734                         }
735               
736                         if (datalen == 0) {
737                                 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
738                                 break;
739                         }
740
741                         datalen=0;
742                 }
743
744                 if (wrote_tar_header) {
745                         /* pad tar file with zero's if we couldn't get entire file */
746                         if (nread < finfo.size) {
747                                 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
748                                                         (double)finfo.size, (int)nread));
749                                 if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
750                                         DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
751                         }
752
753                         /* round tar file to nearest block */
754                         if (finfo.size % TBLOCK)
755                                 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
756       
757                         ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
758                         ntarf++;
759                 } else {
760                         DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
761                         shallitime=0;
762                 }
763         }
764   
765         cli_close(cli, fnum);
766
767         if (shallitime) {
768                 struct timeval tp_end;
769                 int this_time;
770
771                 /* if shallitime is true then we didn't skip */
772                 if (tar_reset && !dry_run)
773                         (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
774       
775                 GetTimeOfDay(&tp_end);
776                 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
777                 get_total_time_ms += this_time;
778                 get_total_size += finfo.size;
779
780                 if (tar_noisy) {
781                         DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
782                                 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
783                                 finfo.name));
784                 }
785
786                 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
787                 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
788                                 finfo.size / MAX(0.001, (1.024*this_time)),
789                                 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
790         }
791 }
792
793 /****************************************************************************
794 Append single file to tar file (or not)
795 ***************************************************************************/
796
797 static void do_tar(file_info *finfo)
798 {
799         pstring rname;
800
801         if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
802                 return;
803
804         /* Is it on the exclude list ? */
805         if (!tar_excl && clipn) {
806                 pstring exclaim;
807
808                 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
809
810                 pstrcpy(exclaim, cur_dir);
811                 *(exclaim+strlen(exclaim)-1)='\0';
812
813                 pstrcat(exclaim, "\\");
814                 pstrcat(exclaim, finfo->name);
815
816                 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
817
818                 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
819                                 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
820                         DEBUG(3,("Skipping file %s\n", exclaim));
821                         return;
822                 }
823         }
824
825         if (finfo->mode & aDIR) {
826                 pstring saved_curdir;
827                 pstring mtar_mask;
828
829                 pstrcpy(saved_curdir, cur_dir);
830
831                 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
832 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
833                         (int)sizeof(cur_dir), (int)strlen(cur_dir),
834                         (int)strlen(finfo->name), finfo->name, cur_dir));
835
836                 pstrcat(cur_dir,finfo->name);
837                 pstrcat(cur_dir,"\\");
838
839                 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
840
841                 /* write a tar directory, don't bother with mode - just set it to
842                         * 40755 */
843                 writetarheader(tarhandle, cur_dir, 0, finfo->mtime_ts.tv_sec, "040755 \0", '5');
844                 if (tar_noisy) {
845                         DEBUG(0,("                directory %s\n", cur_dir));
846                 }
847                 ntarf++;  /* Make sure we have a file on there */
848                 pstrcpy(mtar_mask,cur_dir);
849                 pstrcat(mtar_mask,"*");
850                 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
851                 do_list(mtar_mask, attribute, do_tar, False, True);
852                 pstrcpy(cur_dir,saved_curdir);
853         } else {
854                 pstrcpy(rname,cur_dir);
855                 pstrcat(rname,finfo->name);
856                 do_atar(rname,finfo->name,finfo);
857         }
858 }
859
860 /****************************************************************************
861 Convert from UNIX to DOS file names
862 ***************************************************************************/
863
864 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
865 {
866         /* remove '.' from start of file name, convert from unix /'s to
867          * dos \'s in path. Kill any absolute path names. But only if first!
868          */
869
870         DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
871
872         if (first) {
873                 if (*fp == '.') {
874                         fp++;
875                         l--;
876                 }
877                 if (*fp == '\\' || *fp == '/') {
878                         fp++;
879                         l--;
880                 }
881         }
882
883         safe_strcpy(tptr, fp, l);
884         string_replace(tptr, '/', '\\');
885 }
886
887 /****************************************************************************
888 Move to the next block in the buffer, which may mean read in another set of
889 blocks. FIXME, we should allow more than one block to be skipped.
890 ****************************************************************************/
891
892 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
893 {
894         int bufread, total = 0;
895
896         DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
897         *bufferp += TBLOCK;
898         total = TBLOCK;
899
900         if (*bufferp >= (ltarbuf + bufsiz)) {
901
902                 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
903
904                 /*
905                  * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
906                  * Fixes bug where read can return short if coming from
907                  * a pipe.
908                  */
909
910                 bufread = read(tarhandle, ltarbuf, bufsiz);
911                 total = bufread;
912
913                 while (total < bufsiz) {
914                         if (bufread < 0) { /* An error, return false */
915                                 return (total > 0 ? -2 : bufread);
916                         }
917                         if (bufread == 0) {
918                                 if (total <= 0) {
919                                         return -2;
920                                 }
921                                 break;
922                         }
923                         bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
924                         total += bufread;
925                 }
926
927                 DEBUG(5, ("Total bytes read ... %i\n", total));
928
929                 *bufferp = ltarbuf;
930         }
931
932         return(total);
933 }
934
935 /* Skip a file, even if it includes a long file name? */
936 static int skip_file(int skipsize)
937 {
938         int dsize = skipsize;
939
940         DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
941
942         /* FIXME, we should skip more than one block at a time */
943
944         while (dsize > 0) {
945                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
946                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
947                         return(False);
948                 }
949                 dsize -= TBLOCK;
950         }
951
952         return(True);
953 }
954
955 /*************************************************************
956  Get a file from the tar file and store it.
957  When this is called, tarbuf already contains the first
958  file block. This is a bit broken & needs fixing.
959 **************************************************************/
960
961 static int get_file(file_info2 finfo)
962 {
963         int fnum = -1, pos = 0, dsize = 0, bpos = 0;
964         SMB_BIG_UINT rsize = 0;
965
966         DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
967
968         if (ensurepath(finfo.name) && 
969                         (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
970                 DEBUG(0, ("abandoning restore\n"));
971                 return(False);
972         }
973
974         /* read the blocks from the tar file and write to the remote file */
975
976         rsize = finfo.size;  /* This is how much to write */
977
978         while (rsize > 0) {
979
980                 /* We can only write up to the end of the buffer */
981                 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
982                 dsize = MIN(dsize, rsize);  /* Should be only what is left */
983                 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
984
985                 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
986                         DEBUG(0, ("Error writing remote file\n"));
987                         return 0;
988                 }
989
990                 rsize -= dsize;
991                 pos += dsize;
992
993                 /* Now figure out how much to move in the buffer */
994
995                 /* FIXME, we should skip more than one block at a time */
996
997                 /* First, skip any initial part of the part written that is left over */
998                 /* from the end of the first TBLOCK                                   */
999
1000                 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1001                         dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
1002                         bpos = 0;
1003
1004                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
1005                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1006                                 return False;
1007                         }
1008                 }
1009
1010                 /*
1011                  * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1012                  * If the file being extracted is an exact multiple of
1013                  * TBLOCK bytes then we don't want to extract the next
1014                  * block from the tarfile here, as it will be done in
1015                  * the caller of get_file().
1016                  */
1017
1018                 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1019                                 ((rsize == 0) && (dsize > TBLOCK))) {
1020
1021                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1022                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1023                                 return False;
1024                         }
1025
1026                         dsize -= TBLOCK;
1027                 }
1028                 bpos = dsize;
1029         }
1030
1031         /* Now close the file ... */
1032
1033         if (!cli_close(cli, fnum)) {
1034                 DEBUG(0, ("Error closing remote file\n"));
1035                 return(False);
1036         }
1037
1038         /* Now we update the creation date ... */
1039         DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1040
1041         if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec)) {
1042                 if (tar_real_noisy) {
1043                         DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1044                         /*return(False); */ /* Ignore, as Win95 does not allow changes */
1045                 }
1046         }
1047
1048         ntarf++;
1049         DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1050         return(True);
1051 }
1052
1053 /* Create a directory.  We just ensure that the path exists and return as there
1054    is no file associated with a directory 
1055 */
1056 static int get_dir(file_info2 finfo)
1057 {
1058         DEBUG(0, ("restore directory %s\n", finfo.name));
1059
1060         if (!ensurepath(finfo.name)) {
1061                 DEBUG(0, ("Problems creating directory\n"));
1062                 return(False);
1063         }
1064         ntarf++;
1065         return(True);
1066 }
1067
1068 /* Get a file with a long file name ... first file has file name, next file 
1069    has the data. We only want the long file name, as the loop in do_tarput
1070    will deal with the rest.
1071 */
1072 static char *get_longfilename(file_info2 finfo)
1073 {
1074         /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1075          * header call. */
1076         int namesize = finfo.size + strlen(cur_dir) + 2;
1077         char *longname = (char *)SMB_MALLOC(namesize);
1078         int offset = 0, left = finfo.size;
1079         BOOL first = True;
1080
1081         DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1082         DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1083
1084         if (longname == NULL) {
1085                 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1086                 return(NULL);
1087         }
1088
1089         /* First, add cur_dir to the long file name */
1090
1091         if (strlen(cur_dir) > 0) {
1092                 strncpy(longname, cur_dir, namesize);
1093                 offset = strlen(cur_dir);
1094         }
1095
1096         /* Loop through the blocks picking up the name */
1097
1098         while (left > 0) {
1099                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1100                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1101                         SAFE_FREE(longname);
1102                         return(NULL);
1103                 }
1104
1105                 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1106                 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1107
1108                 offset += TBLOCK;
1109                 left -= TBLOCK;
1110         }
1111
1112         return(longname);
1113 }
1114
1115 static void do_tarput(void)
1116 {
1117         file_info2 finfo;
1118         struct timeval tp_start;
1119         char *longfilename = NULL, linkflag;
1120         int skip = False;
1121
1122         ZERO_STRUCT(finfo);
1123
1124         GetTimeOfDay(&tp_start);
1125         DEBUG(5, ("RJS do_tarput called ...\n"));
1126
1127         buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1128
1129         /* Now read through those files ... */
1130         while (True) {
1131                 /* Get us to the next block, or the first block first time around */
1132                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1133                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1134                         SAFE_FREE(longfilename);
1135                         return;
1136                 }
1137
1138                 DEBUG(5, ("Reading the next header ...\n"));
1139
1140                 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1141                         case -2:    /* Hmm, not good, but not fatal */
1142                                 DEBUG(0, ("Skipping %s...\n", finfo.name));
1143                                 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1144                                         DEBUG(0, ("Short file, bailing out...\n"));
1145                                         return;
1146                                 }
1147                                 break;
1148
1149                         case -1:
1150                                 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1151                                 return;
1152
1153                         case 0: /* chksum is zero - looks like an EOF */
1154                                 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1155                                 return;        /* Hmmm, bad here ... */
1156
1157                         default: 
1158                                 /* No action */
1159                                 break;
1160                 }
1161
1162                 /* Now, do we have a long file name? */
1163                 if (longfilename != NULL) {
1164                         SAFE_FREE(finfo.name);   /* Free the space already allocated */
1165                         finfo.name = longfilename;
1166                         longfilename = NULL;
1167                 }
1168
1169                 /* Well, now we have a header, process the file ...            */
1170                 /* Should we skip the file? We have the long name as well here */
1171                 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1172                                         (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1173
1174                 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1175                 if (skip) {
1176                         skip_file(finfo.size);
1177                         continue;
1178                 }
1179
1180                 /* We only get this far if we should process the file */
1181                 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1182                 switch (linkflag) {
1183                         case '0':  /* Should use symbolic names--FIXME */
1184                                 /* 
1185                                  * Skip to the next block first, so we can get the file, FIXME, should
1186                                  * be in get_file ...
1187                                  * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1188                                  * Fixes bug where file size in tarfile is zero.
1189                                  */
1190                                 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1191                                         DEBUG(0, ("Short file, bailing out...\n"));
1192                                         return;
1193                                 }
1194                                 if (!get_file(finfo)) {
1195                                         DEBUG(0, ("Abandoning restore\n"));
1196                                         return;
1197                                 }
1198                                 break;
1199                         case '5':
1200                                 if (!get_dir(finfo)) {
1201                                         DEBUG(0, ("Abandoning restore \n"));
1202                                         return;
1203                                 }
1204                                 break;
1205                         case 'L':
1206                                 SAFE_FREE(longfilename);
1207                                 longfilename = get_longfilename(finfo);
1208                                 if (!longfilename) {
1209                                         DEBUG(0, ("abandoning restore\n"));
1210                                         return;
1211                                 }
1212                                 DEBUG(5, ("Long file name: %s\n", longfilename));
1213                                 break;
1214
1215                         default:
1216                                 skip_file(finfo.size);  /* Don't handle these yet */
1217                                 break;
1218                 }
1219         }
1220 }
1221
1222 /*
1223  * samba interactive commands
1224  */
1225
1226 /****************************************************************************
1227 Blocksize command
1228 ***************************************************************************/
1229
1230 int cmd_block(void)
1231 {
1232         fstring buf;
1233         int block;
1234
1235         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1236                 DEBUG(0, ("blocksize <n>\n"));
1237                 return 1;
1238         }
1239
1240         block=atoi(buf);
1241         if (block < 0 || block > 65535) {
1242                 DEBUG(0, ("blocksize out of range"));
1243                 return 1;
1244         }
1245
1246         blocksize=block;
1247         DEBUG(2,("blocksize is now %d\n", blocksize));
1248
1249         return 0;
1250 }
1251
1252 /****************************************************************************
1253 command to set incremental / reset mode
1254 ***************************************************************************/
1255
1256 int cmd_tarmode(void)
1257 {
1258         fstring buf;
1259
1260         while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1261                 if (strequal(buf, "full"))
1262                         tar_inc=False;
1263                 else if (strequal(buf, "inc"))
1264                         tar_inc=True;
1265                 else if (strequal(buf, "reset"))
1266                         tar_reset=True;
1267                 else if (strequal(buf, "noreset"))
1268                         tar_reset=False;
1269                 else if (strequal(buf, "system"))
1270                         tar_system=True;
1271                 else if (strequal(buf, "nosystem"))
1272                         tar_system=False;
1273                 else if (strequal(buf, "hidden"))
1274                         tar_hidden=True;
1275                 else if (strequal(buf, "nohidden"))
1276                         tar_hidden=False;
1277                 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1278                         tar_noisy=True;
1279                 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1280                         tar_noisy=False;
1281                 else
1282                         DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1283         }
1284
1285         DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1286                         tar_inc ? "incremental" : "full",
1287                         tar_system ? "system" : "nosystem",
1288                         tar_hidden ? "hidden" : "nohidden",
1289                         tar_reset ? "reset" : "noreset",
1290                         tar_noisy ? "verbose" : "quiet"));
1291         return 0;
1292 }
1293
1294 /****************************************************************************
1295 Feeble attrib command
1296 ***************************************************************************/
1297
1298 int cmd_setmode(void)
1299 {
1300         char *q;
1301         fstring buf;
1302         pstring fname;
1303         uint16 attra[2];
1304         int direct=1;
1305
1306         attra[0] = attra[1] = 0;
1307
1308         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1309                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1310                 return 1;
1311         }
1312
1313         pstrcpy(fname, cur_dir);
1314         pstrcat(fname, buf);
1315
1316         while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1317                 q=buf;
1318
1319                 while(*q) {
1320                         switch (*q++) {
1321                                 case '+':
1322                                         direct=1;
1323                                         break;
1324                                 case '-':
1325                                         direct=0;
1326                                         break;
1327                                 case 'r':
1328                                         attra[direct]|=aRONLY;
1329                                         break;
1330                                 case 'h':
1331                                         attra[direct]|=aHIDDEN;
1332                                         break;
1333                                 case 's':
1334                                         attra[direct]|=aSYSTEM;
1335                                         break;
1336                                 case 'a':
1337                                         attra[direct]|=aARCH;
1338                                         break;
1339                                 default:
1340                                         DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1341                                         return 1;
1342                         }
1343                 }
1344         }
1345
1346         if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1347                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1348                 return 1;
1349         }
1350
1351         DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1352         do_setrattr(fname, attra[ATTRSET], ATTRSET);
1353         do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1354         return 0;
1355 }
1356
1357 /****************************************************************************
1358 Principal command for creating / extracting
1359 ***************************************************************************/
1360
1361 int cmd_tar(void)
1362 {
1363         fstring buf;
1364         char **argl = NULL;
1365         int argcl = 0;
1366         int ret;
1367
1368         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1369                 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1370                 return 1;
1371         }
1372
1373         argl=toktocliplist(&argcl, NULL);
1374         if (!tar_parseargs(argcl, argl, buf, 0))
1375                 return 1;
1376
1377         ret = process_tar();
1378         SAFE_FREE(argl);
1379         return ret;
1380 }
1381
1382 /****************************************************************************
1383 Command line (option) version
1384 ***************************************************************************/
1385
1386 int process_tar(void)
1387 {
1388         int rc = 0;
1389         initarbuf();
1390         switch(tar_type) {
1391                 case 'x':
1392
1393 #if 0
1394                         do_tarput2();
1395 #else
1396                         do_tarput();
1397 #endif
1398                         SAFE_FREE(tarbuf);
1399                         close(tarhandle);
1400                         break;
1401                 case 'r':
1402                 case 'c':
1403                         if (clipn && tar_excl) {
1404                                 int i;
1405                                 pstring tarmac;
1406
1407                                 for (i=0; i<clipn; i++) {
1408                                         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1409
1410                                         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1411                                                 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1412                                         }
1413         
1414                                         if (strrchr_m(cliplist[i], '\\')) {
1415                                                 pstring saved_dir;
1416           
1417                                                 pstrcpy(saved_dir, cur_dir);
1418           
1419                                                 if (*cliplist[i]=='\\') {
1420                                                         pstrcpy(tarmac, cliplist[i]);
1421                                                 } else {
1422                                                         pstrcpy(tarmac, cur_dir);
1423                                                         pstrcat(tarmac, cliplist[i]);
1424                                                 }
1425                                                 pstrcpy(cur_dir, tarmac);
1426                                                 *(strrchr_m(cur_dir, '\\')+1)='\0';
1427
1428                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1429                                                 do_list(tarmac,attribute,do_tar, False, True);
1430                                                 pstrcpy(cur_dir,saved_dir);
1431                                         } else {
1432                                                 pstrcpy(tarmac, cur_dir);
1433                                                 pstrcat(tarmac, cliplist[i]);
1434                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1435                                                 do_list(tarmac,attribute,do_tar, False, True);
1436                                         }
1437                                 }
1438                         } else {
1439                                 pstring mask;
1440                                 pstrcpy(mask,cur_dir);
1441                                 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1442                                 pstrcat(mask,"\\*");
1443                                 do_list(mask,attribute,do_tar,False, True);
1444                         }
1445     
1446                         if (ntarf)
1447                                 dotareof(tarhandle);
1448                         close(tarhandle);
1449                         SAFE_FREE(tarbuf);
1450     
1451                         DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1452                         DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1453                         break;
1454         }
1455
1456         if (must_free_cliplist) {
1457                 int i;
1458                 for (i = 0; i < clipn; ++i) {
1459                         SAFE_FREE(cliplist[i]);
1460                 }
1461                 SAFE_FREE(cliplist);
1462                 cliplist = NULL;
1463                 clipn = 0;
1464                 must_free_cliplist = False;
1465         }
1466         return rc;
1467 }
1468
1469 /****************************************************************************
1470 Find a token (filename) in a clip list
1471 ***************************************************************************/
1472
1473 static int clipfind(char **aret, int ret, char *tok)
1474 {
1475         if (aret==NULL)
1476                 return 0;
1477
1478         /* ignore leading slashes or dots in token */
1479         while(strchr_m("/\\.", *tok))
1480                 tok++;
1481
1482         while(ret--) {
1483                 char *pkey=*aret++;
1484
1485                 /* ignore leading slashes or dots in list */
1486                 while(strchr_m("/\\.", *pkey))
1487                         pkey++;
1488
1489                 if (!strslashcmp(pkey, tok))
1490                         return 1;
1491         }
1492         return 0;
1493 }
1494
1495 /****************************************************************************
1496 Read list of files to include from the file and initialize cliplist
1497 accordingly.
1498 ***************************************************************************/
1499
1500 static int read_inclusion_file(char *filename)
1501 {
1502         XFILE *inclusion = NULL;
1503         char buf[PATH_MAX + 1];
1504         char *inclusion_buffer = NULL;
1505         int inclusion_buffer_size = 0;
1506         int inclusion_buffer_sofar = 0;
1507         char *p;
1508         char *tmpstr;
1509         int i;
1510         int error = 0;
1511
1512         clipn = 0;
1513         buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1514         if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1515                 /* XXX It would be better to include a reason for failure, but without
1516                  * autoconf, it's hard to use strerror, sys_errlist, etc.
1517                  */
1518                 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1519                 return 0;
1520         }
1521
1522         while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1523                 if (inclusion_buffer == NULL) {
1524                         inclusion_buffer_size = 1024;
1525                         if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1526                                 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1527                                 error = 1;
1528                                 break;
1529                         }
1530                 }
1531     
1532                 if (buf[strlen(buf)-1] == '\n') {
1533                         buf[strlen(buf)-1] = '\0';
1534                 }
1535     
1536                 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1537                         inclusion_buffer_size *= 2;
1538                         inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1539                         if (!inclusion_buffer) {
1540                                 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1541                                                 inclusion_buffer_size));
1542                                 error = 1;
1543                                 break;
1544                         }
1545                 }
1546     
1547                 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1548                 inclusion_buffer_sofar += strlen(buf) + 1;
1549                 clipn++;
1550         }
1551         x_fclose(inclusion);
1552
1553         if (! error) {
1554                 /* Allocate an array of clipn + 1 char*'s for cliplist */
1555                 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1556                 if (cliplist == NULL) {
1557                         DEBUG(0,("failure allocating memory for cliplist\n"));
1558                         error = 1;
1559                 } else {
1560                         cliplist[clipn] = NULL;
1561                         p = inclusion_buffer;
1562                         for (i = 0; (! error) && (i < clipn); i++) {
1563                                 /* set current item to NULL so array will be null-terminated even if
1564                                                 * malloc fails below. */
1565                                 cliplist[i] = NULL;
1566                                 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1567                                         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1568                                         error = 1;
1569                                 } else {
1570                                         unfixtarname(tmpstr, p, strlen(p) + 1, True);
1571                                         cliplist[i] = tmpstr;
1572                                         if ((p = strchr_m(p, '\000')) == NULL) {
1573                                                 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1574                                                 abort();
1575                                         }
1576                                 }
1577                                 ++p;
1578                         }
1579                         must_free_cliplist = True;
1580                 }
1581         }
1582
1583         SAFE_FREE(inclusion_buffer);
1584         if (error) {
1585                 if (cliplist) {
1586                         char **pp;
1587                         /* We know cliplist is always null-terminated */
1588                         for (pp = cliplist; *pp; ++pp) {
1589                                 SAFE_FREE(*pp);
1590                         }
1591                         SAFE_FREE(cliplist);
1592                         cliplist = NULL;
1593                         must_free_cliplist = False;
1594                 }
1595                 return 0;
1596         }
1597   
1598         /* cliplist and its elements are freed at the end of process_tar. */
1599         return 1;
1600 }
1601
1602 /****************************************************************************
1603 Parse tar arguments. Sets tar_type, tar_excl, etc.
1604 ***************************************************************************/
1605
1606 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1607 {
1608         int newOptind = Optind;
1609         char tar_clipfl='\0';
1610
1611         /* Reset back to defaults - could be from interactive version 
1612          * reset mode and archive mode left as they are though
1613          */
1614         tar_type='\0';
1615         tar_excl=True;
1616         dry_run=False;
1617
1618         while (*Optarg) {
1619                 switch(*Optarg++) {
1620                         case 'c':
1621                                 tar_type='c';
1622                                 break;
1623                         case 'x':
1624                                 if (tar_type=='c') {
1625                                         printf("Tar must be followed by only one of c or x.\n");
1626                                         return 0;
1627                                 }
1628                                 tar_type='x';
1629                                 break;
1630                         case 'b':
1631                                 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1632                                         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1633                                         return 0;
1634                                 } else {
1635                                         Optind++;
1636                                         newOptind++;
1637                                 }
1638                                 break;
1639                         case 'g':
1640                                 tar_inc=True;
1641                                 break;
1642                         case 'N':
1643                                 if (Optind>=argc) {
1644                                         DEBUG(0,("Option N must be followed by valid file name\n"));
1645                                         return 0;
1646                                 } else {
1647                                         SMB_STRUCT_STAT stbuf;
1648         
1649                                         if (sys_stat(argv[Optind], &stbuf) == 0) {
1650                                                 newer_than = stbuf.st_mtime;
1651                                                 DEBUG(1,("Getting files newer than %s",
1652                                                         time_to_asc(newer_than)));
1653                                                 newOptind++;
1654                                                 Optind++;
1655                                         } else {
1656                                                 DEBUG(0,("Error setting newer-than time\n"));
1657                                                 return 0;
1658                                         }
1659                                 }
1660                                 break;
1661                         case 'a':
1662                                 tar_reset=True;
1663                                 break;
1664                         case 'q':
1665                                 tar_noisy=False;
1666                                 break;
1667                         case 'I':
1668                                 if (tar_clipfl) {
1669                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1670                                         return 0;
1671                                 }
1672                                 tar_clipfl='I';
1673                                 break;
1674                         case 'X':
1675                                 if (tar_clipfl) {
1676                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1677                                         return 0;
1678                                 }
1679                                 tar_clipfl='X';
1680                                 break;
1681                         case 'F':
1682                                 if (tar_clipfl) {
1683                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1684                                         return 0;
1685                                 }
1686                                 tar_clipfl='F';
1687                                 break;
1688                         case 'r':
1689                                 DEBUG(0, ("tar_re_search set\n"));
1690                                 tar_re_search = True;
1691                                 break;
1692                         case 'n':
1693                                 if (tar_type == 'c') {
1694                                         DEBUG(0, ("dry_run set\n"));
1695                                         dry_run = True;
1696                                 } else {
1697                                         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1698                                         return 0;
1699                                 }
1700                                 break;
1701                         default:
1702                                 DEBUG(0,("Unknown tar option\n"));
1703                                 return 0;
1704                 }
1705         }
1706
1707         if (!tar_type) {
1708                 printf("Option T must be followed by one of c or x.\n");
1709                 return 0;
1710         }
1711
1712         /* tar_excl is true if cliplist lists files to be included.
1713          * Both 'I' and 'F' mean include. */
1714         tar_excl=tar_clipfl!='X';
1715
1716         if (tar_clipfl=='F') {
1717                 if (argc-Optind-1 != 1) {
1718                         DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1719                         return 0;
1720                 }
1721                 newOptind++;
1722                 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1723                 if (! read_inclusion_file(argv[Optind+1])) {
1724                         return 0;
1725                 }
1726         } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1727                 char *tmpstr;
1728                 char **tmplist;
1729                 int clipcount;
1730
1731                 cliplist=argv+Optind+1;
1732                 clipn=argc-Optind-1;
1733                 clipcount = clipn;
1734
1735                 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1736                         DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1737                         return 0;
1738                 }
1739
1740                 for (clipcount = 0; clipcount < clipn; clipcount++) {
1741
1742                         DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1743
1744                         if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1745                                 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1746                                 SAFE_FREE(tmplist);
1747                                 return 0;
1748                         }
1749
1750                         unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1751                         tmplist[clipcount] = tmpstr;
1752                         DEBUG(5, ("Processed an item, %s\n", tmpstr));
1753
1754                         DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1755                 }
1756
1757                 cliplist = tmplist;
1758                 must_free_cliplist = True;
1759
1760                 newOptind += clipn;
1761         }
1762
1763         if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1764                 /* Doing regular expression seaches not from an inclusion file. */
1765                 clipn=argc-Optind-1;
1766                 cliplist=argv+Optind+1;
1767                 newOptind += clipn;
1768         }
1769
1770         if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1771                 /* Sets tar handle to either 0 or 1, as appropriate */
1772                 tarhandle=(tar_type=='c');
1773                 /*
1774                  * Make sure that dbf points to stderr if we are using stdout for 
1775                  * tar output
1776                  */
1777                 if (tarhandle == 1)  {
1778                         dbf = x_stderr;
1779                 }
1780                 if (!argv[Optind]) {
1781                         DEBUG(0,("Must specify tar filename\n"));
1782                         return 0;
1783                 }
1784                 if (!strcmp(argv[Optind], "-")) {
1785                         newOptind++;
1786                 }
1787
1788         } else {
1789                 if (tar_type=='c' && dry_run) {
1790                         tarhandle=-1;
1791                 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1792                                         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1793                         DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1794                         return(0);
1795                 }
1796                 newOptind++;
1797         }
1798
1799         return newOptind;
1800 }