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