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