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