Fixed compile errors in new code.
[kai/samba.git] / source3 / client / clitar.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Tar Extensions
5    Copyright (C) Ricky Poulten 1995-1998
6    Copyright (C) Richard Sharpe 1998
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 /* The following changes developed by Richard Sharpe for Canon Information
23    Systems Research Australia (CISRA)
24
25    1. Restore can now restore files with long file names
26    2. Save now saves directory information so that we can restore 
27       directory creation times
28    3. tar now accepts both UNIX path names and DOS path names. I prefer
29       those lovely /'s to those UGLY \'s :-)
30    4. the files to exclude can be specified as a regular expression by adding
31       an r flag to the other tar flags. Eg:
32
33          -TcrX file.tar "*.(obj|exe)"
34
35       will skip all .obj and .exe files
36 */
37
38
39 #include "includes.h"
40 #include "clitar.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 {
48   int size;
49   int mode;
50   int uid;
51   int gid;
52   /* These times are normally kept in GMT */
53   time_t mtime;
54   time_t atime;
55   time_t ctime;
56   char *name;     /* This is dynamically allocate */
57
58   file_info2 *next, *prev;  /* Used in the stack ... */
59
60 };
61
62 typedef struct
63 {
64   file_info2 *top;
65   int items;
66
67 } stack;
68
69 stack dir_stack = {NULL, 0}; /* Want an empty stack */
70
71 extern BOOL recurse;
72
73 #define SEPARATORS " \t\n\r"
74 extern int DEBUGLEVEL;
75 extern int Client;
76
77 /* These defines are for the do_setrattr routine, to indicate
78  * setting and reseting of file attributes in the function call */
79 #define ATTRSET 1
80 #define ATTRRESET 0
81
82 static int attribute = aDIR | aSYSTEM | aHIDDEN;
83
84 #ifndef CLIENT_TIMEOUT
85 #define CLIENT_TIMEOUT (30*1000)
86 #endif
87
88 static char *tarbuf, *buffer_p;
89 static int tp, ntarf, tbufsiz, ttarf;
90 /* Incremental mode */
91 BOOL tar_inc=False;
92 /* Reset archive bit */
93 BOOL tar_reset=False;
94 /* Include / exclude mode (true=include, false=exclude) */
95 BOOL tar_excl=True;
96 /* use regular expressions for search on file names */
97 BOOL tar_re_search=False;
98 #ifdef HAVE_REGEX_H
99 regex_t *preg;
100 #endif
101 /* Dump files with System attribute */
102 BOOL tar_system=True;
103 /* Dump files with Hidden attribute */
104 BOOL tar_hidden=True;
105 /* Be noisy - make a catalogue */
106 BOOL tar_noisy=True;
107 BOOL tar_real_noisy=True;
108
109 char tar_type='\0';
110 static char **cliplist=NULL;
111 static int clipn=0;
112 static BOOL must_free_cliplist = False;
113
114 extern file_info def_finfo;
115 extern BOOL lowercase;
116 extern int cnum;
117 extern BOOL readbraw_supported;
118 extern int max_xmit;
119 extern pstring cur_dir;
120 extern int get_total_time_ms;
121 extern int get_total_size;
122 extern int Protocol;
123
124 int blocksize=20;
125 int tarhandle;
126
127 static void writetarheader(int f,  char *aname, int size, time_t mtime,
128                            char *amode, unsigned char ftype);
129 static void do_atar(char *rname,char *lname,file_info *finfo1);
130 static void do_tar(file_info *finfo);
131 static void oct_it(long value, int ndgs, char *p);
132 static void fixtarname(char *tptr, char *fp, int l);
133 static int dotarbuf(int f, char *b, int n);
134 static void dozerobuf(int f, int n);
135 static void dotareof(int f);
136 static void initarbuf(void);
137 static int do_setrattr(char *fname, int attr, int setit);
138
139 /* restore functions */
140 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
141 static long unoct(char *p, int ndgs);
142 static void do_tarput(void);
143 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
144
145 /*
146  * tar specific utitlities
147  */
148
149 #if 0 /* Removed to get around gcc 'defined but not used' error. */
150
151 /*
152  * Stack routines, push_dir, pop_dir, top_dir_name
153  */
154
155 static BOOL push_dir(stack *tar_dir_stack, file_info2 *dir)
156 {
157   dir -> next = tar_dir_stack -> top;
158   dir -> prev = NULL;
159   tar_dir_stack -> items++;
160   tar_dir_stack -> top = dir;
161   return(True);
162
163 }
164
165 static file_info2 *pop_dir(stack *tar_dir_stack)
166 {
167   file_info2 *ptr;
168   
169   ptr = tar_dir_stack -> top;
170   if (tar_dir_stack -> top != NULL) {
171
172     tar_dir_stack -> top = tar_dir_stack -> top -> next;
173     tar_dir_stack -> items--;
174
175   }
176
177   return ptr;
178
179 }
180
181 static char *top_dir_name(stack *tar_dir_stack)
182 {
183
184   return(tar_dir_stack -> top != NULL?tar_dir_stack -> top -> name:NULL);
185
186 }
187
188 static BOOL sub_dir(char *dir1, char *dir2)
189 {
190
191   return(True);
192
193 }
194
195 #endif /* Removed to get around gcc 'defined but not used' error. */
196
197 /*******************************************************************
198 Create  a string of size size+1 (for the null)
199 *******************************************************************/
200 static char *string_create_s(int size)
201 {
202   char *tmp;
203
204   tmp = (char *)malloc(size+1);
205
206   if (tmp == NULL) {
207
208     DEBUG(0, ("Out of memory in string_create_s\n"));
209
210   }
211
212   return(tmp);
213
214 }
215
216 /****************************************************************************
217 Write a tar header to buffer
218 ****************************************************************************/
219 static void writetarheader(int f,  char *aname, int size, time_t mtime,
220                            char *amode, unsigned char ftype)
221 {
222   union hblock hb;
223   int i, chk, l;
224   char *jp;
225
226   DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
227
228   memset(hb.dummy, 0, sizeof(hb.dummy));
229   
230   l=strlen(aname);
231   if (l >= NAMSIZ) {
232           /* write a GNU tar style long header */
233           char *b;
234           b = (char *)malloc(l+TBLOCK+100);
235           if (!b) {
236                   DEBUG(0,("out of memory\n"));
237                   exit(1);
238           }
239           writetarheader(f, "/./@LongLink", l+1, 0, "     0 \0", 'L');
240           memset(b, 0, l+TBLOCK+100);
241           fixtarname(b, aname, l);
242           i = strlen(b)+1;
243           DEBUG(5, ("File name in tar file: %s, size=%i, \n", b, strlen(b)));
244           dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
245           free(b);
246   }
247
248   /* use l + 1 to do the null too */
249   fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
250
251   if (lowercase)
252     strlower(hb.dbuf.name);
253
254   /* write out a "standard" tar format header */
255
256   hb.dbuf.name[NAMSIZ-1]='\0';
257   safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
258   oct_it(0L, 8, hb.dbuf.uid);
259   oct_it(0L, 8, hb.dbuf.gid);
260   oct_it((long) size, 13, hb.dbuf.size);
261   oct_it((long) mtime, 13, hb.dbuf.mtime);
262   memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
263   memset(hb.dbuf.linkname, 0, NAMSIZ);
264   hb.dbuf.linkflag=ftype;
265   
266   for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
267
268   oct_it((long) chk, 8, hb.dbuf.chksum);
269   hb.dbuf.chksum[6] = '\0';
270
271   (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
272 }
273
274 /****************************************************************************
275 Read a tar header into a hblock structure, and validate
276 ***************************************************************************/
277 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
278 {
279   long chk, fchk;
280   int i;
281   char *jp;
282
283   /*
284    * read in a "standard" tar format header - we're not that interested
285    * in that many fields, though
286    */
287
288   /* check the checksum */
289   for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
290
291   if (chk == 0)
292     return chk;
293
294   /* compensate for blanks in chksum header */
295   for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
296     chk-=(0xFF & *jp++);
297
298   chk += ' ' * sizeof(hb->dbuf.chksum);
299
300   fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
301
302   DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
303             chk, fchk, hb->dbuf.chksum));
304
305   if (fchk != chk)
306     {
307       DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
308 /*      for (i = 0; i < sizeof(hb -> dummy); i++) {
309         fprintf(stdout, "%2X ", hb -> dummy[i]);
310       }
311       fprintf(stdout, "\n");
312       fprintf(stdout, "%s\n", hb -> dummy);
313       fprintf(stdout, "Tarbuf = %X, hb = %X\n", (int)tarbuf, (int)hb);*/
314       return -1;
315     }
316
317   if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
318
319     DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
320     return(-1);
321
322   }
323
324   safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
325
326   /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
327   unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
328                strlen(hb->dbuf.name) + 1, True);
329
330 /* can't handle some links at present */
331   if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
332     if (hb->dbuf.linkflag == 0) {
333       DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
334                 finfo->name));
335     } else { 
336       if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
337          /* Do nothing here at the moment. do_tarput will handle this
338             as long as the longlink gets back to it, as it has to advance 
339             the buffer pointer, etc */
340
341       } else {
342         DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
343         return -2;
344       }
345     }
346   }
347     
348   if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
349     || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
350     {
351       finfo->mode=aDIR;
352     }
353   else
354     finfo->mode=0; /* we don't care about mode at the moment, we'll
355                     * just make it a regular file */
356   /*
357    * Bug fix by richard@sj.co.uk
358    *
359    * REC: restore times correctly (as does tar)
360    * We only get the modification time of the file; set the creation time
361    * from the mod. time, and the access time to current time
362    */
363   finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
364   finfo->atime = time(NULL);
365   finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
366
367   return True;
368 }
369
370 /****************************************************************************
371 Write out the tar buffer to tape or wherever
372 ****************************************************************************/
373 static int dotarbuf(int f, char *b, int n)
374 {
375   int fail=1, writ=n;
376
377   /* This routine and the next one should be the only ones that do write()s */
378   if (tp + n >= tbufsiz)
379     {
380       int diff;
381
382       diff=tbufsiz-tp;
383       memcpy(tarbuf + tp, b, diff);
384       fail=fail && (1+write(f, tarbuf, tbufsiz));
385       n-=diff;
386       b+=diff;
387       tp=0;
388
389       while (n >= tbufsiz)
390         {
391           fail=fail && (1 + write(f, b, tbufsiz));
392           n-=tbufsiz;
393           b+=tbufsiz;
394         }
395     }
396   if (n>0) {
397     memcpy(tarbuf+tp, b, n);
398     tp+=n;
399   }
400
401   return(fail ? writ : 0);
402 }
403
404 /****************************************************************************
405 Write zeros to buffer / tape
406 ****************************************************************************/
407 static void dozerobuf(int f, int n)
408 {
409   /* short routine just to write out n zeros to buffer -
410    * used to round files to nearest block
411    * and to do tar EOFs */
412
413   if (n+tp >= tbufsiz)
414     {
415       memset(tarbuf+tp, 0, tbufsiz-tp);
416
417       write(f, tarbuf, tbufsiz);
418       memset(tarbuf, 0, (tp+=n-tbufsiz));
419     }
420   else
421     {
422       memset(tarbuf+tp, 0, n);
423       tp+=n;
424     }
425 }
426
427 /****************************************************************************
428 Malloc tape buffer
429 ****************************************************************************/
430 static void initarbuf()
431 {
432   /* initialize tar buffer */
433   tbufsiz=blocksize*TBLOCK;
434   tarbuf=malloc(tbufsiz);      /* FIXME: We might not get the buffer */
435
436   /* reset tar buffer pointer and tar file counter and total dumped */
437   tp=0; ntarf=0; ttarf=0;
438 }
439
440 /****************************************************************************
441 Write two zero blocks at end of file
442 ****************************************************************************/
443 static void dotareof(int f)
444 {
445   SMB_STRUCT_STAT stbuf;
446   /* Two zero blocks at end of file, write out full buffer */
447
448   (void) dozerobuf(f, TBLOCK);
449   (void) dozerobuf(f, TBLOCK);
450
451   if (sys_fstat(f, &stbuf) == -1)
452     {
453       DEBUG(0, ("Couldn't stat file handle\n"));
454       return;
455     }
456
457   /* Could be a pipe, in which case S_ISREG should fail,
458    * and we should write out at full size */
459   if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
460 }
461
462 /****************************************************************************
463 (Un)mangle DOS pathname, make nonabsolute
464 ****************************************************************************/
465 static void fixtarname(char *tptr, char *fp, int l)
466 {
467   /* add a '.' to start of file name, convert from ugly dos \'s in path
468    * to lovely unix /'s :-} */
469
470   *tptr++='.';
471
472   while (l > 0) {
473     int skip;
474     if((skip = skip_multibyte_char( *fp)) != 0) {
475       if (skip == 2) {
476         *tptr++ = *fp++;
477         *tptr++ = *fp++;
478         l -= 2;
479       } else if (skip == 1) {
480         *tptr++ = *fp++;
481         l--;
482       }
483     } else if (*fp == '\\') {
484       *tptr++ = '/';
485       fp++;
486       l--;
487     } else {
488       *tptr++ = *fp++;
489       l--;
490     }
491   }
492 }
493
494 /****************************************************************************
495 Convert from decimal to octal string
496 ****************************************************************************/
497 static void oct_it (long value, int ndgs, char *p)
498 {
499   /* Converts long to octal string, pads with leading zeros */
500
501   /* skip final null, but do final space */
502   --ndgs;
503   p[--ndgs] = ' ';
504  
505   /* Loop does at least one digit */
506   do {
507       p[--ndgs] = '0' + (char) (value & 7);
508       value >>= 3;
509     }
510   while (ndgs > 0 && value != 0);
511  
512   /* Do leading zeros */
513   while (ndgs > 0)
514     p[--ndgs] = '0';
515 }
516
517 /****************************************************************************
518 Convert from octal string to long
519 ***************************************************************************/
520 static long unoct(char *p, int ndgs)
521 {
522   long value=0;
523   /* Converts octal string to long, ignoring any non-digit */
524
525   while (--ndgs)
526     {
527       if (isdigit((int)*p))
528         value = (value << 3) | (long) (*p - '0');
529
530       p++;
531     }
532
533   return value;
534 }
535
536 /****************************************************************************
537 Compare two strings in a slash insensitive way, allowing s1 to match s2 
538 if s1 is an "initial" string (up to directory marker).  Thus, if s2 is 
539 a file in any subdirectory of s1, declare a match.
540 ***************************************************************************/
541 static int strslashcmp(char *s1, char *s2)
542 {
543   char *s1_0=s1;
544
545   while(*s1 && *s2 &&
546         (*s1 == *s2
547          || tolower(*s1) == tolower(*s2)
548          || (*s1 == '\\' && *s2=='/')
549          || (*s1 == '/' && *s2=='\\'))) {
550           s1++; s2++;
551   }
552
553   /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" 
554      string of s2.
555    */
556   if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
557
558   /* ignore trailing slash on s1 */
559   if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
560
561   /* check for s1 is an "initial" string of s2 */
562   if (*s2 == '/' || *s2 == '\\') return 0;
563
564   return *s1-*s2;
565 }
566
567 /*
568  * general smb utility functions
569  */
570 /**********************************************************************
571 do_setrtime, set time on a file or dir ...
572 **********************************************************************/
573
574 static int do_setrtime(char *fname, int mtime, BOOL err_silent)
575 {
576   char *inbuf, *outbuf, *p;
577   char *name;
578
579   DEBUG(5, ("Setting time on: %s, fnlen=%i.\n", fname, strlen(fname)));
580
581   name = (char *)malloc(strlen(fname) + 1 + 1);
582   if (name == NULL) {
583
584      DEBUG(0, ("Failed to allocate space while setting time on file: %s", fname));
585      return False;
586
587   }
588
589   if (*fname != '\\')
590     safe_strcpy(name, "\\", strlen(fname) + 1);
591   else
592     safe_strcpy(name, "", strlen(fname) + 1);
593   safe_strcat(name, fname, strlen(fname) + 1);
594
595   if (fname[strlen(name) - 1] == '\\')
596     name[strlen(name) - 1] = '\0';
597
598   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
599   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
600
601   if (!inbuf || !outbuf) {
602
603     DEBUG(0, ("Could not allocate memory for inbuf or outbuf while changing time on: %s\n", fname));
604     free(name);
605     return False;
606
607   }
608
609   memset(outbuf, 0, smb_size);
610   set_message(outbuf, 8, 4 + strlen(name), True);
611   CVAL(outbuf, smb_com) = SMBsetatr;
612   SSVAL(outbuf, smb_tid, cnum);
613   cli_setup_pkt(outbuf);
614
615   SSVAL(outbuf, smb_vwv0, 0);
616   put_dos_date3(outbuf, smb_vwv1, mtime);
617
618   p = smb_buf(outbuf);
619   *p++ = 4;
620   safe_strcpy(p, name, strlen(name));
621   p+= (strlen(fname)+1);
622
623   *p++ = 4;
624   *p++ = 0;
625
626   send_smb(Client, outbuf);
627   client_receive_smb(Client, inbuf, CLIENT_TIMEOUT);
628
629   if (CVAL(inbuf,smb_rcls) != 0)
630     {
631       if (!err_silent) {
632         DEBUG(0,("%s setting attributes on file %s\n",
633                  smb_errstr(inbuf), fname));
634       }
635       free(name);free(inbuf);free(outbuf);
636       return(False);
637     }
638
639   free(name);
640   free(inbuf);free(outbuf);
641   return(True);
642
643 }
644
645 /****************************************************************************
646 Set DOS file attributes
647 ***************************************************************************/
648 static int do_setrattr(char *fname, int attr, int setit)
649 {
650   /*
651    * First get the existing attribs from existing file
652    */
653   char *inbuf,*outbuf;
654   char *p;
655   char *name;
656   int fattr;
657
658   name = (char *)malloc(strlen(fname) + 1 + 1);
659   if (name == NULL) {
660
661      DEBUG(0, ("Failed to allocate space in do_setrattr while setting time on file: %s", fname));
662      return False;
663
664   }
665
666   safe_strcpy(name, "\\", strlen(fname) + 1);
667   safe_strcat(name, fname, strlen(fname) + 1);
668
669   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
670   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
671
672   if (!inbuf || !outbuf)
673     {
674       DEBUG(0,("out of memory\n"));
675       free(name);
676       return False;
677     }
678
679   /* send an smb getatr message */
680
681   memset(outbuf,0,smb_size);
682   set_message(outbuf,0,2 + strlen(fname),True);
683   CVAL(outbuf,smb_com) = SMBgetatr;
684   SSVAL(outbuf,smb_tid,cnum);
685   cli_setup_pkt(outbuf);
686
687   p = smb_buf(outbuf);
688   *p++ = 4;
689   safe_strcpy(p,name, strlen(name));
690   p += (strlen(name)+1);
691   
692   *p++ = 4;
693   *p++ = 0;
694
695   send_smb(Client,outbuf);
696   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
697
698   if (CVAL(inbuf,smb_rcls) != 0)
699     DEBUG(5,("getatr: %s\n",smb_errstr(inbuf)));
700   else
701     {
702       DEBUG(5,("\nattr 0x%X  time %d  size %d\n",
703                (int)CVAL(inbuf,smb_vwv0),
704                SVAL(inbuf,smb_vwv1),
705                SVAL(inbuf,smb_vwv3)));
706     }
707
708   fattr=CVAL(inbuf,smb_vwv0);
709
710   /* combine found attributes with bits to be set or reset */
711
712   attr=setit ? (fattr | attr) : (fattr & ~attr);
713
714   /* now try and set attributes by sending smb reset message */
715
716   /* clear out buffer and start again */
717   memset(outbuf,0,smb_size);
718   set_message(outbuf,8,4 + strlen(name),True);
719   CVAL(outbuf,smb_com) = SMBsetatr;
720   SSVAL(outbuf,smb_tid,cnum);
721   cli_setup_pkt(outbuf);
722
723   SSVAL(outbuf,smb_vwv0,attr);
724   
725   p = smb_buf(outbuf);
726   *p++ = 4;      
727   safe_strcpy(p,name, strlen(name));
728   p += (strlen(name)+1);
729   
730   *p++ = 4;
731   *p++ = 0;
732
733   send_smb(Client,outbuf);
734   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
735   
736   if (CVAL(inbuf,smb_rcls) != 0)
737     {
738       DEBUG(0,("%s setting attributes on file %s\n",
739             smb_errstr(inbuf), name));
740       free(name);free(inbuf);free(outbuf);
741       return(False);
742     }
743
744   free(name);
745   free(inbuf);free(outbuf);
746   return(True);
747 }
748
749 /****************************************************************************
750 Create a file on a share
751 ***************************************************************************/
752 static BOOL smbcreat(file_info2 finfo, int *fnum, char *inbuf, char *outbuf)
753 {
754   char *p;
755   /* *must* be called with buffer ready malloc'ed */
756   /* open remote file */
757
758   memset(outbuf,0,smb_size);
759   set_message(outbuf,3,2 + strlen(finfo.name),True);
760   CVAL(outbuf,smb_com) = SMBcreate;
761   SSVAL(outbuf,smb_tid,cnum);
762   cli_setup_pkt(outbuf);
763   
764   SSVAL(outbuf,smb_vwv0,finfo.mode);
765   put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
766   
767   p = smb_buf(outbuf);
768   *p++ = 4;      
769   safe_strcpy(p,finfo.name, strlen(finfo.name));
770   
771   send_smb(Client,outbuf);
772   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
773   
774   if (CVAL(inbuf,smb_rcls) != 0)
775     {
776       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),
777                finfo.name));
778       return 0;
779     }
780   
781   *fnum = SVAL(inbuf,smb_vwv0);
782   return True;
783 }
784
785 /****************************************************************************
786 Write a file to a share
787 ***************************************************************************/
788 static BOOL smbwrite(int fnum, int n, int low, int high, int left,
789                      char *bufferp, char *inbuf, char *outbuf)
790 {
791   /* *must* be called with buffer ready malloc'ed */
792
793   memset(outbuf,0,smb_size);
794   set_message(outbuf,5,n + 3,True);
795   
796   memcpy(smb_buf(outbuf)+3, bufferp, n);
797   
798   set_message(outbuf,5,n + 3, False);
799   CVAL(outbuf,smb_com) = SMBwrite;
800   SSVAL(outbuf,smb_tid,cnum);
801   cli_setup_pkt(outbuf);
802   
803   SSVAL(outbuf,smb_vwv0,fnum);
804   SSVAL(outbuf,smb_vwv1,n);
805   SIVAL(outbuf,smb_vwv2,low);
806   SSVAL(outbuf,smb_vwv4,left);
807   CVAL(smb_buf(outbuf),0) = 1;
808   SSVAL(smb_buf(outbuf),1,n);
809
810   send_smb(Client,outbuf); 
811   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
812   
813   if (CVAL(inbuf,smb_rcls) != 0)
814     {
815       DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
816       return False;
817     }
818   
819   if (n != SVAL(inbuf,smb_vwv0))
820     {
821       DEBUG(0,("Error: only wrote %d bytes out of %d\n",
822                SVAL(inbuf,smb_vwv0), n));
823       return False;
824     }
825
826   return True;
827 }
828
829 /****************************************************************************
830 Close a file on a share
831 ***************************************************************************/
832 static BOOL smbshut(file_info2 finfo, int fnum, char *inbuf, char *outbuf)
833 {
834   /* *must* be called with buffer ready malloc'ed */
835
836   memset(outbuf,0,smb_size);
837   set_message(outbuf,3,0,True);
838   CVAL(outbuf,smb_com) = SMBclose;
839   SSVAL(outbuf,smb_tid,cnum);
840   cli_setup_pkt(outbuf);
841   
842   SSVAL(outbuf,smb_vwv0,fnum);
843   put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
844   
845   DEBUG(3,("Setting date to %s (0x%lX)",
846            asctime(LocalTime(&finfo.mtime)),
847            finfo.mtime));
848   
849   send_smb(Client,outbuf);
850   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
851   
852   if (CVAL(inbuf,smb_rcls) != 0)
853     {
854       DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),
855                finfo.name));
856       return False;
857     }
858
859   return True;
860 }
861
862 /****************************************************************************
863 Verify existence of path on share
864 ***************************************************************************/
865 static BOOL smbchkpath(char *fname, char *inbuf, char *outbuf)
866 {
867   char *p;
868
869   memset(outbuf,0,smb_size);
870   set_message(outbuf,0,4 + strlen(fname),True);
871   CVAL(outbuf,smb_com) = SMBchkpth;
872   SSVAL(outbuf,smb_tid,cnum);
873   cli_setup_pkt(outbuf);
874
875   p = smb_buf(outbuf);
876   *p++ = 4;
877   safe_strcpy(p,fname, strlen(fname));
878
879   send_smb(Client,outbuf);
880   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
881
882   DEBUG(5,("smbchkpath: %s\n",smb_errstr(inbuf)));
883
884   return(CVAL(inbuf,smb_rcls) == 0);
885 }
886
887 /****************************************************************************
888 Make a directory on share
889 ***************************************************************************/
890 static BOOL smbmkdir(char *fname, char *inbuf, char *outbuf)
891 {
892   /* *must* be called with buffer ready malloc'ed */
893   char *p;
894
895   memset(outbuf,0,smb_size);
896   set_message(outbuf,0,2 + strlen(fname),True);
897   
898   CVAL(outbuf,smb_com) = SMBmkdir;
899   SSVAL(outbuf,smb_tid,cnum);
900   cli_setup_pkt(outbuf);
901   
902   p = smb_buf(outbuf);
903   *p++ = 4;      
904   safe_strcpy(p,fname, strlen(fname));
905   
906   send_smb(Client,outbuf);
907   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
908   
909   if (CVAL(inbuf,smb_rcls) != 0)
910     {
911       DEBUG(0,("%s making remote directory %s\n",
912                smb_errstr(inbuf),fname));
913       return(False);
914     }
915
916   return(True);
917 }
918
919 /****************************************************************************
920 Ensure a remote path exists (make if necessary)
921 ***************************************************************************/
922 static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
923 {
924   /* *must* be called with buffer ready malloc'ed */
925   /* ensures path exists */
926
927   char *partpath, *ffname;
928   char *p=fname, *basehack;
929
930   DEBUG(5, ( "Ensurepath called with: %s\n", fname));
931
932   partpath = string_create_s(strlen(fname));
933   ffname = string_create_s(strlen(fname));
934
935   if ((partpath == NULL) || (ffname == NULL)){
936
937     DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
938     return(False);
939
940   }
941
942   *partpath = 0;
943
944   /* fname copied to ffname so can strtok */
945
946   safe_strcpy(ffname, fname, strlen(fname));
947
948   /* do a `basename' on ffname, so don't try and make file name directory */
949   if ((basehack=strrchr(ffname, '\\')) == NULL)
950     return True;
951   else
952     *basehack='\0';
953
954   p=strtok(ffname, "\\");
955
956   while (p)
957     {
958       safe_strcat(partpath, p, strlen(fname) + 1);
959
960       if (!smbchkpath(partpath, inbuf, outbuf)) {
961         if (!smbmkdir(partpath, inbuf, outbuf))
962           {
963             DEBUG(0, ("Error mkdirhiering\n"));
964             return False;
965           }
966         else
967           DEBUG(3, ("mkdirhiering %s\n", partpath));
968
969       }
970
971       safe_strcat(partpath, "\\", strlen(fname) + 1);
972       p = strtok(NULL,"/\\");
973     }
974
975     return True;
976 }
977
978 static int padit(char *buf, int bufsize, int padsize)
979 {
980   int berr= 0;
981   int bytestowrite;
982   
983   DEBUG(5, ("Padding with %d zeros\n", padsize));
984   memset(buf, 0, bufsize);
985   while( !berr && padsize > 0 ) {
986     bytestowrite= MIN(bufsize, padsize);
987     berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
988     padsize -= bytestowrite;
989   }
990   
991   return berr;
992 }
993
994 /*
995  * smbclient functions
996  */
997 /****************************************************************************
998 append one remote file to the tar file
999 ***************************************************************************/
1000 static void do_atar(char *rname,char *lname,file_info *finfo1)
1001 {
1002   int fnum;
1003   uint32 nread=0;
1004   char *p, ftype;
1005   char *inbuf,*outbuf;
1006   file_info2 finfo;
1007   BOOL close_done = False;
1008   BOOL shallitime=True;
1009   BOOL ignore_close_error = False;
1010   char *dataptr=NULL;
1011   int datalen=0;
1012
1013   struct timeval tp_start;
1014   GetTimeOfDay(&tp_start);
1015
1016   ftype = '0'; /* An ordinary file ... */
1017
1018   if (finfo1) {
1019     finfo.size  = finfo1 -> size;
1020     finfo.mode  = finfo1 -> mode;
1021     finfo.uid   = finfo1 -> uid;
1022     finfo.gid   = finfo1 -> gid;
1023     finfo.mtime = finfo1 -> mtime;
1024     finfo.atime = finfo1 -> atime;
1025     finfo.ctime = finfo1 -> ctime;
1026   }
1027   else {
1028     finfo.size  = def_finfo.size;
1029     finfo.mode  = def_finfo.mode;
1030     finfo.uid   = def_finfo.uid;
1031     finfo.gid   = def_finfo.gid;
1032     finfo.mtime = def_finfo.mtime;
1033     finfo.atime = def_finfo.atime;
1034     finfo.ctime = def_finfo.ctime;
1035   }
1036
1037
1038   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1039   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1040
1041   if (!inbuf || !outbuf)
1042     {
1043       DEBUG(0,("out of memory\n"));
1044       return;
1045     }
1046
1047   memset(outbuf,0,smb_size);
1048   set_message(outbuf,15,1 + strlen(rname),True);
1049
1050   CVAL(outbuf,smb_com) = SMBopenX;
1051   SSVAL(outbuf,smb_tid,cnum);
1052   cli_setup_pkt(outbuf);
1053
1054   SSVAL(outbuf,smb_vwv0,0xFF);
1055   SSVAL(outbuf,smb_vwv2,1);
1056   SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
1057   SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1058   SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
1059   SSVAL(outbuf,smb_vwv8,1);
1060
1061   p = smb_buf(outbuf);
1062   safe_strcpy(p, rname, strlen(rname));
1063   p = skip_string(p,1);
1064
1065   dos_clean_name(rname);
1066
1067   /* do a chained openX with a readX? */  
1068   if (finfo.size > 0)
1069     {
1070       SSVAL(outbuf,smb_vwv0,SMBreadX);
1071       SSVAL(outbuf,smb_vwv1,PTR_DIFF(p,outbuf) - 4);
1072       memset(p,0,200);
1073       p -= smb_wct;
1074       SCVAL(p,smb_wct,10);
1075       SSVAL(p,smb_vwv0,0xFF);
1076       SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
1077       SSVAL(p,smb_vwv9,MIN(0xFFFF,finfo.size));
1078       smb_setlen(outbuf,smb_len(outbuf)+11*2+1);  
1079     }
1080   
1081   send_smb(Client,outbuf);
1082   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1083
1084   if (CVAL(inbuf,smb_rcls) != 0)
1085     {
1086       if (CVAL(inbuf,smb_rcls) == ERRSRV &&
1087           SVAL(inbuf,smb_err) == ERRnoresource &&
1088           cli_reopen_connection(inbuf,outbuf))
1089         {
1090           do_atar(rname,lname,finfo1);
1091           free(inbuf);free(outbuf);
1092           return;
1093         }
1094
1095       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),rname));
1096       free(inbuf);free(outbuf);
1097       return;
1098     }
1099
1100   finfo.name = string_create_s(strlen(rname));
1101   if (finfo.name == NULL) {
1102
1103     DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
1104     free(inbuf); free(outbuf);
1105     return;
1106
1107   }
1108
1109   safe_strcpy(finfo.name,rname, strlen(rname));
1110   if (!finfo1)
1111     {
1112       finfo.mode = SVAL(inbuf,smb_vwv3);
1113       finfo.size = IVAL(inbuf,smb_vwv4);
1114       finfo.mtime = make_unix_date3(inbuf+smb_vwv6);
1115       finfo.atime = finfo.ctime = finfo.mtime;
1116     }
1117
1118   DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
1119
1120   fnum = SVAL(inbuf,smb_vwv2);
1121
1122   if (tar_inc && !(finfo.mode & aARCH))
1123     {
1124       DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
1125       shallitime=0;
1126     }
1127   else if (!tar_system && (finfo.mode & aSYSTEM))
1128     {
1129       DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
1130       shallitime=0;
1131     }
1132   else if (!tar_hidden && (finfo.mode & aHIDDEN))
1133     {
1134       DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
1135       shallitime=0;
1136     }
1137   else
1138     {
1139       if (SVAL(inbuf,smb_vwv0) == SMBreadX)
1140         {
1141           p = (inbuf+4+SVAL(inbuf,smb_vwv1)) - smb_wct;
1142           datalen = SVAL(p,smb_vwv5);
1143           dataptr = inbuf + 4 + SVAL(p,smb_vwv6);
1144         }
1145       else
1146         {
1147           dataptr = NULL;
1148           datalen = 0;
1149         }
1150
1151       DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
1152                finfo.name,
1153                finfo.size,
1154                lname));
1155       
1156       /* write a tar header, don't bother with mode - just set to 100644 */
1157       writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
1158       
1159       while (nread < finfo.size && !close_done)
1160         {
1161           int method = -1;
1162           static BOOL can_chain_close=True;
1163
1164           p=NULL;
1165           
1166           DEBUG(3,("nread=%d\n",nread));
1167           
1168           /* 3 possible read types. readbraw if a large block is required.
1169              readX + close if not much left and read if neither is supported */
1170
1171           /* we might have already read some data from a chained readX */
1172           if (dataptr && datalen>0)
1173             method=3;
1174           
1175           /* if we can finish now then readX+close */
1176           if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) && 
1177               ((finfo.size - nread) < 
1178                (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
1179             method = 0;
1180           
1181           /* if we support readraw then use that */
1182           if (method<0 && readbraw_supported)
1183             method = 1;
1184           
1185           /* if we can then use readX */
1186           if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
1187             method = 2;
1188           
1189           
1190           switch (method)
1191             {
1192               /* use readX */
1193             case 0:
1194             case 2:
1195               if (method == 0)
1196                 close_done = True;
1197               
1198               /* use readX + close */
1199               memset(outbuf,0,smb_size);
1200               set_message(outbuf,10,0,True);
1201               CVAL(outbuf,smb_com) = SMBreadX;
1202               SSVAL(outbuf,smb_tid,cnum);
1203               cli_setup_pkt(outbuf);
1204               
1205               if (close_done)
1206                 {
1207                   CVAL(outbuf,smb_vwv0) = SMBclose;
1208                   SSVAL(outbuf,smb_vwv1,PTR_DIFF(smb_buf(outbuf),outbuf) - 4);
1209                 }
1210               else
1211                 CVAL(outbuf,smb_vwv0) = 0xFF;         
1212               
1213               
1214               SSVAL(outbuf,smb_vwv2,fnum);
1215               SIVAL(outbuf,smb_vwv3,nread);
1216               SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
1217               SSVAL(outbuf,smb_vwv6,0);
1218               SIVAL(outbuf,smb_vwv7,0);
1219               SSVAL(outbuf,smb_vwv9,MIN(0xFFFF,finfo.size-nread));
1220               
1221               if (close_done)
1222                 {
1223                   p = smb_buf(outbuf);
1224                   memset(p,0,9);
1225                   
1226                   CVAL(p,0) = 3;
1227                   SSVAL(p,1,fnum);
1228                   SIVALS(p,3,-1);
1229                   
1230                   /* now set the total packet length */
1231                   smb_setlen(outbuf,smb_len(outbuf)+9);
1232                 }
1233               
1234               send_smb(Client,outbuf);
1235               client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1236               
1237               if (CVAL(inbuf,smb_rcls) != 0)
1238                 {
1239                   DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1240                   break;
1241                 }
1242               
1243               if (close_done &&
1244                   SVAL(inbuf,smb_vwv0) != SMBclose)
1245                 {
1246                   /* NOTE: WfWg sometimes just ignores the chained
1247                      command! This seems to break the spec? */
1248                   DEBUG(3,("Rejected chained close?\n"));
1249                   close_done = False;
1250                   can_chain_close = False;
1251                   ignore_close_error = True;
1252                 }
1253               
1254               datalen = SVAL(inbuf,smb_vwv5);
1255               dataptr = inbuf + 4 + SVAL(inbuf,smb_vwv6);
1256               break;
1257               
1258               
1259               /* use readbraw */
1260             case 1:
1261               {
1262                 static int readbraw_size = 0xFFFF;
1263                 
1264                 extern int Client;
1265                 memset(outbuf,0,smb_size);
1266                 set_message(outbuf,8,0,True);
1267                 CVAL(outbuf,smb_com) = SMBreadbraw;
1268                 SSVAL(outbuf,smb_tid,cnum);
1269                 cli_setup_pkt(outbuf);
1270                 SSVAL(outbuf,smb_vwv0,fnum);
1271                 SIVAL(outbuf,smb_vwv1,nread);
1272                 SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
1273                 SSVAL(outbuf,smb_vwv4,0);
1274                 SIVALS(outbuf,smb_vwv5,-1);
1275                 send_smb(Client,outbuf);
1276                 
1277                 /* Now read the raw data into the buffer and write it */          
1278                 if(read_smb_length(Client,inbuf,0) == -1) {
1279                   DEBUG(0,("Failed to read length in readbraw\n"));         
1280                   exit(1);
1281                 }
1282                 
1283                 /* Even though this is not an smb message, smb_len
1284                    returns the generic length of an smb message */
1285                 datalen = smb_len(inbuf);
1286                 
1287                 if (datalen == 0)
1288                   {
1289                     /* we got a readbraw error */
1290                     DEBUG(4,("readbraw error - reducing size\n"));
1291                     readbraw_size = (readbraw_size * 9) / 10;
1292                     
1293                     if (readbraw_size < max_xmit)
1294                       {
1295                         DEBUG(0,("disabling readbraw\n"));
1296                         readbraw_supported = False;
1297                       }
1298
1299                     dataptr=NULL;
1300                     continue;
1301                   }
1302
1303                 if(read_data(Client,inbuf,datalen) != datalen) {
1304                   DEBUG(0,("Failed to read data in readbraw\n"));
1305                   exit(1);
1306                 }
1307                 dataptr = inbuf;
1308               }
1309               break;
1310
1311             case 3:
1312               /* we've already read some data with a chained readX */
1313               break;
1314               
1315             default:
1316               /* use plain read */
1317               memset(outbuf,0,smb_size);
1318               set_message(outbuf,5,0,True);
1319               CVAL(outbuf,smb_com) = SMBread;
1320               SSVAL(outbuf,smb_tid,cnum);
1321               cli_setup_pkt(outbuf);
1322               
1323               SSVAL(outbuf,smb_vwv0,fnum);
1324               SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
1325               SIVAL(outbuf,smb_vwv2,nread);
1326               SSVAL(outbuf,smb_vwv4,finfo.size - nread);
1327               
1328               send_smb(Client,outbuf);
1329               client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1330               
1331               if (CVAL(inbuf,smb_rcls) != 0)
1332                 {
1333                   DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1334                   break;
1335                 }
1336               
1337               datalen = SVAL(inbuf,smb_vwv0);
1338               dataptr = smb_buf(inbuf) + 3;
1339               break;
1340             }
1341           
1342           
1343           /* add received bits of file to buffer - dotarbuf will
1344            * write out in 512 byte intervals */
1345           if (dotarbuf(tarhandle,dataptr,datalen) != datalen)
1346             {
1347               DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
1348               break;
1349             }
1350           
1351           nread += datalen;
1352           if (datalen == 0) 
1353             {
1354               DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
1355               break;
1356             }
1357
1358           dataptr=NULL;
1359           datalen=0;
1360         }
1361
1362        /* pad tar file with zero's if we couldn't get entire file */
1363        if (nread < finfo.size)
1364         {
1365           DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
1366           if (padit(inbuf, BUFFER_SIZE, finfo.size - nread))
1367               DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
1368         }
1369
1370       /* round tar file to nearest block */
1371       if (finfo.size % TBLOCK)
1372         dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
1373       
1374       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
1375       ntarf++;
1376     }
1377   
1378   if (!close_done)
1379     {
1380       memset(outbuf,0,smb_size);
1381       set_message(outbuf,3,0,True);
1382       CVAL(outbuf,smb_com) = SMBclose;
1383       SSVAL(outbuf,smb_tid,cnum);
1384       cli_setup_pkt(outbuf);
1385       
1386       SSVAL(outbuf,smb_vwv0,fnum);
1387       SIVALS(outbuf,smb_vwv1,-1);
1388       
1389       send_smb(Client,outbuf);
1390       client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1391       
1392       if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
1393         {
1394           DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
1395           free(inbuf);free(outbuf);
1396           return;
1397         }
1398     }
1399
1400   if (shallitime)
1401     {
1402       struct timeval tp_end;
1403       int this_time;
1404
1405       /* if shallitime is true then we didn't skip */
1406       if (tar_reset) (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
1407       
1408       GetTimeOfDay(&tp_end);
1409       this_time = 
1410         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1411           (tp_end.tv_usec - tp_start.tv_usec)/1000;
1412       get_total_time_ms += this_time;
1413       get_total_size += finfo.size;
1414
1415       if (tar_noisy)
1416         {
1417           DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
1418                finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
1419                finfo.name));
1420         }
1421
1422       /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
1423       DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
1424                finfo.size / MAX(0.001, (1.024*this_time)),
1425                get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
1426     }
1427   
1428   free(inbuf);free(outbuf);
1429 }
1430
1431 /****************************************************************************
1432 Append single file to tar file (or not)
1433 ***************************************************************************/
1434 static void do_tar(file_info *finfo)
1435 {
1436   pstring rname;
1437
1438   if (strequal(finfo->name,".."))
1439     return;
1440
1441   /* Is it on the exclude list ? */
1442   if (!tar_excl && clipn) {
1443     pstring exclaim;
1444
1445     DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir)));
1446
1447     safe_strcpy(exclaim, cur_dir, sizeof(pstring));
1448     *(exclaim+strlen(exclaim)-1)='\0';
1449
1450     safe_strcat(exclaim, "\\", sizeof(pstring));
1451     safe_strcat(exclaim, finfo->name, sizeof(exclaim));
1452
1453     DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
1454
1455     if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
1456 #ifdef HAVE_REGEX_H
1457         (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
1458 #else
1459         (tar_re_search && mask_match(exclaim, cliplist[0], True, False))) {
1460 #endif
1461       DEBUG(3,("Skipping file %s\n", exclaim));
1462       return;
1463     }
1464   }
1465
1466   if (finfo->mode & aDIR)
1467     {
1468       pstring saved_curdir;
1469       pstring mtar_mask;
1470       char *inbuf,*outbuf;
1471
1472       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1473       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1474
1475       if (!inbuf || !outbuf)
1476         {
1477           DEBUG(0,("out of memory\n"));
1478           return;
1479         }
1480
1481       safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
1482
1483       DEBUG(5, ("Sizeof(cur_dir)=%i, strlen(cur_dir)=%i, strlen(finfo->name)=%i\nname=%s,cur_dir=%s\n", sizeof(cur_dir), strlen(cur_dir), strlen(finfo->name), finfo->name, cur_dir));
1484
1485       safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
1486       safe_strcat(cur_dir,"\\", sizeof(cur_dir));
1487
1488       DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
1489
1490       /* write a tar directory, don't bother with mode - just set it to
1491        * 40755 */
1492       writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
1493       if (tar_noisy) {
1494
1495           DEBUG(0, ("                directory %s\n", cur_dir));
1496
1497       }
1498       ntarf++;  /* Make sure we have a file on there */
1499       safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
1500       safe_strcat(mtar_mask,"*", sizeof(pstring));
1501       /*      do_dir((char *)inbuf,(char *)outbuf,mtar_mask,attribute,do_tar,recurse,True); */
1502       safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
1503       free(inbuf);free(outbuf);
1504     }
1505   else
1506     {
1507       safe_strcpy(rname,cur_dir, sizeof(pstring));
1508       safe_strcat(rname,finfo->name, sizeof(pstring));
1509       do_atar(rname,finfo->name,finfo);
1510     }
1511 }
1512
1513 /****************************************************************************
1514 Convert from UNIX to DOS file names
1515 ***************************************************************************/
1516 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
1517 {
1518   /* remove '.' from start of file name, convert from unix /'s to
1519    * dos \'s in path. Kill any absolute path names. But only if first!
1520    */
1521
1522   DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
1523
1524   if (first) {
1525     if (*fp == '.') {
1526       fp++;
1527       l--;
1528     }
1529     if (*fp == '\\' || *fp == '/') {
1530       fp++;
1531       l--;
1532     }
1533   }
1534
1535   while (l > 0) {
1536     int skip;
1537     if(( skip = skip_multibyte_char( *fp )) != 0) {
1538       if (skip == 2) {
1539         *tptr++ = *fp++;
1540         *tptr++ = *fp++;
1541         l -= 2;
1542       } else if (skip == 1) {
1543         *tptr++ = *fp++;
1544         l--;
1545       }
1546     } else if (*fp == '/') {
1547       *tptr++ = '\\';
1548       fp++;
1549       l--;
1550     } else {
1551       *tptr++ = *fp++;
1552       l--;
1553     }
1554   }
1555 }
1556
1557 #ifndef OLD_DOTARPUT 
1558
1559 /****************************************************************************
1560 Move to the next block in the buffer, which may mean read in another set of
1561 blocks. FIXME, we should allow more than one block to be skipped.
1562 ****************************************************************************/
1563 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
1564 {
1565   int bufread, total = 0;
1566
1567   DEBUG(5, ("Advancing to next block: %0X\n", *bufferp));
1568   *bufferp += TBLOCK;
1569   total = TBLOCK;
1570
1571   if (*bufferp >= (ltarbuf + bufsiz)) {
1572
1573     DEBUG(5, ("Reading more data into ltarbuf ...\n"));
1574
1575     total = 0;
1576
1577     for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
1578
1579       if (bufread <= 0) { /* An error, return false */
1580         return (total > 0 ? -2 : bufread);
1581       }
1582
1583     }
1584
1585     DEBUG(5, ("Total bytes read ... %i\n", total));
1586
1587     *bufferp = ltarbuf;
1588
1589   }
1590
1591   return(total);
1592
1593 }
1594
1595 /* Skip a file, even if it includes a long file name? */
1596 static int skip_file(int skipsize)
1597 {
1598   int dsize = skipsize;
1599
1600   DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
1601
1602   /* FIXME, we should skip more than one block at a time */
1603
1604   while (dsize > 0) {
1605
1606     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1607
1608         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1609         return(False);
1610
1611     }
1612
1613     dsize -= TBLOCK;
1614
1615   }
1616
1617   return(True);
1618 }
1619
1620 /* We get a file from the tar file and store it */
1621 static int get_file(file_info2 finfo, char * inbuf, char * outbuf)
1622 {
1623   int fsize = finfo.size;
1624   int fnum, pos = 0, dsize = 0, wsize = 0, rsize = 0;
1625
1626   DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
1627
1628   if (ensurepath(finfo.name, inbuf, outbuf) &&
1629       !smbcreat(finfo, &fnum, inbuf, outbuf))
1630     {
1631       DEBUG(0, ("abandoning restore\n"));
1632       return(False);
1633     }
1634
1635   DEBUG(0, ("restore tar file %s of size %d bytes\n",
1636             finfo.name, finfo.size));
1637
1638   /* read the blocks from the tar file and write to the remote file */
1639
1640   rsize = fsize;
1641
1642   while (rsize > 0) {
1643
1644     dsize = MIN(tbufsiz - (buffer_p - tarbuf), rsize); /* Calculate the size to write */
1645
1646     DEBUG(5, ("writing %i bytes ...\n", dsize));
1647
1648     if (!smbwrite(fnum, dsize, pos, 0, fsize - pos, buffer_p, inbuf, outbuf)) {
1649
1650       DEBUG(0, ("Error writing remote file\n"));
1651       return 0;
1652
1653     }
1654
1655     rsize -= dsize;
1656
1657     /* Now figure out how much to move in the buffer */
1658
1659     /* FIXME, we should skip more than one block at a time */
1660
1661     while (dsize > 0) {
1662
1663       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1664
1665         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1666         return False;
1667
1668       }
1669
1670       dsize -= TBLOCK;
1671
1672     }
1673
1674   }
1675
1676   /* Now close the file ... */
1677
1678   if (!smbshut(finfo, fnum, inbuf, outbuf)) {
1679
1680     DEBUG(0, ("Error closing remote file\n"));
1681     return(False);
1682
1683   }
1684
1685   /* Now we update the creation date ... */
1686
1687   DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1688
1689   if (!do_setrtime(finfo.name, finfo.mtime, True)) {
1690
1691     DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1692     /*return(False); */ /* Ignore, as Win95 does not allow changes */
1693
1694   }
1695
1696   ntarf++;
1697   return(True);
1698
1699 }
1700
1701 /* Create a directory.  We just ensure that the path exists and return as there
1702    is no file associated with a directory 
1703 */
1704 static int get_dir(file_info2 finfo, char * inbuf, char * outbuf)
1705 {
1706
1707   DEBUG(5, ("Creating directory: %s\n", finfo.name));
1708
1709   if (!ensurepath(finfo.name, inbuf, outbuf)) {
1710
1711     DEBUG(0, ("Problems creating directory\n"));
1712     return(False);
1713
1714   }
1715   return(True);
1716
1717 }
1718 /* Get a file with a long file name ... first file has file name, next file 
1719    has the data. We only want the long file name, as the loop in do_tarput
1720    will deal with the rest.
1721 */
1722 static char * get_longfilename(file_info2 finfo)
1723 {
1724   int namesize = finfo.size + strlen(cur_dir) + 2;
1725   char *longname = malloc(namesize);
1726   char *xxx;
1727   int offset = 0, left = finfo.size;
1728
1729   DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1730   DEBUG(5, ("Len = %i\n", finfo.size));
1731   fflush(stderr);
1732
1733   if (longname == NULL) {
1734
1735     DEBUG(0, ("could not allocate buffer of size %d for longname\n", 
1736               finfo.size + strlen(cur_dir) + 2));
1737     return(NULL);
1738   }
1739
1740   /* First, add cur_dir to the long file name */
1741
1742   if (strlen(cur_dir) > 0) {
1743     strncpy(longname, cur_dir, namesize);
1744     offset = strlen(cur_dir);
1745   }
1746
1747   /* Loop through the blocks picking up the name */
1748
1749   while (left > 0) {
1750
1751     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1752
1753       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1754       return(NULL);
1755
1756     }
1757
1758     unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size),False);
1759     DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1760
1761     offset += TBLOCK;
1762     left -= TBLOCK;
1763
1764   }
1765
1766   return(longname);
1767
1768 }
1769
1770 static void do_tarput(void)
1771 {
1772   file_info2 finfo, *finfo2;
1773   struct timeval tp_start;
1774   char *inbuf, *outbuf, *longfilename = NULL;
1775   int skip = False;
1776
1777   GetTimeOfDay(&tp_start);
1778
1779   DEBUG(5, ("RJS do_tarput called ...\n"));
1780
1781   buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1782
1783 #if 0   /* Fix later ... */
1784   if (push_dir(&dir_stack, &finfo)) {
1785
1786     finfo2 = pop_dir(&dir_stack);
1787     inbuf = top_dir_name(&dir_stack); /* FIXME */
1788     if (sub_dir(inbuf, finfo2 -> name)){
1789
1790       DEBUG(0, (""));
1791
1792     }
1793   }
1794 #endif
1795
1796   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1797   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1798
1799   if (!inbuf || !outbuf) {
1800
1801     DEBUG(0, ("Out of memory during allocate of inbuf and outbuf!\n"));
1802     return;
1803
1804   }
1805
1806   /* Now read through those files ... */
1807
1808   while (True) {
1809
1810     /* Get us to the next block, or the first block first time around */
1811
1812     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1813
1814       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1815
1816       return;
1817
1818     }
1819
1820     DEBUG(5, ("Reading the next header ...\n"));
1821     fflush(stdout);
1822     switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1823
1824     case -2:    /* Hmm, not good, but not fatal */
1825       DEBUG(0, ("Skipping %s...\n", finfo.name));
1826       if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1827           !skip_file(finfo.size)) {
1828
1829         DEBUG(0, ("Short file, bailing out...\n"));
1830         free(inbuf); free(outbuf);
1831         continue;
1832
1833       }
1834
1835       break;
1836
1837     case -1:
1838       DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1839       free(inbuf); free(outbuf);
1840       return;
1841
1842     case 0: /* chksum is zero - looks like an EOF */
1843       DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
1844       free(inbuf); free(outbuf);
1845       return;        /* Hmmm, bad here ... */
1846
1847     default:
1848       break;
1849
1850     }
1851
1852     /* Now, do we have a long file name? */
1853
1854     if (longfilename != NULL) {
1855
1856       free(finfo.name);   /* Free the space already allocated */
1857       finfo.name = longfilename;
1858       longfilename = NULL;
1859
1860     }
1861
1862     /* Well, now we have a header, process the file ...            */
1863
1864     /* Should we skip the file? We have the long name as well here */
1865
1866     skip = clipn &&
1867       ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1868 #ifdef HAVE_REGEX_H
1869       || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1870 #else
1871       || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
1872 #endif
1873
1874   DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, cliplist[0], finfo.name));
1875
1876   if (skip) {
1877
1878     skip_file(finfo.size);
1879     continue;
1880
1881   }
1882
1883     /* We only get this far if we should process the file */
1884
1885     switch (((union hblock *)buffer_p) -> dbuf.linkflag) {
1886
1887     case '0':  /* Should use symbolic names--FIXME */
1888       if (!get_file(finfo, inbuf, outbuf)) {
1889
1890         free(inbuf); free(outbuf);
1891         DEBUG(0, ("Abandoning restore\n"));
1892         return;
1893
1894       }
1895       break;
1896
1897     case '5':
1898       if (!get_dir(finfo, inbuf, outbuf)) {
1899         free(inbuf); free(outbuf);
1900         DEBUG(0, ("Abandoning restore \n"));
1901         return;
1902       }
1903       break;
1904
1905     case 'L':
1906       longfilename = get_longfilename(finfo);
1907       if (!longfilename) {
1908         free(inbuf); free(outbuf);
1909         DEBUG(0, ("abandoning restore\n"));
1910         return;
1911
1912       }
1913       DEBUG(5, ("Long file name: %s\n", longfilename));
1914       break;
1915
1916     default:
1917       skip_file(finfo.size);  /* Don't handle these yet */
1918       break;
1919
1920     }
1921
1922   }
1923
1924
1925 }
1926
1927 #else 
1928
1929 static void do_tarput()
1930 {
1931   file_info2 finfo;
1932   int nread=0, bufread;
1933   char *inbuf,*outbuf, *longname = NULL; 
1934   int fsize=0;
1935   int fnum;
1936   struct timeval tp_start;
1937   BOOL tskip=False;       /* We'll take each file as it comes */
1938
1939   finfo.name = NULL;      /* No name in here ... */
1940
1941   GetTimeOfDay(&tp_start);
1942   
1943   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1944   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1945   
1946   if (!inbuf || !outbuf)
1947     {
1948       DEBUG(0,("out of memory\n"));
1949       return;
1950     }
1951   
1952   /*
1953    * Must read in tbufsiz dollops
1954    */
1955
1956   /* These should be the only reads in clitar.c */
1957   while ((bufread=read(tarhandle, tarbuf, tbufsiz))>0) {
1958     char *endofbuffer;
1959     int chunk;
1960
1961     /* Code to handle a short read.
1962      * We always need a TBLOCK full of stuff
1963      */
1964     if (bufread % TBLOCK) {
1965       int lchunk=TBLOCK-(bufread % TBLOCK);
1966       int lread;
1967
1968       /* It's a shorty - a short read that is */
1969       DEBUG(3, ("Short read, read %d so far (need %d)\n", bufread, lchunk));
1970
1971       while ((lread=read(tarhandle, tarbuf+bufread, lchunk))>0) {
1972         bufread+=lread;
1973         if (!(lchunk-=lread)) break;
1974       }
1975
1976       /* If we've reached EOF then that must be a short file */
1977       if (lread<=0) break;
1978     }
1979
1980     buffer_p=tarbuf; 
1981     endofbuffer=tarbuf+bufread;
1982
1983     if (tskip) {
1984       if (fsize<bufread) {
1985         tskip=False;
1986         buffer_p+=fsize;
1987         fsize=0;
1988       } else {
1989         if (fsize==bufread) tskip=False;
1990         fsize-=bufread;
1991         continue;
1992       }
1993     }
1994
1995     do {
1996       if (!fsize)
1997         {
1998           int next_header = 1;  /* Want at least one header */
1999           while (next_header) 
2000             {  
2001             if (buffer_p >= endofbuffer) {
2002
2003               bufread = read(tarhandle, tarbuf, tbufsiz);
2004               buffer_p = tarbuf;
2005
2006             }
2007             next_header = 0;    /* Don't want the next one ... */
2008
2009             if (finfo.name != NULL) { /* Free the space */
2010
2011               free(finfo.name);
2012               finfo.name = NULL;
2013
2014             }
2015             DEBUG(5, ("Tarbuf=%X, buffer=%X, endofbuf=%X\n", 
2016                       (int)tarbuf, (int)buffer_p, (int)endofbuffer));
2017             switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir))
2018               {
2019               case -2:             /* something dodgy but not fatal about this */
2020                 DEBUG(0, ("skipping %s...\n", finfo.name));
2021                 buffer_p+=TBLOCK;   /* header - like a link */
2022                 continue;
2023               case -1:
2024                 DEBUG(0, ("abandoning restore, -1 from readtarheader\n"));
2025                 free(inbuf); free(outbuf);
2026                 return;
2027               case 0: /* chksum is zero - we assume that one all zero
2028                        *header block will do for eof */
2029                 DEBUG(0,
2030                       ("total of %d tar files restored to share\n", ntarf));
2031                 free(inbuf); free(outbuf);
2032                 return;
2033               default:
2034                 break;
2035               }
2036
2037             /* If we have a longname left from the last time through, 
2038                copy it into finfo.name and free it.
2039
2040                The size of a pstring is the limiting factor on filenames
2041                and directory names now. The total pathname length must be
2042                less than sizeof(pstring) - 1, which is currently 1023. */
2043
2044             if (longname != NULL) {
2045
2046               free(finfo.name);  /* Free the name in the finfo */
2047               finfo.name = string_create_s(strlen(longname) + 2);
2048               strncpy(finfo.name, longname, strlen(longname) + 1);
2049               DEBUG(5, ("Long name = \"%s\", filename=\"%s\"\n", longname, finfo.name));
2050               free(longname);
2051               longname = NULL;
2052
2053             }
2054
2055             /* Check if a long-link. We do this before the clip checking
2056                because clip-checking should clip on real name - RJS */
2057
2058             if (((union hblock *)buffer_p) -> dbuf.linkflag == 'L') {
2059               int file_len, first = 0; char *cp;
2060
2061               /* Skip this header, but pick up length, get the name and 
2062                  fix the name and skip the name. Hmmm, what about end of
2063                  buffer??? */
2064
2065               longname = malloc(finfo.size + strlen(cur_dir) + 1);
2066               if (longname == NULL) {
2067
2068                  DEBUG(0, ("could not allocate buffer of size %d for longname\n",
2069                            finfo.size + strlen(cur_dir) + 1)
2070                       );
2071                  free(inbuf); free(outbuf);
2072                  return;
2073               }
2074
2075
2076               bzero(longname, finfo.size + strlen(cur_dir) +1);
2077
2078               buffer_p += TBLOCK;   /* Skip that longlink header */
2079
2080               /* This needs restructuring ... */
2081
2082               safe_strcpy(longname, cur_dir, strlen(cur_dir) + 1); 
2083               cp = longname + strlen(cur_dir);
2084               file_len = finfo.size;
2085
2086               DEBUG(5, ("longname=%0X, cp=%0X, file_len=%i\n", 
2087                         (int)longname, (int)cp, file_len));
2088
2089               while (file_len > 0) {
2090
2091                 if (buffer_p >= endofbuffer) {
2092
2093                   bufread = read(tarhandle, tarbuf, tbufsiz);
2094
2095                   buffer_p = tarbuf;
2096
2097                 }
2098
2099                 unfixtarname(cp, buffer_p, file_len >= TBLOCK?TBLOCK:file_len, first == 0);
2100
2101                 first++;              /* Not the first anymore */
2102                 cp = cp + strlen(cp); /* Move to end of string */
2103                 buffer_p += TBLOCK;
2104                 file_len -= TBLOCK;
2105                 DEBUG(5, ("cp=%0X, file_len=%i\n", (int)cp, file_len));
2106                 next_header = 1;  /* Force read of next header */
2107
2108               }
2109             }
2110           }
2111           tskip=clipn
2112             && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
2113 #ifdef HAVE_REGEX_H
2114                 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
2115 #else
2116                 || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
2117 #endif
2118           if (tskip) {
2119             buffer_p+=TBLOCK;
2120             if (finfo.mode & aDIR)
2121               continue;
2122             else if ((fsize=finfo.size) % TBLOCK) {
2123               fsize+=TBLOCK-(fsize%TBLOCK);
2124             }
2125             if (fsize<endofbuffer-buffer_p) {
2126               buffer_p+=fsize;
2127               fsize=0;
2128               continue;
2129             } else {
2130               fsize-=endofbuffer-buffer_p;
2131               break;
2132             }
2133           }
2134
2135           DEBUG(5, ("do_tarput: File is: %s\n", finfo.name));
2136
2137           if (finfo.mode & aDIR)
2138             {
2139
2140               DEBUG(5, ("Creating directory: %s\n", finfo.name));
2141               DEBUG(0, ("restore tar dir  %s of size %d bytes\n",
2142                         finfo.name, finfo.size));
2143
2144               if (!ensurepath(finfo.name, inbuf, outbuf))
2145                 {
2146                   DEBUG(0, ("abandoning restore, problems ensuring path\n"));
2147                   free(inbuf); free(outbuf);
2148                   return;
2149               }
2150               else
2151                 {
2152                   /* Now we update the creation date ... */
2153
2154                   DEBUG(5, ("Updating creation date on %s\n", finfo.name));
2155
2156                   if (!do_setrtime(finfo.name, finfo.mtime, True)) {
2157
2158                     if (tar_real_noisy) {
2159                       DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
2160                     }
2161                     /*return;  - Win 95 does not like setting time on dirs */
2162
2163                   }
2164
2165                   ntarf++;
2166                   buffer_p+=TBLOCK;
2167                   continue;
2168                 }
2169             }
2170           
2171           fsize=finfo.size;
2172
2173           if (ensurepath(finfo.name, inbuf, outbuf)
2174               && !smbcreat(finfo, &fnum, inbuf, outbuf))
2175             {
2176               DEBUG(0, ("abandoning restore\n"));
2177               free(inbuf);free(outbuf);
2178               return;
2179             }
2180
2181           DEBUG(0 ,("restore tar file %s of size %d bytes\n",
2182                    finfo.name, finfo.size));
2183
2184           /*          if (!finfo.size) {
2185             if (!smbshut(finfo, fnum, inbuf, outbuf)){
2186               DEBUG(0, ("Error closing remote file of length 0: %s\n", finfo.name));
2187               free(inbuf);free(outbuf);
2188               return;
2189             }
2190             } */
2191
2192           nread=0;
2193           if ((buffer_p+=TBLOCK) >= endofbuffer) break;   
2194         } /* if (!fsize) */
2195         
2196       /* write out the file in chunk sized chunks - don't
2197        * go past end of buffer though */
2198       chunk=(fsize-nread < endofbuffer - buffer_p)
2199         ? fsize - nread : endofbuffer - buffer_p;
2200       
2201       while (chunk > 0) {
2202         int minichunk=MIN(chunk, max_xmit-200);
2203         
2204         if (!smbwrite(fnum, /* file descriptor */
2205                       minichunk, /* n */
2206                       nread, /* offset low */
2207                       0, /* offset high - not implemented */
2208                       fsize-nread, /* left - only hint to server */
2209                       buffer_p,
2210                       inbuf,
2211                       outbuf))
2212           {
2213             DEBUG(0, ("Error writing remote file\n"));
2214             free(inbuf); free(outbuf);
2215             return;
2216           }
2217         DEBUG(5, ("chunk writing fname=%s fnum=%d nread=%d minichunk=%d chunk=%d size=%d\n", finfo.name, fnum, nread, minichunk, chunk, fsize));
2218         
2219         buffer_p+=minichunk; nread+=minichunk;
2220         chunk-=minichunk;
2221       }
2222
2223       if (nread>=fsize)
2224         {
2225           if (!smbshut(finfo, fnum, inbuf, outbuf))
2226             {
2227               DEBUG(0, ("Error closing remote file\n"));
2228               free(inbuf);free(outbuf);
2229               return;
2230             }
2231           if (fsize % TBLOCK) buffer_p+=TBLOCK - (fsize % TBLOCK);
2232           DEBUG(5, ("buffer_p is now %d (psn=%d)\n",
2233                     (int) buffer_p, (int)(buffer_p - tarbuf)));
2234           ntarf++;
2235           fsize=0;
2236
2237         }
2238     } while (buffer_p < endofbuffer);
2239   }
2240
2241   DEBUG(0, ("premature eof on tar file ?\n"));
2242   DEBUG(0,("total of %d tar files restored to share\n", ntarf));
2243
2244   free(inbuf); free(outbuf);
2245 }
2246 #endif
2247
2248 /*
2249  * samba interactive commands
2250  */
2251
2252 /****************************************************************************
2253 Blocksize command
2254 ***************************************************************************/
2255 void cmd_block(char *dum_in, char *dum_out)
2256 {
2257   fstring buf;
2258   int block;
2259
2260   if (!next_token(NULL,buf,NULL,sizeof(buf)))
2261     {
2262       DEBUG(0, ("blocksize <n>\n"));
2263       return;
2264     }
2265
2266   block=atoi(buf);
2267   if (block < 0 || block > 65535)
2268     {
2269       DEBUG(0, ("blocksize out of range"));
2270       return;
2271     }
2272
2273   blocksize=block;
2274   DEBUG(2,("blocksize is now %d\n", blocksize));
2275 }
2276
2277 /****************************************************************************
2278 command to set incremental / reset mode
2279 ***************************************************************************/
2280 void cmd_tarmode(char *dum_in, char *dum_out)
2281 {
2282   fstring buf;
2283
2284   while (next_token(NULL,buf,NULL,sizeof(buf))) {
2285     if (strequal(buf, "full"))
2286       tar_inc=False;
2287     else if (strequal(buf, "inc"))
2288       tar_inc=True;
2289     else if (strequal(buf, "reset"))
2290       tar_reset=True;
2291     else if (strequal(buf, "noreset"))
2292       tar_reset=False;
2293     else if (strequal(buf, "system"))
2294       tar_system=True;
2295     else if (strequal(buf, "nosystem"))
2296       tar_system=False;
2297     else if (strequal(buf, "hidden"))
2298       tar_hidden=True;
2299     else if (strequal(buf, "nohidden"))
2300       tar_hidden=False;
2301     else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
2302       tar_noisy=True;
2303     else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
2304       tar_noisy=False;
2305     else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
2306   }
2307
2308   DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
2309             tar_inc ? "incremental" : "full",
2310             tar_system ? "system" : "nosystem",
2311             tar_hidden ? "hidden" : "nohidden",
2312             tar_reset ? "reset" : "noreset",
2313             tar_noisy ? "verbose" : "quiet"));
2314
2315 }
2316
2317 /****************************************************************************
2318 Feeble attrib command
2319 ***************************************************************************/
2320 void cmd_setmode(char *dum_in, char *dum_out)
2321 {
2322   char *q;
2323   fstring buf;
2324   pstring fname;
2325   int attra[2];
2326   int direct=1;
2327
2328   attra[0] = attra[1] = 0;
2329
2330   if (!next_token(NULL,buf,NULL,sizeof(buf)))
2331     {
2332       DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
2333       return;
2334     }
2335
2336   safe_strcpy(fname, cur_dir, sizeof(pstring));
2337   safe_strcat(fname, buf, sizeof(pstring));
2338
2339   while (next_token(NULL,buf,NULL,sizeof(buf))) {
2340     q=buf;
2341
2342     while(*q)
2343       switch (*q++) {
2344       case '+': direct=1;
2345         break;
2346       case '-': direct=0;
2347         break;
2348       case 'r': attra[direct]|=aRONLY;
2349         break;
2350       case 'h': attra[direct]|=aHIDDEN;
2351         break;
2352       case 's': attra[direct]|=aSYSTEM;
2353         break;
2354       case 'a': attra[direct]|=aARCH;
2355         break;
2356       default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
2357         return;
2358       }
2359   }
2360
2361   if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
2362     {
2363       DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
2364       return;
2365     }
2366
2367   DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
2368   (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
2369   (void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
2370 }
2371
2372 /****************************************************************************
2373 Principal command for creating / extracting
2374 ***************************************************************************/
2375 void cmd_tar(char *inbuf, char *outbuf)
2376 {
2377   fstring buf;
2378   char **argl;
2379   int argcl;
2380
2381   if (!next_token(NULL,buf,NULL,sizeof(buf)))
2382     {
2383       DEBUG(0,("tar <c|x>[IXbga] <filename>\n"));
2384       return;
2385     }
2386
2387   argl=toktocliplist(&argcl, NULL);
2388   if (!tar_parseargs(argcl, argl, buf, 0))
2389     return;
2390
2391   process_tar(inbuf, outbuf);
2392
2393   free(argl);
2394 }
2395
2396 /****************************************************************************
2397 Command line (option) version
2398 ***************************************************************************/
2399 int process_tar(char *inbuf, char *outbuf)
2400 {
2401   initarbuf();
2402   switch(tar_type) {
2403   case 'x':
2404
2405 #if 0
2406     do_tarput2();
2407 #else
2408     do_tarput();
2409 #endif
2410     free(tarbuf);
2411     close(tarhandle);
2412     break;
2413   case 'r':
2414   case 'c':
2415     if (clipn && tar_excl) {
2416       int i;
2417       pstring tarmac;
2418
2419       for (i=0; i<clipn; i++) {
2420         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
2421
2422         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
2423           *(cliplist[i]+strlen(cliplist[i])-1)='\0';
2424         }
2425         
2426         if (strrchr(cliplist[i], '\\')) {
2427           pstring saved_dir;
2428           
2429           safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
2430           
2431           if (*cliplist[i]=='\\') {
2432             safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
2433           } else {
2434             safe_strcpy(tarmac, cur_dir, sizeof(pstring));
2435             safe_strcat(tarmac, cliplist[i], sizeof(pstring));
2436           }
2437           safe_strcpy(cur_dir, tarmac, sizeof(pstring));
2438           *(strrchr(cur_dir, '\\')+1)='\0';
2439
2440           do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
2441           safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
2442         } else {
2443           safe_strcpy(tarmac, cur_dir, sizeof(pstring));
2444           safe_strcat(tarmac, cliplist[i], sizeof(pstring));
2445           do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
2446         }
2447       }
2448     } else {
2449       pstring mask;
2450       safe_strcpy(mask,cur_dir, sizeof(pstring));
2451       safe_strcat(mask,"\\*", sizeof(pstring));
2452       do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse, True);
2453     }
2454     
2455     if (ntarf) dotareof(tarhandle);
2456     close(tarhandle);
2457     free(tarbuf);
2458     
2459     DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
2460     DEBUG(0, ("Total bytes written: %d\n", ttarf));
2461     break;
2462   }
2463
2464   if (must_free_cliplist) {
2465     int i;
2466     for (i = 0; i < clipn; ++i) {
2467       free(cliplist[i]);
2468     }
2469     free(cliplist);
2470     cliplist = NULL;
2471     clipn = 0;
2472     must_free_cliplist = False;
2473   }
2474
2475   return(0);
2476 }
2477
2478 /****************************************************************************
2479 Find a token (filename) in a clip list
2480 ***************************************************************************/
2481 static int clipfind(char **aret, int ret, char *tok)
2482 {
2483   if (aret==NULL) return 0;
2484
2485   /* ignore leading slashes or dots in token */
2486   while(strchr("/\\.", *tok)) tok++;
2487
2488   while(ret--) {
2489     char *pkey=*aret++;
2490
2491     /* ignore leading slashes or dots in list */
2492     while(strchr("/\\.", *pkey)) pkey++;
2493
2494     if (!strslashcmp(pkey, tok)) return 1;
2495   }
2496
2497   return 0;
2498 }
2499
2500 /****************************************************************************
2501 Read list of files to include from the file and initialize cliplist
2502 accordingly.
2503 ***************************************************************************/
2504 static int read_inclusion_file(char *filename)
2505 {
2506   FILE *inclusion = NULL;
2507   char buf[MAXPATHLEN + 1];
2508   char *inclusion_buffer = NULL;
2509   int inclusion_buffer_size = 0;
2510   int inclusion_buffer_sofar = 0;
2511   char *p;
2512   char *tmpstr;
2513   int i;
2514   int error = 0;
2515
2516   clipn = 0;
2517   buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
2518   if ((inclusion = fopen(filename, "r")) == NULL) {
2519     /* XXX It would be better to include a reason for failure, but without
2520      * autoconf, it's hard to use strerror, sys_errlist, etc.
2521      */
2522     DEBUG(0,("Unable to open inclusion file %s\n", filename));
2523     return 0;
2524   }
2525
2526   while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
2527     if (inclusion_buffer == NULL) {
2528       inclusion_buffer_size = 1024;
2529       if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
2530         DEBUG(0,("failure allocating buffer to read inclusion file\n"));
2531         error = 1;
2532         break;
2533       }
2534     }
2535     
2536     if (buf[strlen(buf)-1] == '\n') {
2537       buf[strlen(buf)-1] = '\0';
2538     }
2539     
2540     if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
2541       inclusion_buffer_size *= 2;
2542       inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
2543       if (! inclusion_buffer) {
2544         DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
2545                  inclusion_buffer_size));
2546         error = 1;
2547         break;
2548       }
2549     }
2550     
2551     safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
2552     inclusion_buffer_sofar += strlen(buf) + 1;
2553     clipn++;
2554   }
2555   fclose(inclusion);
2556
2557   if (! error) {
2558     /* Allocate an array of clipn + 1 char*'s for cliplist */
2559     cliplist = malloc((clipn + 1) * sizeof(char *));
2560     if (cliplist == NULL) {
2561       DEBUG(0,("failure allocating memory for cliplist\n"));
2562       error = 1;
2563     } else {
2564       cliplist[clipn] = NULL;
2565       p = inclusion_buffer;
2566       for (i = 0; (! error) && (i < clipn); i++) {
2567         /* set current item to NULL so array will be null-terminated even if
2568          * malloc fails below. */
2569         cliplist[i] = NULL;
2570         if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
2571           DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
2572           error = 1;
2573         } else {
2574           unfixtarname(tmpstr, p, strlen(p) + 1, True);
2575           cliplist[i] = tmpstr;
2576           if ((p = strchr(p, '\000')) == NULL) {
2577             DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
2578             abort();
2579           }
2580         }
2581         ++p;
2582       }
2583       must_free_cliplist = True;
2584     }
2585   }
2586
2587   if (inclusion_buffer) {
2588     free(inclusion_buffer);
2589   }
2590   if (error) {
2591     if (cliplist) {
2592       char **pp;
2593       /* We know cliplist is always null-terminated */
2594       for (pp = cliplist; *pp; ++pp) {
2595         free(*pp);
2596       }
2597       free(cliplist);
2598       cliplist = NULL;
2599       must_free_cliplist = False;
2600     }
2601     return 0;
2602   }
2603   
2604   /* cliplist and its elements are freed at the end of process_tar. */
2605   return 1;
2606 }
2607
2608 /****************************************************************************
2609 Parse tar arguments. Sets tar_type, tar_excl, etc.
2610 ***************************************************************************/
2611 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
2612 {
2613   char tar_clipfl='\0';
2614
2615   /* Reset back to defaults - could be from interactive version 
2616    * reset mode and archive mode left as they are though
2617    */
2618   tar_type='\0';
2619   tar_excl=True;
2620
2621   while (*Optarg) 
2622     switch(*Optarg++) {
2623     case 'c':
2624       tar_type='c';
2625       break;
2626     case 'x':
2627       if (tar_type=='c') {
2628         printf("Tar must be followed by only one of c or x.\n");
2629         return 0;
2630       }
2631       tar_type='x';
2632       break;
2633     case 'b':
2634       if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
2635         DEBUG(0,("Option b must be followed by valid blocksize\n"));
2636         return 0;
2637       } else {
2638         Optind++;
2639       }
2640       break;
2641     case 'g':
2642       tar_inc=True;
2643       break;
2644     case 'N':
2645       if (Optind>=argc) {
2646         DEBUG(0,("Option N must be followed by valid file name\n"));
2647         return 0;
2648       } else {
2649         SMB_STRUCT_STAT stbuf;
2650         extern time_t newer_than;
2651         
2652         if (dos_stat(argv[Optind], &stbuf) == 0) {
2653           newer_than = stbuf.st_mtime;
2654           DEBUG(1,("Getting files newer than %s",
2655                    asctime(LocalTime(&newer_than))));
2656           Optind++;
2657         } else {
2658           DEBUG(0,("Error setting newer-than time\n"));
2659           return 0;
2660         }
2661       }
2662       break;
2663     case 'a':
2664       tar_reset=True;
2665       break;
2666     case 'I':
2667       if (tar_clipfl) {
2668         DEBUG(0,("Only one of I,X,F must be specified\n"));
2669         return 0;
2670       }
2671       tar_clipfl='I';
2672       break;
2673     case 'X':
2674       if (tar_clipfl) {
2675         DEBUG(0,("Only one of I,X,F must be specified\n"));
2676         return 0;
2677       }
2678       tar_clipfl='X';
2679       break;
2680     case 'F':
2681       if (tar_clipfl) {
2682         DEBUG(0,("Only one of I,X,F must be specified\n"));
2683         return 0;
2684       }
2685       tar_clipfl='F';
2686       break;
2687     case 'r':
2688       DEBUG(0, ("tar_re_search set\n"));
2689       tar_re_search = True;
2690       break;
2691     default:
2692       DEBUG(0,("Unknown tar option\n"));
2693       return 0;
2694     }
2695
2696   if (!tar_type) {
2697     printf("Option T must be followed by one of c or x.\n");
2698     return 0;
2699   }
2700
2701   /* tar_excl is true if cliplist lists files to be included.
2702    * Both 'I' and 'F' mean include. */
2703   tar_excl=tar_clipfl!='X';
2704
2705   if (tar_clipfl=='F') {
2706     if (argc-Optind-1 != 1) {
2707       DEBUG(0,("Option F must be followed by exactly one filename.\n"));
2708       return 0;
2709     }
2710     if (! read_inclusion_file(argv[Optind+1])) {
2711       return 0;
2712     }
2713   } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
2714     char *tmpstr;
2715     char **tmplist;
2716     int clipcount;
2717
2718     cliplist=argv+Optind+1;
2719     clipn=argc-Optind-1;
2720     clipcount = clipn;
2721
2722     if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
2723       DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
2724                clipn)
2725            );
2726       return 0;
2727     }
2728
2729     for (clipcount = 0; clipcount < clipn; clipcount++) {
2730
2731       DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
2732
2733       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
2734         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
2735                  clipcount)
2736              );
2737         return 0;
2738       }
2739       unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
2740       tmplist[clipcount] = tmpstr;
2741       DEBUG(5, ("Processed an item, %s\n", tmpstr));
2742
2743       DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
2744     }
2745     cliplist = tmplist;
2746     must_free_cliplist = True;
2747   }
2748
2749   if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
2750 #ifdef HAVE_REGEX_H
2751     int errcode;
2752
2753     if ((preg = (regex_t *)malloc(65536)) == NULL) {
2754
2755       DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
2756       return;
2757
2758     }
2759
2760     if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
2761       char errstr[1024];
2762       size_t errlen;
2763
2764       errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
2765       
2766       DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
2767       return;
2768
2769     }
2770 #endif
2771
2772     clipn=argc-Optind-1;
2773     cliplist=argv+Optind+1;
2774
2775   }
2776
2777   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
2778     /* Sets tar handle to either 0 or 1, as appropriate */
2779     tarhandle=(tar_type=='c');
2780   } else {
2781     if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
2782         || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
2783       {
2784         DEBUG(0,("Error opening local file %s - %s\n",
2785                  argv[Optind], strerror(errno)));
2786         return(0);
2787       }
2788   }
2789
2790   return 1;
2791 }