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