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