Apply the changes that Derrell Lipman supplied ...
[Samba/gebeck_regimport.git] / source3 / client / clitar.c
blobf38d6fe91a5a728f2e28c99c6a9c8e799597025b
1 /*
2 Unix SMB/CIFS implementation.
3 Tar Extensions
4 Copyright (C) Ricky Poulten 1995-1998
5 Copyright (C) Richard Sharpe 1998
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.
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.
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.
21 /* The following changes developed by Richard Sharpe for Canon Information
22 Systems Research Australia (CISRA)
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:
32 -TcrX file.tar "*.(obj|exe)"
34 will skip all .obj and .exe files
38 #include "includes.h"
39 #include "clitar.h"
40 #include "../client/client_proto.h"
42 static int clipfind(char **aret, int ret, char *tok);
44 typedef struct file_info_struct file_info2;
46 struct 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 */
57 file_info2 *next, *prev; /* Used in the stack ... */
60 typedef struct {
61 file_info2 *top;
62 int items;
63 } stack;
65 #define SEPARATORS " \t\n\r"
66 extern struct cli_state *cli;
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
73 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
75 #ifndef CLIENT_TIMEOUT
76 #define CLIENT_TIMEOUT (30*1000)
77 #endif
79 static char *tarbuf, *buffer_p;
80 static int tp, ntarf, tbufsiz;
81 static double ttarf;
82 /* Incremental mode */
83 static BOOL tar_inc=False;
84 /* Reset archive bit */
85 static BOOL tar_reset=False;
86 /* Include / exclude mode (true=include, false=exclude) */
87 static BOOL tar_excl=True;
88 /* use regular expressions for search on file names */
89 static BOOL tar_re_search=False;
90 #ifdef HAVE_REGEX_H
91 regex_t *preg;
92 #endif
93 /* Do not dump anything, just calculate sizes */
94 static BOOL dry_run=False;
95 /* Dump files with System attribute */
96 static BOOL tar_system=True;
97 /* Dump files with Hidden attribute */
98 static BOOL tar_hidden=True;
99 /* Be noisy - make a catalogue */
100 static BOOL tar_noisy=True;
101 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
103 char tar_type='\0';
104 static char **cliplist=NULL;
105 static int clipn=0;
106 static BOOL must_free_cliplist = False;
108 extern file_info def_finfo;
109 extern BOOL lowercase;
110 extern uint16 cnum;
111 extern BOOL readbraw_supported;
112 extern int max_xmit;
113 extern pstring cur_dir;
114 extern int get_total_time_ms;
115 extern int get_total_size;
117 static int blocksize=20;
118 static int tarhandle;
120 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
121 const char *amode, unsigned char ftype);
122 static void do_atar(char *rname,char *lname,file_info *finfo1);
123 static void do_tar(file_info *finfo);
124 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
125 static void fixtarname(char *tptr, const char *fp, size_t l);
126 static int dotarbuf(int f, char *b, int n);
127 static void dozerobuf(int f, int n);
128 static void dotareof(int f);
129 static void initarbuf(void);
131 /* restore functions */
132 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
133 static long unoct(char *p, int ndgs);
134 static void do_tarput(void);
135 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
138 * tar specific utitlities
141 /*******************************************************************
142 Create a string of size size+1 (for the null)
143 *******************************************************************/
145 static char *string_create_s(int size)
147 char *tmp;
149 tmp = (char *)malloc(size+1);
151 if (tmp == NULL) {
152 DEBUG(0, ("Out of memory in string_create_s\n"));
155 return(tmp);
158 /****************************************************************************
159 Write a tar header to buffer
160 ****************************************************************************/
162 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
163 const char *amode, unsigned char ftype)
165 union hblock hb;
166 int i, chk, l;
167 char *jp;
169 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
171 memset(hb.dummy, 0, sizeof(hb.dummy));
173 l=strlen(aname);
174 /* We will be prepending a '.' in fixtarheader so use +2 to
175 * take care of the . and terminating zero. JRA.
177 if (l+2 >= NAMSIZ) {
178 /* write a GNU tar style long header */
179 char *b;
180 b = (char *)malloc(l+TBLOCK+100);
181 if (!b) {
182 DEBUG(0,("out of memory\n"));
183 exit(1);
185 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
186 memset(b, 0, l+TBLOCK+100);
187 fixtarname(b, aname, l+2);
188 i = strlen(b)+1;
189 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
190 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
191 SAFE_FREE(b);
194 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
196 if (lowercase)
197 strlower_m(hb.dbuf.name);
199 /* write out a "standard" tar format header */
201 hb.dbuf.name[NAMSIZ-1]='\0';
202 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
203 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
204 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
205 oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
206 if (size > (SMB_BIG_UINT)077777777777LL) {
208 /* This is a non-POSIX compatible extention to store files
209 greater than 8GB. */
211 memset(hb.dbuf.size, 0, 4);
212 hb.dbuf.size[0]=128;
213 for (i = 8, jp=(char*)&size; i; i--)
214 hb.dbuf.size[i+3] = *(jp++);
216 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
217 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
218 memset(hb.dbuf.linkname, 0, NAMSIZ);
219 hb.dbuf.linkflag=ftype;
221 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
222 chk+=(0xFF & *jp++);
224 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
225 hb.dbuf.chksum[6] = '\0';
227 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
230 /****************************************************************************
231 Read a tar header into a hblock structure, and validate
232 ***************************************************************************/
234 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
236 long chk, fchk;
237 int i;
238 char *jp;
241 * read in a "standard" tar format header - we're not that interested
242 * in that many fields, though
245 /* check the checksum */
246 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
247 chk+=(0xFF & *jp++);
249 if (chk == 0)
250 return chk;
252 /* compensate for blanks in chksum header */
253 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
254 chk-=(0xFF & *jp++);
256 chk += ' ' * sizeof(hb->dbuf.chksum);
258 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
260 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
261 chk, fchk, hb->dbuf.chksum));
263 if (fchk != chk) {
264 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
265 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
266 return -1;
269 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
270 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
271 return(-1);
274 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
276 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
277 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
278 strlen(hb->dbuf.name) + 1, True);
280 /* can't handle some links at present */
281 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
282 if (hb->dbuf.linkflag == 0) {
283 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
284 finfo->name));
285 } else {
286 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
287 /* Do nothing here at the moment. do_tarput will handle this
288 as long as the longlink gets back to it, as it has to advance
289 the buffer pointer, etc */
290 } else {
291 DEBUG(0, ("this tar file appears to contain some kind \
292 of link other than a GNUtar Longlink - ignoring\n"));
293 return -2;
298 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
299 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
300 finfo->mode=aDIR;
301 } else {
302 finfo->mode=0; /* we don't care about mode at the moment, we'll
303 * just make it a regular file */
307 * Bug fix by richard@sj.co.uk
309 * REC: restore times correctly (as does tar)
310 * We only get the modification time of the file; set the creation time
311 * from the mod. time, and the access time to current time
313 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
314 finfo->atime = time(NULL);
315 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
317 return True;
320 /****************************************************************************
321 Write out the tar buffer to tape or wherever
322 ****************************************************************************/
324 static int dotarbuf(int f, char *b, int n)
326 int fail=1, writ=n;
328 if (dry_run) {
329 return writ;
331 /* This routine and the next one should be the only ones that do write()s */
332 if (tp + n >= tbufsiz) {
333 int diff;
335 diff=tbufsiz-tp;
336 memcpy(tarbuf + tp, b, diff);
337 fail=fail && (1+write(f, tarbuf, tbufsiz));
338 n-=diff;
339 b+=diff;
340 tp=0;
342 while (n >= tbufsiz) {
343 fail=fail && (1 + write(f, b, tbufsiz));
344 n-=tbufsiz;
345 b+=tbufsiz;
349 if (n>0) {
350 memcpy(tarbuf+tp, b, n);
351 tp+=n;
354 return(fail ? writ : 0);
357 /****************************************************************************
358 Write zeros to buffer / tape
359 ****************************************************************************/
361 static void dozerobuf(int f, int n)
363 /* short routine just to write out n zeros to buffer -
364 * used to round files to nearest block
365 * and to do tar EOFs */
367 if (dry_run)
368 return;
370 if (n+tp >= tbufsiz) {
371 memset(tarbuf+tp, 0, tbufsiz-tp);
372 write(f, tarbuf, tbufsiz);
373 memset(tarbuf, 0, (tp+=n-tbufsiz));
374 } else {
375 memset(tarbuf+tp, 0, n);
376 tp+=n;
380 /****************************************************************************
381 Malloc tape buffer
382 ****************************************************************************/
384 static void initarbuf(void)
386 /* initialize tar buffer */
387 tbufsiz=blocksize*TBLOCK;
388 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
390 /* reset tar buffer pointer and tar file counter and total dumped */
391 tp=0; ntarf=0; ttarf=0;
394 /****************************************************************************
395 Write two zero blocks at end of file
396 ****************************************************************************/
398 static void dotareof(int f)
400 SMB_STRUCT_STAT stbuf;
401 /* Two zero blocks at end of file, write out full buffer */
403 if (dry_run)
404 return;
406 (void) dozerobuf(f, TBLOCK);
407 (void) dozerobuf(f, TBLOCK);
409 if (sys_fstat(f, &stbuf) == -1) {
410 DEBUG(0, ("Couldn't stat file handle\n"));
411 return;
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)
417 write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
420 /****************************************************************************
421 (Un)mangle DOS pathname, make nonabsolute
422 ****************************************************************************/
424 static void fixtarname(char *tptr, const char *fp, size_t l)
426 /* add a '.' to start of file name, convert from ugly dos \'s in path
427 * to lovely unix /'s :-} */
428 *tptr++='.';
429 l--;
431 StrnCpy(tptr, fp, l-1);
432 string_replace(tptr, '\\', '/');
435 /****************************************************************************
436 Convert from decimal to octal string
437 ****************************************************************************/
439 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
441 /* Converts long to octal string, pads with leading zeros */
443 /* skip final null, but do final space */
444 --ndgs;
445 p[--ndgs] = ' ';
447 /* Loop does at least one digit */
448 do {
449 p[--ndgs] = '0' + (char) (value & 7);
450 value >>= 3;
451 } while (ndgs > 0 && value != 0);
453 /* Do leading zeros */
454 while (ndgs > 0)
455 p[--ndgs] = '0';
458 /****************************************************************************
459 Convert from octal string to long
460 ***************************************************************************/
462 static long unoct(char *p, int ndgs)
464 long value=0;
465 /* Converts octal string to long, ignoring any non-digit */
467 while (--ndgs) {
468 if (isdigit((int)*p))
469 value = (value << 3) | (long) (*p - '0');
471 p++;
474 return value;
477 /****************************************************************************
478 Compare two strings in a slash insensitive way, allowing s1 to match s2
479 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
480 a file in any subdirectory of s1, declare a match.
481 ***************************************************************************/
483 static int strslashcmp(char *s1, char *s2)
485 char *s1_0=s1;
487 while(*s1 && *s2 && (*s1 == *s2 || tolower(*s1) == tolower(*s2) ||
488 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
489 s1++; s2++;
492 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
493 string of s2.
495 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
496 return 0;
498 /* ignore trailing slash on s1 */
499 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
500 return 0;
502 /* check for s1 is an "initial" string of s2 */
503 if ((*s2 == '/' || *s2 == '\\') && !*s1)
504 return 0;
506 return *s1-*s2;
509 /****************************************************************************
510 Ensure a remote path exists (make if necessary)
511 ***************************************************************************/
513 static BOOL ensurepath(char *fname)
515 /* *must* be called with buffer ready malloc'ed */
516 /* ensures path exists */
518 char *partpath, *ffname;
519 char *p=fname, *basehack;
521 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
523 partpath = string_create_s(strlen(fname));
524 ffname = string_create_s(strlen(fname));
526 if ((partpath == NULL) || (ffname == NULL)){
527 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
528 return(False);
531 *partpath = 0;
533 /* fname copied to ffname so can strtok */
535 safe_strcpy(ffname, fname, strlen(fname));
537 /* do a `basename' on ffname, so don't try and make file name directory */
538 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
539 return True;
540 else
541 *basehack='\0';
543 p=strtok(ffname, "\\");
545 while (p) {
546 safe_strcat(partpath, p, strlen(fname) + 1);
548 if (!cli_chkpath(cli, partpath)) {
549 if (!cli_mkdir(cli, partpath)) {
550 DEBUG(0, ("Error mkdirhiering\n"));
551 return False;
552 } else {
553 DEBUG(3, ("mkdirhiering %s\n", partpath));
557 safe_strcat(partpath, "\\", strlen(fname) + 1);
558 p = strtok(NULL,"/\\");
561 return True;
564 static int padit(char *buf, int bufsize, int padsize)
566 int berr= 0;
567 int bytestowrite;
569 DEBUG(5, ("Padding with %d zeros\n", padsize));
570 memset(buf, 0, bufsize);
571 while( !berr && padsize > 0 ) {
572 bytestowrite= MIN(bufsize, padsize);
573 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
574 padsize -= bytestowrite;
577 return berr;
580 static void do_setrattr(char *name, uint16 attr, int set)
582 uint16 oldattr;
584 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
586 if (set == ATTRSET) {
587 attr |= oldattr;
588 } else {
589 attr = oldattr & ~attr;
592 if (!cli_setatr(cli, name, attr, 0)) {
593 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
597 /****************************************************************************
598 append one remote file to the tar file
599 ***************************************************************************/
601 static void do_atar(char *rname,char *lname,file_info *finfo1)
603 int fnum;
604 SMB_BIG_UINT nread=0;
605 char ftype;
606 file_info2 finfo;
607 BOOL close_done = False;
608 BOOL shallitime=True;
609 char data[65520];
610 int read_size = 65520;
611 int datalen=0;
613 struct timeval tp_start;
615 GetTimeOfDay(&tp_start);
617 ftype = '0'; /* An ordinary file ... */
619 if (finfo1) {
620 finfo.size = finfo1 -> size;
621 finfo.mode = finfo1 -> mode;
622 finfo.uid = finfo1 -> uid;
623 finfo.gid = finfo1 -> gid;
624 finfo.mtime = finfo1 -> mtime;
625 finfo.atime = finfo1 -> atime;
626 finfo.ctime = finfo1 -> ctime;
627 finfo.name = finfo1 -> name;
628 } else {
629 finfo.size = def_finfo.size;
630 finfo.mode = def_finfo.mode;
631 finfo.uid = def_finfo.uid;
632 finfo.gid = def_finfo.gid;
633 finfo.mtime = def_finfo.mtime;
634 finfo.atime = def_finfo.atime;
635 finfo.ctime = def_finfo.ctime;
636 finfo.name = def_finfo.name;
639 if (dry_run) {
640 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
641 (double)finfo.size));
642 shallitime=0;
643 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
644 ntarf++;
645 return;
648 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
650 dos_clean_name(rname);
652 if (fnum == -1) {
653 DEBUG(0,("%s opening remote file %s (%s)\n",
654 cli_errstr(cli),rname, cur_dir));
655 return;
658 finfo.name = string_create_s(strlen(rname));
659 if (finfo.name == NULL) {
660 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
661 return;
664 safe_strcpy(finfo.name,rname, strlen(rname));
665 if (!finfo1) {
666 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
667 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
668 return;
670 finfo.ctime = finfo.mtime;
673 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
675 if (tar_inc && !(finfo.mode & aARCH)) {
676 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
677 shallitime=0;
678 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
679 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
680 shallitime=0;
681 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
682 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
683 shallitime=0;
684 } else {
685 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
686 finfo.name, (double)finfo.size, lname));
688 /* write a tar header, don't bother with mode - just set to 100644 */
689 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
691 while (nread < finfo.size && !close_done) {
693 DEBUG(3,("nread=%.0f\n",(double)nread));
695 datalen = cli_read(cli, fnum, data, nread, read_size);
697 if (datalen == -1) {
698 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
699 break;
702 nread += datalen;
704 /* if file size has increased since we made file size query, truncate
705 read so tar header for this file will be correct.
708 if (nread > finfo.size) {
709 datalen -= nread - finfo.size;
710 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
711 finfo.name, (double)finfo.size));
714 /* add received bits of file to buffer - dotarbuf will
715 * write out in 512 byte intervals */
717 if (dotarbuf(tarhandle,data,datalen) != datalen) {
718 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
719 break;
722 if (datalen == 0) {
723 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
724 break;
727 datalen=0;
730 /* pad tar file with zero's if we couldn't get entire file */
731 if (nread < finfo.size) {
732 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
733 (double)finfo.size, (int)nread));
734 if (padit(data, sizeof(data), finfo.size - nread))
735 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
738 /* round tar file to nearest block */
739 if (finfo.size % TBLOCK)
740 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
742 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
743 ntarf++;
746 cli_close(cli, fnum);
748 if (shallitime) {
749 struct timeval tp_end;
750 int this_time;
752 /* if shallitime is true then we didn't skip */
753 if (tar_reset && !dry_run)
754 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
756 GetTimeOfDay(&tp_end);
757 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
758 get_total_time_ms += this_time;
759 get_total_size += finfo.size;
761 if (tar_noisy) {
762 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
763 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
764 finfo.name));
767 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
768 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
769 finfo.size / MAX(0.001, (1.024*this_time)),
770 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
774 /****************************************************************************
775 Append single file to tar file (or not)
776 ***************************************************************************/
778 static void do_tar(file_info *finfo)
780 pstring rname;
782 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
783 return;
785 /* Is it on the exclude list ? */
786 if (!tar_excl && clipn) {
787 pstring exclaim;
789 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
791 pstrcpy(exclaim, cur_dir);
792 *(exclaim+strlen(exclaim)-1)='\0';
794 pstrcat(exclaim, "\\");
795 pstrcat(exclaim, finfo->name);
797 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
799 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
800 #ifdef HAVE_REGEX_H
801 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
802 #else
803 (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
804 #endif
805 DEBUG(3,("Skipping file %s\n", exclaim));
806 return;
810 if (finfo->mode & aDIR) {
811 pstring saved_curdir;
812 pstring mtar_mask;
814 pstrcpy(saved_curdir, cur_dir);
816 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
817 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
818 (int)sizeof(cur_dir), (int)strlen(cur_dir),
819 (int)strlen(finfo->name), finfo->name, cur_dir));
821 pstrcat(cur_dir,finfo->name);
822 pstrcat(cur_dir,"\\");
824 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
826 /* write a tar directory, don't bother with mode - just set it to
827 * 40755 */
828 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
829 if (tar_noisy) {
830 DEBUG(0,(" directory %s\n", cur_dir));
832 ntarf++; /* Make sure we have a file on there */
833 pstrcpy(mtar_mask,cur_dir);
834 pstrcat(mtar_mask,"*");
835 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
836 do_list(mtar_mask, attribute, do_tar, False, True);
837 pstrcpy(cur_dir,saved_curdir);
838 } else {
839 pstrcpy(rname,cur_dir);
840 pstrcat(rname,finfo->name);
841 do_atar(rname,finfo->name,finfo);
845 /****************************************************************************
846 Convert from UNIX to DOS file names
847 ***************************************************************************/
849 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
851 /* remove '.' from start of file name, convert from unix /'s to
852 * dos \'s in path. Kill any absolute path names. But only if first!
855 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
857 if (first) {
858 if (*fp == '.') {
859 fp++;
860 l--;
862 if (*fp == '\\' || *fp == '/') {
863 fp++;
864 l--;
868 safe_strcpy(tptr, fp, l);
869 string_replace(tptr, '/', '\\');
872 /****************************************************************************
873 Move to the next block in the buffer, which may mean read in another set of
874 blocks. FIXME, we should allow more than one block to be skipped.
875 ****************************************************************************/
877 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
879 int bufread, total = 0;
881 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
882 *bufferp += TBLOCK;
883 total = TBLOCK;
885 if (*bufferp >= (ltarbuf + bufsiz)) {
887 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
890 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
891 * Fixes bug where read can return short if coming from
892 * a pipe.
895 bufread = read(tarhandle, ltarbuf, bufsiz);
896 total = bufread;
898 while (total < bufsiz) {
899 if (bufread < 0) { /* An error, return false */
900 return (total > 0 ? -2 : bufread);
902 if (bufread == 0) {
903 if (total <= 0) {
904 return -2;
906 break;
908 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
909 total += bufread;
912 DEBUG(5, ("Total bytes read ... %i\n", total));
914 *bufferp = ltarbuf;
917 return(total);
920 /* Skip a file, even if it includes a long file name? */
921 static int skip_file(int skipsize)
923 int dsize = skipsize;
925 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
927 /* FIXME, we should skip more than one block at a time */
929 while (dsize > 0) {
930 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
931 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
932 return(False);
934 dsize -= TBLOCK;
937 return(True);
940 /*************************************************************
941 Get a file from the tar file and store it.
942 When this is called, tarbuf already contains the first
943 file block. This is a bit broken & needs fixing.
944 **************************************************************/
946 static int get_file(file_info2 finfo)
948 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
949 SMB_BIG_UINT rsize = 0;
951 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
953 if (ensurepath(finfo.name) &&
954 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
955 DEBUG(0, ("abandoning restore\n"));
956 return(False);
959 /* read the blocks from the tar file and write to the remote file */
961 rsize = finfo.size; /* This is how much to write */
963 while (rsize > 0) {
965 /* We can only write up to the end of the buffer */
966 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
967 dsize = MIN(dsize, rsize); /* Should be only what is left */
968 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
970 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
971 DEBUG(0, ("Error writing remote file\n"));
972 return 0;
975 rsize -= dsize;
976 pos += dsize;
978 /* Now figure out how much to move in the buffer */
980 /* FIXME, we should skip more than one block at a time */
982 /* First, skip any initial part of the part written that is left over */
983 /* from the end of the first TBLOCK */
985 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
986 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
987 bpos = 0;
989 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
990 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
991 return False;
996 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
997 * If the file being extracted is an exact multiple of
998 * TBLOCK bytes then we don't want to extract the next
999 * block from the tarfile here, as it will be done in
1000 * the caller of get_file().
1003 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1004 ((rsize == 0) && (dsize > TBLOCK))) {
1006 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1007 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1008 return False;
1011 dsize -= TBLOCK;
1013 bpos = dsize;
1016 /* Now close the file ... */
1018 if (!cli_close(cli, fnum)) {
1019 DEBUG(0, ("Error closing remote file\n"));
1020 return(False);
1023 /* Now we update the creation date ... */
1024 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1026 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1027 if (tar_real_noisy) {
1028 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1029 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1033 ntarf++;
1034 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1035 return(True);
1038 /* Create a directory. We just ensure that the path exists and return as there
1039 is no file associated with a directory
1041 static int get_dir(file_info2 finfo)
1043 DEBUG(0, ("restore directory %s\n", finfo.name));
1045 if (!ensurepath(finfo.name)) {
1046 DEBUG(0, ("Problems creating directory\n"));
1047 return(False);
1049 ntarf++;
1050 return(True);
1053 /* Get a file with a long file name ... first file has file name, next file
1054 has the data. We only want the long file name, as the loop in do_tarput
1055 will deal with the rest.
1057 static char *get_longfilename(file_info2 finfo)
1059 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1060 * header call. */
1061 int namesize = finfo.size + strlen(cur_dir) + 2;
1062 char *longname = malloc(namesize);
1063 int offset = 0, left = finfo.size;
1064 BOOL first = True;
1066 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1067 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1069 if (longname == NULL) {
1070 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1071 return(NULL);
1074 /* First, add cur_dir to the long file name */
1076 if (strlen(cur_dir) > 0) {
1077 strncpy(longname, cur_dir, namesize);
1078 offset = strlen(cur_dir);
1081 /* Loop through the blocks picking up the name */
1083 while (left > 0) {
1084 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1085 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1086 return(NULL);
1089 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1090 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1092 offset += TBLOCK;
1093 left -= TBLOCK;
1096 return(longname);
1099 static void do_tarput(void)
1101 file_info2 finfo;
1102 struct timeval tp_start;
1103 char *longfilename = NULL, linkflag;
1104 int skip = False;
1106 GetTimeOfDay(&tp_start);
1107 DEBUG(5, ("RJS do_tarput called ...\n"));
1109 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1111 /* Now read through those files ... */
1112 while (True) {
1113 /* Get us to the next block, or the first block first time around */
1114 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1115 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1116 return;
1119 DEBUG(5, ("Reading the next header ...\n"));
1121 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1122 case -2: /* Hmm, not good, but not fatal */
1123 DEBUG(0, ("Skipping %s...\n", finfo.name));
1124 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1125 DEBUG(0, ("Short file, bailing out...\n"));
1126 return;
1128 break;
1130 case -1:
1131 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1132 return;
1134 case 0: /* chksum is zero - looks like an EOF */
1135 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1136 return; /* Hmmm, bad here ... */
1138 default:
1139 /* No action */
1140 break;
1143 /* Now, do we have a long file name? */
1144 if (longfilename != NULL) {
1145 SAFE_FREE(finfo.name); /* Free the space already allocated */
1146 finfo.name = longfilename;
1147 longfilename = NULL;
1150 /* Well, now we have a header, process the file ... */
1151 /* Should we skip the file? We have the long name as well here */
1152 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1153 #ifdef HAVE_REGEX_H
1154 (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1155 #else
1156 (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
1157 #endif
1159 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1160 if (skip) {
1161 skip_file(finfo.size);
1162 continue;
1165 /* We only get this far if we should process the file */
1166 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1167 switch (linkflag) {
1168 case '0': /* Should use symbolic names--FIXME */
1170 * Skip to the next block first, so we can get the file, FIXME, should
1171 * be in get_file ...
1172 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1173 * Fixes bug where file size in tarfile is zero.
1175 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1176 DEBUG(0, ("Short file, bailing out...\n"));
1177 return;
1179 if (!get_file(finfo)) {
1180 DEBUG(0, ("Abandoning restore\n"));
1181 return;
1183 break;
1184 case '5':
1185 if (!get_dir(finfo)) {
1186 DEBUG(0, ("Abandoning restore \n"));
1187 return;
1189 break;
1190 case 'L':
1191 longfilename = get_longfilename(finfo);
1192 if (!longfilename) {
1193 DEBUG(0, ("abandoning restore\n"));
1194 return;
1196 DEBUG(5, ("Long file name: %s\n", longfilename));
1197 break;
1199 default:
1200 skip_file(finfo.size); /* Don't handle these yet */
1201 break;
1207 * samba interactive commands
1210 /****************************************************************************
1211 Blocksize command
1212 ***************************************************************************/
1214 int cmd_block(void)
1216 fstring buf;
1217 int block;
1219 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1220 DEBUG(0, ("blocksize <n>\n"));
1221 return 1;
1224 block=atoi(buf);
1225 if (block < 0 || block > 65535) {
1226 DEBUG(0, ("blocksize out of range"));
1227 return 1;
1230 blocksize=block;
1231 DEBUG(2,("blocksize is now %d\n", blocksize));
1233 return 0;
1236 /****************************************************************************
1237 command to set incremental / reset mode
1238 ***************************************************************************/
1240 int cmd_tarmode(void)
1242 fstring buf;
1244 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1245 if (strequal(buf, "full"))
1246 tar_inc=False;
1247 else if (strequal(buf, "inc"))
1248 tar_inc=True;
1249 else if (strequal(buf, "reset"))
1250 tar_reset=True;
1251 else if (strequal(buf, "noreset"))
1252 tar_reset=False;
1253 else if (strequal(buf, "system"))
1254 tar_system=True;
1255 else if (strequal(buf, "nosystem"))
1256 tar_system=False;
1257 else if (strequal(buf, "hidden"))
1258 tar_hidden=True;
1259 else if (strequal(buf, "nohidden"))
1260 tar_hidden=False;
1261 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1262 tar_noisy=True;
1263 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1264 tar_noisy=False;
1265 else
1266 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1269 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1270 tar_inc ? "incremental" : "full",
1271 tar_system ? "system" : "nosystem",
1272 tar_hidden ? "hidden" : "nohidden",
1273 tar_reset ? "reset" : "noreset",
1274 tar_noisy ? "verbose" : "quiet"));
1275 return 0;
1278 /****************************************************************************
1279 Feeble attrib command
1280 ***************************************************************************/
1282 int cmd_setmode(void)
1284 char *q;
1285 fstring buf;
1286 pstring fname;
1287 uint16 attra[2];
1288 int direct=1;
1290 attra[0] = attra[1] = 0;
1292 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1293 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1294 return 1;
1297 pstrcpy(fname, cur_dir);
1298 pstrcat(fname, buf);
1300 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1301 q=buf;
1303 while(*q) {
1304 switch (*q++) {
1305 case '+':
1306 direct=1;
1307 break;
1308 case '-':
1309 direct=0;
1310 break;
1311 case 'r':
1312 attra[direct]|=aRONLY;
1313 break;
1314 case 'h':
1315 attra[direct]|=aHIDDEN;
1316 break;
1317 case 's':
1318 attra[direct]|=aSYSTEM;
1319 break;
1320 case 'a':
1321 attra[direct]|=aARCH;
1322 break;
1323 default:
1324 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1325 return 1;
1330 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1331 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1332 return 1;
1335 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1336 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1337 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1338 return 0;
1341 /****************************************************************************
1342 Principal command for creating / extracting
1343 ***************************************************************************/
1345 int cmd_tar(void)
1347 fstring buf;
1348 char **argl;
1349 int argcl;
1351 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1352 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1353 return 1;
1356 argl=toktocliplist(&argcl, NULL);
1357 if (!tar_parseargs(argcl, argl, buf, 0))
1358 return 1;
1360 process_tar();
1361 SAFE_FREE(argl);
1362 return 0;
1365 /****************************************************************************
1366 Command line (option) version
1367 ***************************************************************************/
1369 int process_tar(void)
1371 initarbuf();
1372 switch(tar_type) {
1373 case 'x':
1375 #if 0
1376 do_tarput2();
1377 #else
1378 do_tarput();
1379 #endif
1380 SAFE_FREE(tarbuf);
1381 close(tarhandle);
1382 break;
1383 case 'r':
1384 case 'c':
1385 if (clipn && tar_excl) {
1386 int i;
1387 pstring tarmac;
1389 for (i=0; i<clipn; i++) {
1390 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1392 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1393 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1396 if (strrchr_m(cliplist[i], '\\')) {
1397 pstring saved_dir;
1399 pstrcpy(saved_dir, cur_dir);
1401 if (*cliplist[i]=='\\') {
1402 pstrcpy(tarmac, cliplist[i]);
1403 } else {
1404 pstrcpy(tarmac, cur_dir);
1405 pstrcat(tarmac, cliplist[i]);
1407 pstrcpy(cur_dir, tarmac);
1408 *(strrchr_m(cur_dir, '\\')+1)='\0';
1410 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1411 do_list(tarmac,attribute,do_tar, False, True);
1412 pstrcpy(cur_dir,saved_dir);
1413 } else {
1414 pstrcpy(tarmac, cur_dir);
1415 pstrcat(tarmac, cliplist[i]);
1416 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1417 do_list(tarmac,attribute,do_tar, False, True);
1420 } else {
1421 pstring mask;
1422 pstrcpy(mask,cur_dir);
1423 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1424 pstrcat(mask,"\\*");
1425 do_list(mask,attribute,do_tar,False, True);
1428 if (ntarf)
1429 dotareof(tarhandle);
1430 close(tarhandle);
1431 SAFE_FREE(tarbuf);
1433 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1434 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1435 break;
1438 if (must_free_cliplist) {
1439 int i;
1440 for (i = 0; i < clipn; ++i) {
1441 SAFE_FREE(cliplist[i]);
1443 SAFE_FREE(cliplist);
1444 cliplist = NULL;
1445 clipn = 0;
1446 must_free_cliplist = False;
1448 return(0);
1451 /****************************************************************************
1452 Find a token (filename) in a clip list
1453 ***************************************************************************/
1455 static int clipfind(char **aret, int ret, char *tok)
1457 if (aret==NULL)
1458 return 0;
1460 /* ignore leading slashes or dots in token */
1461 while(strchr_m("/\\.", *tok))
1462 tok++;
1464 while(ret--) {
1465 char *pkey=*aret++;
1467 /* ignore leading slashes or dots in list */
1468 while(strchr_m("/\\.", *pkey))
1469 pkey++;
1471 if (!strslashcmp(pkey, tok))
1472 return 1;
1474 return 0;
1477 /****************************************************************************
1478 Read list of files to include from the file and initialize cliplist
1479 accordingly.
1480 ***************************************************************************/
1482 static int read_inclusion_file(char *filename)
1484 XFILE *inclusion = NULL;
1485 char buf[PATH_MAX + 1];
1486 char *inclusion_buffer = NULL;
1487 int inclusion_buffer_size = 0;
1488 int inclusion_buffer_sofar = 0;
1489 char *p;
1490 char *tmpstr;
1491 int i;
1492 int error = 0;
1494 clipn = 0;
1495 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1496 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1497 /* XXX It would be better to include a reason for failure, but without
1498 * autoconf, it's hard to use strerror, sys_errlist, etc.
1500 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1501 return 0;
1504 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1505 if (inclusion_buffer == NULL) {
1506 inclusion_buffer_size = 1024;
1507 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1508 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1509 error = 1;
1510 break;
1514 if (buf[strlen(buf)-1] == '\n') {
1515 buf[strlen(buf)-1] = '\0';
1518 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1519 char *ib;
1520 inclusion_buffer_size *= 2;
1521 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1522 if (! ib) {
1523 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1524 inclusion_buffer_size));
1525 error = 1;
1526 break;
1527 } else {
1528 inclusion_buffer = ib;
1532 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1533 inclusion_buffer_sofar += strlen(buf) + 1;
1534 clipn++;
1536 x_fclose(inclusion);
1538 if (! error) {
1539 /* Allocate an array of clipn + 1 char*'s for cliplist */
1540 cliplist = malloc((clipn + 1) * sizeof(char *));
1541 if (cliplist == NULL) {
1542 DEBUG(0,("failure allocating memory for cliplist\n"));
1543 error = 1;
1544 } else {
1545 cliplist[clipn] = NULL;
1546 p = inclusion_buffer;
1547 for (i = 0; (! error) && (i < clipn); i++) {
1548 /* set current item to NULL so array will be null-terminated even if
1549 * malloc fails below. */
1550 cliplist[i] = NULL;
1551 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1552 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1553 error = 1;
1554 } else {
1555 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1556 cliplist[i] = tmpstr;
1557 if ((p = strchr_m(p, '\000')) == NULL) {
1558 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1559 abort();
1562 ++p;
1564 must_free_cliplist = True;
1568 SAFE_FREE(inclusion_buffer);
1569 if (error) {
1570 if (cliplist) {
1571 char **pp;
1572 /* We know cliplist is always null-terminated */
1573 for (pp = cliplist; *pp; ++pp) {
1574 SAFE_FREE(*pp);
1576 SAFE_FREE(cliplist);
1577 cliplist = NULL;
1578 must_free_cliplist = False;
1580 return 0;
1583 /* cliplist and its elements are freed at the end of process_tar. */
1584 return 1;
1587 /****************************************************************************
1588 Parse tar arguments. Sets tar_type, tar_excl, etc.
1589 ***************************************************************************/
1591 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1593 int newOptind = Optind;
1594 char tar_clipfl='\0';
1596 /* Reset back to defaults - could be from interactive version
1597 * reset mode and archive mode left as they are though
1599 tar_type='\0';
1600 tar_excl=True;
1601 dry_run=False;
1603 while (*Optarg) {
1604 switch(*Optarg++) {
1605 case 'c':
1606 tar_type='c';
1607 break;
1608 case 'x':
1609 if (tar_type=='c') {
1610 printf("Tar must be followed by only one of c or x.\n");
1611 return 0;
1613 tar_type='x';
1614 break;
1615 case 'b':
1616 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1617 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1618 return 0;
1619 } else {
1620 Optind++;
1621 newOptind++;
1623 break;
1624 case 'g':
1625 tar_inc=True;
1626 break;
1627 case 'N':
1628 if (Optind>=argc) {
1629 DEBUG(0,("Option N must be followed by valid file name\n"));
1630 return 0;
1631 } else {
1632 SMB_STRUCT_STAT stbuf;
1633 extern time_t newer_than;
1635 if (sys_stat(argv[Optind], &stbuf) == 0) {
1636 newer_than = stbuf.st_mtime;
1637 DEBUG(1,("Getting files newer than %s",
1638 asctime(LocalTime(&newer_than))));
1639 newOptind++;
1640 Optind++;
1641 } else {
1642 DEBUG(0,("Error setting newer-than time\n"));
1643 return 0;
1646 break;
1647 case 'a':
1648 tar_reset=True;
1649 break;
1650 case 'q':
1651 tar_noisy=False;
1652 break;
1653 case 'I':
1654 if (tar_clipfl) {
1655 DEBUG(0,("Only one of I,X,F must be specified\n"));
1656 return 0;
1658 tar_clipfl='I';
1659 break;
1660 case 'X':
1661 if (tar_clipfl) {
1662 DEBUG(0,("Only one of I,X,F must be specified\n"));
1663 return 0;
1665 tar_clipfl='X';
1666 break;
1667 case 'F':
1668 if (tar_clipfl) {
1669 DEBUG(0,("Only one of I,X,F must be specified\n"));
1670 return 0;
1672 tar_clipfl='F';
1673 break;
1674 case 'r':
1675 DEBUG(0, ("tar_re_search set\n"));
1676 tar_re_search = True;
1677 break;
1678 case 'n':
1679 if (tar_type == 'c') {
1680 DEBUG(0, ("dry_run set\n"));
1681 dry_run = True;
1682 } else {
1683 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1684 return 0;
1686 break;
1687 default:
1688 DEBUG(0,("Unknown tar option\n"));
1689 return 0;
1693 if (!tar_type) {
1694 printf("Option T must be followed by one of c or x.\n");
1695 return 0;
1698 /* tar_excl is true if cliplist lists files to be included.
1699 * Both 'I' and 'F' mean include. */
1700 tar_excl=tar_clipfl!='X';
1702 if (tar_clipfl=='F') {
1703 if (argc-Optind-1 != 1) {
1704 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1705 return 0;
1707 newOptind++;
1708 Optind++;
1709 if (! read_inclusion_file(argv[Optind])) {
1710 return 0;
1712 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1713 char *tmpstr;
1714 char **tmplist;
1715 int clipcount;
1717 cliplist=argv+Optind+1;
1718 clipn=argc-Optind-1;
1719 clipcount = clipn;
1721 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1722 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1723 return 0;
1726 for (clipcount = 0; clipcount < clipn; clipcount++) {
1728 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1730 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1731 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1732 return 0;
1735 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1736 tmplist[clipcount] = tmpstr;
1737 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1739 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1742 cliplist = tmplist;
1743 must_free_cliplist = True;
1745 newOptind += clipn;
1748 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1749 #ifdef HAVE_REGEX_H
1750 int errcode;
1752 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1754 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1755 return;
1758 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1759 char errstr[1024];
1760 size_t errlen;
1762 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1763 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1764 return;
1766 #endif
1768 clipn=argc-Optind-1;
1769 cliplist=argv+Optind+1;
1770 newOptind += clipn;
1773 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1774 /* Sets tar handle to either 0 or 1, as appropriate */
1775 tarhandle=(tar_type=='c');
1777 * Make sure that dbf points to stderr if we are using stdout for
1778 * tar output
1780 if (tarhandle == 1) {
1781 dbf = x_stderr;
1783 if (!argv[Optind]) {
1784 DEBUG(0,("Must specify tar filename\n"));
1785 return 0;
1787 if (!strcmp(argv[Optind], "-")) {
1788 newOptind++;
1791 } else {
1792 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0)) {
1793 if (!dry_run) {
1794 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1795 dry_run = True;
1797 tarhandle=-1;
1798 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1799 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1800 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1801 return(0);
1803 newOptind++;
1806 return newOptind;