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