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