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