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