Makefile.in: Fixed bug with continuation line causing proto to fail.
[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 /* 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=True;
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     DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1727     /*return(False); */ /* Ignore, as Win95 does not allow changes */
1728
1729   }
1730
1731   ntarf++;
1732
1733   DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
1734   
1735   return(True);
1736
1737 }
1738
1739 /* Create a directory.  We just ensure that the path exists and return as there
1740    is no file associated with a directory 
1741 */
1742 static int get_dir(file_info2 finfo, char * inbuf, char * outbuf)
1743 {
1744
1745   DEBUG(5, ("Creating directory: %s\n", finfo.name));
1746
1747   if (!ensurepath(finfo.name, inbuf, outbuf)) {
1748
1749     DEBUG(0, ("Problems creating directory\n"));
1750     return(False);
1751
1752   }
1753   return(True);
1754
1755 }
1756 /* Get a file with a long file name ... first file has file name, next file 
1757    has the data. We only want the long file name, as the loop in do_tarput
1758    will deal with the rest.
1759 */
1760 static char * get_longfilename(file_info2 finfo)
1761 {
1762   int namesize = finfo.size + strlen(cur_dir) + 2;
1763   char *longname = malloc(namesize);
1764   int offset = 0, left = finfo.size;
1765   BOOL first = True;
1766
1767   DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1768   DEBUG(5, ("Len = %i\n", finfo.size));
1769
1770   if (longname == NULL) {
1771
1772     DEBUG(0, ("could not allocate buffer of size %d for longname\n", 
1773               finfo.size + strlen(cur_dir) + 2));
1774     return(NULL);
1775   }
1776
1777   /* First, add cur_dir to the long file name */
1778
1779   if (strlen(cur_dir) > 0) {
1780     strncpy(longname, cur_dir, namesize);
1781     offset = strlen(cur_dir);
1782   }
1783
1784   /* Loop through the blocks picking up the name */
1785
1786   while (left > 0) {
1787
1788     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1789
1790       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1791       return(NULL);
1792
1793     }
1794
1795     unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1796     DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1797
1798     offset += TBLOCK;
1799     left -= TBLOCK;
1800
1801   }
1802
1803   return(longname);
1804
1805 }
1806
1807 static void do_tarput(void)
1808 {
1809   file_info2 finfo;
1810   struct timeval tp_start;
1811   char *inbuf, *outbuf, *longfilename = NULL, linkflag;
1812   int skip = False;
1813
1814   GetTimeOfDay(&tp_start);
1815
1816   DEBUG(5, ("RJS do_tarput called ...\n"));
1817
1818   buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1819
1820 #if 0   /* Fix later ... */
1821   if (push_dir(&dir_stack, &finfo)) {
1822     file_info2 *finfo2;
1823
1824     finfo2 = pop_dir(&dir_stack);
1825     inbuf = top_dir_name(&dir_stack); /* FIXME */
1826     if (sub_dir(inbuf, finfo2 -> name)){
1827
1828       DEBUG(0, (""));
1829
1830     }
1831   }
1832 #endif
1833
1834   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1835   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1836
1837   if (!inbuf || !outbuf) {
1838
1839     DEBUG(0, ("Out of memory during allocate of inbuf and outbuf!\n"));
1840     return;
1841
1842   }
1843
1844   /* Now read through those files ... */
1845
1846   while (True) {
1847
1848     /* Get us to the next block, or the first block first time around */
1849
1850     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1851
1852       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1853
1854       return;
1855
1856     }
1857
1858     DEBUG(5, ("Reading the next header ...\n"));
1859
1860     switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1861
1862     case -2:    /* Hmm, not good, but not fatal */
1863       DEBUG(0, ("Skipping %s...\n", finfo.name));
1864       if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1865           !skip_file(finfo.size)) {
1866
1867         DEBUG(0, ("Short file, bailing out...\n"));
1868         free(inbuf); free(outbuf);
1869         return;
1870
1871       }
1872
1873       break;
1874
1875     case -1:
1876       DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1877       free(inbuf); free(outbuf);
1878       return;
1879
1880     case 0: /* chksum is zero - looks like an EOF */
1881       DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
1882       free(inbuf); free(outbuf);
1883       return;        /* Hmmm, bad here ... */
1884
1885     default: 
1886       /* No action */
1887
1888       break;
1889
1890     }
1891
1892     /* Now, do we have a long file name? */
1893
1894     if (longfilename != NULL) {
1895
1896       free(finfo.name);   /* Free the space already allocated */
1897       finfo.name = longfilename;
1898       longfilename = NULL;
1899
1900     }
1901
1902     /* Well, now we have a header, process the file ...            */
1903
1904     /* Should we skip the file? We have the long name as well here */
1905
1906     skip = clipn &&
1907       ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1908 #ifdef HAVE_REGEX_H
1909       || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1910 #else
1911       || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
1912 #endif
1913
1914   DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1915
1916   if (skip) {
1917
1918     skip_file(finfo.size);
1919     continue;
1920
1921   }
1922
1923     /* We only get this far if we should process the file */
1924   linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1925
1926     switch (linkflag) {
1927
1928     case '0':  /* Should use symbolic names--FIXME */
1929
1930       /* Skip to the next block first, so we can get the file, FIXME, should
1931          be in get_file ... */
1932
1933       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1934         DEBUG(0, ("Short file, bailing out...\n"));
1935         free(inbuf); free(outbuf);
1936         return;
1937       }
1938       if (!get_file(finfo, inbuf, outbuf)) {
1939
1940         free(inbuf); free(outbuf);
1941         DEBUG(0, ("Abandoning restore\n"));
1942         return;
1943
1944       }
1945       break;
1946
1947     case '5':
1948       if (!get_dir(finfo, inbuf, outbuf)) {
1949         free(inbuf); free(outbuf);
1950         DEBUG(0, ("Abandoning restore \n"));
1951         return;
1952       }
1953       break;
1954
1955     case 'L':
1956       longfilename = get_longfilename(finfo);
1957       if (!longfilename) {
1958         free(inbuf); free(outbuf);
1959         DEBUG(0, ("abandoning restore\n"));
1960         return;
1961
1962       }
1963       DEBUG(5, ("Long file name: %s\n", longfilename));
1964       break;
1965
1966     default:
1967       skip_file(finfo.size);  /* Don't handle these yet */
1968       break;
1969
1970     }
1971
1972   }
1973
1974
1975 }
1976
1977 #else 
1978
1979 static void do_tarput()
1980 {
1981   file_info2 finfo;
1982   int nread=0, bufread;
1983   char *inbuf,*outbuf, *longname = NULL; 
1984   int fsize=0;
1985   int fnum;
1986   struct timeval tp_start;
1987   BOOL tskip=False;       /* We'll take each file as it comes */
1988
1989   finfo.name = NULL;      /* No name in here ... */
1990
1991   GetTimeOfDay(&tp_start);
1992   
1993   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1994   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1995   
1996   if (!inbuf || !outbuf)
1997     {
1998       DEBUG(0,("out of memory\n"));
1999       return;
2000     }
2001   
2002   /*
2003    * Must read in tbufsiz dollops
2004    */
2005
2006   /* These should be the only reads in clitar.c */
2007   while ((bufread=read(tarhandle, tarbuf, tbufsiz))>0) {
2008     char *endofbuffer;
2009     int chunk;
2010
2011     /* Code to handle a short read.
2012      * We always need a TBLOCK full of stuff
2013      */
2014     if (bufread % TBLOCK) {
2015       int lchunk=TBLOCK-(bufread % TBLOCK);
2016       int lread;
2017
2018       /* It's a shorty - a short read that is */
2019       DEBUG(3, ("Short read, read %d so far (need %d)\n", bufread, lchunk));
2020
2021       while ((lread=read(tarhandle, tarbuf+bufread, lchunk))>0) {
2022         bufread+=lread;
2023         if (!(lchunk-=lread)) break;
2024       }
2025
2026       /* If we've reached EOF then that must be a short file */
2027       if (lread<=0) break;
2028     }
2029
2030     buffer_p=tarbuf; 
2031     endofbuffer=tarbuf+bufread;
2032
2033     if (tskip) {
2034       if (fsize<bufread) {
2035         tskip=False;
2036         buffer_p+=fsize;
2037         fsize=0;
2038       } else {
2039         if (fsize==bufread) tskip=False;
2040         fsize-=bufread;
2041         continue;
2042       }
2043     }
2044
2045     do {
2046       if (!fsize)
2047         {
2048           int next_header = 1;  /* Want at least one header */
2049           while (next_header) 
2050             {  
2051             if (buffer_p >= endofbuffer) {
2052
2053               bufread = read(tarhandle, tarbuf, tbufsiz);
2054               buffer_p = tarbuf;
2055
2056             }
2057             next_header = 0;    /* Don't want the next one ... */
2058
2059             if (finfo.name != NULL) { /* Free the space */
2060
2061               free(finfo.name);
2062               finfo.name = NULL;
2063
2064             }
2065             DEBUG(5, ("Tarbuf=%X, buffer=%X, endofbuf=%X\n", 
2066                       (int)tarbuf, (int)buffer_p, (int)endofbuffer));
2067             switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir))
2068               {
2069               case -2:             /* something dodgy but not fatal about this */
2070                 DEBUG(0, ("skipping %s...\n", finfo.name));
2071                 buffer_p+=TBLOCK;   /* header - like a link */
2072                 continue;
2073               case -1:
2074                 DEBUG(0, ("abandoning restore, -1 from readtarheader\n"));
2075                 free(inbuf); free(outbuf);
2076                 return;
2077               case 0: /* chksum is zero - we assume that one all zero
2078                        *header block will do for eof */
2079                 DEBUG(0,
2080                       ("total of %d tar files restored to share\n", ntarf));
2081                 free(inbuf); free(outbuf);
2082                 return;
2083               default:
2084                 break;
2085               }
2086
2087             /* If we have a longname left from the last time through, 
2088                copy it into finfo.name and free it.
2089
2090                The size of a pstring is the limiting factor on filenames
2091                and directory names now. The total pathname length must be
2092                less than sizeof(pstring) - 1, which is currently 1023. */
2093
2094             if (longname != NULL) {
2095
2096               free(finfo.name);  /* Free the name in the finfo */
2097               finfo.name = string_create_s(strlen(longname) + 2);
2098               strncpy(finfo.name, longname, strlen(longname) + 1);
2099               DEBUG(5, ("Long name = \"%s\", filename=\"%s\"\n", longname, finfo.name));
2100               free(longname);
2101               longname = NULL;
2102
2103             }
2104
2105             /* Check if a long-link. We do this before the clip checking
2106                because clip-checking should clip on real name - RJS */
2107
2108             if (((union hblock *)buffer_p) -> dbuf.linkflag == 'L') {
2109               int file_len, first = 0; char *cp;
2110
2111               /* Skip this header, but pick up length, get the name and 
2112                  fix the name and skip the name. Hmmm, what about end of
2113                  buffer??? */
2114
2115               longname = malloc(finfo.size + strlen(cur_dir) + 1);
2116               if (longname == NULL) {
2117
2118                  DEBUG(0, ("could not allocate buffer of size %d for longname\n",
2119                            finfo.size + strlen(cur_dir) + 1)
2120                       );
2121                  free(inbuf); free(outbuf);
2122                  return;
2123               }
2124
2125
2126               bzero(longname, finfo.size + strlen(cur_dir) +1);
2127
2128               buffer_p += TBLOCK;   /* Skip that longlink header */
2129
2130               /* This needs restructuring ... */
2131
2132               safe_strcpy(longname, cur_dir, strlen(cur_dir) + 1); 
2133               cp = longname + strlen(cur_dir);
2134               file_len = finfo.size;
2135
2136               DEBUG(5, ("longname=%0X, cp=%0X, file_len=%i\n", 
2137                         (int)longname, (int)cp, file_len));
2138
2139               while (file_len > 0) {
2140
2141                 if (buffer_p >= endofbuffer) {
2142
2143                   bufread = read(tarhandle, tarbuf, tbufsiz);
2144
2145                   buffer_p = tarbuf;
2146
2147                 }
2148
2149                 unfixtarname(cp, buffer_p, file_len >= TBLOCK?TBLOCK:file_len, first == 0);
2150
2151                 first++;              /* Not the first anymore */
2152                 cp = cp + strlen(cp); /* Move to end of string */
2153                 buffer_p += TBLOCK;
2154                 file_len -= TBLOCK;
2155                 DEBUG(5, ("cp=%0X, file_len=%i\n", (int)cp, file_len));
2156                 next_header = 1;  /* Force read of next header */
2157
2158               }
2159             }
2160           }
2161           tskip=clipn
2162             && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
2163 #ifdef HAVE_REGEX_H
2164                 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
2165 #else
2166                 || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
2167 #endif
2168           if (tskip) {
2169             buffer_p+=TBLOCK;
2170             if (finfo.mode & aDIR)
2171               continue;
2172             else if ((fsize=finfo.size) % TBLOCK) {
2173               fsize+=TBLOCK-(fsize%TBLOCK);
2174             }
2175             if (fsize<endofbuffer-buffer_p) {
2176               buffer_p+=fsize;
2177               fsize=0;
2178               continue;
2179             } else {
2180               fsize-=endofbuffer-buffer_p;
2181               break;
2182             }
2183           }
2184
2185           DEBUG(5, ("do_tarput: File is: %s\n", finfo.name));
2186
2187           if (finfo.mode & aDIR)
2188             {
2189
2190               DEBUG(5, ("Creating directory: %s\n", finfo.name));
2191               DEBUG(0, ("restore tar dir  %s of size %d bytes\n",
2192                         finfo.name, finfo.size));
2193
2194               if (!ensurepath(finfo.name, inbuf, outbuf))
2195                 {
2196                   DEBUG(0, ("abandoning restore, problems ensuring path\n"));
2197                   free(inbuf); free(outbuf);
2198                   return;
2199               }
2200               else
2201                 {
2202                   /* Now we update the creation date ... */
2203
2204                   DEBUG(5, ("Updating creation date on %s\n", finfo.name));
2205
2206                   if (!do_setrtime(finfo.name, finfo.mtime, True)) {
2207
2208                     if (tar_real_noisy) {
2209                       DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
2210                     }
2211                     /*return;  - Win 95 does not like setting time on dirs */
2212
2213                   }
2214
2215                   ntarf++;
2216                   buffer_p+=TBLOCK;
2217                   continue;
2218                 }
2219             }
2220           
2221           fsize=finfo.size;
2222
2223           if (ensurepath(finfo.name, inbuf, outbuf)
2224               && !smbcreat(finfo, &fnum, inbuf, outbuf))
2225             {
2226               DEBUG(0, ("abandoning restore\n"));
2227               free(inbuf);free(outbuf);
2228               return;
2229             }
2230
2231           DEBUG(0 ,("restore tar file %s of size %d bytes\n",
2232                    finfo.name, finfo.size));
2233
2234           /*          if (!finfo.size) {
2235             if (!smbshut(finfo, fnum, inbuf, outbuf)){
2236               DEBUG(0, ("Error closing remote file of length 0: %s\n", finfo.name));
2237               free(inbuf);free(outbuf);
2238               return;
2239             }
2240             } */
2241
2242           nread=0;
2243           if ((buffer_p+=TBLOCK) >= endofbuffer) break;   
2244         } /* if (!fsize) */
2245         
2246       /* write out the file in chunk sized chunks - don't
2247        * go past end of buffer though */
2248       chunk=(fsize-nread < endofbuffer - buffer_p)
2249         ? fsize - nread : endofbuffer - buffer_p;
2250       
2251       while (chunk > 0) {
2252         int minichunk=MIN(chunk, max_xmit-200);
2253         
2254         if (!smbwrite(fnum, /* file descriptor */
2255                       minichunk, /* n */
2256                       nread, /* offset low */
2257                       0, /* offset high - not implemented */
2258                       fsize-nread, /* left - only hint to server */
2259                       buffer_p,
2260                       inbuf,
2261                       outbuf))
2262           {
2263             DEBUG(0, ("Error writing remote file\n"));
2264             free(inbuf); free(outbuf);
2265             return;
2266           }
2267         DEBUG(5, ("chunk writing fname=%s fnum=%d nread=%d minichunk=%d chunk=%d size=%d\n", finfo.name, fnum, nread, minichunk, chunk, fsize));
2268         
2269         buffer_p+=minichunk; nread+=minichunk;
2270         chunk-=minichunk;
2271       }
2272
2273       if (nread>=fsize)
2274         {
2275           if (!smbshut(finfo, fnum, inbuf, outbuf))
2276             {
2277               DEBUG(0, ("Error closing remote file\n"));
2278               free(inbuf);free(outbuf);
2279               return;
2280             }
2281           if (fsize % TBLOCK) buffer_p+=TBLOCK - (fsize % TBLOCK);
2282           DEBUG(5, ("buffer_p is now %d (psn=%d)\n",
2283                     (int) buffer_p, (int)(buffer_p - tarbuf)));
2284           ntarf++;
2285           fsize=0;
2286
2287         }
2288     } while (buffer_p < endofbuffer);
2289   }
2290
2291   DEBUG(0, ("premature eof on tar file ?\n"));
2292   DEBUG(0,("total of %d tar files restored to share\n", ntarf));
2293
2294   free(inbuf); free(outbuf);
2295 }
2296 #endif
2297
2298 /*
2299  * samba interactive commands
2300  */
2301
2302 /****************************************************************************
2303 Blocksize command
2304 ***************************************************************************/
2305 void cmd_block(char *dum_in, char *dum_out)
2306 {
2307   fstring buf;
2308   int block;
2309
2310   if (!next_token(NULL,buf,NULL,sizeof(buf)))
2311     {
2312       DEBUG(0, ("blocksize <n>\n"));
2313       return;
2314     }
2315
2316   block=atoi(buf);
2317   if (block < 0 || block > 65535)
2318     {
2319       DEBUG(0, ("blocksize out of range"));
2320       return;
2321     }
2322
2323   blocksize=block;
2324   DEBUG(2,("blocksize is now %d\n", blocksize));
2325 }
2326
2327 /****************************************************************************
2328 command to set incremental / reset mode
2329 ***************************************************************************/
2330 void cmd_tarmode(char *dum_in, char *dum_out)
2331 {
2332   fstring buf;
2333
2334   while (next_token(NULL,buf,NULL,sizeof(buf))) {
2335     if (strequal(buf, "full"))
2336       tar_inc=False;
2337     else if (strequal(buf, "inc"))
2338       tar_inc=True;
2339     else if (strequal(buf, "reset"))
2340       tar_reset=True;
2341     else if (strequal(buf, "noreset"))
2342       tar_reset=False;
2343     else if (strequal(buf, "system"))
2344       tar_system=True;
2345     else if (strequal(buf, "nosystem"))
2346       tar_system=False;
2347     else if (strequal(buf, "hidden"))
2348       tar_hidden=True;
2349     else if (strequal(buf, "nohidden"))
2350       tar_hidden=False;
2351     else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
2352       tar_noisy=True;
2353     else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
2354       tar_noisy=False;
2355     else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
2356   }
2357
2358   DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
2359             tar_inc ? "incremental" : "full",
2360             tar_system ? "system" : "nosystem",
2361             tar_hidden ? "hidden" : "nohidden",
2362             tar_reset ? "reset" : "noreset",
2363             tar_noisy ? "verbose" : "quiet"));
2364
2365 }
2366
2367 /****************************************************************************
2368 Feeble attrib command
2369 ***************************************************************************/
2370 void cmd_setmode(char *dum_in, char *dum_out)
2371 {
2372   char *q;
2373   fstring buf;
2374   pstring fname;
2375   int attra[2];
2376   int direct=1;
2377
2378   attra[0] = attra[1] = 0;
2379
2380   if (!next_token(NULL,buf,NULL,sizeof(buf)))
2381     {
2382       DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
2383       return;
2384     }
2385
2386   safe_strcpy(fname, cur_dir, sizeof(pstring));
2387   safe_strcat(fname, buf, sizeof(pstring));
2388
2389   while (next_token(NULL,buf,NULL,sizeof(buf))) {
2390     q=buf;
2391
2392     while(*q)
2393       switch (*q++) {
2394       case '+': direct=1;
2395         break;
2396       case '-': direct=0;
2397         break;
2398       case 'r': attra[direct]|=aRONLY;
2399         break;
2400       case 'h': attra[direct]|=aHIDDEN;
2401         break;
2402       case 's': attra[direct]|=aSYSTEM;
2403         break;
2404       case 'a': attra[direct]|=aARCH;
2405         break;
2406       default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
2407         return;
2408       }
2409   }
2410
2411   if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
2412     {
2413       DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
2414       return;
2415     }
2416
2417   DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
2418   (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
2419   (void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
2420 }
2421
2422 /****************************************************************************
2423 Principal command for creating / extracting
2424 ***************************************************************************/
2425 void cmd_tar(char *inbuf, char *outbuf)
2426 {
2427   fstring buf;
2428   char **argl;
2429   int argcl;
2430
2431   if (!next_token(NULL,buf,NULL,sizeof(buf)))
2432     {
2433       DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
2434       return;
2435     }
2436
2437   argl=toktocliplist(&argcl, NULL);
2438   if (!tar_parseargs(argcl, argl, buf, 0))
2439     return;
2440
2441   process_tar(inbuf, outbuf);
2442
2443   free(argl);
2444 }
2445
2446 /****************************************************************************
2447 Command line (option) version
2448 ***************************************************************************/
2449 int process_tar(char *inbuf, char *outbuf)
2450 {
2451   initarbuf();
2452   switch(tar_type) {
2453   case 'x':
2454
2455 #if 0
2456     do_tarput2();
2457 #else
2458     do_tarput();
2459 #endif
2460     free(tarbuf);
2461     close(tarhandle);
2462     break;
2463   case 'r':
2464   case 'c':
2465     if (clipn && tar_excl) {
2466       int i;
2467       pstring tarmac;
2468
2469       for (i=0; i<clipn; i++) {
2470         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
2471
2472         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
2473           *(cliplist[i]+strlen(cliplist[i])-1)='\0';
2474         }
2475         
2476         if (strrchr(cliplist[i], '\\')) {
2477           pstring saved_dir;
2478           
2479           safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
2480           
2481           if (*cliplist[i]=='\\') {
2482             safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
2483           } else {
2484             safe_strcpy(tarmac, cur_dir, sizeof(pstring));
2485             safe_strcat(tarmac, cliplist[i], sizeof(pstring));
2486           }
2487           safe_strcpy(cur_dir, tarmac, sizeof(pstring));
2488           *(strrchr(cur_dir, '\\')+1)='\0';
2489
2490           do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
2491           safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
2492         } else {
2493           safe_strcpy(tarmac, cur_dir, sizeof(pstring));
2494           safe_strcat(tarmac, cliplist[i], sizeof(pstring));
2495           do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
2496         }
2497       }
2498     } else {
2499       pstring mask;
2500       safe_strcpy(mask,cur_dir, sizeof(pstring));
2501       safe_strcat(mask,"\\*", sizeof(pstring));
2502       do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse, True);
2503     }
2504     
2505     if (ntarf) dotareof(tarhandle);
2506     close(tarhandle);
2507     free(tarbuf);
2508     
2509     DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
2510     DEBUG(0, ("Total bytes written: %d\n", ttarf));
2511     break;
2512   }
2513
2514   if (must_free_cliplist) {
2515     int i;
2516     for (i = 0; i < clipn; ++i) {
2517       free(cliplist[i]);
2518     }
2519     free(cliplist);
2520     cliplist = NULL;
2521     clipn = 0;
2522     must_free_cliplist = False;
2523   }
2524
2525   return(0);
2526 }
2527
2528 /****************************************************************************
2529 Find a token (filename) in a clip list
2530 ***************************************************************************/
2531 static int clipfind(char **aret, int ret, char *tok)
2532 {
2533   if (aret==NULL) return 0;
2534
2535   /* ignore leading slashes or dots in token */
2536   while(strchr("/\\.", *tok)) tok++;
2537
2538   while(ret--) {
2539     char *pkey=*aret++;
2540
2541     /* ignore leading slashes or dots in list */
2542     while(strchr("/\\.", *pkey)) pkey++;
2543
2544     if (!strslashcmp(pkey, tok)) return 1;
2545   }
2546
2547   return 0;
2548 }
2549
2550 /****************************************************************************
2551 Read list of files to include from the file and initialize cliplist
2552 accordingly.
2553 ***************************************************************************/
2554 static int read_inclusion_file(char *filename)
2555 {
2556   FILE *inclusion = NULL;
2557   char buf[MAXPATHLEN + 1];
2558   char *inclusion_buffer = NULL;
2559   int inclusion_buffer_size = 0;
2560   int inclusion_buffer_sofar = 0;
2561   char *p;
2562   char *tmpstr;
2563   int i;
2564   int error = 0;
2565
2566   clipn = 0;
2567   buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
2568   if ((inclusion = fopen(filename, "r")) == NULL) {
2569     /* XXX It would be better to include a reason for failure, but without
2570      * autoconf, it's hard to use strerror, sys_errlist, etc.
2571      */
2572     DEBUG(0,("Unable to open inclusion file %s\n", filename));
2573     return 0;
2574   }
2575
2576   while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
2577     if (inclusion_buffer == NULL) {
2578       inclusion_buffer_size = 1024;
2579       if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
2580         DEBUG(0,("failure allocating buffer to read inclusion file\n"));
2581         error = 1;
2582         break;
2583       }
2584     }
2585     
2586     if (buf[strlen(buf)-1] == '\n') {
2587       buf[strlen(buf)-1] = '\0';
2588     }
2589     
2590     if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
2591       inclusion_buffer_size *= 2;
2592       inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
2593       if (! inclusion_buffer) {
2594         DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
2595                  inclusion_buffer_size));
2596         error = 1;
2597         break;
2598       }
2599     }
2600     
2601     safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
2602     inclusion_buffer_sofar += strlen(buf) + 1;
2603     clipn++;
2604   }
2605   fclose(inclusion);
2606
2607   if (! error) {
2608     /* Allocate an array of clipn + 1 char*'s for cliplist */
2609     cliplist = malloc((clipn + 1) * sizeof(char *));
2610     if (cliplist == NULL) {
2611       DEBUG(0,("failure allocating memory for cliplist\n"));
2612       error = 1;
2613     } else {
2614       cliplist[clipn] = NULL;
2615       p = inclusion_buffer;
2616       for (i = 0; (! error) && (i < clipn); i++) {
2617         /* set current item to NULL so array will be null-terminated even if
2618          * malloc fails below. */
2619         cliplist[i] = NULL;
2620         if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
2621           DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
2622           error = 1;
2623         } else {
2624           unfixtarname(tmpstr, p, strlen(p) + 1, True);
2625           cliplist[i] = tmpstr;
2626           if ((p = strchr(p, '\000')) == NULL) {
2627             DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
2628             abort();
2629           }
2630         }
2631         ++p;
2632       }
2633       must_free_cliplist = True;
2634     }
2635   }
2636
2637   if (inclusion_buffer) {
2638     free(inclusion_buffer);
2639   }
2640   if (error) {
2641     if (cliplist) {
2642       char **pp;
2643       /* We know cliplist is always null-terminated */
2644       for (pp = cliplist; *pp; ++pp) {
2645         free(*pp);
2646       }
2647       free(cliplist);
2648       cliplist = NULL;
2649       must_free_cliplist = False;
2650     }
2651     return 0;
2652   }
2653   
2654   /* cliplist and its elements are freed at the end of process_tar. */
2655   return 1;
2656 }
2657
2658 /****************************************************************************
2659 Parse tar arguments. Sets tar_type, tar_excl, etc.
2660 ***************************************************************************/
2661 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
2662 {
2663   char tar_clipfl='\0';
2664
2665   /* Reset back to defaults - could be from interactive version 
2666    * reset mode and archive mode left as they are though
2667    */
2668   tar_type='\0';
2669   tar_excl=True;
2670   dry_run=False;
2671
2672   while (*Optarg) 
2673     switch(*Optarg++) {
2674     case 'c':
2675       tar_type='c';
2676       break;
2677     case 'x':
2678       if (tar_type=='c') {
2679         printf("Tar must be followed by only one of c or x.\n");
2680         return 0;
2681       }
2682       tar_type='x';
2683       break;
2684     case 'b':
2685       if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
2686         DEBUG(0,("Option b must be followed by valid blocksize\n"));
2687         return 0;
2688       } else {
2689         Optind++;
2690       }
2691       break;
2692     case 'g':
2693       tar_inc=True;
2694       break;
2695     case 'N':
2696       if (Optind>=argc) {
2697         DEBUG(0,("Option N must be followed by valid file name\n"));
2698         return 0;
2699       } else {
2700         SMB_STRUCT_STAT stbuf;
2701         extern time_t newer_than;
2702         
2703         if (dos_stat(argv[Optind], &stbuf) == 0) {
2704           newer_than = stbuf.st_mtime;
2705           DEBUG(1,("Getting files newer than %s",
2706                    asctime(LocalTime(&newer_than))));
2707           Optind++;
2708         } else {
2709           DEBUG(0,("Error setting newer-than time\n"));
2710           return 0;
2711         }
2712       }
2713       break;
2714     case 'a':
2715       tar_reset=True;
2716       break;
2717     case 'I':
2718       if (tar_clipfl) {
2719         DEBUG(0,("Only one of I,X,F must be specified\n"));
2720         return 0;
2721       }
2722       tar_clipfl='I';
2723       break;
2724     case 'X':
2725       if (tar_clipfl) {
2726         DEBUG(0,("Only one of I,X,F must be specified\n"));
2727         return 0;
2728       }
2729       tar_clipfl='X';
2730       break;
2731     case 'F':
2732       if (tar_clipfl) {
2733         DEBUG(0,("Only one of I,X,F must be specified\n"));
2734         return 0;
2735       }
2736       tar_clipfl='F';
2737       break;
2738     case 'r':
2739       DEBUG(0, ("tar_re_search set\n"));
2740       tar_re_search = True;
2741       break;
2742     case 'n':
2743       if (tar_type == 'c') {
2744         DEBUG(0, ("dry_run set\n"));
2745         dry_run = True;
2746       } else {
2747         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
2748         return 0;
2749       }
2750       break;
2751     default:
2752       DEBUG(0,("Unknown tar option\n"));
2753       return 0;
2754     }
2755
2756   if (!tar_type) {
2757     printf("Option T must be followed by one of c or x.\n");
2758     return 0;
2759   }
2760
2761   /* tar_excl is true if cliplist lists files to be included.
2762    * Both 'I' and 'F' mean include. */
2763   tar_excl=tar_clipfl!='X';
2764
2765   if (tar_clipfl=='F') {
2766     if (argc-Optind-1 != 1) {
2767       DEBUG(0,("Option F must be followed by exactly one filename.\n"));
2768       return 0;
2769     }
2770     if (! read_inclusion_file(argv[Optind+1])) {
2771       return 0;
2772     }
2773   } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
2774     char *tmpstr;
2775     char **tmplist;
2776     int clipcount;
2777
2778     cliplist=argv+Optind+1;
2779     clipn=argc-Optind-1;
2780     clipcount = clipn;
2781
2782     if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
2783       DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
2784                clipn)
2785            );
2786       return 0;
2787     }
2788
2789     for (clipcount = 0; clipcount < clipn; clipcount++) {
2790
2791       DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
2792
2793       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
2794         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
2795                  clipcount)
2796              );
2797         return 0;
2798       }
2799       unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
2800       tmplist[clipcount] = tmpstr;
2801       DEBUG(5, ("Processed an item, %s\n", tmpstr));
2802
2803       DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
2804     }
2805     cliplist = tmplist;
2806     must_free_cliplist = True;
2807   }
2808
2809   if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
2810 #ifdef HAVE_REGEX_H
2811     int errcode;
2812
2813     if ((preg = (regex_t *)malloc(65536)) == NULL) {
2814
2815       DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
2816       return;
2817
2818     }
2819
2820     if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
2821       char errstr[1024];
2822       size_t errlen;
2823
2824       errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
2825       
2826       DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
2827       return;
2828
2829     }
2830 #endif
2831
2832     clipn=argc-Optind-1;
2833     cliplist=argv+Optind+1;
2834
2835   }
2836
2837   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
2838     /* Sets tar handle to either 0 or 1, as appropriate */
2839     tarhandle=(tar_type=='c');
2840   } else {
2841     if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
2842       {
2843         if (!dry_run) {
2844           DEBUG(0,("Output is /dev/null, assuming dry_run"));
2845           dry_run = True;
2846         }
2847         tarhandle=-1;
2848       } else
2849     if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
2850         || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
2851       {
2852         DEBUG(0,("Error opening local file %s - %s\n",
2853                  argv[Optind], strerror(errno)));
2854         return(0);
2855       }
2856   }
2857
2858   return 1;
2859 }