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