make man
[Samba.git] / source / client / clitar.c
blob50a46c700074f9e1d0eef5348fb99bb94c9213b7
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Tar Extensions
5 Copyright (C) Ricky Poulten 1995-1998
6 Copyright (C) Richard Sharpe 1998
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* The following changes developed by Richard Sharpe for Canon Information
23 Systems Research Australia (CISRA)
25 1. Restore can now restore files with long file names
26 2. Save now saves directory information so that we can restore
27 directory creation times
28 3. tar now accepts both UNIX path names and DOS path names. I prefer
29 those lovely /'s to those UGLY \'s :-)
30 4. the files to exclude can be specified as a regular expression by adding
31 an r flag to the other tar flags. Eg:
33 -TcrX file.tar "*.(obj|exe)"
35 will skip all .obj and .exe files
39 #include "includes.h"
40 #include "clitar.h"
42 static int clipfind(char **aret, int ret, char *tok);
44 typedef struct file_info_struct file_info2;
46 struct file_info_struct
48 size_t size;
49 uint16 mode;
50 int uid;
51 int gid;
52 /* These times are normally kept in GMT */
53 time_t mtime;
54 time_t atime;
55 time_t ctime;
56 char *name; /* This is dynamically allocate */
58 file_info2 *next, *prev; /* Used in the stack ... */
62 typedef struct
64 file_info2 *top;
65 int items;
67 } stack;
69 stack dir_stack = {NULL, 0}; /* Want an empty stack */
71 #define SEPARATORS " \t\n\r"
72 extern struct cli_state *cli;
73 extern FILE *dbf;
75 /* These defines are for the do_setrattr routine, to indicate
76 * setting and reseting of file attributes in the function call */
77 #define ATTRSET 1
78 #define ATTRRESET 0
80 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
82 #ifndef CLIENT_TIMEOUT
83 #define CLIENT_TIMEOUT (30*1000)
84 #endif
86 static char *tarbuf, *buffer_p;
87 static int tp, ntarf, tbufsiz;
88 static double ttarf;
89 /* Incremental mode */
90 BOOL tar_inc=False;
91 /* Reset archive bit */
92 BOOL tar_reset=False;
93 /* Include / exclude mode (true=include, false=exclude) */
94 BOOL tar_excl=True;
95 /* use regular expressions for search on file names */
96 BOOL tar_re_search=False;
97 #ifdef HAVE_REGEX_H
98 regex_t *preg;
99 #endif
100 /* Do not dump anything, just calculate sizes */
101 BOOL dry_run=False;
102 /* Dump files with System attribute */
103 BOOL tar_system=True;
104 /* Dump files with Hidden attribute */
105 BOOL tar_hidden=True;
106 /* Be noisy - make a catalogue */
107 BOOL tar_noisy=True;
108 BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
110 char tar_type='\0';
111 static char **cliplist=NULL;
112 static int clipn=0;
113 static BOOL must_free_cliplist = False;
115 extern file_info def_finfo;
116 extern BOOL lowercase;
117 extern uint16 cnum;
118 extern BOOL readbraw_supported;
119 extern int max_xmit;
120 extern pstring cur_dir;
121 extern int get_total_time_ms;
122 extern int get_total_size;
123 extern int Protocol;
125 int blocksize=20;
126 int tarhandle;
128 static void writetarheader(int f, char *aname, int size, time_t mtime,
129 char *amode, unsigned char ftype);
130 static void do_atar(char *rname,char *lname,file_info *finfo1);
131 static void do_tar(file_info *finfo);
132 static void oct_it(long value, int ndgs, char *p);
133 static void fixtarname(char *tptr, char *fp, int l);
134 static int dotarbuf(int f, char *b, int n);
135 static void dozerobuf(int f, int n);
136 static void dotareof(int f);
137 static void initarbuf(void);
139 /* restore functions */
140 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
141 static long unoct(char *p, int ndgs);
142 static void do_tarput(void);
143 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
146 * tar specific utitlities
149 /*******************************************************************
150 Create a string of size size+1 (for the null)
151 *******************************************************************/
152 static char *string_create_s(int size)
154 char *tmp;
156 tmp = (char *)malloc(size+1);
158 if (tmp == NULL) {
160 DEBUG(0, ("Out of memory in string_create_s\n"));
164 return(tmp);
168 /****************************************************************************
169 Write a tar header to buffer
170 ****************************************************************************/
171 static void writetarheader(int f, char *aname, int size, time_t mtime,
172 char *amode, unsigned char ftype)
174 union hblock hb;
175 int i, chk, l;
176 char *jp;
178 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
180 memset(hb.dummy, 0, sizeof(hb.dummy));
182 l=strlen(aname);
183 if (l >= NAMSIZ - 1) {
184 /* write a GNU tar style long header */
185 char *b;
186 b = (char *)malloc(l+TBLOCK+100);
187 if (!b) {
188 DEBUG(0,("out of memory\n"));
189 exit(1);
191 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
192 memset(b, 0, l+TBLOCK+100);
193 fixtarname(b, aname, l);
194 i = strlen(b)+1;
195 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
196 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
197 SAFE_FREE(b);
200 /* use l + 1 to do the null too */
201 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
203 if (lowercase)
204 strlower(hb.dbuf.name);
206 /* write out a "standard" tar format header */
208 hb.dbuf.name[NAMSIZ-1]='\0';
209 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
210 oct_it(0L, 8, hb.dbuf.uid);
211 oct_it(0L, 8, hb.dbuf.gid);
212 oct_it((long) size, 13, hb.dbuf.size);
213 oct_it((long) 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;
218 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
220 oct_it((long) chk, 8, hb.dbuf.chksum);
221 hb.dbuf.chksum[6] = '\0';
223 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
226 /****************************************************************************
227 Read a tar header into a hblock structure, and validate
228 ***************************************************************************/
229 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
231 long chk, fchk;
232 int i;
233 char *jp;
236 * read in a "standard" tar format header - we're not that interested
237 * in that many fields, though
240 /* check the checksum */
241 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
243 if (chk == 0)
244 return chk;
246 /* compensate for blanks in chksum header */
247 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
248 chk-=(0xFF & *jp++);
250 chk += ' ' * sizeof(hb->dbuf.chksum);
252 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
254 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
255 chk, fchk, hb->dbuf.chksum));
257 if (fchk != chk)
259 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
260 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
261 return -1;
264 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
266 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
267 return(-1);
271 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
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);
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 */
288 } else {
289 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
290 return -2;
295 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
296 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
298 finfo->mode=aDIR;
300 else
301 finfo->mode=0; /* we don't care about mode at the moment, we'll
302 * just make it a regular file */
304 * Bug fix by richard@sj.co.uk
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
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));
314 return True;
317 /****************************************************************************
318 Write out the tar buffer to tape or wherever
319 ****************************************************************************/
320 static int dotarbuf(int f, char *b, int n)
322 int fail=1, writ=n;
324 if (dry_run) {
325 return writ;
327 /* This routine and the next one should be the only ones that do write()s */
328 if (tp + n >= tbufsiz)
330 int diff;
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;
339 while (n >= tbufsiz)
341 fail=fail && (1 + write(f, b, tbufsiz));
342 n-=tbufsiz;
343 b+=tbufsiz;
346 if (n>0) {
347 memcpy(tarbuf+tp, b, n);
348 tp+=n;
351 return(fail ? writ : 0);
354 /****************************************************************************
355 Write zeros to buffer / tape
356 ****************************************************************************/
357 static void dozerobuf(int f, int n)
359 /* short routine just to write out n zeros to buffer -
360 * used to round files to nearest block
361 * and to do tar EOFs */
363 if (dry_run)
364 return;
366 if (n+tp >= tbufsiz)
368 memset(tarbuf+tp, 0, tbufsiz-tp);
370 write(f, tarbuf, tbufsiz);
371 memset(tarbuf, 0, (tp+=n-tbufsiz));
373 else
375 memset(tarbuf+tp, 0, n);
376 tp+=n;
380 /****************************************************************************
381 Malloc tape buffer
382 ****************************************************************************/
383 static void initarbuf(void)
385 /* initialize tar buffer */
386 tbufsiz=blocksize*TBLOCK;
387 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
389 /* reset tar buffer pointer and tar file counter and total dumped */
390 tp=0; ntarf=0; ttarf=0;
393 /****************************************************************************
394 Write two zero blocks at end of file
395 ****************************************************************************/
396 static void dotareof(int f)
398 SMB_STRUCT_STAT stbuf;
399 /* Two zero blocks at end of file, write out full buffer */
401 if (dry_run)
402 return;
404 (void) dozerobuf(f, TBLOCK);
405 (void) dozerobuf(f, TBLOCK);
407 if (sys_fstat(f, &stbuf) == -1)
409 DEBUG(0, ("Couldn't stat file handle\n"));
410 return;
413 /* Could be a pipe, in which case S_ISREG should fail,
414 * and we should write out at full size */
415 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
418 /****************************************************************************
419 (Un)mangle DOS pathname, make nonabsolute
420 ****************************************************************************/
421 static void fixtarname(char *tptr, char *fp, int l)
423 /* add a '.' to start of file name, convert from ugly dos \'s in path
424 * to lovely unix /'s :-} */
426 *tptr++='.';
428 while (l > 0) {
429 int skip = get_character_len(*fp);
430 if(skip != 0) {
431 if (skip == 2) {
432 *tptr++ = *fp++;
433 *tptr++ = *fp++;
434 l -= 2;
435 } else if (skip == 1) {
436 *tptr++ = *fp++;
437 l--;
439 } else if (*fp == '\\') {
440 *tptr++ = '/';
441 fp++;
442 l--;
443 } else {
444 *tptr++ = *fp++;
445 l--;
450 /****************************************************************************
451 Convert from decimal to octal string
452 ****************************************************************************/
453 static void oct_it (long value, int ndgs, char *p)
455 /* Converts long to octal string, pads with leading zeros */
457 /* skip final null, but do final space */
458 --ndgs;
459 p[--ndgs] = ' ';
461 /* Loop does at least one digit */
462 do {
463 p[--ndgs] = '0' + (char) (value & 7);
464 value >>= 3;
466 while (ndgs > 0 && value != 0);
468 /* Do leading zeros */
469 while (ndgs > 0)
470 p[--ndgs] = '0';
473 /****************************************************************************
474 Convert from octal string to long
475 ***************************************************************************/
476 static long unoct(char *p, int ndgs)
478 long value=0;
479 /* Converts octal string to long, ignoring any non-digit */
481 while (--ndgs)
483 if (isdigit((int)*p))
484 value = (value << 3) | (long) (*p - '0');
486 p++;
489 return value;
492 /****************************************************************************
493 Compare two strings in a slash insensitive way, allowing s1 to match s2
494 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
495 a file in any subdirectory of s1, declare a match.
496 ***************************************************************************/
497 static int strslashcmp(char *s1, char *s2)
499 char *s1_0=s1;
501 while(*s1 && *s2 &&
502 (*s1 == *s2
503 || tolower(*s1) == tolower(*s2)
504 || (*s1 == '\\' && *s2=='/')
505 || (*s1 == '/' && *s2=='\\'))) {
506 s1++; s2++;
509 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
510 string of s2.
512 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
514 /* ignore trailing slash on s1 */
515 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
517 /* check for s1 is an "initial" string of s2 */
518 if (*s2 == '/' || *s2 == '\\') return 0;
520 return *s1-*s2;
524 /****************************************************************************
525 Ensure a remote path exists (make if necessary)
526 ***************************************************************************/
527 static BOOL ensurepath(char *fname)
529 /* *must* be called with buffer ready malloc'ed */
530 /* ensures path exists */
532 char *partpath, *ffname;
533 char *p=fname, *basehack;
535 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
537 partpath = string_create_s(strlen(fname));
538 ffname = string_create_s(strlen(fname));
540 if ((partpath == NULL) || (ffname == NULL)){
542 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
543 return(False);
547 *partpath = 0;
549 /* fname copied to ffname so can strtok */
551 safe_strcpy(ffname, fname, strlen(fname));
553 /* do a `basename' on ffname, so don't try and make file name directory */
554 if ((basehack=strrchr(ffname, '\\')) == NULL)
555 return True;
556 else
557 *basehack='\0';
559 p=strtok(ffname, "\\");
561 while (p)
563 safe_strcat(partpath, p, strlen(fname) + 1);
565 if (!cli_chkpath(cli, partpath)) {
566 if (!cli_mkdir(cli, partpath))
568 DEBUG(0, ("Error mkdirhiering\n"));
569 return False;
571 else
572 DEBUG(3, ("mkdirhiering %s\n", partpath));
576 safe_strcat(partpath, "\\", strlen(fname) + 1);
577 p = strtok(NULL,"/\\");
580 return True;
583 static int padit(char *buf, int bufsize, int padsize)
585 int berr= 0;
586 int bytestowrite;
588 DEBUG(5, ("Padding with %d zeros\n", padsize));
589 memset(buf, 0, bufsize);
590 while( !berr && padsize > 0 ) {
591 bytestowrite= MIN(bufsize, padsize);
592 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
593 padsize -= bytestowrite;
596 return berr;
600 static void do_setrattr(char *name, uint16 attr, int set)
602 uint16 oldattr;
604 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
606 if (set == ATTRSET) {
607 attr |= oldattr;
608 } else {
609 attr = oldattr & ~attr;
612 if (!cli_setatr(cli, name, attr, 0)) {
613 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
618 /****************************************************************************
619 append one remote file to the tar file
620 ***************************************************************************/
621 static void do_atar(char *rname,char *lname,file_info *finfo1)
623 int fnum;
624 uint32 nread=0;
625 char ftype;
626 file_info2 finfo;
627 BOOL close_done = False;
628 BOOL shallitime=True;
629 char data[65520];
630 int read_size = 65520;
631 int datalen=0;
633 struct timeval tp_start;
634 GetTimeOfDay(&tp_start);
636 ftype = '0'; /* An ordinary file ... */
638 if (finfo1) {
639 finfo.size = finfo1 -> size;
640 finfo.mode = finfo1 -> mode;
641 finfo.uid = finfo1 -> uid;
642 finfo.gid = finfo1 -> gid;
643 finfo.mtime = finfo1 -> mtime;
644 finfo.atime = finfo1 -> atime;
645 finfo.ctime = finfo1 -> ctime;
647 else {
648 finfo.size = def_finfo.size;
649 finfo.mode = def_finfo.mode;
650 finfo.uid = def_finfo.uid;
651 finfo.gid = def_finfo.gid;
652 finfo.mtime = def_finfo.mtime;
653 finfo.atime = def_finfo.atime;
654 finfo.ctime = def_finfo.ctime;
657 if (dry_run)
659 DEBUG(3,("skipping file %s of size %d bytes\n",
660 finfo.name,
661 (int)finfo.size));
662 shallitime=0;
663 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
664 ntarf++;
665 return;
668 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
670 dos_clean_name(rname);
672 if (fnum == -1) {
673 DEBUG(0,("%s opening remote file %s (%s)\n",
674 cli_errstr(cli),rname, cur_dir));
675 return;
678 finfo.name = string_create_s(strlen(rname));
679 if (finfo.name == NULL) {
680 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
681 return;
684 safe_strcpy(finfo.name,rname, strlen(rname));
685 if (!finfo1) {
686 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
687 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
688 return;
690 finfo.ctime = finfo.mtime;
693 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
695 if (tar_inc && !(finfo.mode & aARCH))
697 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
698 shallitime=0;
700 else if (!tar_system && (finfo.mode & aSYSTEM))
702 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
703 shallitime=0;
705 else if (!tar_hidden && (finfo.mode & aHIDDEN))
707 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
708 shallitime=0;
710 else
712 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
713 finfo.name,
714 (int)finfo.size,
715 lname));
717 /* write a tar header, don't bother with mode - just set to 100644 */
718 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
720 while (nread < finfo.size && !close_done) {
722 DEBUG(3,("nread=%d\n",nread));
724 datalen = cli_read(cli, fnum, data, nread, read_size);
726 if (datalen == -1) {
727 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
728 break;
731 nread += datalen;
733 /* if file size has increased since we made file size query, truncate
734 read so tar header for this file will be correct.
737 if (nread > finfo.size) {
738 datalen -= nread - finfo.size;
739 DEBUG(0,("File size change - truncating %s to %d bytes\n", finfo.name, (int)finfo.size));
742 /* add received bits of file to buffer - dotarbuf will
743 * write out in 512 byte intervals */
744 if (dotarbuf(tarhandle,data,datalen) != datalen) {
745 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
746 break;
749 if (datalen == 0) {
750 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
751 break;
754 datalen=0;
757 /* pad tar file with zero's if we couldn't get entire file */
758 if (nread < finfo.size) {
759 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", (int)finfo.size, (int)nread));
760 if (padit(data, sizeof(data), finfo.size - nread))
761 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
764 /* round tar file to nearest block */
765 if (finfo.size % TBLOCK)
766 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
768 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
769 ntarf++;
772 cli_close(cli, fnum);
774 if (shallitime)
776 struct timeval tp_end;
777 int this_time;
779 /* if shallitime is true then we didn't skip */
780 if (tar_reset && !dry_run)
781 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
783 GetTimeOfDay(&tp_end);
784 this_time =
785 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
786 (tp_end.tv_usec - tp_start.tv_usec)/1000;
787 get_total_time_ms += this_time;
788 get_total_size += finfo.size;
790 if (tar_noisy)
792 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
793 (int)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
794 finfo.name));
797 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
798 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
799 finfo.size / MAX(0.001, (1.024*this_time)),
800 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
804 /****************************************************************************
805 Append single file to tar file (or not)
806 ***************************************************************************/
807 static void do_tar(file_info *finfo)
809 pstring rname;
811 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
812 return;
814 /* Is it on the exclude list ? */
815 if (!tar_excl && clipn) {
816 pstring exclaim;
818 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
820 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
821 *(exclaim+strlen(exclaim)-1)='\0';
823 safe_strcat(exclaim, "\\", sizeof(pstring));
824 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
826 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
828 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
829 #ifdef HAVE_REGEX_H
830 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
831 #else
832 (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
833 #endif
834 DEBUG(3,("Skipping file %s\n", exclaim));
835 return;
839 if (finfo->mode & aDIR)
841 pstring saved_curdir;
842 pstring mtar_mask;
844 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
846 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", (int)sizeof(cur_dir), (int)strlen(cur_dir), (int)strlen(finfo->name), finfo->name, cur_dir));
848 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
849 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
851 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
853 /* write a tar directory, don't bother with mode - just set it to
854 * 40755 */
855 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
856 if (tar_noisy) {
857 DEBUG(0,(" directory %s\n", cur_dir));
859 ntarf++; /* Make sure we have a file on there */
860 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
861 safe_strcat(mtar_mask,"*", sizeof(pstring));
862 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
863 do_list(mtar_mask, attribute, do_tar, False, True);
864 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
866 else
868 safe_strcpy(rname,cur_dir, sizeof(pstring));
869 safe_strcat(rname,finfo->name, sizeof(pstring));
870 do_atar(rname,finfo->name,finfo);
874 /****************************************************************************
875 Convert from UNIX to DOS file names
876 ***************************************************************************/
877 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
879 /* remove '.' from start of file name, convert from unix /'s to
880 * dos \'s in path. Kill any absolute path names. But only if first!
883 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
885 if (first) {
886 if (*fp == '.') {
887 fp++;
888 l--;
890 if (*fp == '\\' || *fp == '/') {
891 fp++;
892 l--;
896 while (l > 0) {
897 int skip = get_character_len(*fp);
898 if(skip != 0) {
899 if (skip == 2) {
900 *tptr++ = *fp++;
901 *tptr++ = *fp++;
902 l -= 2;
903 } else if (skip == 1) {
904 *tptr++ = *fp++;
905 l--;
907 } else if (*fp == '/') {
908 *tptr++ = '\\';
909 fp++;
910 l--;
911 } else {
912 *tptr++ = *fp++;
913 l--;
919 /****************************************************************************
920 Move to the next block in the buffer, which may mean read in another set of
921 blocks. FIXME, we should allow more than one block to be skipped.
922 ****************************************************************************/
923 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
925 int bufread, total = 0;
927 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
928 *bufferp += TBLOCK;
929 total = TBLOCK;
931 if (*bufferp >= (ltarbuf + bufsiz)) {
933 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
936 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
937 * Fixes bug where read can return short if coming from
938 * a pipe.
941 bufread = read(tarhandle, ltarbuf, bufsiz);
942 total = bufread;
944 while (total < bufsiz) {
945 if (bufread < 0) { /* An error, return false */
946 return (total > 0 ? -2 : bufread);
948 if (bufread == 0) {
949 if (total <= 0) {
950 return -2;
952 break;
954 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
955 total += bufread;
958 DEBUG(5, ("Total bytes read ... %i\n", total));
960 *bufferp = ltarbuf;
964 return(total);
968 /* Skip a file, even if it includes a long file name? */
969 static int skip_file(int skipsize)
971 int dsize = skipsize;
973 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
975 /* FIXME, we should skip more than one block at a time */
977 while (dsize > 0) {
979 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
981 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
982 return(False);
986 dsize -= TBLOCK;
990 return(True);
993 /*************************************************************
994 Get a file from the tar file and store it.
995 When this is called, tarbuf already contains the first
996 file block. This is a bit broken & needs fixing.
997 **************************************************************/
999 static int get_file(file_info2 finfo)
1001 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
1003 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
1005 if (ensurepath(finfo.name) &&
1006 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
1007 DEBUG(0, ("abandoning restore\n"));
1008 return(False);
1011 /* read the blocks from the tar file and write to the remote file */
1013 rsize = finfo.size; /* This is how much to write */
1015 while (rsize > 0) {
1017 /* We can only write up to the end of the buffer */
1019 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1020 dsize = MIN(dsize, rsize); /* Should be only what is left */
1021 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1023 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1024 DEBUG(0, ("Error writing remote file\n"));
1025 return 0;
1028 rsize -= dsize;
1029 pos += dsize;
1031 /* Now figure out how much to move in the buffer */
1033 /* FIXME, we should skip more than one block at a time */
1035 /* First, skip any initial part of the part written that is left over */
1036 /* from the end of the first TBLOCK */
1038 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1040 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1041 bpos = 0;
1043 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1044 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1045 return False;
1052 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1053 * If the file being extracted is an exact multiple of
1054 * TBLOCK bytes then we don't want to extract the next
1055 * block from the tarfile here, as it will be done in
1056 * the caller of get_file().
1059 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1060 ((rsize == 0) && (dsize > TBLOCK))) {
1062 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1063 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1064 return False;
1067 dsize -= TBLOCK;
1070 bpos = dsize;
1074 /* Now close the file ... */
1076 if (!cli_close(cli, fnum)) {
1077 DEBUG(0, ("Error closing remote file\n"));
1078 return(False);
1081 /* Now we update the creation date ... */
1083 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1085 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1086 if (tar_real_noisy) {
1087 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1088 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1092 ntarf++;
1094 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1096 return(True);
1099 /* Create a directory. We just ensure that the path exists and return as there
1100 is no file associated with a directory
1102 static int get_dir(file_info2 finfo)
1105 DEBUG(0, ("restore directory %s\n", finfo.name));
1107 if (!ensurepath(finfo.name)) {
1109 DEBUG(0, ("Problems creating directory\n"));
1110 return(False);
1114 ntarf++;
1115 return(True);
1118 /* Get a file with a long file name ... first file has file name, next file
1119 has the data. We only want the long file name, as the loop in do_tarput
1120 will deal with the rest.
1122 static char * get_longfilename(file_info2 finfo)
1124 int namesize = finfo.size + strlen(cur_dir) + 2;
1125 char *longname = malloc(namesize);
1126 int offset = 0, left = finfo.size;
1127 BOOL first = True;
1129 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1130 DEBUG(5, ("Len = %d\n", (int)finfo.size));
1132 if (longname == NULL) {
1134 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1135 (int)(finfo.size + strlen(cur_dir) + 2)));
1136 return(NULL);
1139 /* First, add cur_dir to the long file name */
1141 if (strlen(cur_dir) > 0) {
1142 strncpy(longname, cur_dir, namesize);
1143 offset = strlen(cur_dir);
1146 /* Loop through the blocks picking up the name */
1148 while (left > 0) {
1150 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1152 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1153 return(NULL);
1157 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1158 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1160 offset += TBLOCK;
1161 left -= TBLOCK;
1165 return(longname);
1169 static void do_tarput(void)
1171 file_info2 finfo;
1172 struct timeval tp_start;
1173 char *longfilename = NULL, linkflag;
1174 int skip = False;
1176 GetTimeOfDay(&tp_start);
1178 DEBUG(5, ("RJS do_tarput called ...\n"));
1180 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1182 /* Now read through those files ... */
1184 while (True) {
1186 /* Get us to the next block, or the first block first time around */
1188 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1190 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1192 return;
1196 DEBUG(5, ("Reading the next header ...\n"));
1198 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1200 case -2: /* Hmm, not good, but not fatal */
1201 DEBUG(0, ("Skipping %s...\n", finfo.name));
1202 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1203 !skip_file(finfo.size)) {
1205 DEBUG(0, ("Short file, bailing out...\n"));
1206 return;
1210 break;
1212 case -1:
1213 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1214 return;
1216 case 0: /* chksum is zero - looks like an EOF */
1217 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1218 return; /* Hmmm, bad here ... */
1220 default:
1221 /* No action */
1223 break;
1227 /* Now, do we have a long file name? */
1229 if (longfilename != NULL) {
1231 SAFE_FREE(finfo.name); /* Free the space already allocated */
1232 finfo.name = longfilename;
1233 longfilename = NULL;
1237 /* Well, now we have a header, process the file ... */
1239 /* Should we skip the file? We have the long name as well here */
1241 skip = clipn &&
1242 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1243 #ifdef HAVE_REGEX_H
1244 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1245 #else
1246 || (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
1247 #endif
1249 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1251 if (skip) {
1253 skip_file(finfo.size);
1254 continue;
1258 /* We only get this far if we should process the file */
1259 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1261 switch (linkflag) {
1263 case '0': /* Should use symbolic names--FIXME */
1266 * Skip to the next block first, so we can get the file, FIXME, should
1267 * be in get_file ...
1268 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1269 * Fixes bug where file size in tarfile is zero.
1272 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1273 DEBUG(0, ("Short file, bailing out...\n"));
1274 return;
1276 if (!get_file(finfo)) {
1277 DEBUG(0, ("Abandoning restore\n"));
1278 return;
1281 break;
1283 case '5':
1284 if (!get_dir(finfo)) {
1285 DEBUG(0, ("Abandoning restore \n"));
1286 return;
1288 break;
1290 case 'L':
1291 longfilename = get_longfilename(finfo);
1292 if (!longfilename) {
1293 DEBUG(0, ("abandoning restore\n"));
1294 return;
1297 DEBUG(5, ("Long file name: %s\n", longfilename));
1298 break;
1300 default:
1301 skip_file(finfo.size); /* Don't handle these yet */
1302 break;
1313 * samba interactive commands
1316 /****************************************************************************
1317 Blocksize command
1318 ***************************************************************************/
1319 void cmd_block(void)
1321 fstring buf;
1322 int block;
1324 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1326 DEBUG(0, ("blocksize <n>\n"));
1327 return;
1330 block=atoi(buf);
1331 if (block < 0 || block > 65535)
1333 DEBUG(0, ("blocksize out of range"));
1334 return;
1337 blocksize=block;
1338 DEBUG(2,("blocksize is now %d\n", blocksize));
1341 /****************************************************************************
1342 command to set incremental / reset mode
1343 ***************************************************************************/
1344 void cmd_tarmode(void)
1346 fstring buf;
1348 while (next_token(NULL,buf,NULL,sizeof(buf))) {
1349 if (strequal(buf, "full"))
1350 tar_inc=False;
1351 else if (strequal(buf, "inc"))
1352 tar_inc=True;
1353 else if (strequal(buf, "reset"))
1354 tar_reset=True;
1355 else if (strequal(buf, "noreset"))
1356 tar_reset=False;
1357 else if (strequal(buf, "system"))
1358 tar_system=True;
1359 else if (strequal(buf, "nosystem"))
1360 tar_system=False;
1361 else if (strequal(buf, "hidden"))
1362 tar_hidden=True;
1363 else if (strequal(buf, "nohidden"))
1364 tar_hidden=False;
1365 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1366 tar_noisy=True;
1367 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1368 tar_noisy=False;
1369 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1372 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1373 tar_inc ? "incremental" : "full",
1374 tar_system ? "system" : "nosystem",
1375 tar_hidden ? "hidden" : "nohidden",
1376 tar_reset ? "reset" : "noreset",
1377 tar_noisy ? "verbose" : "quiet"));
1381 /****************************************************************************
1382 Feeble attrib command
1383 ***************************************************************************/
1384 void cmd_setmode(void)
1386 char *q;
1387 fstring buf;
1388 pstring fname;
1389 uint16 attra[2];
1390 int direct=1;
1392 attra[0] = attra[1] = 0;
1394 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1396 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1397 return;
1400 safe_strcpy(fname, cur_dir, sizeof(pstring));
1401 safe_strcat(fname, buf, sizeof(pstring));
1403 while (next_token(NULL,buf,NULL,sizeof(buf))) {
1404 q=buf;
1406 while(*q)
1407 switch (*q++) {
1408 case '+': direct=1;
1409 break;
1410 case '-': direct=0;
1411 break;
1412 case 'r': attra[direct]|=aRONLY;
1413 break;
1414 case 'h': attra[direct]|=aHIDDEN;
1415 break;
1416 case 's': attra[direct]|=aSYSTEM;
1417 break;
1418 case 'a': attra[direct]|=aARCH;
1419 break;
1420 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1421 return;
1425 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1427 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1428 return;
1431 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1432 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1433 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1436 /****************************************************************************
1437 Principal command for creating / extracting
1438 ***************************************************************************/
1439 void cmd_tar(void)
1441 fstring buf;
1442 char **argl;
1443 int argcl;
1445 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1447 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1448 return;
1451 argl=toktocliplist(&argcl, NULL);
1452 if (!tar_parseargs(argcl, argl, buf, 0))
1453 return;
1455 process_tar();
1457 SAFE_FREE(argl);
1460 /****************************************************************************
1461 Command line (option) version
1462 ***************************************************************************/
1463 int process_tar(void)
1465 initarbuf();
1466 switch(tar_type) {
1467 case 'x':
1469 #if 0
1470 do_tarput2();
1471 #else
1472 do_tarput();
1473 #endif
1474 SAFE_FREE(tarbuf);
1475 close(tarhandle);
1476 break;
1477 case 'r':
1478 case 'c':
1479 if (clipn && tar_excl) {
1480 int i;
1481 pstring tarmac;
1483 for (i=0; i<clipn; i++) {
1484 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1486 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1487 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1490 if (strrchr(cliplist[i], '\\')) {
1491 pstring saved_dir;
1493 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1495 if (*cliplist[i]=='\\') {
1496 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1497 } else {
1498 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1499 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1501 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1502 *(strrchr(cur_dir, '\\')+1)='\0';
1504 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1505 do_list(tarmac,attribute,do_tar, False, True);
1506 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1507 } else {
1508 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1509 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1510 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1511 do_list(tarmac,attribute,do_tar, False, True);
1514 } else {
1515 pstring mask;
1516 safe_strcpy(mask,cur_dir, sizeof(pstring));
1517 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1518 safe_strcat(mask,"\\*", sizeof(pstring));
1519 do_list(mask,attribute,do_tar,False, True);
1522 if (ntarf) dotareof(tarhandle);
1523 close(tarhandle);
1524 SAFE_FREE(tarbuf);
1526 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1527 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1528 break;
1531 if (must_free_cliplist) {
1532 int i;
1533 for (i = 0; i < clipn; ++i) {
1534 SAFE_FREE(cliplist[i]);
1536 SAFE_FREE(cliplist);
1537 cliplist = NULL;
1538 clipn = 0;
1539 must_free_cliplist = False;
1542 return(0);
1545 /****************************************************************************
1546 Find a token (filename) in a clip list
1547 ***************************************************************************/
1548 static int clipfind(char **aret, int ret, char *tok)
1550 if (aret==NULL) return 0;
1552 /* ignore leading slashes or dots in token */
1553 while(strchr("/\\.", *tok)) tok++;
1555 while(ret--) {
1556 char *pkey=*aret++;
1558 /* ignore leading slashes or dots in list */
1559 while(strchr("/\\.", *pkey)) pkey++;
1561 if (!strslashcmp(pkey, tok)) return 1;
1564 return 0;
1567 /****************************************************************************
1568 Read list of files to include from the file and initialize cliplist
1569 accordingly.
1570 ***************************************************************************/
1571 static int read_inclusion_file(char *filename)
1573 FILE *inclusion = NULL;
1574 char buf[MAXPATHLEN + 1];
1575 char *inclusion_buffer = NULL;
1576 int inclusion_buffer_size = 0;
1577 int inclusion_buffer_sofar = 0;
1578 char *p;
1579 char *tmpstr;
1580 int i;
1581 int error = 0;
1583 clipn = 0;
1584 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1585 if ((inclusion = sys_fopen(filename, "r")) == NULL) {
1586 /* XXX It would be better to include a reason for failure, but without
1587 * autoconf, it's hard to use strerror, sys_errlist, etc.
1589 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1590 return 0;
1593 while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1594 if (inclusion_buffer == NULL) {
1595 inclusion_buffer_size = 1024;
1596 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1597 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1598 error = 1;
1599 break;
1603 if (buf[strlen(buf)-1] == '\n') {
1604 buf[strlen(buf)-1] = '\0';
1607 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1608 char *ib;
1609 inclusion_buffer_size *= 2;
1610 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1611 if (! ib) {
1612 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n", inclusion_buffer_size));
1613 error = 1;
1614 break;
1615 } else
1616 inclusion_buffer = ib;
1619 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1620 inclusion_buffer_sofar += strlen(buf) + 1;
1621 clipn++;
1623 fclose(inclusion);
1625 if (! error) {
1626 /* Allocate an array of clipn + 1 char*'s for cliplist */
1627 cliplist = malloc((clipn + 1) * sizeof(char *));
1628 if (cliplist == NULL) {
1629 DEBUG(0,("failure allocating memory for cliplist\n"));
1630 error = 1;
1631 } else {
1632 cliplist[clipn] = NULL;
1633 p = inclusion_buffer;
1634 for (i = 0; (! error) && (i < clipn); i++) {
1635 /* set current item to NULL so array will be null-terminated even if
1636 * malloc fails below. */
1637 cliplist[i] = NULL;
1638 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1639 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1640 error = 1;
1641 } else {
1642 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1643 cliplist[i] = tmpstr;
1644 if ((p = strchr(p, '\000')) == NULL) {
1645 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1646 abort();
1649 ++p;
1651 must_free_cliplist = True;
1655 if (inclusion_buffer) {
1656 SAFE_FREE(inclusion_buffer);
1658 if (error) {
1659 if (cliplist) {
1660 char **pp;
1661 /* We know cliplist is always null-terminated */
1662 for (pp = cliplist; *pp; ++pp) {
1663 SAFE_FREE(*pp);
1665 SAFE_FREE(cliplist);
1666 cliplist = NULL;
1667 must_free_cliplist = False;
1669 return 0;
1672 /* cliplist and its elements are freed at the end of process_tar. */
1673 return 1;
1676 /****************************************************************************
1677 Parse tar arguments. Sets tar_type, tar_excl, etc.
1678 ***************************************************************************/
1679 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1681 char tar_clipfl='\0';
1683 /* Reset back to defaults - could be from interactive version
1684 * reset mode and archive mode left as they are though
1686 tar_type='\0';
1687 tar_excl=True;
1688 dry_run=False;
1690 while (*Optarg)
1691 switch(*Optarg++) {
1692 case 'c':
1693 tar_type='c';
1694 break;
1695 case 'x':
1696 if (tar_type=='c') {
1697 printf("Tar must be followed by only one of c or x.\n");
1698 return 0;
1700 tar_type='x';
1701 break;
1702 case 'b':
1703 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1704 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1705 return 0;
1706 } else {
1707 Optind++;
1709 break;
1710 case 'g':
1711 tar_inc=True;
1712 break;
1713 case 'N':
1714 if (Optind>=argc) {
1715 DEBUG(0,("Option N must be followed by valid file name\n"));
1716 return 0;
1717 } else {
1718 SMB_STRUCT_STAT stbuf;
1719 extern time_t newer_than;
1721 if (sys_stat(dos_to_unix_static(argv[Optind]), &stbuf) == 0) {
1722 newer_than = stbuf.st_mtime;
1723 DEBUG(1,("Getting files newer than %s",
1724 asctime(LocalTime(&newer_than))));
1725 Optind++;
1726 } else {
1727 DEBUG(0,("Error setting newer-than time\n"));
1728 return 0;
1731 break;
1732 case 'a':
1733 tar_reset=True;
1734 break;
1735 case 'q':
1736 tar_noisy=False;
1737 break;
1738 case 'I':
1739 if (tar_clipfl) {
1740 DEBUG(0,("Only one of I,X,F must be specified\n"));
1741 return 0;
1743 tar_clipfl='I';
1744 break;
1745 case 'X':
1746 if (tar_clipfl) {
1747 DEBUG(0,("Only one of I,X,F must be specified\n"));
1748 return 0;
1750 tar_clipfl='X';
1751 break;
1752 case 'F':
1753 if (tar_clipfl) {
1754 DEBUG(0,("Only one of I,X,F must be specified\n"));
1755 return 0;
1757 tar_clipfl='F';
1758 break;
1759 case 'r':
1760 DEBUG(0, ("tar_re_search set\n"));
1761 tar_re_search = True;
1762 break;
1763 case 'n':
1764 if (tar_type == 'c') {
1765 DEBUG(0, ("dry_run set\n"));
1766 dry_run = True;
1767 } else {
1768 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1769 return 0;
1771 break;
1772 default:
1773 DEBUG(0,("Unknown tar option\n"));
1774 return 0;
1777 if (!tar_type) {
1778 printf("Option T must be followed by one of c or x.\n");
1779 return 0;
1782 /* tar_excl is true if cliplist lists files to be included.
1783 * Both 'I' and 'F' mean include. */
1784 tar_excl=tar_clipfl!='X';
1786 if (tar_clipfl=='F') {
1787 if (argc-Optind-1 != 1) {
1788 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1789 return 0;
1791 if (! read_inclusion_file(argv[Optind+1])) {
1792 return 0;
1794 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1795 char *tmpstr;
1796 char **tmplist;
1797 int clipcount;
1799 cliplist=argv+Optind+1;
1800 clipn=argc-Optind-1;
1801 clipcount = clipn;
1803 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1804 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1805 clipn)
1807 return 0;
1810 for (clipcount = 0; clipcount < clipn; clipcount++) {
1812 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1814 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1815 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1816 clipcount)
1818 return 0;
1820 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1821 tmplist[clipcount] = tmpstr;
1822 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1824 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1826 cliplist = tmplist;
1827 must_free_cliplist = True;
1830 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1831 #ifdef HAVE_REGEX_H
1832 int errcode;
1834 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1836 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1837 return;
1841 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1842 char errstr[1024];
1843 size_t errlen;
1845 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1847 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1848 return;
1851 #endif
1853 clipn=argc-Optind-1;
1854 cliplist=argv+Optind+1;
1858 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1859 /* Sets tar handle to either 0 or 1, as appropriate */
1860 tarhandle=(tar_type=='c');
1862 * Make sure that dbf points to stderr if we are using stdout for
1863 * tar output
1865 if (tarhandle == 1)
1866 dbf = stderr;
1867 } else {
1868 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1870 if (!dry_run) {
1871 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1872 dry_run = True;
1874 tarhandle=-1;
1875 } else
1876 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1877 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1879 DEBUG(0,("Error opening local file %s - %s\n",
1880 argv[Optind], strerror(errno)));
1881 return(0);
1885 return 1;