r3220: merging current 3.0 code to release branch
[Samba.git] / source / client / clitar.c
blobb4d6273f7bb695c8dd12c6e50aa78ea7202abff1
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_list(exclaim, cliplist, clipn, 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_list(finfo.name, cliplist, clipn, 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 = NULL;
1349 int argcl = 0;
1350 int ret;
1352 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1353 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1354 return 1;
1357 argl=toktocliplist(&argcl, NULL);
1358 if (!tar_parseargs(argcl, argl, buf, 0))
1359 return 1;
1361 ret = process_tar();
1362 SAFE_FREE(argl);
1363 return ret;
1366 /****************************************************************************
1367 Command line (option) version
1368 ***************************************************************************/
1370 int process_tar(void)
1372 int rc = 0;
1373 initarbuf();
1374 switch(tar_type) {
1375 case 'x':
1377 #if 0
1378 do_tarput2();
1379 #else
1380 do_tarput();
1381 #endif
1382 SAFE_FREE(tarbuf);
1383 close(tarhandle);
1384 break;
1385 case 'r':
1386 case 'c':
1387 if (clipn && tar_excl) {
1388 int i;
1389 pstring tarmac;
1391 for (i=0; i<clipn; i++) {
1392 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1394 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1395 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1398 if (strrchr_m(cliplist[i], '\\')) {
1399 pstring saved_dir;
1401 pstrcpy(saved_dir, cur_dir);
1403 if (*cliplist[i]=='\\') {
1404 pstrcpy(tarmac, cliplist[i]);
1405 } else {
1406 pstrcpy(tarmac, cur_dir);
1407 pstrcat(tarmac, cliplist[i]);
1409 pstrcpy(cur_dir, tarmac);
1410 *(strrchr_m(cur_dir, '\\')+1)='\0';
1412 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1413 do_list(tarmac,attribute,do_tar, False, True);
1414 pstrcpy(cur_dir,saved_dir);
1415 } else {
1416 pstrcpy(tarmac, cur_dir);
1417 pstrcat(tarmac, cliplist[i]);
1418 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1419 do_list(tarmac,attribute,do_tar, False, True);
1422 } else {
1423 pstring mask;
1424 pstrcpy(mask,cur_dir);
1425 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1426 pstrcat(mask,"\\*");
1427 do_list(mask,attribute,do_tar,False, True);
1430 if (ntarf)
1431 dotareof(tarhandle);
1432 close(tarhandle);
1433 SAFE_FREE(tarbuf);
1435 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1436 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1437 break;
1440 if (must_free_cliplist) {
1441 int i;
1442 for (i = 0; i < clipn; ++i) {
1443 SAFE_FREE(cliplist[i]);
1445 SAFE_FREE(cliplist);
1446 cliplist = NULL;
1447 clipn = 0;
1448 must_free_cliplist = False;
1450 return rc;
1453 /****************************************************************************
1454 Find a token (filename) in a clip list
1455 ***************************************************************************/
1457 static int clipfind(char **aret, int ret, char *tok)
1459 if (aret==NULL)
1460 return 0;
1462 /* ignore leading slashes or dots in token */
1463 while(strchr_m("/\\.", *tok))
1464 tok++;
1466 while(ret--) {
1467 char *pkey=*aret++;
1469 /* ignore leading slashes or dots in list */
1470 while(strchr_m("/\\.", *pkey))
1471 pkey++;
1473 if (!strslashcmp(pkey, tok))
1474 return 1;
1476 return 0;
1479 /****************************************************************************
1480 Read list of files to include from the file and initialize cliplist
1481 accordingly.
1482 ***************************************************************************/
1484 static int read_inclusion_file(char *filename)
1486 XFILE *inclusion = NULL;
1487 char buf[PATH_MAX + 1];
1488 char *inclusion_buffer = NULL;
1489 int inclusion_buffer_size = 0;
1490 int inclusion_buffer_sofar = 0;
1491 char *p;
1492 char *tmpstr;
1493 int i;
1494 int error = 0;
1496 clipn = 0;
1497 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1498 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1499 /* XXX It would be better to include a reason for failure, but without
1500 * autoconf, it's hard to use strerror, sys_errlist, etc.
1502 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1503 return 0;
1506 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1507 if (inclusion_buffer == NULL) {
1508 inclusion_buffer_size = 1024;
1509 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1510 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1511 error = 1;
1512 break;
1516 if (buf[strlen(buf)-1] == '\n') {
1517 buf[strlen(buf)-1] = '\0';
1520 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1521 char *ib;
1522 inclusion_buffer_size *= 2;
1523 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1524 if (! ib) {
1525 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1526 inclusion_buffer_size));
1527 error = 1;
1528 break;
1529 } else {
1530 inclusion_buffer = ib;
1534 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1535 inclusion_buffer_sofar += strlen(buf) + 1;
1536 clipn++;
1538 x_fclose(inclusion);
1540 if (! error) {
1541 /* Allocate an array of clipn + 1 char*'s for cliplist */
1542 cliplist = malloc((clipn + 1) * sizeof(char *));
1543 if (cliplist == NULL) {
1544 DEBUG(0,("failure allocating memory for cliplist\n"));
1545 error = 1;
1546 } else {
1547 cliplist[clipn] = NULL;
1548 p = inclusion_buffer;
1549 for (i = 0; (! error) && (i < clipn); i++) {
1550 /* set current item to NULL so array will be null-terminated even if
1551 * malloc fails below. */
1552 cliplist[i] = NULL;
1553 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1554 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1555 error = 1;
1556 } else {
1557 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1558 cliplist[i] = tmpstr;
1559 if ((p = strchr_m(p, '\000')) == NULL) {
1560 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1561 abort();
1564 ++p;
1566 must_free_cliplist = True;
1570 SAFE_FREE(inclusion_buffer);
1571 if (error) {
1572 if (cliplist) {
1573 char **pp;
1574 /* We know cliplist is always null-terminated */
1575 for (pp = cliplist; *pp; ++pp) {
1576 SAFE_FREE(*pp);
1578 SAFE_FREE(cliplist);
1579 cliplist = NULL;
1580 must_free_cliplist = False;
1582 return 0;
1585 /* cliplist and its elements are freed at the end of process_tar. */
1586 return 1;
1589 /****************************************************************************
1590 Parse tar arguments. Sets tar_type, tar_excl, etc.
1591 ***************************************************************************/
1593 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1595 int newOptind = Optind;
1596 char tar_clipfl='\0';
1598 /* Reset back to defaults - could be from interactive version
1599 * reset mode and archive mode left as they are though
1601 tar_type='\0';
1602 tar_excl=True;
1603 dry_run=False;
1605 while (*Optarg) {
1606 switch(*Optarg++) {
1607 case 'c':
1608 tar_type='c';
1609 break;
1610 case 'x':
1611 if (tar_type=='c') {
1612 printf("Tar must be followed by only one of c or x.\n");
1613 return 0;
1615 tar_type='x';
1616 break;
1617 case 'b':
1618 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1619 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1620 return 0;
1621 } else {
1622 Optind++;
1623 newOptind++;
1625 break;
1626 case 'g':
1627 tar_inc=True;
1628 break;
1629 case 'N':
1630 if (Optind>=argc) {
1631 DEBUG(0,("Option N must be followed by valid file name\n"));
1632 return 0;
1633 } else {
1634 SMB_STRUCT_STAT stbuf;
1635 extern time_t newer_than;
1637 if (sys_stat(argv[Optind], &stbuf) == 0) {
1638 newer_than = stbuf.st_mtime;
1639 DEBUG(1,("Getting files newer than %s",
1640 asctime(LocalTime(&newer_than))));
1641 newOptind++;
1642 Optind++;
1643 } else {
1644 DEBUG(0,("Error setting newer-than time\n"));
1645 return 0;
1648 break;
1649 case 'a':
1650 tar_reset=True;
1651 break;
1652 case 'q':
1653 tar_noisy=False;
1654 break;
1655 case 'I':
1656 if (tar_clipfl) {
1657 DEBUG(0,("Only one of I,X,F must be specified\n"));
1658 return 0;
1660 tar_clipfl='I';
1661 break;
1662 case 'X':
1663 if (tar_clipfl) {
1664 DEBUG(0,("Only one of I,X,F must be specified\n"));
1665 return 0;
1667 tar_clipfl='X';
1668 break;
1669 case 'F':
1670 if (tar_clipfl) {
1671 DEBUG(0,("Only one of I,X,F must be specified\n"));
1672 return 0;
1674 tar_clipfl='F';
1675 break;
1676 case 'r':
1677 DEBUG(0, ("tar_re_search set\n"));
1678 tar_re_search = True;
1679 break;
1680 case 'n':
1681 if (tar_type == 'c') {
1682 DEBUG(0, ("dry_run set\n"));
1683 dry_run = True;
1684 } else {
1685 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1686 return 0;
1688 break;
1689 default:
1690 DEBUG(0,("Unknown tar option\n"));
1691 return 0;
1695 if (!tar_type) {
1696 printf("Option T must be followed by one of c or x.\n");
1697 return 0;
1700 /* tar_excl is true if cliplist lists files to be included.
1701 * Both 'I' and 'F' mean include. */
1702 tar_excl=tar_clipfl!='X';
1704 if (tar_clipfl=='F') {
1705 if (argc-Optind-1 != 1) {
1706 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1707 return 0;
1709 newOptind++;
1710 Optind++;
1711 if (! read_inclusion_file(argv[Optind])) {
1712 return 0;
1714 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1715 char *tmpstr;
1716 char **tmplist;
1717 int clipcount;
1719 cliplist=argv+Optind+1;
1720 clipn=argc-Optind-1;
1721 clipcount = clipn;
1723 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1724 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1725 return 0;
1728 for (clipcount = 0; clipcount < clipn; clipcount++) {
1730 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1732 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1733 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1734 return 0;
1737 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1738 tmplist[clipcount] = tmpstr;
1739 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1741 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1744 cliplist = tmplist;
1745 must_free_cliplist = True;
1747 newOptind += clipn;
1750 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1751 #ifdef HAVE_REGEX_H
1752 int errcode;
1754 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1756 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1757 return;
1760 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1761 char errstr[1024];
1762 size_t errlen;
1764 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1765 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1766 return;
1768 #endif
1770 clipn=argc-Optind-1;
1771 cliplist=argv+Optind+1;
1772 newOptind += clipn;
1775 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1776 /* Sets tar handle to either 0 or 1, as appropriate */
1777 tarhandle=(tar_type=='c');
1779 * Make sure that dbf points to stderr if we are using stdout for
1780 * tar output
1782 if (tarhandle == 1) {
1783 dbf = x_stderr;
1785 if (!argv[Optind]) {
1786 DEBUG(0,("Must specify tar filename\n"));
1787 return 0;
1789 if (!strcmp(argv[Optind], "-")) {
1790 newOptind++;
1793 } else {
1794 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0)) {
1795 if (!dry_run) {
1796 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1797 dry_run = True;
1799 tarhandle=-1;
1800 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1801 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1802 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1803 return(0);
1805 newOptind++;
1808 return newOptind;