r1654: rename cli_ -> smbcli_
[bbaumbach/samba-autobuild/.git] / source4 / client / clitar.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Tar Extensions
4    Copyright (C) Ricky Poulten 1995-1998
5    Copyright (C) Richard Sharpe 1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 /* The following changes developed by Richard Sharpe for Canon Information
22    Systems Research Australia (CISRA)
23
24    1. Restore can now restore files with long file names
25    2. Save now saves directory information so that we can restore 
26       directory creation times
27    3. tar now accepts both UNIX path names and DOS path names. I prefer
28       those lovely /'s to those UGLY \'s :-)
29    4. the files to exclude can be specified as a regular expression by adding
30       an r flag to the other tar flags. Eg:
31
32          -TcrX file.tar "*.(obj|exe)"
33
34       will skip all .obj and .exe files
35 */
36
37
38 #include "includes.h"
39 #include "clitar.h"
40
41 static int clipfind(char **aret, int ret, char *tok);
42 void dos_clean_name(char *s);
43
44 typedef struct file_info_struct file_info2;
45
46 struct file_info_struct
47 {
48   uint64_t size;
49   uint16_t mode;
50   uid_t uid;
51   gid_t 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 #define SEPARATORS " \t\n\r"
70 extern struct smbcli_state *cli;
71
72 /* These defines are for the do_setrattr routine, to indicate
73  * setting and reseting of file attributes in the function call */
74 #define ATTRSET 1
75 #define ATTRRESET 0
76
77 static uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
78
79 #ifndef CLIENT_TIMEOUT
80 #define CLIENT_TIMEOUT (30*1000)
81 #endif
82
83 static char *tarbuf, *buffer_p;
84 static int tp, ntarf, tbufsiz;
85 static double ttarf;
86 /* Incremental mode */
87 static BOOL tar_inc=False;
88 /* Reset archive bit */
89 static BOOL tar_reset=False;
90 /* Include / exclude mode (true=include, false=exclude) */
91 static BOOL tar_excl=True;
92 /* use regular expressions for search on file names */
93 static BOOL tar_re_search=False;
94 #ifdef HAVE_REGEX_H
95 regex_t *preg;
96 #endif
97 /* Do not dump anything, just calculate sizes */
98 static BOOL dry_run=False;
99 /* Dump files with System attribute */
100 static BOOL tar_system=True;
101 /* Dump files with Hidden attribute */
102 static BOOL tar_hidden=True;
103 /* Be noisy - make a catalogue */
104 static BOOL tar_noisy=True;
105 static BOOL tar_real_noisy=False;  /* Don't want to be really noisy by default */
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 BOOL lowercase;
113 extern uint16_t cnum;
114 extern BOOL readbraw_supported;
115 extern int max_xmit;
116 extern pstring cur_dir;
117 extern int get_total_time_ms;
118 extern int get_total_size;
119
120 static int blocksize=20;
121 static int tarhandle;
122
123 static void writetarheader(int f,  const char *aname, uint64_t size, time_t mtime,
124                            const char *amode, uint8_t ftype);
125 static void do_atar(char *rname,char *lname,file_info *finfo1);
126 static void do_tar(file_info *finfo);
127 static void oct_it(uint64_t value, int ndgs, char *p);
128 static void fixtarname(char *tptr, const char *fp, int l);
129 static int dotarbuf(int f, char *b, int n);
130 static void dozerobuf(int f, int n);
131 static void dotareof(int f);
132 static void initarbuf(void);
133
134 /* restore functions */
135 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
136 static long unoct(char *p, int ndgs);
137 static void do_tarput(void);
138 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
139
140 /*
141  * tar specific utitlities
142  */
143
144 /*******************************************************************
145 Create  a string of size size+1 (for the null)
146 *******************************************************************/
147 static char *string_create_s(int size)
148 {
149   char *tmp;
150
151   tmp = (char *)malloc(size+1);
152
153   if (tmp == NULL) {
154
155     DEBUG(0, ("Out of memory in string_create_s\n"));
156
157   }
158
159   return(tmp);
160
161 }
162
163 /****************************************************************************
164 Write a tar header to buffer
165 ****************************************************************************/
166 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
167                            const char *amode, uint8_t ftype)
168 {
169   union hblock hb;
170   int i, chk, l;
171   char *jp;
172
173   DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
174
175   memset(hb.dummy, 0, sizeof(hb.dummy));
176   
177   l=strlen(aname);
178   if (l >= NAMSIZ - 1) {
179           /* write a GNU tar style long header */
180           char *b;
181           b = (char *)malloc(l+TBLOCK+100);
182           if (!b) {
183                   DEBUG(0,("out of memory\n"));
184                   exit(1);
185           }
186           writetarheader(f, "/./@LongLink", l+2, 0, "     0 \0", 'L');
187           memset(b, 0, l+TBLOCK+100);
188           fixtarname(b, aname, l);
189           i = strlen(b)+1;
190           DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
191           dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
192           SAFE_FREE(b);
193   }
194
195   /* use l + 1 to do the null too */
196   fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
197
198   if (lowercase)
199     strlower(hb.dbuf.name);
200
201   /* write out a "standard" tar format header */
202
203   hb.dbuf.name[NAMSIZ-1]='\0';
204   safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
205   oct_it((uint64_t)0, 8, hb.dbuf.uid);
206   oct_it((uint64_t)0, 8, hb.dbuf.gid);
207   oct_it((uint64_t) size, 13, hb.dbuf.size);
208   oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
209   memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
210   memset(hb.dbuf.linkname, 0, NAMSIZ);
211   hb.dbuf.linkflag=ftype;
212   
213   for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
214
215   oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
216   hb.dbuf.chksum[6] = '\0';
217
218   (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
219 }
220
221 /****************************************************************************
222 Read a tar header into a hblock structure, and validate
223 ***************************************************************************/
224 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
225 {
226   long chk, fchk;
227   int i;
228   char *jp;
229
230   /*
231    * read in a "standard" tar format header - we're not that interested
232    * in that many fields, though
233    */
234
235   /* check the checksum */
236   for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
237
238   if (chk == 0)
239     return chk;
240
241   /* compensate for blanks in chksum header */
242   for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
243     chk-=(0xFF & *jp++);
244
245   chk += ' ' * sizeof(hb->dbuf.chksum);
246
247   fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
248
249   DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
250             chk, fchk, hb->dbuf.chksum));
251
252   if (fchk != chk)
253     {
254       DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
255       dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
256       return -1;
257     }
258
259   if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
260
261     DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
262     return(-1);
263
264   }
265
266   safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
267
268   /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
269   unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
270                strlen(hb->dbuf.name) + 1, True);
271
272   /* can't handle some links at present */
273   if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
274     if (hb->dbuf.linkflag == 0) {
275       DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
276                 finfo->name));
277     } else { 
278       if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
279          /* Do nothing here at the moment. do_tarput will handle this
280             as long as the longlink gets back to it, as it has to advance 
281             the buffer pointer, etc */
282
283       } else {
284         DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
285         return -2;
286       }
287     }
288   }
289     
290   if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
291     || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
292     {
293       finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
294     }
295   else
296     finfo->mode=0; /* we don't care about mode at the moment, we'll
297                     * just make it a regular file */
298   /*
299    * Bug fix by richard@sj.co.uk
300    *
301    * REC: restore times correctly (as does tar)
302    * We only get the modification time of the file; set the creation time
303    * from the mod. time, and the access time to current time
304    */
305   finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
306   finfo->atime = time(NULL);
307   finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
308
309   return True;
310 }
311
312 /****************************************************************************
313 Write out the tar buffer to tape or wherever
314 ****************************************************************************/
315 static int dotarbuf(int f, char *b, int n)
316 {
317   int fail=1, writ=n;
318
319   if (dry_run) {
320     return writ;
321   }
322   /* This routine and the next one should be the only ones that do write()s */
323   if (tp + n >= tbufsiz)
324     {
325       int diff;
326
327       diff=tbufsiz-tp;
328       memcpy(tarbuf + tp, b, diff);
329       fail=fail && (1+write(f, tarbuf, tbufsiz));
330       n-=diff;
331       b+=diff;
332       tp=0;
333
334       while (n >= tbufsiz)
335         {
336           fail=fail && (1 + write(f, b, tbufsiz));
337           n-=tbufsiz;
338           b+=tbufsiz;
339         }
340     }
341   if (n>0) {
342     memcpy(tarbuf+tp, b, n);
343     tp+=n;
344   }
345
346   return(fail ? writ : 0);
347 }
348
349 /****************************************************************************
350 Write zeros to buffer / tape
351 ****************************************************************************/
352 static void dozerobuf(int f, int n)
353 {
354   /* short routine just to write out n zeros to buffer -
355    * used to round files to nearest block
356    * and to do tar EOFs */
357
358   if (dry_run)
359     return;
360   
361   if (n+tp >= tbufsiz)
362     {
363       memset(tarbuf+tp, 0, tbufsiz-tp);
364
365       write(f, tarbuf, tbufsiz);
366       memset(tarbuf, 0, (tp+=n-tbufsiz));
367     }
368   else
369     {
370       memset(tarbuf+tp, 0, n);
371       tp+=n;
372     }
373 }
374
375 /****************************************************************************
376 Malloc tape buffer
377 ****************************************************************************/
378 static void initarbuf(void)
379 {
380   /* initialize tar buffer */
381   tbufsiz=blocksize*TBLOCK;
382   tarbuf=malloc(tbufsiz);      /* FIXME: We might not get the buffer */
383
384   /* reset tar buffer pointer and tar file counter and total dumped */
385   tp=0; ntarf=0; ttarf=0;
386 }
387
388 /****************************************************************************
389 Write two zero blocks at end of file
390 ****************************************************************************/
391 static void dotareof(int f)
392 {
393   SMB_STRUCT_STAT stbuf;
394   /* Two zero blocks at end of file, write out full buffer */
395
396   if (dry_run)
397     return;
398
399   (void) dozerobuf(f, TBLOCK);
400   (void) dozerobuf(f, TBLOCK);
401
402   if (sys_fstat(f, &stbuf) == -1)
403     {
404       DEBUG(0, ("Couldn't stat file handle\n"));
405       return;
406     }
407
408   /* Could be a pipe, in which case S_ISREG should fail,
409    * and we should write out at full size */
410   if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
411 }
412
413 /****************************************************************************
414 (Un)mangle DOS pathname, make nonabsolute
415 ****************************************************************************/
416 static void fixtarname(char *tptr, const char *fp, int l)
417 {
418         /* add a '.' to start of file name, convert from ugly dos \'s in path
419          * to lovely unix /'s :-} */
420         *tptr++='.';
421
422         safe_strcpy(tptr, fp, l);
423         string_replace(tptr, '\\', '/');
424 }
425
426 /****************************************************************************
427 Convert from decimal to octal string
428 ****************************************************************************/
429 static void oct_it (uint64_t value, int ndgs, char *p)
430 {
431   /* Converts long to octal string, pads with leading zeros */
432
433   /* skip final null, but do final space */
434   --ndgs;
435   p[--ndgs] = ' ';
436  
437   /* Loop does at least one digit */
438   do {
439       p[--ndgs] = '0' + (char) (value & 7);
440       value >>= 3;
441     }
442   while (ndgs > 0 && value != 0);
443  
444   /* Do leading zeros */
445   while (ndgs > 0)
446     p[--ndgs] = '0';
447 }
448
449 /****************************************************************************
450 Convert from octal string to long
451 ***************************************************************************/
452 static long unoct(char *p, int ndgs)
453 {
454   long value=0;
455   /* Converts octal string to long, ignoring any non-digit */
456
457   while (--ndgs)
458     {
459       if (isdigit((int)*p))
460         value = (value << 3) | (long) (*p - '0');
461
462       p++;
463     }
464
465   return value;
466 }
467
468 /****************************************************************************
469 Compare two strings in a slash insensitive way, allowing s1 to match s2 
470 if s1 is an "initial" string (up to directory marker).  Thus, if s2 is 
471 a file in any subdirectory of s1, declare a match.
472 ***************************************************************************/
473 static int strslashcmp(char *s1, char *s2)
474 {
475   char *s1_0=s1;
476
477   while(*s1 && *s2 &&
478         (*s1 == *s2
479          || tolower(*s1) == tolower(*s2)
480          || (*s1 == '\\' && *s2=='/')
481          || (*s1 == '/' && *s2=='\\'))) {
482           s1++; s2++;
483   }
484
485   /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" 
486      string of s2.
487    */
488   if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
489
490   /* ignore trailing slash on s1 */
491   if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
492
493   /* check for s1 is an "initial" string of s2 */
494   if ((*s2 == '/' || *s2 == '\\') && !*s1) return 0;
495
496   return *s1-*s2;
497 }
498
499
500 /****************************************************************************
501 Ensure a remote path exists (make if necessary)
502 ***************************************************************************/
503 static BOOL ensurepath(char *fname)
504 {
505   /* *must* be called with buffer ready malloc'ed */
506   /* ensures path exists */
507
508   char *partpath, *ffname;
509   char *p=fname, *basehack;
510
511   DEBUG(5, ( "Ensurepath called with: %s\n", fname));
512
513   partpath = string_create_s(strlen(fname));
514   ffname = string_create_s(strlen(fname));
515
516   if ((partpath == NULL) || (ffname == NULL)){
517
518     DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
519     return(False);
520
521   }
522
523   *partpath = 0;
524
525   /* fname copied to ffname so can strtok */
526
527   safe_strcpy(ffname, fname, strlen(fname));
528
529   /* do a `basename' on ffname, so don't try and make file name directory */
530   if ((basehack=strrchr_m(ffname, '\\')) == NULL)
531     return True;
532   else
533     *basehack='\0';
534
535   p=strtok(ffname, "\\");
536
537   while (p)
538     {
539       safe_strcat(partpath, p, strlen(fname) + 1);
540
541       if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, partpath))) {
542         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, partpath)))
543           {
544             DEBUG(0, ("Error mkdirhiering\n"));
545             return False;
546           }
547         else
548           DEBUG(3, ("mkdirhiering %s\n", partpath));
549
550       }
551
552       safe_strcat(partpath, "\\", strlen(fname) + 1);
553       p = strtok(NULL,"/\\");
554     }
555
556     return True;
557 }
558
559 static int padit(char *buf, int bufsize, int padsize)
560 {
561         int berr= 0;
562         int bytestowrite;
563   
564         DEBUG(5, ("Padding with %d zeros\n", padsize));
565         memset(buf, 0, bufsize);
566         while( !berr && padsize > 0 ) {
567                 bytestowrite= MIN(bufsize, padsize);
568                 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
569                 padsize -= bytestowrite;
570         }
571   
572         return berr;
573 }
574
575
576 static void do_setrattr(char *name, uint16_t attr, int set)
577 {
578         uint16_t oldattr;
579
580         if (NT_STATUS_IS_ERR(smbcli_getatr(cli->tree, name, &oldattr, NULL, NULL)))
581                 return;
582
583         if (set == ATTRSET) {
584                 attr |= oldattr;
585         } else {
586                 attr = oldattr & ~attr;
587         }
588
589         if (NT_STATUS_IS_ERR(smbcli_setatr(cli->tree, name, attr, 0))) {
590                 DEBUG(1,("setatr failed: %s\n", smbcli_errstr(cli->tree)));
591         }
592 }
593
594
595 /****************************************************************************
596 append one remote file to the tar file
597 ***************************************************************************/
598 static void do_atar(char *rname,char *lname,file_info *finfo1)
599 {
600   int fnum;
601   uint64_t nread=0;
602   char ftype;
603   file_info2 finfo;
604   BOOL close_done = False;
605   BOOL shallitime=True;
606   char data[65520];
607   int read_size = 65520;
608   int datalen=0;
609
610   struct timeval tp_start;
611   GetTimeOfDay(&tp_start);
612
613   ftype = '0'; /* An ordinary file ... */
614
615   if (finfo1) {
616     finfo.size  = finfo1 -> size;
617     finfo.mode  = finfo1 -> mode;
618     finfo.uid   = finfo1 -> uid;
619     finfo.gid   = finfo1 -> gid;
620     finfo.mtime = finfo1 -> mtime;
621     finfo.atime = finfo1 -> atime;
622     finfo.ctime = finfo1 -> ctime;
623     finfo.name  = finfo1 -> name;
624   }
625   else {
626           ZERO_STRUCT(finfo);
627   }
628
629   if (dry_run)
630     {
631       DEBUG(3,("skipping file %s of size %12.0f bytes\n",
632                finfo.name,
633                (double)finfo.size));
634       shallitime=0;
635       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
636       ntarf++;
637       return;
638     }
639
640   fnum = smbcli_open(cli->tree, rname, O_RDONLY, DENY_NONE);
641
642   dos_clean_name(rname);
643
644   if (fnum == -1) {
645           DEBUG(0,("%s opening remote file %s (%s)\n",
646                    smbcli_errstr(cli->tree),rname, cur_dir));
647           return;
648   }
649
650   finfo.name = string_create_s(strlen(rname));
651   if (finfo.name == NULL) {
652           DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
653           return;
654   }
655
656   safe_strcpy(finfo.name,rname, strlen(rname));
657   if (!finfo1) {
658           size_t size;
659           if (NT_STATUS_IS_ERR(smbcli_getattrE(cli->tree, fnum, &finfo.mode, &size, NULL, &finfo.atime, &finfo.mtime))) {
660                   DEBUG(0, ("getattrE: %s\n", smbcli_errstr(cli->tree)));
661                   return;
662           }
663           finfo.size = size;
664           finfo.ctime = finfo.mtime;
665   }
666
667   DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
668
669   if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE))
670     {
671       DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
672       shallitime=0;
673     }
674   else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM))
675     {
676       DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
677       shallitime=0;
678     }
679   else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN))
680     {
681       DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
682       shallitime=0;
683     }
684   else
685     {
686       DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
687                finfo.name,
688                (double)finfo.size,
689                lname));
690       
691       /* write a tar header, don't bother with mode - just set to 100644 */
692       writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
693
694       while (nread < finfo.size && !close_done) {
695               
696               DEBUG(3,("nread=%.0f\n",(double)nread));
697               
698               datalen = smbcli_read(cli->tree, fnum, data, nread, read_size);
699               
700               if (datalen == -1) {
701                       DEBUG(0,("Error reading file %s : %s\n", rname, smbcli_errstr(cli->tree)));
702                       break;
703               }
704               
705                   nread += datalen;
706
707                   /* if file size has increased since we made file size query, truncate
708                         read so tar header for this file will be correct.
709                    */
710
711                   if (nread > finfo.size) {
712                         datalen -= nread - finfo.size;
713                         DEBUG(0,("File size change - truncating %s to %.0f bytes\n", finfo.name, (double)finfo.size));
714                   }
715
716               /* add received bits of file to buffer - dotarbuf will
717                * write out in 512 byte intervals */
718               if (dotarbuf(tarhandle,data,datalen) != datalen) {
719                       DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
720                       break;
721               }
722               
723               if (datalen == 0) {
724                       DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
725                       break;
726               }
727
728               datalen=0;
729       }
730
731       /* pad tar file with zero's if we couldn't get entire file */
732       if (nread < finfo.size) {
733               DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n", (double)finfo.size, (int)nread));
734               if (padit(data, sizeof(data), finfo.size - nread))
735                       DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
736       }
737
738       /* round tar file to nearest block */
739       if (finfo.size % TBLOCK)
740         dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
741       
742       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
743       ntarf++;
744     }
745   
746   smbcli_close(cli->tree, fnum);
747
748   if (shallitime)
749     {
750       struct timeval tp_end;
751       int this_time;
752
753       /* if shallitime is true then we didn't skip */
754       if (tar_reset && !dry_run)
755         (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
756       
757       GetTimeOfDay(&tp_end);
758       this_time = 
759         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
760           (tp_end.tv_usec - tp_start.tv_usec)/1000;
761       get_total_time_ms += this_time;
762       get_total_size += finfo.size;
763
764       if (tar_noisy)
765         {
766           DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
767                (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
768                finfo.name));
769         }
770
771       /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
772       DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
773                finfo.size / MAX(0.001, (1.024*this_time)),
774                get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
775     }
776 }
777
778 /****************************************************************************
779 Append single file to tar file (or not)
780 ***************************************************************************/
781 static void do_tar(file_info *finfo)
782 {
783   pstring rname;
784
785   if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
786     return;
787
788   /* Is it on the exclude list ? */
789   if (!tar_excl && clipn) {
790     pstring exclaim;
791
792     DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
793
794     safe_strcpy(exclaim, cur_dir, sizeof(pstring));
795     *(exclaim+strlen(exclaim)-1)='\0';
796
797     safe_strcat(exclaim, "\\", sizeof(pstring));
798     safe_strcat(exclaim, finfo->name, sizeof(exclaim));
799
800     DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
801
802     if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
803 #ifdef HAVE_REGEX_H
804         (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
805 #else
806         (tar_re_search && mask_match(cli, exclaim, cliplist[0], True))) {
807 #endif
808       DEBUG(3,("Skipping file %s\n", exclaim));
809       return;
810     }
811   }
812
813   if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY)
814     {
815       pstring saved_curdir;
816       pstring mtar_mask;
817
818       safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
819
820       DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", (int)sizeof(cur_dir), (int)strlen(cur_dir), (int)strlen(finfo->name), finfo->name, cur_dir));
821
822       safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
823       safe_strcat(cur_dir,"\\", sizeof(cur_dir));
824
825       DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
826
827       /* write a tar directory, don't bother with mode - just set it to
828        * 40755 */
829       writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
830       if (tar_noisy) {
831           DEBUG(0,("                directory %s\n", cur_dir));
832       }
833       ntarf++;  /* Make sure we have a file on there */
834       safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
835       safe_strcat(mtar_mask,"*", sizeof(pstring));
836       DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
837       do_list(mtar_mask, attribute, do_tar, False, True);
838       safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
839     }
840   else
841     {
842       safe_strcpy(rname,cur_dir, sizeof(pstring));
843       safe_strcat(rname,finfo->name, sizeof(pstring));
844       do_atar(rname,finfo->name,finfo);
845     }
846 }
847
848 /****************************************************************************
849 Convert from UNIX to DOS file names
850 ***************************************************************************/
851 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
852 {
853         /* remove '.' from start of file name, convert from unix /'s to
854          * dos \'s in path. Kill any absolute path names. But only if first!
855          */
856
857         DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
858
859         if (first) {
860                 if (*fp == '.') {
861                         fp++;
862                         l--;
863                 }
864                 if (*fp == '\\' || *fp == '/') {
865                         fp++;
866                         l--;
867                 }
868         }
869
870         safe_strcpy(tptr, fp, l);
871         string_replace(tptr, '/', '\\');
872 }
873
874
875 /****************************************************************************
876 Move to the next block in the buffer, which may mean read in another set of
877 blocks. FIXME, we should allow more than one block to be skipped.
878 ****************************************************************************/
879 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
880 {
881   int bufread, total = 0;
882
883   DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
884   *bufferp += TBLOCK;
885   total = TBLOCK;
886
887   if (*bufferp >= (ltarbuf + bufsiz)) {
888
889     DEBUG(5, ("Reading more data into ltarbuf ...\n"));
890
891     /*
892      * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
893      * Fixes bug where read can return short if coming from
894      * a pipe.
895      */
896
897     bufread = read(tarhandle, ltarbuf, bufsiz);
898     total = bufread;
899
900     while (total < bufsiz) {
901       if (bufread < 0) { /* An error, return false */
902         return (total > 0 ? -2 : bufread);
903       }
904       if (bufread == 0) {
905         if (total <= 0) {
906             return -2;
907         }
908         break;
909       }
910       bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
911       total += bufread;
912     }
913
914     DEBUG(5, ("Total bytes read ... %i\n", total));
915
916     *bufferp = ltarbuf;
917
918   }
919
920   return(total);
921
922 }
923
924 /* Skip a file, even if it includes a long file name? */
925 static int skip_file(int skipsize)
926 {
927   int dsize = skipsize;
928
929   DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
930
931   /* FIXME, we should skip more than one block at a time */
932
933   while (dsize > 0) {
934
935     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
936
937         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
938         return(False);
939
940     }
941
942     dsize -= TBLOCK;
943
944   }
945
946   return(True);
947 }
948
949 /*************************************************************
950  Get a file from the tar file and store it.
951  When this is called, tarbuf already contains the first
952  file block. This is a bit broken & needs fixing.
953 **************************************************************/
954
955 static int get_file(file_info2 finfo)
956 {
957   int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
958
959   DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
960
961   if (ensurepath(finfo.name) && 
962       (fnum=smbcli_open(cli->tree, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
963       DEBUG(0, ("abandoning restore\n"));
964       return(False);
965   }
966
967   /* read the blocks from the tar file and write to the remote file */
968
969   rsize = finfo.size;  /* This is how much to write */
970
971   while (rsize > 0) {
972
973     /* We can only write up to the end of the buffer */
974
975     dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
976     dsize = MIN(dsize, rsize);  /* Should be only what is left */
977     DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
978
979     if (smbcli_write(cli->tree, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
980             DEBUG(0, ("Error writing remote file\n"));
981             return 0;
982     }
983
984     rsize -= dsize;
985     pos += dsize;
986
987     /* Now figure out how much to move in the buffer */
988
989     /* FIXME, we should skip more than one block at a time */
990
991     /* First, skip any initial part of the part written that is left over */
992     /* from the end of the first TBLOCK                                   */
993
994     if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
995
996       dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
997       bpos = 0;
998
999       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
1000         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1001         return False;
1002
1003       }
1004
1005     }
1006
1007     /*
1008      * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1009      * If the file being extracted is an exact multiple of
1010      * TBLOCK bytes then we don't want to extract the next
1011      * block from the tarfile here, as it will be done in
1012      * the caller of get_file().
1013      */
1014
1015     while (((rsize != 0) && (dsize >= TBLOCK)) ||
1016          ((rsize == 0) && (dsize > TBLOCK))) {
1017
1018       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1019         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1020         return False;
1021       }
1022
1023       dsize -= TBLOCK;
1024     }
1025
1026     bpos = dsize;
1027
1028   }
1029
1030   /* Now close the file ... */
1031
1032   if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
1033           DEBUG(0, ("Error closing remote file\n"));
1034           return(False);
1035   }
1036
1037   /* Now we update the creation date ... */
1038
1039   DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1040
1041   if (NT_STATUS_IS_ERR(smbcli_setatr(cli->tree, finfo.name, finfo.mode, finfo.mtime))) {
1042           if (tar_real_noisy) {
1043                   DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1044                   /*return(False); */ /* Ignore, as Win95 does not allow changes */
1045           }
1046   }
1047
1048   ntarf++;
1049
1050   DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1051   
1052   return(True);
1053 }
1054
1055 /* Create a directory.  We just ensure that the path exists and return as there
1056    is no file associated with a directory 
1057 */
1058 static int get_dir(file_info2 finfo)
1059 {
1060
1061   DEBUG(0, ("restore directory %s\n", finfo.name));
1062
1063   if (!ensurepath(finfo.name)) {
1064
1065     DEBUG(0, ("Problems creating directory\n"));
1066     return(False);
1067
1068   }
1069
1070   ntarf++;
1071   return(True);
1072
1073 }
1074 /* Get a file with a long file name ... first file has file name, next file 
1075    has the data. We only want the long file name, as the loop in do_tarput
1076    will deal with the rest.
1077 */
1078 static char * get_longfilename(file_info2 finfo)
1079 {
1080   int namesize = finfo.size + strlen(cur_dir) + 2;
1081   char *longname = malloc(namesize);
1082   int offset = 0, left = finfo.size;
1083   BOOL first = True;
1084
1085   DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1086   DEBUG(5, ("Len = %d\n", (int)finfo.size));
1087
1088   if (longname == NULL) {
1089
1090     DEBUG(0, ("could not allocate buffer of size %d for longname\n", 
1091               (int)(finfo.size + strlen(cur_dir) + 2)));
1092     return(NULL);
1093   }
1094
1095   /* First, add cur_dir to the long file name */
1096
1097   if (strlen(cur_dir) > 0) {
1098     strncpy(longname, cur_dir, namesize);
1099     offset = strlen(cur_dir);
1100   }
1101
1102   /* Loop through the blocks picking up the name */
1103
1104   while (left > 0) {
1105
1106     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1107
1108       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1109       return(NULL);
1110
1111     }
1112
1113     unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1114     DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1115
1116     offset += TBLOCK;
1117     left -= TBLOCK;
1118
1119   }
1120
1121   return(longname);
1122
1123 }
1124
1125 static void do_tarput(void)
1126 {
1127   file_info2 finfo;
1128   struct timeval tp_start;
1129   char *longfilename = NULL, linkflag;
1130   int skip = False;
1131
1132   GetTimeOfDay(&tp_start);
1133
1134   DEBUG(5, ("RJS do_tarput called ...\n"));
1135
1136   buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1137
1138   /* Now read through those files ... */
1139
1140   while (True) {
1141
1142     /* Get us to the next block, or the first block first time around */
1143
1144     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1145
1146       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1147
1148       return;
1149
1150     }
1151
1152     DEBUG(5, ("Reading the next header ...\n"));
1153
1154     switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1155
1156     case -2:    /* Hmm, not good, but not fatal */
1157       DEBUG(0, ("Skipping %s...\n", finfo.name));
1158       if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1159           !skip_file(finfo.size)) {
1160
1161         DEBUG(0, ("Short file, bailing out...\n"));
1162         return;
1163
1164       }
1165
1166       break;
1167
1168     case -1:
1169       DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1170       return;
1171
1172     case 0: /* chksum is zero - looks like an EOF */
1173       DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1174       return;        /* Hmmm, bad here ... */
1175
1176     default: 
1177       /* No action */
1178
1179       break;
1180
1181     }
1182
1183     /* Now, do we have a long file name? */
1184
1185     if (longfilename != NULL) {
1186
1187       SAFE_FREE(finfo.name);   /* Free the space already allocated */
1188       finfo.name = longfilename;
1189       longfilename = NULL;
1190
1191     }
1192
1193     /* Well, now we have a header, process the file ...            */
1194
1195     /* Should we skip the file? We have the long name as well here */
1196
1197     skip = clipn &&
1198       ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1199 #ifdef HAVE_REGEX_H
1200       || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1201 #else
1202       || (tar_re_search && mask_match(cli, finfo.name, cliplist[0], True)));
1203 #endif
1204
1205   DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1206
1207   if (skip) {
1208
1209     skip_file(finfo.size);
1210     continue;
1211
1212   }
1213
1214     /* We only get this far if we should process the file */
1215   linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1216
1217     switch (linkflag) {
1218
1219     case '0':  /* Should use symbolic names--FIXME */
1220
1221       /* 
1222        * Skip to the next block first, so we can get the file, FIXME, should
1223        * be in get_file ...
1224        * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1225        * Fixes bug where file size in tarfile is zero.
1226        */
1227
1228       if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1229         DEBUG(0, ("Short file, bailing out...\n"));
1230         return;
1231       }
1232       if (!get_file(finfo)) {
1233         DEBUG(0, ("Abandoning restore\n"));
1234         return;
1235
1236       }
1237       break;
1238
1239     case '5':
1240       if (!get_dir(finfo)) {
1241         DEBUG(0, ("Abandoning restore \n"));
1242         return;
1243       }
1244       break;
1245
1246     case 'L':
1247       longfilename = get_longfilename(finfo);
1248       if (!longfilename) {
1249         DEBUG(0, ("abandoning restore\n"));
1250         return;
1251
1252       }
1253       DEBUG(5, ("Long file name: %s\n", longfilename));
1254       break;
1255
1256     default:
1257       skip_file(finfo.size);  /* Don't handle these yet */
1258       break;
1259
1260     }
1261
1262   }
1263
1264
1265 }
1266
1267
1268 /*
1269  * samba interactive commands
1270  */
1271
1272 /****************************************************************************
1273 Blocksize command
1274 ***************************************************************************/
1275 int cmd_block(void)
1276 {
1277   fstring buf;
1278   int block;
1279
1280   if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1281     {
1282       DEBUG(0, ("blocksize <n>\n"));
1283       return 1;
1284     }
1285
1286   block=atoi(buf);
1287   if (block < 0 || block > 65535)
1288     {
1289       DEBUG(0, ("blocksize out of range"));
1290       return 1;
1291     }
1292
1293   blocksize=block;
1294   DEBUG(2,("blocksize is now %d\n", blocksize));
1295
1296   return 0;
1297 }
1298
1299 /****************************************************************************
1300 command to set incremental / reset mode
1301 ***************************************************************************/
1302 int cmd_tarmode(void)
1303 {
1304   fstring buf;
1305
1306   while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1307     if (strequal(buf, "full"))
1308       tar_inc=False;
1309     else if (strequal(buf, "inc"))
1310       tar_inc=True;
1311     else if (strequal(buf, "reset"))
1312       tar_reset=True;
1313     else if (strequal(buf, "noreset"))
1314       tar_reset=False;
1315     else if (strequal(buf, "system"))
1316       tar_system=True;
1317     else if (strequal(buf, "nosystem"))
1318       tar_system=False;
1319     else if (strequal(buf, "hidden"))
1320       tar_hidden=True;
1321     else if (strequal(buf, "nohidden"))
1322       tar_hidden=False;
1323     else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1324       tar_noisy=True;
1325     else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1326       tar_noisy=False;
1327     else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1328   }
1329
1330   DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1331             tar_inc ? "incremental" : "full",
1332             tar_system ? "system" : "nosystem",
1333             tar_hidden ? "hidden" : "nohidden",
1334             tar_reset ? "reset" : "noreset",
1335             tar_noisy ? "verbose" : "quiet"));
1336
1337   return 0;
1338 }
1339
1340 /****************************************************************************
1341 Feeble attrib command
1342 ***************************************************************************/
1343 int cmd_setmode(void)
1344 {
1345   char *q;
1346   fstring buf;
1347   pstring fname;
1348   uint16_t attra[2];
1349   int direct=1;
1350
1351   attra[0] = attra[1] = 0;
1352
1353   if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1354     {
1355       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1356       return 1;
1357     }
1358
1359   safe_strcpy(fname, cur_dir, sizeof(pstring));
1360   safe_strcat(fname, buf, sizeof(pstring));
1361
1362   while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1363     q=buf;
1364
1365     while(*q)
1366       switch (*q++) {
1367       case '+': direct=1;
1368         break;
1369       case '-': direct=0;
1370         break;
1371       case 'r': attra[direct]|=FILE_ATTRIBUTE_READONLY;
1372         break;
1373       case 'h': attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1374         break;
1375       case 's': attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1376         break;
1377       case 'a': attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1378         break;
1379       default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1380         return 1;
1381       }
1382   }
1383
1384   if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1385     {
1386       DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1387       return 1;
1388     }
1389
1390   DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1391   do_setrattr(fname, attra[ATTRSET], ATTRSET);
1392   do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1393
1394   return 0;
1395 }
1396
1397 /****************************************************************************
1398 Principal command for creating / extracting
1399 ***************************************************************************/
1400 int cmd_tar(void)
1401 {
1402   fstring buf;
1403   char **argl;
1404   int argcl;
1405
1406   if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1407     {
1408       DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1409       return 1;
1410     }
1411
1412   argl=toktocliplist(&argcl, NULL);
1413   if (!tar_parseargs(argcl, argl, buf, 0))
1414     return 1;
1415
1416   process_tar();
1417
1418   SAFE_FREE(argl);
1419
1420   return 0;
1421 }
1422
1423 /****************************************************************************
1424 Command line (option) version
1425 ***************************************************************************/
1426 int process_tar(void)
1427 {
1428   initarbuf();
1429   switch(tar_type) {
1430   case 'x':
1431
1432 #if 0
1433     do_tarput2();
1434 #else
1435     do_tarput();
1436 #endif
1437     SAFE_FREE(tarbuf);
1438     close(tarhandle);
1439     break;
1440   case 'r':
1441   case 'c':
1442     if (clipn && tar_excl) {
1443       int i;
1444       pstring tarmac;
1445
1446       for (i=0; i<clipn; i++) {
1447         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1448
1449         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1450           *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1451         }
1452         
1453         if (strrchr_m(cliplist[i], '\\')) {
1454           pstring saved_dir;
1455           
1456           safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1457           
1458           if (*cliplist[i]=='\\') {
1459             safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1460           } else {
1461             safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1462             safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1463           }
1464           safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1465           *(strrchr_m(cur_dir, '\\')+1)='\0';
1466
1467           DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1468           do_list(tarmac,attribute,do_tar, False, True);
1469           safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1470         } else {
1471           safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1472           safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1473           DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1474           do_list(tarmac,attribute,do_tar, False, True);
1475         }
1476       }
1477     } else {
1478       pstring mask;
1479       safe_strcpy(mask,cur_dir, sizeof(pstring));
1480       DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1481       safe_strcat(mask,"\\*", sizeof(pstring));
1482       do_list(mask,attribute,do_tar,False, True);
1483     }
1484     
1485     if (ntarf) dotareof(tarhandle);
1486     close(tarhandle);
1487     SAFE_FREE(tarbuf);
1488     
1489     DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1490     DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1491     break;
1492   }
1493
1494   if (must_free_cliplist) {
1495     int i;
1496     for (i = 0; i < clipn; ++i) {
1497       SAFE_FREE(cliplist[i]);
1498     }
1499     SAFE_FREE(cliplist);
1500     cliplist = NULL;
1501     clipn = 0;
1502     must_free_cliplist = False;
1503   }
1504
1505   return(0);
1506 }
1507
1508 /****************************************************************************
1509 Find a token (filename) in a clip list
1510 ***************************************************************************/
1511 static int clipfind(char **aret, int ret, char *tok)
1512 {
1513   if (aret==NULL) return 0;
1514
1515   /* ignore leading slashes or dots in token */
1516   while(strchr_m("/\\.", *tok)) tok++;
1517
1518   while(ret--) {
1519     char *pkey=*aret++;
1520
1521     /* ignore leading slashes or dots in list */
1522     while(strchr_m("/\\.", *pkey)) pkey++;
1523
1524     if (!strslashcmp(pkey, tok)) return 1;
1525   }
1526
1527   return 0;
1528 }
1529
1530 /****************************************************************************
1531 Read list of files to include from the file and initialize cliplist
1532 accordingly.
1533 ***************************************************************************/
1534 static int read_inclusion_file(char *filename)
1535 {
1536   XFILE *inclusion = NULL;
1537   char buf[MAXPATHLEN + 1];
1538   char *inclusion_buffer = NULL;
1539   int inclusion_buffer_size = 0;
1540   int inclusion_buffer_sofar = 0;
1541   char *p;
1542   char *tmpstr;
1543   int i;
1544   int error = 0;
1545
1546   clipn = 0;
1547   buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1548   if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1549     /* XXX It would be better to include a reason for failure, but without
1550      * autoconf, it's hard to use strerror, sys_errlist, etc.
1551      */
1552     DEBUG(0,("Unable to open inclusion file %s\n", filename));
1553     return 0;
1554   }
1555
1556   while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1557     if (inclusion_buffer == NULL) {
1558       inclusion_buffer_size = 1024;
1559       if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1560         DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1561         error = 1;
1562         break;
1563       }
1564     }
1565     
1566     if (buf[strlen(buf)-1] == '\n') {
1567       buf[strlen(buf)-1] = '\0';
1568     }
1569     
1570     if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1571       char *ib;
1572       inclusion_buffer_size *= 2;
1573       ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1574       if (! ib) {
1575         DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1576                  inclusion_buffer_size));
1577         error = 1;
1578         break;
1579       }
1580       else inclusion_buffer = ib;
1581     }
1582     
1583     safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1584     inclusion_buffer_sofar += strlen(buf) + 1;
1585     clipn++;
1586   }
1587   x_fclose(inclusion);
1588
1589   if (! error) {
1590     /* Allocate an array of clipn + 1 char*'s for cliplist */
1591     cliplist = malloc((clipn + 1) * sizeof(char *));
1592     if (cliplist == NULL) {
1593       DEBUG(0,("failure allocating memory for cliplist\n"));
1594       error = 1;
1595     } else {
1596       cliplist[clipn] = NULL;
1597       p = inclusion_buffer;
1598       for (i = 0; (! error) && (i < clipn); i++) {
1599         /* set current item to NULL so array will be null-terminated even if
1600          * malloc fails below. */
1601         cliplist[i] = NULL;
1602         if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1603           DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1604           error = 1;
1605         } else {
1606           unfixtarname(tmpstr, p, strlen(p) + 1, True);
1607           cliplist[i] = tmpstr;
1608           if ((p = strchr_m(p, '\000')) == NULL) {
1609             DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1610             abort();
1611           }
1612         }
1613         ++p;
1614       }
1615       must_free_cliplist = True;
1616     }
1617   }
1618
1619   SAFE_FREE(inclusion_buffer);
1620   if (error) {
1621     if (cliplist) {
1622       char **pp;
1623       /* We know cliplist is always null-terminated */
1624       for (pp = cliplist; *pp; ++pp) {
1625         SAFE_FREE(*pp);
1626       }
1627       SAFE_FREE(cliplist);
1628       cliplist = NULL;
1629       must_free_cliplist = False;
1630     }
1631     return 0;
1632   }
1633   
1634   /* cliplist and its elements are freed at the end of process_tar. */
1635   return 1;
1636 }
1637
1638 /****************************************************************************
1639 Parse tar arguments. Sets tar_type, tar_excl, etc.
1640 ***************************************************************************/
1641 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1642 {
1643   char tar_clipfl='\0';
1644
1645   /* Reset back to defaults - could be from interactive version 
1646    * reset mode and archive mode left as they are though
1647    */
1648   tar_type='\0';
1649   tar_excl=True;
1650   dry_run=False;
1651
1652   while (*Optarg) 
1653     switch(*Optarg++) {
1654     case 'c':
1655       tar_type='c';
1656       break;
1657     case 'x':
1658       if (tar_type=='c') {
1659         printf("Tar must be followed by only one of c or x.\n");
1660         return 0;
1661       }
1662       tar_type='x';
1663       break;
1664     case 'b':
1665       if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1666         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1667         return 0;
1668       } else {
1669         Optind++;
1670       }
1671       break;
1672     case 'g':
1673       tar_inc=True;
1674       break;
1675     case 'N':
1676       if (Optind>=argc) {
1677         DEBUG(0,("Option N must be followed by valid file name\n"));
1678         return 0;
1679       } else {
1680         SMB_STRUCT_STAT stbuf;
1681         extern time_t newer_than;
1682         
1683         if (sys_stat(argv[Optind], &stbuf) == 0) {
1684           newer_than = stbuf.st_mtime;
1685           DEBUG(1,("Getting files newer than %s",
1686                    asctime(localtime(&newer_than))));
1687           Optind++;
1688         } else {
1689           DEBUG(0,("Error setting newer-than time\n"));
1690           return 0;
1691         }
1692       }
1693       break;
1694     case 'a':
1695       tar_reset=True;
1696       break;
1697     case 'q':
1698       tar_noisy=False;
1699       break;
1700     case 'I':
1701       if (tar_clipfl) {
1702         DEBUG(0,("Only one of I,X,F must be specified\n"));
1703         return 0;
1704       }
1705       tar_clipfl='I';
1706       break;
1707     case 'X':
1708       if (tar_clipfl) {
1709         DEBUG(0,("Only one of I,X,F must be specified\n"));
1710         return 0;
1711       }
1712       tar_clipfl='X';
1713       break;
1714     case 'F':
1715       if (tar_clipfl) {
1716         DEBUG(0,("Only one of I,X,F must be specified\n"));
1717         return 0;
1718       }
1719       tar_clipfl='F';
1720       break;
1721     case 'r':
1722       DEBUG(0, ("tar_re_search set\n"));
1723       tar_re_search = True;
1724       break;
1725     case 'n':
1726       if (tar_type == 'c') {
1727         DEBUG(0, ("dry_run set\n"));
1728         dry_run = True;
1729       } else {
1730         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1731         return 0;
1732       }
1733       break;
1734     default:
1735       DEBUG(0,("Unknown tar option\n"));
1736       return 0;
1737     }
1738
1739   if (!tar_type) {
1740     printf("Option T must be followed by one of c or x.\n");
1741     return 0;
1742   }
1743
1744   /* tar_excl is true if cliplist lists files to be included.
1745    * Both 'I' and 'F' mean include. */
1746   tar_excl=tar_clipfl!='X';
1747
1748   if (tar_clipfl=='F') {
1749     if (argc-Optind-1 != 1) {
1750       DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1751       return 0;
1752     }
1753     if (! read_inclusion_file(argv[Optind+1])) {
1754       return 0;
1755     }
1756   } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1757     char *tmpstr;
1758     char **tmplist;
1759     int clipcount;
1760
1761     cliplist=argv+Optind+1;
1762     clipn=argc-Optind-1;
1763     clipcount = clipn;
1764
1765     if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1766       DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
1767                clipn)
1768            );
1769       return 0;
1770     }
1771
1772     for (clipcount = 0; clipcount < clipn; clipcount++) {
1773
1774       DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1775
1776       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1777         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1778                  clipcount)
1779              );
1780         return 0;
1781       }
1782       unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1783       tmplist[clipcount] = tmpstr;
1784       DEBUG(5, ("Processed an item, %s\n", tmpstr));
1785
1786       DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1787     }
1788     cliplist = tmplist;
1789     must_free_cliplist = True;
1790   }
1791
1792   if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
1793 #ifdef HAVE_REGEX_H
1794     int errcode;
1795
1796     if ((preg = (regex_t *)malloc(65536)) == NULL) {
1797
1798       DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1799       return;
1800
1801     }
1802
1803     if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1804       char errstr[1024];
1805       size_t errlen;
1806
1807       errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1808       
1809       DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1810       return;
1811
1812     }
1813 #endif
1814
1815     clipn=argc-Optind-1;
1816     cliplist=argv+Optind+1;
1817
1818   }
1819
1820   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1821     /* Sets tar handle to either 0 or 1, as appropriate */
1822     tarhandle=(tar_type=='c');
1823     /*
1824      * Make sure that dbf points to stderr if we are using stdout for 
1825      * tar output
1826     */
1827     if (tarhandle == 1) 
1828             setup_logging("clitar", DEBUG_STDERR);
1829   } else {
1830     if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1831       {
1832         if (!dry_run) {
1833           DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1834           dry_run = True;
1835         }
1836         tarhandle=-1;
1837       } else
1838     if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1839         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1840       {
1841         DEBUG(0,("Error opening local file %s - %s\n",
1842                  argv[Optind], strerror(errno)));
1843         return(0);
1844       }
1845   }
1846
1847   return 1;
1848 }