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