32731200b0d2a6f2e64e9ff14e04c4eb5dcefe92
[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    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 /* The following changes developed by Richard Sharpe for Canon Information
22    Systems Research Australia (CISRA) are Copyright (C) 1998 by CISRA and are 
23    made available under the terms of the GPL as listed above:
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
31 */
32
33
34 #include "includes.h"
35 #include "clitar.h"
36 #include <regex.h>
37
38 extern BOOL recurse;
39
40 #define SEPARATORS " \t\n\r"
41 extern int DEBUGLEVEL;
42 extern int Client;
43
44 /* These defines are for the do_setrattr routine, to indicate
45  * setting and reseting of file attributes in the function call */
46 #define ATTRSET 1
47 #define ATTRRESET 0
48
49 static int attribute = aDIR | aSYSTEM | aHIDDEN;
50
51 #ifndef CLIENT_TIMEOUT
52 #define CLIENT_TIMEOUT (30*1000)
53 #endif
54
55 static char *tarbuf;
56 static int tp, ntarf, tbufsiz, ttarf;
57 /* Incremental mode */
58 BOOL tar_inc=False;
59 /* Reset archive bit */
60 BOOL tar_reset=False;
61 /* Include / exclude mode (true=include, false=exclude) */
62 BOOL tar_excl=True;
63 /* Dump files with System attribute */
64 BOOL tar_system=False;
65 /* Dump files with Hidden attribute */
66 BOOL tar_hidden=True;
67 /* Be noisy - make a catalogue */
68 BOOL tar_noisy=True;
69
70 char tar_type='\0';
71 static char **cliplist=NULL;
72 static int clipn=0;
73
74 extern file_info def_finfo;
75 extern BOOL lowercase;
76 extern int cnum;
77 extern BOOL readbraw_supported;
78 extern int max_xmit;
79 extern pstring cur_dir;
80 extern int get_total_time_ms;
81 extern int get_total_size;
82 extern int Protocol;
83
84 int blocksize=20;
85 int tarhandle;
86
87 static void writetarheader(int f,  char *aname, int size, time_t mtime,
88                            char *amode, unsigned char ftype);
89
90 /* Forward references. */
91 static void fixtarname(char *tptr, char *fp, int l);
92 static int dotarbuf(int f, char *b, int n);
93 static void oct_it (long value, int ndgs, char *p);
94 static long unoct(char *p, int ndgs);
95 static void unfixtarname(char *tptr, char *fp, int l);
96
97 /*
98  * tar specific utitlities
99  */
100
101 /****************************************************************************
102 Write a tar header to buffer
103 ****************************************************************************/
104 static void writetarheader(int f,  char *aname, int size, time_t mtime,
105                            char *amode, unsigned char ftype)
106 {
107   union hblock hb;
108   int i, chk, l;
109   char *jp;
110
111   DEBUG(5, ("WriteTarHdr, Type = %c, Name = %s\n", ftype, aname));
112
113   memset(hb.dummy, 0, sizeof(hb.dummy));
114   
115   l=strlen(aname);
116   if (l >= NAMSIZ) {
117           /* write a GNU tar style long header */
118           char *b;
119           b = (char *)malloc(l+TBLOCK+100);
120           if (!b) {
121                   DEBUG(0,("out of memory\n"));
122                   exit(1);
123           }
124           writetarheader(f, "/./@LongLink", l+1, 0, "     0 \0", 'L');
125           memset(b, 0, l+TBLOCK+100);
126           fixtarname(b, aname, l+1);
127           i = strlen(b)+1;
128           dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
129           free(b);
130   }
131
132   /* use l + 1 to do the null too */
133   fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
134
135   if (lowercase)
136     strlower(hb.dbuf.name);
137
138   /* write out a "standard" tar format header */
139
140   hb.dbuf.name[NAMSIZ-1]='\0';
141   strcpy(hb.dbuf.mode, amode);
142   oct_it(0L, 8, hb.dbuf.uid);
143   oct_it(0L, 8, hb.dbuf.gid);
144   oct_it((long) size, 13, hb.dbuf.size);
145   oct_it((long) mtime, 13, hb.dbuf.mtime);
146   memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
147   memset(hb.dbuf.linkname, 0, NAMSIZ);
148   hb.dbuf.linkflag=ftype;
149   
150   for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
151
152   oct_it((long) chk, 8, hb.dbuf.chksum);
153   hb.dbuf.chksum[6] = '\0';
154
155   (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
156 }
157
158 /****************************************************************************
159 Read a tar header into a hblock structure, and validate
160 ***************************************************************************/
161 static long readtarheader(union hblock *hb, file_info *finfo, char *prefix)
162 {
163   long chk, fchk;
164   int i;
165   char *jp;
166
167   /*
168    * read in a "standard" tar format header - we're not that interested
169    * in that many fields, though
170    */
171
172   /* check the checksum */
173   for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
174
175   if (chk == 0)
176     return chk;
177
178   /* compensate for blanks in chksum header */
179   for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
180     chk-=(0xFF & *jp++);
181
182   chk += ' ' * sizeof(hb->dbuf.chksum);
183
184   fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
185
186   DEBUG(5, ("checksum totals chk=%d fchk=%d chksum=%s\n",
187             chk, fchk, hb->dbuf.chksum));
188
189   if (fchk != chk)
190     {
191       DEBUG(0, ("checksums don't match %d %d\n", fchk, chk));
192       return -1;
193     }
194
195   strcpy(finfo->name, prefix);
196
197   /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
198   unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
199                strlen(hb->dbuf.name) + 1);
200
201 /* can't handle some links at present */
202   if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
203     if (hb->dbuf.linkflag == 0) {
204       DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
205                 finfo->name));
206     } else { 
207       if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
208          /* Do nothing here at the moment. do_tarput will handle this
209             as long as the longlink gets back to it, as it has to advance 
210             the buffer pointer, etc */
211
212       } else {
213         DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
214         return -2;
215       }
216     }
217   }
218     
219   if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
220     || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
221     {
222       finfo->mode=aDIR;
223     }
224   else
225     finfo->mode=0; /* we don't care about mode at the moment, we'll
226                     * just make it a regular file */
227   /*
228    * Bug fix by richard@sj.co.uk
229    *
230    * REC: restore times correctly (as does tar)
231    * We only get the modification time of the file; set the creation time
232    * from the mod. time, and the access time to current time
233    */
234   finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
235   finfo->atime = time(NULL);
236   finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
237
238   return True;
239 }
240
241 /****************************************************************************
242 Write out the tar buffer to tape or wherever
243 ****************************************************************************/
244 static int dotarbuf(int f, char *b, int n)
245 {
246   int fail=1, writ=n;
247
248   /* This routine and the next one should be the only ones that do write()s */
249   if (tp + n >= tbufsiz)
250     {
251       int diff;
252
253       diff=tbufsiz-tp;
254       memcpy(tarbuf + tp, b, diff);
255       fail=fail && (1+write(f, tarbuf, tbufsiz));
256       n-=diff;
257       b+=diff;
258       tp=0;
259
260       while (n >= tbufsiz)
261         {
262           fail=fail && (1 + write(f, b, tbufsiz));
263           n-=tbufsiz;
264           b+=tbufsiz;
265         }
266     }
267   if (n>0) {
268     memcpy(tarbuf+tp, b, n);
269     tp+=n;
270   }
271
272   return(fail ? writ : 0);
273 }
274
275 /****************************************************************************
276 Write zeros to buffer / tape
277 ****************************************************************************/
278 static void dozerobuf(int f, int n)
279 {
280   /* short routine just to write out n zeros to buffer -
281    * used to round files to nearest block
282    * and to do tar EOFs */
283
284   if (n+tp >= tbufsiz)
285     {
286       memset(tarbuf+tp, 0, tbufsiz-tp);
287
288       write(f, tarbuf, tbufsiz);
289       memset(tarbuf, 0, (tp+=n-tbufsiz));
290     }
291   else
292     {
293       memset(tarbuf+tp, 0, n);
294       tp+=n;
295     }
296 }
297
298 /****************************************************************************
299 Malloc tape buffer
300 ****************************************************************************/
301 static void initarbuf(void)
302 {
303   /* initialize tar buffer */
304   tbufsiz=blocksize*TBLOCK;
305   tarbuf=malloc(tbufsiz);      /* FIXME: We might not get the buffer */
306
307   /* reset tar buffer pointer and tar file counter and total dumped */
308   tp=0; ntarf=0; ttarf=0;
309 }
310
311 /****************************************************************************
312 Write two zero blocks at end of file
313 ****************************************************************************/
314 static void dotareof(int f)
315 {
316   struct stat stbuf;
317   /* Two zero blocks at end of file, write out full buffer */
318
319   (void) dozerobuf(f, TBLOCK);
320   (void) dozerobuf(f, TBLOCK);
321
322   if (fstat(f, &stbuf) == -1)
323     {
324       DEBUG(0, ("Couldn't stat file handle\n"));
325       return;
326     }
327
328   /* Could be a pipe, in which case S_ISREG should fail,
329    * and we should write out at full size */
330   if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
331 }
332
333 /****************************************************************************
334 (Un)mangle DOS pathname, make nonabsolute
335 ****************************************************************************/
336 static void fixtarname(char *tptr, char *fp, int l)
337 {
338   /* add a '.' to start of file name, convert from ugly dos \'s in path
339    * to lovely unix /'s :-} */
340
341   *tptr++='.';
342
343   while (l > 0) {
344     int skip;
345     if((skip = skip_multibyte_char( *fp)) != 0) {
346       if (skip == 2) {
347         *tptr++ = *fp++;
348         *tptr++ = *fp++;
349         l -= 2;
350       } else if (skip == 1) {
351         *tptr++ = *fp++;
352         l--;
353       }
354     } else if (*fp == '\\') {
355       *tptr++ = '/';
356       fp++;
357       l--;
358     } else {
359       *tptr++ = *fp++;
360       l--;
361     }
362   }
363 }
364
365 /****************************************************************************
366 Convert from decimal to octal string
367 ****************************************************************************/
368 static void oct_it (long value, int ndgs, char *p)
369 {
370   /* Converts long to octal string, pads with leading zeros */
371
372   /* skip final null, but do final space */
373   --ndgs;
374   p[--ndgs] = ' ';
375  
376   /* Loop does at least one digit */
377   do {
378       p[--ndgs] = '0' + (char) (value & 7);
379       value >>= 3;
380     }
381   while (ndgs > 0 && value != 0);
382  
383   /* Do leading zeros */
384   while (ndgs > 0)
385     p[--ndgs] = '0';
386 }
387
388 /****************************************************************************
389 Convert from octal string to long
390 ***************************************************************************/
391 static long unoct(char *p, int ndgs)
392 {
393   long value=0;
394   /* Converts octal string to long, ignoring any non-digit */
395
396   while (--ndgs)
397     {
398       if (isdigit(*p))
399         value = (value << 3) | (long) (*p - '0');
400
401       p++;
402     }
403
404   return value;
405 }
406
407 /****************************************************************************
408 Compare two strings in a slash insensitive way, allowing s1 to match s2 
409 if s1 is an "initial" string (up to directory marker).  Thus, if s2 is 
410 a file in any subdirectory of s1, declare a match.
411 ***************************************************************************/
412 static int strslashcmp(char *s1, char *s2)
413 {
414   char *s1_0=s1;
415
416   while(*s1 && *s2 &&
417         (*s1 == *s2
418          || tolower(*s1) == tolower(*s2)
419          || (*s1 == '\\' && *s2=='/')
420          || (*s1 == '/' && *s2=='\\'))) {
421           s1++; s2++;
422   }
423
424   /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" 
425      string of s2.
426    */
427   if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
428
429   /* ignore trailing slash on s1 */
430   if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
431
432   /* check for s1 is an "initial" string of s2 */
433   if (*s2 == '/' || *s2 == '\\') return 0;
434
435   return *s1-*s2;
436 }
437
438 /*
439  * general smb utility functions
440  */
441 /**********************************************************************
442 do_setrtime, set time on a file or dir ...
443 **********************************************************************/
444
445 static int do_setrtime(char *fname, int mtime)
446 {
447   char *inbuf, *outbuf, *p;
448   char *name;
449
450   name = (char *)malloc(strlen(fname) + 1 + 1);
451   if (name == NULL) {
452
453      DEBUG(0, ("Failed to allocate space while setting time on file: %s", fname));
454      return False;
455
456   }
457
458   strcpy(name, fname);
459   strcpy(fname, "\\");
460   strcat(fname, name);
461
462   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
463   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
464
465   if (!inbuf || !outbuf) {
466
467     DEBUG(0, ("Could not allocate memory for inbuf or outbuf while changing time on: %s\n", fname));
468     return False;
469
470   }
471
472   memset(outbuf, 0, smb_size);
473   set_message(outbuf, 8, 4 + strlen(fname), True);
474   CVAL(outbuf, smb_com) = SMBsetatr;
475   SSVAL(outbuf, smb_tid, cnum);
476   cli_setup_pkt(outbuf);
477
478   SSVAL(outbuf, smb_vwv0, 0);
479   put_dos_date3(outbuf, smb_vwv1, mtime);
480
481   p = smb_buf(outbuf);
482   *p++ = 4;
483   strcpy(p, fname);
484   p+= (strlen(fname)+1);
485
486   *p++ = 4;
487   *p++ = 0;
488
489   send_smb(Client, outbuf);
490   client_receive_smb(Client, inbuf, CLIENT_TIMEOUT);
491
492   if (CVAL(inbuf,smb_rcls) != 0)
493     {
494       DEBUG(0,("%s setting attributes on file %s\n",
495             smb_errstr(inbuf), fname));
496       free(inbuf);free(outbuf);
497       return(False);
498     }
499
500   free(inbuf);free(outbuf);
501   return(True);
502
503 }
504
505 /****************************************************************************
506 Set DOS file attributes
507 ***************************************************************************/
508 static int do_setrattr(char *fname, int attr, int setit)
509 {
510   /*
511    * First get the existing attribs from existing file
512    */
513   char *inbuf,*outbuf;
514   char *p;
515   pstring name;
516   int fattr;
517
518   strcpy(name,fname);
519   strcpy(fname,"\\");
520   strcat(fname,name);
521
522   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
523   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
524
525   if (!inbuf || !outbuf)
526     {
527       DEBUG(0,("out of memory\n"));
528       return False;
529     }
530
531   /* send an smb getatr message */
532
533   memset(outbuf,0,smb_size);
534   set_message(outbuf,0,2 + strlen(fname),True);
535   CVAL(outbuf,smb_com) = SMBgetatr;
536   SSVAL(outbuf,smb_tid,cnum);
537   cli_setup_pkt(outbuf);
538
539   p = smb_buf(outbuf);
540   *p++ = 4;
541   strcpy(p,fname);
542   p += (strlen(fname)+1);
543   
544   *p++ = 4;
545   *p++ = 0;
546
547   send_smb(Client,outbuf);
548   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
549
550   if (CVAL(inbuf,smb_rcls) != 0)
551     DEBUG(5,("getatr: %s\n",smb_errstr(inbuf)));
552   else
553     {
554       DEBUG(5,("\nattr 0x%X  time %d  size %d\n",
555                (int)CVAL(inbuf,smb_vwv0),
556                SVAL(inbuf,smb_vwv1),
557                SVAL(inbuf,smb_vwv3)));
558     }
559
560   fattr=CVAL(inbuf,smb_vwv0);
561
562   /* combine found attributes with bits to be set or reset */
563
564   attr=setit ? (fattr | attr) : (fattr & ~attr);
565
566   /* now try and set attributes by sending smb reset message */
567
568   /* clear out buffer and start again */
569   memset(outbuf,0,smb_size);
570   set_message(outbuf,8,4 + strlen(fname),True);
571   CVAL(outbuf,smb_com) = SMBsetatr;
572   SSVAL(outbuf,smb_tid,cnum);
573   cli_setup_pkt(outbuf);
574
575   SSVAL(outbuf,smb_vwv0,attr);
576   
577   p = smb_buf(outbuf);
578   *p++ = 4;      
579   strcpy(p,fname);
580   p += (strlen(fname)+1);
581   
582   *p++ = 4;
583   *p++ = 0;
584
585   send_smb(Client,outbuf);
586   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
587   
588   if (CVAL(inbuf,smb_rcls) != 0)
589     {
590       DEBUG(0,("%s setting attributes on file %s\n",
591             smb_errstr(inbuf), fname));
592       free(inbuf);free(outbuf);
593       return(False);
594     }
595
596   free(inbuf);free(outbuf);
597   return(True);
598 }
599
600 /****************************************************************************
601 Create a file on a share
602 ***************************************************************************/
603 static BOOL smbcreat(file_info finfo, int *fnum, char *inbuf, char *outbuf)
604 {
605   char *p;
606   /* *must* be called with buffer ready malloc'ed */
607   /* open remote file */
608
609   memset(outbuf,0,smb_size);
610   set_message(outbuf,3,2 + strlen(finfo.name),True);
611   CVAL(outbuf,smb_com) = SMBcreate;
612   SSVAL(outbuf,smb_tid,cnum);
613   cli_setup_pkt(outbuf);
614   
615   SSVAL(outbuf,smb_vwv0,finfo.mode);
616   put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
617   
618   p = smb_buf(outbuf);
619   *p++ = 4;      
620   strcpy(p,finfo.name);
621   
622   send_smb(Client,outbuf);
623   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
624   
625   if (CVAL(inbuf,smb_rcls) != 0)
626     {
627       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),
628                finfo.name));
629       return 0;
630     }
631   
632   *fnum = SVAL(inbuf,smb_vwv0);
633   return True;
634 }
635
636 /****************************************************************************
637 Write a file to a share
638 ***************************************************************************/
639 static BOOL smbwrite(int fnum, int n, int low, int high, int left,
640                      char *bufferp, char *inbuf, char *outbuf)
641 {
642   /* *must* be called with buffer ready malloc'ed */
643
644   memset(outbuf,0,smb_size);
645   set_message(outbuf,5,n + 3,True);
646   
647   memcpy(smb_buf(outbuf)+3, bufferp, n);
648   
649   set_message(outbuf,5,n + 3, False);
650   CVAL(outbuf,smb_com) = SMBwrite;
651   SSVAL(outbuf,smb_tid,cnum);
652   cli_setup_pkt(outbuf);
653   
654   SSVAL(outbuf,smb_vwv0,fnum);
655   SSVAL(outbuf,smb_vwv1,n);
656   SIVAL(outbuf,smb_vwv2,low);
657   SSVAL(outbuf,smb_vwv4,left);
658   CVAL(smb_buf(outbuf),0) = 1;
659   SSVAL(smb_buf(outbuf),1,n);
660
661   send_smb(Client,outbuf); 
662   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
663   
664   if (CVAL(inbuf,smb_rcls) != 0)
665     {
666       DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
667       return False;
668     }
669   
670   if (n != SVAL(inbuf,smb_vwv0))
671     {
672       DEBUG(0,("Error: only wrote %d bytes out of %d\n",
673                SVAL(inbuf,smb_vwv0), n));
674       return False;
675     }
676
677   return True;
678 }
679
680 /****************************************************************************
681 Close a file on a share
682 ***************************************************************************/
683 static BOOL smbshut(file_info finfo, int fnum, char *inbuf, char *outbuf)
684 {
685   /* *must* be called with buffer ready malloc'ed */
686
687   memset(outbuf,0,smb_size);
688   set_message(outbuf,3,0,True);
689   CVAL(outbuf,smb_com) = SMBclose;
690   SSVAL(outbuf,smb_tid,cnum);
691   cli_setup_pkt(outbuf);
692   
693   SSVAL(outbuf,smb_vwv0,fnum);
694   put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
695   
696   DEBUG(3,("Setting date to %s (0x%X)",
697            asctime(LocalTime(&finfo.mtime)),
698            finfo.mtime));
699   
700   send_smb(Client,outbuf);
701   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
702   
703   if (CVAL(inbuf,smb_rcls) != 0)
704     {
705       DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),
706                finfo.name));
707       return False;
708     }
709
710   return True;
711 }
712
713 /****************************************************************************
714 Verify existence of path on share
715 ***************************************************************************/
716 static BOOL smbchkpath(char *fname, char *inbuf, char *outbuf)
717 {
718   char *p;
719
720   memset(outbuf,0,smb_size);
721   set_message(outbuf,0,4 + strlen(fname),True);
722   CVAL(outbuf,smb_com) = SMBchkpth;
723   SSVAL(outbuf,smb_tid,cnum);
724   cli_setup_pkt(outbuf);
725
726   p = smb_buf(outbuf);
727   *p++ = 4;
728   strcpy(p,fname);
729
730   send_smb(Client,outbuf);
731   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
732
733   DEBUG(5,("smbchkpath: %s\n",smb_errstr(inbuf)));
734
735   return(CVAL(inbuf,smb_rcls) == 0);
736 }
737
738 /****************************************************************************
739 Make a directory on share
740 ***************************************************************************/
741 static BOOL smbmkdir(char *fname, char *inbuf, char *outbuf)
742 {
743   /* *must* be called with buffer ready malloc'ed */
744   char *p;
745
746   memset(outbuf,0,smb_size);
747   set_message(outbuf,0,2 + strlen(fname),True);
748   
749   CVAL(outbuf,smb_com) = SMBmkdir;
750   SSVAL(outbuf,smb_tid,cnum);
751   cli_setup_pkt(outbuf);
752   
753   p = smb_buf(outbuf);
754   *p++ = 4;      
755   strcpy(p,fname);
756   
757   send_smb(Client,outbuf);
758   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
759   
760   if (CVAL(inbuf,smb_rcls) != 0)
761     {
762       DEBUG(0,("%s making remote directory %s\n",
763                smb_errstr(inbuf),fname));
764       return(False);
765     }
766
767   return(True);
768 }
769
770 /****************************************************************************
771 Ensure a remote path exists (make if necessary)
772 ***************************************************************************/
773 static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
774 {
775   /* *must* be called with buffer ready malloc'ed */
776   /* ensures path exists */
777
778   pstring partpath, ffname;
779   char *p=fname, *basehack;
780
781   DEBUG(5, ( "Ensurepath called with: %s\n", fname));
782
783   *partpath = 0;
784
785   /* fname copied to ffname so can strtok */
786
787   strcpy(ffname, fname);
788
789   /* do a `basename' on ffname, so don't try and make file name directory */
790   if ((basehack=strrchr(ffname, '\\')) == NULL)
791     return True;
792   else
793     *basehack='\0';
794
795   p=strtok(ffname, "\\");
796
797   while (p)
798     {
799       strcat(partpath, p);
800
801       if (!smbchkpath(partpath, inbuf, outbuf)) {
802         if (!smbmkdir(partpath, inbuf, outbuf))
803           {
804             DEBUG(0, ("Error mkdirhiering\n"));
805             return False;
806           }
807         else
808           DEBUG(3, ("mkdirhiering %s\n", partpath));
809
810       }
811
812       strcat(partpath, "\\");
813       p = strtok(NULL,"/\\");
814     }
815
816     return True;
817 }
818
819 int padit(char *buf, int bufsize, int padsize)
820 {
821   int berr= 0;
822   int bytestowrite;
823   
824   DEBUG(0, ("Padding with %d zeros\n", padsize));
825   memset(buf, 0, bufsize);
826   while( !berr && padsize > 0 ) {
827     bytestowrite= MIN(bufsize, padsize);
828     berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
829     padsize -= bytestowrite;
830   }
831   
832   return berr;
833 }
834
835 /*
836  * smbclient functions
837  */
838 /****************************************************************************
839 append one remote file to the tar file
840 ***************************************************************************/
841 static void do_atar(char *rname,char *lname,file_info *finfo1)
842 {
843   int fnum;
844   uint32 nread=0;
845   char *p, ftype;
846   char *inbuf,*outbuf;
847   file_info finfo;
848   BOOL close_done = False;
849   BOOL shallitime=True;
850   BOOL ignore_close_error = False;
851   char *dataptr=NULL;
852   int datalen=0;
853
854   struct timeval tp_start;
855   GetTimeOfDay(&tp_start);
856
857   ftype = '0'; /* An ordinary file ... */
858
859   if (finfo1) 
860     finfo = *finfo1;
861   else
862     finfo = def_finfo;
863
864   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
865   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
866
867   if (!inbuf || !outbuf)
868     {
869       DEBUG(0,("out of memory\n"));
870       return;
871     }
872
873   memset(outbuf,0,smb_size);
874   set_message(outbuf,15,1 + strlen(rname),True);
875
876   CVAL(outbuf,smb_com) = SMBopenX;
877   SSVAL(outbuf,smb_tid,cnum);
878   cli_setup_pkt(outbuf);
879
880   SSVAL(outbuf,smb_vwv0,0xFF);
881   SSVAL(outbuf,smb_vwv2,1);
882   SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
883   SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
884   SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
885   SSVAL(outbuf,smb_vwv8,1);
886
887   p = smb_buf(outbuf);
888   strcpy(p,rname);
889   p = skip_string(p,1);
890
891   dos_clean_name(rname);
892
893   /* do a chained openX with a readX? */  
894   if (finfo.size > 0)
895     {
896       SSVAL(outbuf,smb_vwv0,SMBreadX);
897       SSVAL(outbuf,smb_vwv1,PTR_DIFF(p,outbuf) - 4);
898       memset(p,0,200);
899       p -= smb_wct;
900       SSVAL(p,smb_wct,10);
901       SSVAL(p,smb_vwv0,0xFF);
902       SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
903       SSVAL(p,smb_vwv9,MIN(0xFFFF,finfo.size));
904       smb_setlen(outbuf,smb_len(outbuf)+11*2+1);  
905     }
906   
907   send_smb(Client,outbuf);
908   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
909
910   if (CVAL(inbuf,smb_rcls) != 0)
911     {
912       if (CVAL(inbuf,smb_rcls) == ERRSRV &&
913           SVAL(inbuf,smb_err) == ERRnoresource &&
914           cli_reopen_connection(inbuf,outbuf))
915         {
916           do_atar(rname,lname,finfo1);
917           free(inbuf);free(outbuf);
918           return;
919         }
920
921       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),rname));
922       free(inbuf);free(outbuf);
923       return;
924     }
925
926   strcpy(finfo.name,rname);
927   if (!finfo1)
928     {
929       finfo.mode = SVAL(inbuf,smb_vwv3);
930       finfo.size = IVAL(inbuf,smb_vwv4);
931       finfo.mtime = make_unix_date3(inbuf+smb_vwv6);
932       finfo.atime = finfo.ctime = finfo.mtime;
933     }
934
935   DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
936
937   fnum = SVAL(inbuf,smb_vwv2);
938
939   if (tar_inc && !(finfo.mode & aARCH))
940     {
941       DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
942       shallitime=0;
943     }
944   else if (!tar_system && (finfo.mode & aSYSTEM))
945     {
946       DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
947       shallitime=0;
948     }
949   else if (!tar_hidden && (finfo.mode & aHIDDEN))
950     {
951       DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
952       shallitime=0;
953     }
954   else
955     {
956       if (SVAL(inbuf,smb_vwv0) == SMBreadX)
957         {
958           p = (inbuf+4+SVAL(inbuf,smb_vwv1)) - smb_wct;
959           datalen = SVAL(p,smb_vwv5);
960           dataptr = inbuf + 4 + SVAL(p,smb_vwv6);
961         }
962       else
963         {
964           dataptr = NULL;
965           datalen = 0;
966         }
967
968       DEBUG(2,("getting file %s of size %d bytes as a tar file %s",
969                finfo.name,
970                finfo.size,
971                lname));
972       
973       /* write a tar header, don't bother with mode - just set to 100644 */
974       writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
975       
976       while (nread < finfo.size && !close_done)
977         {
978           int method = -1;
979           static BOOL can_chain_close=True;
980
981           p=NULL;
982           
983           DEBUG(3,("nread=%d\n",nread));
984           
985           /* 3 possible read types. readbraw if a large block is required.
986              readX + close if not much left and read if neither is supported */
987
988           /* we might have already read some data from a chained readX */
989           if (dataptr && datalen>0)
990             method=3;
991           
992           /* if we can finish now then readX+close */
993           if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) && 
994               ((finfo.size - nread) < 
995                (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
996             method = 0;
997           
998           /* if we support readraw then use that */
999           if (method<0 && readbraw_supported)
1000             method = 1;
1001           
1002           /* if we can then use readX */
1003           if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
1004             method = 2;
1005           
1006           
1007           switch (method)
1008             {
1009               /* use readX */
1010             case 0:
1011             case 2:
1012               if (method == 0)
1013                 close_done = True;
1014               
1015               /* use readX + close */
1016               memset(outbuf,0,smb_size);
1017               set_message(outbuf,10,0,True);
1018               CVAL(outbuf,smb_com) = SMBreadX;
1019               SSVAL(outbuf,smb_tid,cnum);
1020               cli_setup_pkt(outbuf);
1021               
1022               if (close_done)
1023                 {
1024                   CVAL(outbuf,smb_vwv0) = SMBclose;
1025                   SSVAL(outbuf,smb_vwv1,PTR_DIFF(smb_buf(outbuf),outbuf) - 4);
1026                 }
1027               else
1028                 CVAL(outbuf,smb_vwv0) = 0xFF;         
1029               
1030               
1031               SSVAL(outbuf,smb_vwv2,fnum);
1032               SIVAL(outbuf,smb_vwv3,nread);
1033               SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
1034               SSVAL(outbuf,smb_vwv6,0);
1035               SIVAL(outbuf,smb_vwv7,0);
1036               SSVAL(outbuf,smb_vwv9,MIN(0xFFFF,finfo.size-nread));
1037               
1038               if (close_done)
1039                 {
1040                   p = smb_buf(outbuf);
1041                   memset(p,0,9);
1042                   
1043                   CVAL(p,0) = 3;
1044                   SSVAL(p,1,fnum);
1045                   SIVALS(p,3,-1);
1046                   
1047                   /* now set the total packet length */
1048                   smb_setlen(outbuf,smb_len(outbuf)+9);
1049                 }
1050               
1051               send_smb(Client,outbuf);
1052               client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1053               
1054               if (CVAL(inbuf,smb_rcls) != 0)
1055                 {
1056                   DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1057                   break;
1058                 }
1059               
1060               if (close_done &&
1061                   SVAL(inbuf,smb_vwv0) != SMBclose)
1062                 {
1063                   /* NOTE: WfWg sometimes just ignores the chained
1064                      command! This seems to break the spec? */
1065                   DEBUG(3,("Rejected chained close?\n"));
1066                   close_done = False;
1067                   can_chain_close = False;
1068                   ignore_close_error = True;
1069                 }
1070               
1071               datalen = SVAL(inbuf,smb_vwv5);
1072               dataptr = inbuf + 4 + SVAL(inbuf,smb_vwv6);
1073               break;
1074               
1075               
1076               /* use readbraw */
1077             case 1:
1078               {
1079                 static int readbraw_size = 0xFFFF;
1080                 
1081                 extern int Client;
1082                 memset(outbuf,0,smb_size);
1083                 set_message(outbuf,8,0,True);
1084                 CVAL(outbuf,smb_com) = SMBreadbraw;
1085                 SSVAL(outbuf,smb_tid,cnum);
1086                 cli_setup_pkt(outbuf);
1087                 SSVAL(outbuf,smb_vwv0,fnum);
1088                 SIVAL(outbuf,smb_vwv1,nread);
1089                 SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
1090                 SSVAL(outbuf,smb_vwv4,0);
1091                 SIVALS(outbuf,smb_vwv5,-1);
1092                 send_smb(Client,outbuf);
1093                 
1094                 /* Now read the raw data into the buffer and write it */          
1095                 if(read_smb_length(Client,inbuf,0) == -1) {
1096                   DEBUG(0,("Failed to read length in readbraw\n"));         
1097                   exit(1);
1098                 }
1099                 
1100                 /* Even though this is not an smb message, smb_len
1101                    returns the generic length of an smb message */
1102                 datalen = smb_len(inbuf);
1103                 
1104                 if (datalen == 0)
1105                   {
1106                     /* we got a readbraw error */
1107                     DEBUG(4,("readbraw error - reducing size\n"));
1108                     readbraw_size = (readbraw_size * 9) / 10;
1109                     
1110                     if (readbraw_size < max_xmit)
1111                       {
1112                         DEBUG(0,("disabling readbraw\n"));
1113                         readbraw_supported = False;
1114                       }
1115
1116                     dataptr=NULL;
1117                     continue;
1118                   }
1119
1120                 if(read_data(Client,inbuf,datalen) != datalen) {
1121                   DEBUG(0,("Failed to read data in readbraw\n"));
1122                   exit(1);
1123                 }
1124                 dataptr = inbuf;
1125               }
1126               break;
1127
1128             case 3:
1129               /* we've already read some data with a chained readX */
1130               break;
1131               
1132             default:
1133               /* use plain read */
1134               memset(outbuf,0,smb_size);
1135               set_message(outbuf,5,0,True);
1136               CVAL(outbuf,smb_com) = SMBread;
1137               SSVAL(outbuf,smb_tid,cnum);
1138               cli_setup_pkt(outbuf);
1139               
1140               SSVAL(outbuf,smb_vwv0,fnum);
1141               SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
1142               SIVAL(outbuf,smb_vwv2,nread);
1143               SSVAL(outbuf,smb_vwv4,finfo.size - nread);
1144               
1145               send_smb(Client,outbuf);
1146               client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1147               
1148               if (CVAL(inbuf,smb_rcls) != 0)
1149                 {
1150                   DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1151                   break;
1152                 }
1153               
1154               datalen = SVAL(inbuf,smb_vwv0);
1155               dataptr = smb_buf(inbuf) + 3;
1156               break;
1157             }
1158           
1159           
1160           /* add received bits of file to buffer - dotarbuf will
1161            * write out in 512 byte intervals */
1162           if (dotarbuf(tarhandle,dataptr,datalen) != datalen)
1163             {
1164               DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
1165               break;
1166             }
1167           
1168           nread += datalen;
1169           if (datalen == 0) 
1170             {
1171               DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
1172               break;
1173             }
1174
1175           dataptr=NULL;
1176           datalen=0;
1177         }
1178
1179        /* pad tar file with zero's if we couldn't get entire file */
1180        if (nread < finfo.size)
1181         {
1182           DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
1183           if (padit(inbuf, BUFFER_SIZE, finfo.size - nread))
1184               DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
1185         }
1186
1187       /* round tar file to nearest block */
1188       if (finfo.size % TBLOCK)
1189         dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
1190       
1191       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
1192       ntarf++;
1193     }
1194   
1195   if (!close_done)
1196     {
1197       memset(outbuf,0,smb_size);
1198       set_message(outbuf,3,0,True);
1199       CVAL(outbuf,smb_com) = SMBclose;
1200       SSVAL(outbuf,smb_tid,cnum);
1201       cli_setup_pkt(outbuf);
1202       
1203       SSVAL(outbuf,smb_vwv0,fnum);
1204       SIVALS(outbuf,smb_vwv1,-1);
1205       
1206       send_smb(Client,outbuf);
1207       client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1208       
1209       if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
1210         {
1211           DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
1212           free(inbuf);free(outbuf);
1213           return;
1214         }
1215     }
1216
1217   if (shallitime)
1218     {
1219       struct timeval tp_end;
1220       int this_time;
1221
1222       /* if shallitime is true then we didn't skip */
1223       if (tar_reset) (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
1224       
1225       GetTimeOfDay(&tp_end);
1226       this_time = 
1227         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1228           (tp_end.tv_usec - tp_start.tv_usec)/1000;
1229       get_total_time_ms += this_time;
1230       get_total_size += finfo.size;
1231
1232       /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
1233       DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
1234                finfo.size / MAX(0.001, (1.024*this_time)),
1235                get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
1236       if (tar_noisy)
1237         {
1238           printf("%10d (%7.1f kb/s) %s\n",
1239                finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
1240                finfo.name);
1241         }
1242
1243     }
1244   
1245   free(inbuf);free(outbuf);
1246 }
1247
1248 /****************************************************************************
1249 Append single file to tar file (or not)
1250 ***************************************************************************/
1251 static void do_tar(file_info *finfo)
1252 {
1253   pstring rname;
1254
1255   if (strequal(finfo->name,".."))
1256     return;
1257
1258   /* Is it on the exclude list ? */
1259   if (!tar_excl && clipn) {
1260     pstring exclaim;
1261
1262     strcpy(exclaim, cur_dir);
1263     *(exclaim+strlen(exclaim)-1)='\0';
1264
1265     strcat(exclaim, "\\");
1266     strcat(exclaim, finfo->name);
1267
1268     if (clipfind(cliplist, clipn, exclaim)) {
1269       DEBUG(3,("Skipping file %s\n", exclaim));
1270       return;
1271     }
1272   }
1273
1274   if (finfo->mode & aDIR)
1275     {
1276       pstring saved_curdir;
1277       pstring mtar_mask;
1278       char *inbuf,*outbuf;
1279
1280       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1281       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1282
1283       if (!inbuf || !outbuf)
1284         {
1285           DEBUG(0,("out of memory\n"));
1286           return;
1287         }
1288
1289       strcpy(saved_curdir,cur_dir);
1290
1291       strcat(cur_dir,finfo->name);
1292       strcat(cur_dir,"\\");
1293
1294       DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
1295
1296       /* write a tar directory, don't bother with mode - just set it to
1297        * 40755 */
1298       writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
1299       ntarf++;  /* Make sure we have a file on there */
1300       strcpy(mtar_mask,cur_dir);
1301       strcat(mtar_mask,"*");
1302       /*      do_dir((char *)inbuf,(char *)outbuf,mtar_mask,attribute,do_tar,recurse,True); */
1303               strcpy(cur_dir,saved_curdir);
1304       free(inbuf);free(outbuf);
1305     }
1306   else
1307     {
1308       strcpy(rname,cur_dir);
1309       strcat(rname,finfo->name);
1310       do_atar(rname,finfo->name,finfo);
1311     }
1312 }
1313
1314 /****************************************************************************
1315 Convert from UNIX to DOS file names
1316 ***************************************************************************/
1317 static void unfixtarname(char *tptr, char *fp, int l)
1318 {
1319   /* remove '.' from start of file name, convert from unix /'s to
1320    * dos \'s in path. Kill any absolute path names.
1321    */
1322
1323   if (*fp == '.') fp++;
1324   if (*fp == '\\' || *fp == '/') fp++;
1325
1326   while (l > 0) {
1327     int skip;
1328     if(( skip = skip_multibyte_char( *fp )) != 0) {
1329       if (skip == 2) {
1330         *tptr++ = *fp++;
1331         *tptr++ = *fp++;
1332         l -= 2;
1333       } else if (skip == 1) {
1334         *tptr++ = *fp++;
1335         l--;
1336       }
1337     } else if (*fp == '/') {
1338       *tptr++ = '\\';
1339       fp++;
1340       l--;
1341     } else {
1342       *tptr++ = *fp++;
1343       l--;
1344     }
1345   }
1346 }
1347
1348 static void do_tarput(void)
1349 {
1350   file_info finfo;
1351   int nread=0, bufread;
1352   char *inbuf,*outbuf, *longname = NULL; 
1353   int fsize=0;
1354   int fnum;
1355   struct timeval tp_start;
1356   BOOL tskip=False;       /* We'll take each file as it comes */
1357
1358   GetTimeOfDay(&tp_start);
1359   
1360   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1361   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1362   
1363   if (!inbuf || !outbuf)
1364     {
1365       DEBUG(0,("out of memory\n"));
1366       return;
1367     }
1368   
1369   /*
1370    * Must read in tbufsiz dollops
1371    */
1372
1373   /* These should be the only reads in clitar.c */
1374   while ((bufread=read(tarhandle, tarbuf, tbufsiz))>0) {
1375     char *bufferp, *endofbuffer;
1376     int chunk;
1377
1378     /* Code to handle a short read.
1379      * We always need a TBLOCK full of stuff
1380      */
1381     if (bufread % TBLOCK) {
1382       int lchunk=TBLOCK-(bufread % TBLOCK);
1383       int lread;
1384
1385       /* It's a shorty - a short read that is */
1386       DEBUG(3, ("Short read, read %d so far (need %d)\n", bufread, lchunk));
1387
1388       while ((lread=read(tarhandle, tarbuf+bufread, lchunk))>0) {
1389         bufread+=lread;
1390         if (!(lchunk-=lread)) break;
1391       }
1392
1393       /* If we've reached EOF then that must be a short file */
1394       if (lread<=0) break;
1395     }
1396
1397     bufferp=tarbuf; 
1398     endofbuffer=tarbuf+bufread;
1399
1400     if (tskip) {
1401       if (fsize<bufread) {
1402         tskip=False;
1403         bufferp+=fsize;
1404         fsize=0;
1405       } else {
1406         if (fsize==bufread) tskip=False;
1407         fsize-=bufread;
1408         continue;
1409       }
1410     }
1411
1412     do {
1413       if (!fsize)
1414         {
1415           int next_header = 1;  /* Want at least one header */
1416           while (next_header) 
1417             {  
1418             if (bufferp >= endofbuffer) {
1419
1420               bufread = read(tarhandle, tarbuf, tbufsiz);
1421               bufferp = tarbuf;
1422
1423             }
1424             next_header = 0;    /* Don't want the next one ... */
1425             switch (readtarheader((union hblock *) bufferp, &finfo, cur_dir))
1426               {
1427               case -2:             /* something dodgy but not fatal about this */
1428                 DEBUG(0, ("skipping %s...\n", finfo.name));
1429                 bufferp+=TBLOCK;   /* header - like a link */
1430                 continue;
1431               case -1:
1432                 DEBUG(0, ("abandoning restore, -1 from readtarheader\n"));
1433                 free(inbuf); free(outbuf);
1434                 return;
1435               case 0: /* chksum is zero - we assume that one all zero
1436                        *header block will do for eof */
1437                 DEBUG(0,
1438                       ("total of %d tar files restored to share\n", ntarf));
1439                 free(inbuf); free(outbuf);
1440                 return;
1441               default:
1442                 break;
1443               }
1444
1445             /* If we have a longname left from the last time through, 
1446                copy it into finfo.name and free it.
1447
1448                The size of a pstring is the limiting factor on filenames
1449                and directory names now. The total pathname length must be
1450                less than sizeof(pstring) - 1, which is currently 1023. */
1451
1452             if (longname != NULL) {
1453
1454               strncpy(finfo.name, longname, sizeof(pstring) - 1);
1455               free(longname);
1456               longname = NULL;
1457
1458             }
1459
1460             /* Check if a long-link. We do this before the clip checking
1461                because clip-checking should clip on real name - RJS */
1462
1463             if (((union hblock *)bufferp) -> dbuf.linkflag == 'L') {
1464
1465               /* Skip this header, but pick up length, get the name and 
1466                  fix the name and skip the name. Hmmm, what about end of
1467                  buffer??? */
1468
1469               longname = malloc(finfo.size + strlen(cur_dir) + 1);
1470               if (longname == NULL) {
1471
1472                  DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1473                            finfo.size + strlen(cur_dir) + 1)
1474                       );
1475                  free(inbuf); free(outbuf);
1476                  return;
1477               }
1478
1479               bufferp += TBLOCK;   /* Skip that longlink header */
1480
1481               /* This needs restructuring ... */
1482
1483               if (bufferp >= endofbuffer) {
1484
1485                 bufread = read(tarhandle, tarbuf, tbufsiz);
1486
1487                 bufferp = tarbuf;
1488
1489               }
1490
1491               strncpy(longname, cur_dir, strlen(cur_dir)); 
1492               unfixtarname(longname+strlen(cur_dir), bufferp, finfo.size);
1493
1494               /* Next rounds up to next TBLOCK and takes care of us being right
1495                  on a TBLOCK boundary */
1496
1497               bufferp += (((finfo.size - 1)/TBLOCK)+1)*TBLOCK;
1498               next_header = 1;  /* Force read of next header */
1499
1500             }
1501           }
1502           tskip=clipn
1503             && (clipfind(cliplist, clipn, finfo.name) ^ tar_excl);
1504           if (tskip) {
1505             bufferp+=TBLOCK;
1506             if (finfo.mode & aDIR)
1507               continue;
1508             else if ((fsize=finfo.size) % TBLOCK) {
1509               fsize+=TBLOCK-(fsize%TBLOCK);
1510             }
1511             if (fsize<endofbuffer-bufferp) {
1512               bufferp+=fsize;
1513               fsize=0;
1514               continue;
1515             } else {
1516               fsize-=endofbuffer-bufferp;
1517               break;
1518             }
1519           }
1520
1521           DEBUG(5, ("do_tarput: File is: %s\n", finfo.name));
1522
1523           if (finfo.mode & aDIR)
1524             {
1525               if (!ensurepath(finfo.name, inbuf, outbuf))
1526 /*            if (!smbchkpath(finfo.name, inbuf, outbuf)
1527                   && !smbmkdir(finfo.name, inbuf, outbuf))*/
1528                 {
1529                   DEBUG(0, ("abandoning restore, problems ensuring path\n"));
1530                   free(inbuf); free(outbuf);
1531                   return;
1532               }
1533               else
1534                 {
1535                   /* Now we update the creation date ... */
1536
1537                   DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1538
1539                   if (!do_setrtime(finfo.name, finfo.mtime)) {
1540
1541                     DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1542                     return;
1543
1544                   }
1545
1546                   ntarf++;
1547                   bufferp+=TBLOCK;
1548                   continue;
1549                 }
1550             }
1551           
1552           fsize=finfo.size;
1553
1554           if (ensurepath(finfo.name, inbuf, outbuf)
1555               && !smbcreat(finfo, &fnum, inbuf, outbuf))
1556             {
1557               DEBUG(0, ("abandoning restore\n"));
1558               free(inbuf);free(outbuf);
1559               return;
1560             }
1561
1562           DEBUG(0 ,("restore tar file %s of size %d bytes\n",
1563                    finfo.name,finfo.size));
1564
1565           if (!finfo.size) {
1566             if (!smbshut(finfo, fnum, inbuf, outbuf)){
1567               DEBUG(0, ("Error closing remote file of length 0: %s\n", finfo.name));
1568               free(inbuf);free(outbuf);
1569               return;
1570             }
1571           }
1572
1573           nread=0;
1574           if ((bufferp+=TBLOCK) >= endofbuffer) break;    
1575         } /* if (!fsize) */
1576         
1577       /* write out the file in chunk sized chunks - don't
1578        * go past end of buffer though */
1579       chunk=(fsize-nread < endofbuffer - bufferp)
1580         ? fsize - nread : endofbuffer - bufferp;
1581       
1582       while (chunk > 0) {
1583         int minichunk=MIN(chunk, max_xmit-200);
1584         
1585         if (!smbwrite(fnum, /* file descriptor */
1586                       minichunk, /* n */
1587                       nread, /* offset low */
1588                       0, /* offset high - not implemented */
1589                       fsize-nread, /* left - only hint to server */
1590                       bufferp,
1591                       inbuf,
1592                       outbuf))
1593           {
1594             DEBUG(0, ("Error writing remote file\n"));
1595             free(inbuf); free(outbuf);
1596             return;
1597           }
1598         DEBUG(5, ("chunk writing fname=%s fnum=%d nread=%d minichunk=%d chunk=%d size=%d\n", finfo.name, fnum, nread, minichunk, chunk, fsize));
1599         
1600         bufferp+=minichunk; nread+=minichunk;
1601         chunk-=minichunk;
1602       }
1603
1604       if (nread>=fsize)
1605         {
1606           if (!smbshut(finfo, fnum, inbuf, outbuf))
1607             {
1608               DEBUG(0, ("Error closing remote file\n"));
1609               free(inbuf);free(outbuf);
1610               return;
1611             }
1612           if (fsize % TBLOCK) bufferp+=TBLOCK - (fsize % TBLOCK);
1613           DEBUG(5, ("bufferp is now %d (psn=%d)\n",
1614                     (long) bufferp, (long)(bufferp - tarbuf)));
1615           ntarf++;
1616           fsize=0;
1617         }
1618     } while (bufferp < endofbuffer);
1619   }
1620
1621   DEBUG(0, ("premature eof on tar file ?\n"));
1622   DEBUG(0,("total of %d tar files restored to share\n", ntarf));
1623
1624   free(inbuf); free(outbuf);
1625 }
1626
1627 /*
1628  * samba interactive commands
1629  */
1630
1631 /****************************************************************************
1632 Blocksize command
1633 ***************************************************************************/
1634 void cmd_block(char *dum_in, char *dum_out)
1635 {
1636   fstring buf;
1637   int block;
1638
1639   if (!next_token(NULL,buf,NULL))
1640     {
1641       DEBUG(0, ("blocksize <n>\n"));
1642       return;
1643     }
1644
1645   block=atoi(buf);
1646   if (block < 0 || block > 65535)
1647     {
1648       DEBUG(0, ("blocksize out of range"));
1649       return;
1650     }
1651
1652   blocksize=block;
1653   DEBUG(2,("blocksize is now %d\n", blocksize));
1654 }
1655
1656 /****************************************************************************
1657 command to set incremental / reset mode
1658 ***************************************************************************/
1659 void cmd_tarmode(char *dum_in, char *dum_out)
1660 {
1661   fstring buf;
1662
1663   while (next_token(NULL,buf,NULL)) {
1664     if (strequal(buf, "full"))
1665       tar_inc=False;
1666     else if (strequal(buf, "inc"))
1667       tar_inc=True;
1668     else if (strequal(buf, "reset"))
1669       tar_reset=True;
1670     else if (strequal(buf, "noreset"))
1671       tar_reset=False;
1672     else if (strequal(buf, "system"))
1673       tar_system=True;
1674     else if (strequal(buf, "nosystem"))
1675       tar_system=False;
1676     else if (strequal(buf, "hidden"))
1677       tar_hidden=True;
1678     else if (strequal(buf, "nohidden"))
1679       tar_hidden=False;
1680     else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1681       tar_noisy=True;
1682     else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1683       tar_noisy=False;
1684     else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1685   }
1686
1687   DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1688             tar_inc ? "incremental" : "full",
1689             tar_system ? "system" : "nosystem",
1690             tar_hidden ? "hidden" : "nohidden",
1691             tar_reset ? "reset" : "noreset",
1692             tar_noisy ? "verbose" : "quiet"));
1693
1694 }
1695
1696 /****************************************************************************
1697 Feeble attrib command
1698 ***************************************************************************/
1699 void cmd_setmode(char *dum_in, char *dum_out)
1700 {
1701   char *q;
1702   fstring buf;
1703   pstring fname;
1704   int attra[2];
1705   int direct=1;
1706
1707   attra[0] = attra[1] = 0;
1708
1709   if (!next_token(NULL,buf,NULL))
1710     {
1711       DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1712       return;
1713     }
1714
1715   strcpy(fname, cur_dir);
1716   strcat(fname, buf);
1717
1718   while (next_token(NULL,buf,NULL)) {
1719     q=buf;
1720
1721     while(*q)
1722       switch (*q++) {
1723       case '+': direct=1;
1724         break;
1725       case '-': direct=0;
1726         break;
1727       case 'r': attra[direct]|=aRONLY;
1728         break;
1729       case 'h': attra[direct]|=aHIDDEN;
1730         break;
1731       case 's': attra[direct]|=aSYSTEM;
1732         break;
1733       case 'a': attra[direct]|=aARCH;
1734         break;
1735       default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1736         return;
1737       }
1738   }
1739
1740   if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1741     {
1742       DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1743       return;
1744     }
1745
1746   DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1747   (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
1748   (void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1749 }
1750
1751 /****************************************************************************
1752 Principal command for creating / extracting
1753 ***************************************************************************/
1754 void cmd_tar(char *inbuf, char *outbuf)
1755 {
1756   fstring buf;
1757   char **argl;
1758   int argcl;
1759
1760   if (!next_token(NULL,buf,NULL))
1761     {
1762       DEBUG(0,("tar <c|x>[IXbga] <filename>\n"));
1763       return;
1764     }
1765
1766   argl=toktocliplist(&argcl, NULL);
1767   if (!tar_parseargs(argcl, argl, buf, 0))
1768     return;
1769
1770   process_tar(inbuf, outbuf);
1771
1772   free(argl);
1773 }
1774
1775 /****************************************************************************
1776 Command line (option) version
1777 ***************************************************************************/
1778 int process_tar(char *inbuf, char *outbuf)
1779 {
1780   initarbuf();
1781   switch(tar_type) {
1782   case 'x':
1783     do_tarput();
1784     free(tarbuf);
1785     close(tarhandle);
1786     break;
1787   case 'r':
1788   case 'c':
1789     if (clipn && tar_excl) {
1790       int i;
1791       pstring tarmac;
1792
1793       for (i=0; i<clipn; i++) {
1794         DEBUG(0,("arg %d = %s\n", i, cliplist[i]));
1795
1796         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1797           *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1798         }
1799         
1800         if (strrchr(cliplist[i], '\\')) {
1801           pstring saved_dir;
1802           
1803           strcpy(saved_dir, cur_dir);
1804           
1805           if (*cliplist[i]=='\\') {
1806             strcpy(tarmac, cliplist[i]);
1807           } else {
1808             strcpy(tarmac, cur_dir);
1809             strcat(tarmac, cliplist[i]);
1810           }
1811           strcpy(cur_dir, tarmac);
1812           *(strrchr(cur_dir, '\\')+1)='\0';
1813
1814           do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
1815           strcpy(cur_dir,saved_dir);
1816         } else {
1817           strcpy(tarmac, cur_dir);
1818           strcat(tarmac, cliplist[i]);
1819           do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
1820         }
1821       }
1822     } else {
1823       pstring mask;
1824       strcpy(mask,cur_dir);
1825       strcat(mask,"\\*");
1826       do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse, True);
1827     }
1828     
1829     if (ntarf) dotareof(tarhandle);
1830     close(tarhandle);
1831     free(tarbuf);
1832     
1833     DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1834     DEBUG(0, ("Total bytes written: %d\n", ttarf));
1835     break;
1836   }
1837
1838   return(0);
1839 }
1840
1841 /****************************************************************************
1842 Find a token (filename) in a clip list
1843 ***************************************************************************/
1844 int clipfind(char **aret, int ret, char *tok)
1845 {
1846   if (aret==NULL) return 0;
1847
1848   /* ignore leading slashes or dots in token */
1849   while(strchr("/\\.", *tok)) tok++;
1850
1851   while(ret--) {
1852     char *pkey=*aret++;
1853
1854     /* ignore leading slashes or dots in list */
1855     while(strchr("/\\.", *pkey)) pkey++;
1856
1857     if (!strslashcmp(pkey, tok)) return 1;
1858   }
1859
1860   return 0;
1861 }
1862
1863 /****************************************************************************
1864 Parse tar arguments. Sets tar_type, tar_excl, etc.
1865 ***************************************************************************/
1866 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1867 {
1868   char tar_clipfl='\0';
1869
1870   /* Reset back to defaults - could be from interactive version 
1871    * reset mode and archive mode left as they are though
1872    */
1873   tar_type='\0';
1874   tar_excl=True;
1875
1876   while (*Optarg) 
1877     switch(*Optarg++) {
1878     case 'c':
1879       tar_type='c';
1880       break;
1881     case 'x':
1882       if (tar_type=='c') {
1883         printf("Tar must be followed by only one of c or x.\n");
1884         return 0;
1885       }
1886       tar_type='x';
1887       break;
1888     case 'b':
1889       if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1890         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1891         return 0;
1892       } else {
1893         Optind++;
1894       }
1895       break;
1896     case 'g':
1897       tar_inc=True;
1898       break;
1899     case 'N':
1900       if (Optind>=argc) {
1901         DEBUG(0,("Option N must be followed by valid file name\n"));
1902         return 0;
1903       } else {
1904         struct stat stbuf;
1905         extern time_t newer_than;
1906         
1907         if (sys_stat(argv[Optind], &stbuf) == 0) {
1908           newer_than = stbuf.st_mtime;
1909           DEBUG(1,("Getting files newer than %s",
1910                    asctime(LocalTime(&newer_than))));
1911           Optind++;
1912         } else {
1913           DEBUG(0,("Error setting newer-than time\n"));
1914           return 0;
1915         }
1916       }
1917       break;
1918     case 'a':
1919       tar_reset=True;
1920       break;
1921     case 'I':
1922       if (tar_clipfl) {
1923         DEBUG(0,("Only one of I,X must be specified\n"));
1924         return 0;
1925       }
1926       tar_clipfl='I';
1927       break;
1928     case 'X':
1929       if (tar_clipfl) {
1930         DEBUG(0,("Only one of I,X must be specified\n"));
1931         return 0;
1932       }
1933       tar_clipfl='X';
1934       break;
1935     default:
1936       DEBUG(0,("Unknown tar option\n"));
1937       return 0;
1938     }
1939
1940   if (!tar_type) {
1941     printf("Option T must be followed by one of c or x.\n");
1942     return 0;
1943   }
1944
1945   tar_excl=tar_clipfl!='X';
1946   if (Optind+1<argc) {
1947     char *tmpstr;
1948     char **tmplist;
1949     int clipcount;
1950
1951     cliplist=argv+Optind+1;
1952     clipn=argc-Optind-1;
1953     clipcount = clipn;
1954
1955     if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1956       DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
1957                clipn)
1958            );
1959       return 0;
1960     }
1961
1962     for (clipcount = 0; clipcount < clipn; clipcount++) {
1963
1964       DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1965
1966       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1967         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1968                  clipcount)
1969              );
1970         return 0;
1971       }
1972       unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1);
1973       tmplist[clipcount] = tmpstr;
1974       DEBUG(5, ("Processed an item, %s\n", tmpstr));
1975
1976       DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1977     }
1978     cliplist = tmplist;
1979   }
1980   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1981     /* Sets tar handle to either 0 or 1, as appropriate */
1982     tarhandle=(tar_type=='c');
1983   } else {
1984     if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
1985         || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
1986       {
1987         DEBUG(0,("Error opening local file %s - %s\n",
1988                  argv[Optind], strerror(errno)));
1989         return(0);
1990       }
1991   }
1992
1993   return 1;
1994 }