change ADS negprot to match more closely the options used by w2k. This
[Samba.git] / source / client / clitar.c
blobc453cfbb5488bbe4fedd9902570c912d05b83372
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
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 #define SEPARATORS " \t\n\r"
70 extern struct cli_state *cli;
72 /* These defines are for the do_setrattr routine, to indicate
73 * setting and reseting of file attributes in the function call */
74 #define ATTRSET 1
75 #define ATTRRESET 0
77 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
79 #ifndef CLIENT_TIMEOUT
80 #define CLIENT_TIMEOUT (30*1000)
81 #endif
83 static char *tarbuf, *buffer_p;
84 static int tp, ntarf, tbufsiz;
85 static double ttarf;
86 /* Incremental mode */
87 static BOOL tar_inc=False;
88 /* Reset archive bit */
89 static BOOL tar_reset=False;
90 /* Include / exclude mode (true=include, false=exclude) */
91 static BOOL tar_excl=True;
92 /* use regular expressions for search on file names */
93 static BOOL tar_re_search=False;
94 #ifdef HAVE_REGEX_H
95 regex_t *preg;
96 #endif
97 /* Do not dump anything, just calculate sizes */
98 static BOOL dry_run=False;
99 /* Dump files with System attribute */
100 static BOOL tar_system=True;
101 /* Dump files with Hidden attribute */
102 static BOOL tar_hidden=True;
103 /* Be noisy - make a catalogue */
104 static BOOL tar_noisy=True;
105 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
107 char tar_type='\0';
108 static char **cliplist=NULL;
109 static int clipn=0;
110 static BOOL must_free_cliplist = False;
112 extern file_info def_finfo;
113 extern BOOL lowercase;
114 extern uint16 cnum;
115 extern BOOL readbraw_supported;
116 extern int max_xmit;
117 extern pstring cur_dir;
118 extern int get_total_time_ms;
119 extern int get_total_size;
121 static int blocksize=20;
122 static int tarhandle;
124 static void writetarheader(int f, char *aname, int size, time_t mtime,
125 char *amode, unsigned char ftype);
126 static void do_atar(char *rname,char *lname,file_info *finfo1);
127 static void do_tar(file_info *finfo);
128 static void oct_it(long value, int ndgs, char *p);
129 static void fixtarname(char *tptr, char *fp, int l);
130 static int dotarbuf(int f, char *b, int n);
131 static void dozerobuf(int f, int n);
132 static void dotareof(int f);
133 static void initarbuf(void);
135 /* restore functions */
136 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
137 static long unoct(char *p, int ndgs);
138 static void do_tarput(void);
139 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
142 * tar specific utitlities
145 /*******************************************************************
146 Create a string of size size+1 (for the null)
147 *******************************************************************/
148 static char *string_create_s(int size)
150 char *tmp;
152 tmp = (char *)malloc(size+1);
154 if (tmp == NULL) {
156 DEBUG(0, ("Out of memory in string_create_s\n"));
160 return(tmp);
164 /****************************************************************************
165 Write a tar header to buffer
166 ****************************************************************************/
167 static void writetarheader(int f, char *aname, int size, time_t mtime,
168 char *amode, unsigned char ftype)
170 union hblock hb;
171 int i, chk, l;
172 char *jp;
174 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
176 memset(hb.dummy, 0, sizeof(hb.dummy));
178 l=strlen(aname);
179 if (l >= NAMSIZ - 1) {
180 /* write a GNU tar style long header */
181 char *b;
182 b = (char *)malloc(l+TBLOCK+100);
183 if (!b) {
184 DEBUG(0,("out of memory\n"));
185 exit(1);
187 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
188 memset(b, 0, l+TBLOCK+100);
189 fixtarname(b, aname, l);
190 i = strlen(b)+1;
191 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
192 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
193 SAFE_FREE(b);
196 /* use l + 1 to do the null too */
197 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
199 if (lowercase)
200 strlower(hb.dbuf.name);
202 /* write out a "standard" tar format header */
204 hb.dbuf.name[NAMSIZ-1]='\0';
205 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
206 oct_it(0L, 8, hb.dbuf.uid);
207 oct_it(0L, 8, hb.dbuf.gid);
208 oct_it((long) size, 13, hb.dbuf.size);
209 oct_it((long) mtime, 13, hb.dbuf.mtime);
210 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
211 memset(hb.dbuf.linkname, 0, NAMSIZ);
212 hb.dbuf.linkflag=ftype;
214 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
216 oct_it((long) chk, 8, hb.dbuf.chksum);
217 hb.dbuf.chksum[6] = '\0';
219 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
222 /****************************************************************************
223 Read a tar header into a hblock structure, and validate
224 ***************************************************************************/
225 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
227 long chk, fchk;
228 int i;
229 char *jp;
232 * read in a "standard" tar format header - we're not that interested
233 * in that many fields, though
236 /* check the checksum */
237 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
239 if (chk == 0)
240 return chk;
242 /* compensate for blanks in chksum header */
243 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
244 chk-=(0xFF & *jp++);
246 chk += ' ' * sizeof(hb->dbuf.chksum);
248 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
250 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
251 chk, fchk, hb->dbuf.chksum));
253 if (fchk != chk)
255 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
256 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
257 return -1;
260 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
262 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
263 return(-1);
267 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
269 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
270 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
271 strlen(hb->dbuf.name) + 1, True);
273 /* can't handle some links at present */
274 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
275 if (hb->dbuf.linkflag == 0) {
276 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
277 finfo->name));
278 } else {
279 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
280 /* Do nothing here at the moment. do_tarput will handle this
281 as long as the longlink gets back to it, as it has to advance
282 the buffer pointer, etc */
284 } else {
285 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
286 return -2;
291 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
292 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
294 finfo->mode=aDIR;
296 else
297 finfo->mode=0; /* we don't care about mode at the moment, we'll
298 * just make it a regular file */
300 * Bug fix by richard@sj.co.uk
302 * REC: restore times correctly (as does tar)
303 * We only get the modification time of the file; set the creation time
304 * from the mod. time, and the access time to current time
306 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
307 finfo->atime = time(NULL);
308 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
310 return True;
313 /****************************************************************************
314 Write out the tar buffer to tape or wherever
315 ****************************************************************************/
316 static int dotarbuf(int f, char *b, int n)
318 int fail=1, writ=n;
320 if (dry_run) {
321 return writ;
323 /* This routine and the next one should be the only ones that do write()s */
324 if (tp + n >= tbufsiz)
326 int diff;
328 diff=tbufsiz-tp;
329 memcpy(tarbuf + tp, b, diff);
330 fail=fail && (1+write(f, tarbuf, tbufsiz));
331 n-=diff;
332 b+=diff;
333 tp=0;
335 while (n >= tbufsiz)
337 fail=fail && (1 + write(f, b, tbufsiz));
338 n-=tbufsiz;
339 b+=tbufsiz;
342 if (n>0) {
343 memcpy(tarbuf+tp, b, n);
344 tp+=n;
347 return(fail ? writ : 0);
350 /****************************************************************************
351 Write zeros to buffer / tape
352 ****************************************************************************/
353 static void dozerobuf(int f, int n)
355 /* short routine just to write out n zeros to buffer -
356 * used to round files to nearest block
357 * and to do tar EOFs */
359 if (dry_run)
360 return;
362 if (n+tp >= tbufsiz)
364 memset(tarbuf+tp, 0, tbufsiz-tp);
366 write(f, tarbuf, tbufsiz);
367 memset(tarbuf, 0, (tp+=n-tbufsiz));
369 else
371 memset(tarbuf+tp, 0, n);
372 tp+=n;
376 /****************************************************************************
377 Malloc tape buffer
378 ****************************************************************************/
379 static void initarbuf(void)
381 /* initialize tar buffer */
382 tbufsiz=blocksize*TBLOCK;
383 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
385 /* reset tar buffer pointer and tar file counter and total dumped */
386 tp=0; ntarf=0; ttarf=0;
389 /****************************************************************************
390 Write two zero blocks at end of file
391 ****************************************************************************/
392 static void dotareof(int f)
394 SMB_STRUCT_STAT stbuf;
395 /* Two zero blocks at end of file, write out full buffer */
397 if (dry_run)
398 return;
400 (void) dozerobuf(f, TBLOCK);
401 (void) dozerobuf(f, TBLOCK);
403 if (sys_fstat(f, &stbuf) == -1)
405 DEBUG(0, ("Couldn't stat file handle\n"));
406 return;
409 /* Could be a pipe, in which case S_ISREG should fail,
410 * and we should write out at full size */
411 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
414 /****************************************************************************
415 (Un)mangle DOS pathname, make nonabsolute
416 ****************************************************************************/
417 static void fixtarname(char *tptr, char *fp, int l)
419 /* add a '.' to start of file name, convert from ugly dos \'s in path
420 * to lovely unix /'s :-} */
421 *tptr++='.';
423 safe_strcpy(tptr, fp, l);
424 string_replace(tptr, '\\', '/');
427 /****************************************************************************
428 Convert from decimal to octal string
429 ****************************************************************************/
430 static void oct_it (long value, int ndgs, char *p)
432 /* Converts long to octal string, pads with leading zeros */
434 /* skip final null, but do final space */
435 --ndgs;
436 p[--ndgs] = ' ';
438 /* Loop does at least one digit */
439 do {
440 p[--ndgs] = '0' + (char) (value & 7);
441 value >>= 3;
443 while (ndgs > 0 && value != 0);
445 /* Do leading zeros */
446 while (ndgs > 0)
447 p[--ndgs] = '0';
450 /****************************************************************************
451 Convert from octal string to long
452 ***************************************************************************/
453 static long unoct(char *p, int ndgs)
455 long value=0;
456 /* Converts octal string to long, ignoring any non-digit */
458 while (--ndgs)
460 if (isdigit((int)*p))
461 value = (value << 3) | (long) (*p - '0');
463 p++;
466 return value;
469 /****************************************************************************
470 Compare two strings in a slash insensitive way, allowing s1 to match s2
471 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
472 a file in any subdirectory of s1, declare a match.
473 ***************************************************************************/
474 static int strslashcmp(char *s1, char *s2)
476 char *s1_0=s1;
478 while(*s1 && *s2 &&
479 (*s1 == *s2
480 || tolower(*s1) == tolower(*s2)
481 || (*s1 == '\\' && *s2=='/')
482 || (*s1 == '/' && *s2=='\\'))) {
483 s1++; s2++;
486 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
487 string of s2.
489 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
491 /* ignore trailing slash on s1 */
492 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
494 /* check for s1 is an "initial" string of s2 */
495 if ((*s2 == '/' || *s2 == '\\') && !*s1) return 0;
497 return *s1-*s2;
501 /****************************************************************************
502 Ensure a remote path exists (make if necessary)
503 ***************************************************************************/
504 static BOOL ensurepath(char *fname)
506 /* *must* be called with buffer ready malloc'ed */
507 /* ensures path exists */
509 char *partpath, *ffname;
510 char *p=fname, *basehack;
512 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
514 partpath = string_create_s(strlen(fname));
515 ffname = string_create_s(strlen(fname));
517 if ((partpath == NULL) || (ffname == NULL)){
519 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
520 return(False);
524 *partpath = 0;
526 /* fname copied to ffname so can strtok */
528 safe_strcpy(ffname, fname, strlen(fname));
530 /* do a `basename' on ffname, so don't try and make file name directory */
531 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
532 return True;
533 else
534 *basehack='\0';
536 p=strtok(ffname, "\\");
538 while (p)
540 safe_strcat(partpath, p, strlen(fname) + 1);
542 if (!cli_chkpath(cli, partpath)) {
543 if (!cli_mkdir(cli, partpath))
545 DEBUG(0, ("Error mkdirhiering\n"));
546 return False;
548 else
549 DEBUG(3, ("mkdirhiering %s\n", partpath));
553 safe_strcat(partpath, "\\", strlen(fname) + 1);
554 p = strtok(NULL,"/\\");
557 return True;
560 static int padit(char *buf, int bufsize, int padsize)
562 int berr= 0;
563 int bytestowrite;
565 DEBUG(5, ("Padding with %d zeros\n", padsize));
566 memset(buf, 0, bufsize);
567 while( !berr && padsize > 0 ) {
568 bytestowrite= MIN(bufsize, padsize);
569 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
570 padsize -= bytestowrite;
573 return berr;
577 static void do_setrattr(char *name, uint16 attr, int set)
579 uint16 oldattr;
581 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
583 if (set == ATTRSET) {
584 attr |= oldattr;
585 } else {
586 attr = oldattr & ~attr;
589 if (!cli_setatr(cli, name, attr, 0)) {
590 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
595 /****************************************************************************
596 append one remote file to the tar file
597 ***************************************************************************/
598 static void do_atar(char *rname,char *lname,file_info *finfo1)
600 int fnum;
601 uint32 nread=0;
602 char ftype;
603 file_info2 finfo;
604 BOOL close_done = False;
605 BOOL shallitime=True;
606 char data[65520];
607 int read_size = 65520;
608 int datalen=0;
610 struct timeval tp_start;
611 GetTimeOfDay(&tp_start);
613 ftype = '0'; /* An ordinary file ... */
615 if (finfo1) {
616 finfo.size = finfo1 -> size;
617 finfo.mode = finfo1 -> mode;
618 finfo.uid = finfo1 -> uid;
619 finfo.gid = finfo1 -> gid;
620 finfo.mtime = finfo1 -> mtime;
621 finfo.atime = finfo1 -> atime;
622 finfo.ctime = finfo1 -> ctime;
624 else {
625 finfo.size = def_finfo.size;
626 finfo.mode = def_finfo.mode;
627 finfo.uid = def_finfo.uid;
628 finfo.gid = def_finfo.gid;
629 finfo.mtime = def_finfo.mtime;
630 finfo.atime = def_finfo.atime;
631 finfo.ctime = def_finfo.ctime;
634 if (dry_run)
636 DEBUG(3,("skipping file %s of size %d bytes\n",
637 finfo.name,
638 (int)finfo.size));
639 shallitime=0;
640 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
641 ntarf++;
642 return;
645 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
647 dos_clean_name(rname);
649 if (fnum == -1) {
650 DEBUG(0,("%s opening remote file %s (%s)\n",
651 cli_errstr(cli),rname, cur_dir));
652 return;
655 finfo.name = string_create_s(strlen(rname));
656 if (finfo.name == NULL) {
657 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
658 return;
661 safe_strcpy(finfo.name,rname, strlen(rname));
662 if (!finfo1) {
663 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
664 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
665 return;
667 finfo.ctime = finfo.mtime;
670 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
672 if (tar_inc && !(finfo.mode & aARCH))
674 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
675 shallitime=0;
677 else if (!tar_system && (finfo.mode & aSYSTEM))
679 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
680 shallitime=0;
682 else if (!tar_hidden && (finfo.mode & aHIDDEN))
684 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
685 shallitime=0;
687 else
689 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
690 finfo.name,
691 (int)finfo.size,
692 lname));
694 /* write a tar header, don't bother with mode - just set to 100644 */
695 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
697 while (nread < finfo.size && !close_done) {
699 DEBUG(3,("nread=%d\n",nread));
701 datalen = cli_read(cli, fnum, data, nread, read_size);
703 if (datalen == -1) {
704 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
705 break;
708 nread += datalen;
710 /* if file size has increased since we made file size query, truncate
711 read so tar header for this file will be correct.
714 if (nread > finfo.size) {
715 datalen -= nread - finfo.size;
716 DEBUG(0,("File size change - truncating %s to %d bytes\n", finfo.name, (int)finfo.size));
719 /* add received bits of file to buffer - dotarbuf will
720 * write out in 512 byte intervals */
721 if (dotarbuf(tarhandle,data,datalen) != datalen) {
722 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
723 break;
726 if (datalen == 0) {
727 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
728 break;
731 datalen=0;
734 /* pad tar file with zero's if we couldn't get entire file */
735 if (nread < finfo.size) {
736 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", (int)finfo.size, (int)nread));
737 if (padit(data, sizeof(data), finfo.size - nread))
738 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
741 /* round tar file to nearest block */
742 if (finfo.size % TBLOCK)
743 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
745 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
746 ntarf++;
749 cli_close(cli, fnum);
751 if (shallitime)
753 struct timeval tp_end;
754 int this_time;
756 /* if shallitime is true then we didn't skip */
757 if (tar_reset && !dry_run)
758 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
760 GetTimeOfDay(&tp_end);
761 this_time =
762 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
763 (tp_end.tv_usec - tp_start.tv_usec)/1000;
764 get_total_time_ms += this_time;
765 get_total_size += finfo.size;
767 if (tar_noisy)
769 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
770 (int)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
771 finfo.name));
774 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
775 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
776 finfo.size / MAX(0.001, (1.024*this_time)),
777 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
781 /****************************************************************************
782 Append single file to tar file (or not)
783 ***************************************************************************/
784 static void do_tar(file_info *finfo)
786 pstring rname;
788 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
789 return;
791 /* Is it on the exclude list ? */
792 if (!tar_excl && clipn) {
793 pstring exclaim;
795 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
797 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
798 *(exclaim+strlen(exclaim)-1)='\0';
800 safe_strcat(exclaim, "\\", sizeof(pstring));
801 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
803 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
805 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
806 #ifdef HAVE_REGEX_H
807 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
808 #else
809 (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
810 #endif
811 DEBUG(3,("Skipping file %s\n", exclaim));
812 return;
816 if (finfo->mode & aDIR)
818 pstring saved_curdir;
819 pstring mtar_mask;
821 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
823 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));
825 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
826 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
828 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
830 /* write a tar directory, don't bother with mode - just set it to
831 * 40755 */
832 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
833 if (tar_noisy) {
834 DEBUG(0,(" directory %s\n", cur_dir));
836 ntarf++; /* Make sure we have a file on there */
837 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
838 safe_strcat(mtar_mask,"*", sizeof(pstring));
839 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
840 do_list(mtar_mask, attribute, do_tar, False, True);
841 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
843 else
845 safe_strcpy(rname,cur_dir, sizeof(pstring));
846 safe_strcat(rname,finfo->name, sizeof(pstring));
847 do_atar(rname,finfo->name,finfo);
851 /****************************************************************************
852 Convert from UNIX to DOS file names
853 ***************************************************************************/
854 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
856 /* remove '.' from start of file name, convert from unix /'s to
857 * dos \'s in path. Kill any absolute path names. But only if first!
860 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
862 if (first) {
863 if (*fp == '.') {
864 fp++;
865 l--;
867 if (*fp == '\\' || *fp == '/') {
868 fp++;
869 l--;
873 safe_strcpy(tptr, fp, l);
874 string_replace(tptr, '/', '\\');
878 /****************************************************************************
879 Move to the next block in the buffer, which may mean read in another set of
880 blocks. FIXME, we should allow more than one block to be skipped.
881 ****************************************************************************/
882 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
884 int bufread, total = 0;
886 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
887 *bufferp += TBLOCK;
888 total = TBLOCK;
890 if (*bufferp >= (ltarbuf + bufsiz)) {
892 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
895 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
896 * Fixes bug where read can return short if coming from
897 * a pipe.
900 bufread = read(tarhandle, ltarbuf, bufsiz);
901 total = bufread;
903 while (total < bufsiz) {
904 if (bufread < 0) { /* An error, return false */
905 return (total > 0 ? -2 : bufread);
907 if (bufread == 0) {
908 if (total <= 0) {
909 return -2;
911 break;
913 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
914 total += bufread;
917 DEBUG(5, ("Total bytes read ... %i\n", total));
919 *bufferp = ltarbuf;
923 return(total);
927 /* Skip a file, even if it includes a long file name? */
928 static int skip_file(int skipsize)
930 int dsize = skipsize;
932 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
934 /* FIXME, we should skip more than one block at a time */
936 while (dsize > 0) {
938 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
940 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
941 return(False);
945 dsize -= TBLOCK;
949 return(True);
952 /*************************************************************
953 Get a file from the tar file and store it.
954 When this is called, tarbuf already contains the first
955 file block. This is a bit broken & needs fixing.
956 **************************************************************/
958 static int get_file(file_info2 finfo)
960 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
962 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
964 if (ensurepath(finfo.name) &&
965 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
966 DEBUG(0, ("abandoning restore\n"));
967 return(False);
970 /* read the blocks from the tar file and write to the remote file */
972 rsize = finfo.size; /* This is how much to write */
974 while (rsize > 0) {
976 /* We can only write up to the end of the buffer */
978 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
979 dsize = MIN(dsize, rsize); /* Should be only what is left */
980 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
982 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
983 DEBUG(0, ("Error writing remote file\n"));
984 return 0;
987 rsize -= dsize;
988 pos += dsize;
990 /* Now figure out how much to move in the buffer */
992 /* FIXME, we should skip more than one block at a time */
994 /* First, skip any initial part of the part written that is left over */
995 /* from the end of the first TBLOCK */
997 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
999 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1000 bpos = 0;
1002 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1003 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1004 return False;
1011 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1012 * If the file being extracted is an exact multiple of
1013 * TBLOCK bytes then we don't want to extract the next
1014 * block from the tarfile here, as it will be done in
1015 * the caller of get_file().
1018 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1019 ((rsize == 0) && (dsize > TBLOCK))) {
1021 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1022 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1023 return False;
1026 dsize -= TBLOCK;
1029 bpos = dsize;
1033 /* Now close the file ... */
1035 if (!cli_close(cli, fnum)) {
1036 DEBUG(0, ("Error closing remote file\n"));
1037 return(False);
1040 /* Now we update the creation date ... */
1042 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1044 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1045 if (tar_real_noisy) {
1046 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1047 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1051 ntarf++;
1053 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1055 return(True);
1058 /* Create a directory. We just ensure that the path exists and return as there
1059 is no file associated with a directory
1061 static int get_dir(file_info2 finfo)
1064 DEBUG(0, ("restore directory %s\n", finfo.name));
1066 if (!ensurepath(finfo.name)) {
1068 DEBUG(0, ("Problems creating directory\n"));
1069 return(False);
1073 ntarf++;
1074 return(True);
1077 /* Get a file with a long file name ... first file has file name, next file
1078 has the data. We only want the long file name, as the loop in do_tarput
1079 will deal with the rest.
1081 static char * get_longfilename(file_info2 finfo)
1083 int namesize = finfo.size + strlen(cur_dir) + 2;
1084 char *longname = malloc(namesize);
1085 int offset = 0, left = finfo.size;
1086 BOOL first = True;
1088 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1089 DEBUG(5, ("Len = %d\n", (int)finfo.size));
1091 if (longname == NULL) {
1093 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1094 (int)(finfo.size + strlen(cur_dir) + 2)));
1095 return(NULL);
1098 /* First, add cur_dir to the long file name */
1100 if (strlen(cur_dir) > 0) {
1101 strncpy(longname, cur_dir, namesize);
1102 offset = strlen(cur_dir);
1105 /* Loop through the blocks picking up the name */
1107 while (left > 0) {
1109 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1111 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1112 return(NULL);
1116 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1117 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1119 offset += TBLOCK;
1120 left -= TBLOCK;
1124 return(longname);
1128 static void do_tarput(void)
1130 file_info2 finfo;
1131 struct timeval tp_start;
1132 char *longfilename = NULL, linkflag;
1133 int skip = False;
1135 GetTimeOfDay(&tp_start);
1137 DEBUG(5, ("RJS do_tarput called ...\n"));
1139 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1141 /* Now read through those files ... */
1143 while (True) {
1145 /* Get us to the next block, or the first block first time around */
1147 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1149 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1151 return;
1155 DEBUG(5, ("Reading the next header ...\n"));
1157 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1159 case -2: /* Hmm, not good, but not fatal */
1160 DEBUG(0, ("Skipping %s...\n", finfo.name));
1161 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1162 !skip_file(finfo.size)) {
1164 DEBUG(0, ("Short file, bailing out...\n"));
1165 return;
1169 break;
1171 case -1:
1172 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1173 return;
1175 case 0: /* chksum is zero - looks like an EOF */
1176 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1177 return; /* Hmmm, bad here ... */
1179 default:
1180 /* No action */
1182 break;
1186 /* Now, do we have a long file name? */
1188 if (longfilename != NULL) {
1190 SAFE_FREE(finfo.name); /* Free the space already allocated */
1191 finfo.name = longfilename;
1192 longfilename = NULL;
1196 /* Well, now we have a header, process the file ... */
1198 /* Should we skip the file? We have the long name as well here */
1200 skip = clipn &&
1201 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1202 #ifdef HAVE_REGEX_H
1203 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1204 #else
1205 || (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
1206 #endif
1208 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1210 if (skip) {
1212 skip_file(finfo.size);
1213 continue;
1217 /* We only get this far if we should process the file */
1218 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1220 switch (linkflag) {
1222 case '0': /* Should use symbolic names--FIXME */
1225 * Skip to the next block first, so we can get the file, FIXME, should
1226 * be in get_file ...
1227 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1228 * Fixes bug where file size in tarfile is zero.
1231 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1232 DEBUG(0, ("Short file, bailing out...\n"));
1233 return;
1235 if (!get_file(finfo)) {
1236 DEBUG(0, ("Abandoning restore\n"));
1237 return;
1240 break;
1242 case '5':
1243 if (!get_dir(finfo)) {
1244 DEBUG(0, ("Abandoning restore \n"));
1245 return;
1247 break;
1249 case 'L':
1250 longfilename = get_longfilename(finfo);
1251 if (!longfilename) {
1252 DEBUG(0, ("abandoning restore\n"));
1253 return;
1256 DEBUG(5, ("Long file name: %s\n", longfilename));
1257 break;
1259 default:
1260 skip_file(finfo.size); /* Don't handle these yet */
1261 break;
1272 * samba interactive commands
1275 /****************************************************************************
1276 Blocksize command
1277 ***************************************************************************/
1278 int cmd_block(void)
1280 fstring buf;
1281 int block;
1283 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1285 DEBUG(0, ("blocksize <n>\n"));
1286 return 1;
1289 block=atoi(buf);
1290 if (block < 0 || block > 65535)
1292 DEBUG(0, ("blocksize out of range"));
1293 return 1;
1296 blocksize=block;
1297 DEBUG(2,("blocksize is now %d\n", blocksize));
1299 return 0;
1302 /****************************************************************************
1303 command to set incremental / reset mode
1304 ***************************************************************************/
1305 int cmd_tarmode(void)
1307 fstring buf;
1309 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1310 if (strequal(buf, "full"))
1311 tar_inc=False;
1312 else if (strequal(buf, "inc"))
1313 tar_inc=True;
1314 else if (strequal(buf, "reset"))
1315 tar_reset=True;
1316 else if (strequal(buf, "noreset"))
1317 tar_reset=False;
1318 else if (strequal(buf, "system"))
1319 tar_system=True;
1320 else if (strequal(buf, "nosystem"))
1321 tar_system=False;
1322 else if (strequal(buf, "hidden"))
1323 tar_hidden=True;
1324 else if (strequal(buf, "nohidden"))
1325 tar_hidden=False;
1326 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1327 tar_noisy=True;
1328 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1329 tar_noisy=False;
1330 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1333 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1334 tar_inc ? "incremental" : "full",
1335 tar_system ? "system" : "nosystem",
1336 tar_hidden ? "hidden" : "nohidden",
1337 tar_reset ? "reset" : "noreset",
1338 tar_noisy ? "verbose" : "quiet"));
1340 return 0;
1343 /****************************************************************************
1344 Feeble attrib command
1345 ***************************************************************************/
1346 int cmd_setmode(void)
1348 char *q;
1349 fstring buf;
1350 pstring fname;
1351 uint16 attra[2];
1352 int direct=1;
1354 attra[0] = attra[1] = 0;
1356 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1358 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1359 return 1;
1362 safe_strcpy(fname, cur_dir, sizeof(pstring));
1363 safe_strcat(fname, buf, sizeof(pstring));
1365 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1366 q=buf;
1368 while(*q)
1369 switch (*q++) {
1370 case '+': direct=1;
1371 break;
1372 case '-': direct=0;
1373 break;
1374 case 'r': attra[direct]|=aRONLY;
1375 break;
1376 case 'h': attra[direct]|=aHIDDEN;
1377 break;
1378 case 's': attra[direct]|=aSYSTEM;
1379 break;
1380 case 'a': attra[direct]|=aARCH;
1381 break;
1382 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1383 return 1;
1387 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1389 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1390 return 1;
1393 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1394 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1395 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1397 return 0;
1400 /****************************************************************************
1401 Principal command for creating / extracting
1402 ***************************************************************************/
1403 int cmd_tar(void)
1405 fstring buf;
1406 char **argl;
1407 int argcl;
1409 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1411 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1412 return 1;
1415 argl=toktocliplist(&argcl, NULL);
1416 if (!tar_parseargs(argcl, argl, buf, 0))
1417 return 1;
1419 process_tar();
1421 SAFE_FREE(argl);
1423 return 0;
1426 /****************************************************************************
1427 Command line (option) version
1428 ***************************************************************************/
1429 int process_tar(void)
1431 initarbuf();
1432 switch(tar_type) {
1433 case 'x':
1435 #if 0
1436 do_tarput2();
1437 #else
1438 do_tarput();
1439 #endif
1440 SAFE_FREE(tarbuf);
1441 close(tarhandle);
1442 break;
1443 case 'r':
1444 case 'c':
1445 if (clipn && tar_excl) {
1446 int i;
1447 pstring tarmac;
1449 for (i=0; i<clipn; i++) {
1450 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1452 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1453 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1456 if (strrchr_m(cliplist[i], '\\')) {
1457 pstring saved_dir;
1459 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1461 if (*cliplist[i]=='\\') {
1462 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1463 } else {
1464 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1465 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1467 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1468 *(strrchr_m(cur_dir, '\\')+1)='\0';
1470 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1471 do_list(tarmac,attribute,do_tar, False, True);
1472 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1473 } else {
1474 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1475 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1476 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1477 do_list(tarmac,attribute,do_tar, False, True);
1480 } else {
1481 pstring mask;
1482 safe_strcpy(mask,cur_dir, sizeof(pstring));
1483 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1484 safe_strcat(mask,"\\*", sizeof(pstring));
1485 do_list(mask,attribute,do_tar,False, True);
1488 if (ntarf) dotareof(tarhandle);
1489 close(tarhandle);
1490 SAFE_FREE(tarbuf);
1492 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1493 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1494 break;
1497 if (must_free_cliplist) {
1498 int i;
1499 for (i = 0; i < clipn; ++i) {
1500 SAFE_FREE(cliplist[i]);
1502 SAFE_FREE(cliplist);
1503 cliplist = NULL;
1504 clipn = 0;
1505 must_free_cliplist = False;
1508 return(0);
1511 /****************************************************************************
1512 Find a token (filename) in a clip list
1513 ***************************************************************************/
1514 static int clipfind(char **aret, int ret, char *tok)
1516 if (aret==NULL) return 0;
1518 /* ignore leading slashes or dots in token */
1519 while(strchr_m("/\\.", *tok)) tok++;
1521 while(ret--) {
1522 char *pkey=*aret++;
1524 /* ignore leading slashes or dots in list */
1525 while(strchr_m("/\\.", *pkey)) pkey++;
1527 if (!strslashcmp(pkey, tok)) return 1;
1530 return 0;
1533 /****************************************************************************
1534 Read list of files to include from the file and initialize cliplist
1535 accordingly.
1536 ***************************************************************************/
1537 static int read_inclusion_file(char *filename)
1539 XFILE *inclusion = NULL;
1540 char buf[MAXPATHLEN + 1];
1541 char *inclusion_buffer = NULL;
1542 int inclusion_buffer_size = 0;
1543 int inclusion_buffer_sofar = 0;
1544 char *p;
1545 char *tmpstr;
1546 int i;
1547 int error = 0;
1549 clipn = 0;
1550 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1551 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1552 /* XXX It would be better to include a reason for failure, but without
1553 * autoconf, it's hard to use strerror, sys_errlist, etc.
1555 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1556 return 0;
1559 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1560 if (inclusion_buffer == NULL) {
1561 inclusion_buffer_size = 1024;
1562 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1563 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1564 error = 1;
1565 break;
1569 if (buf[strlen(buf)-1] == '\n') {
1570 buf[strlen(buf)-1] = '\0';
1573 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1574 char *ib;
1575 inclusion_buffer_size *= 2;
1576 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1577 if (! ib) {
1578 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1579 inclusion_buffer_size));
1580 error = 1;
1581 break;
1583 else inclusion_buffer = ib;
1586 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1587 inclusion_buffer_sofar += strlen(buf) + 1;
1588 clipn++;
1590 x_fclose(inclusion);
1592 if (! error) {
1593 /* Allocate an array of clipn + 1 char*'s for cliplist */
1594 cliplist = malloc((clipn + 1) * sizeof(char *));
1595 if (cliplist == NULL) {
1596 DEBUG(0,("failure allocating memory for cliplist\n"));
1597 error = 1;
1598 } else {
1599 cliplist[clipn] = NULL;
1600 p = inclusion_buffer;
1601 for (i = 0; (! error) && (i < clipn); i++) {
1602 /* set current item to NULL so array will be null-terminated even if
1603 * malloc fails below. */
1604 cliplist[i] = NULL;
1605 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1606 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1607 error = 1;
1608 } else {
1609 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1610 cliplist[i] = tmpstr;
1611 if ((p = strchr_m(p, '\000')) == NULL) {
1612 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1613 abort();
1616 ++p;
1618 must_free_cliplist = True;
1622 SAFE_FREE(inclusion_buffer);
1623 if (error) {
1624 if (cliplist) {
1625 char **pp;
1626 /* We know cliplist is always null-terminated */
1627 for (pp = cliplist; *pp; ++pp) {
1628 SAFE_FREE(*pp);
1630 SAFE_FREE(cliplist);
1631 cliplist = NULL;
1632 must_free_cliplist = False;
1634 return 0;
1637 /* cliplist and its elements are freed at the end of process_tar. */
1638 return 1;
1641 /****************************************************************************
1642 Parse tar arguments. Sets tar_type, tar_excl, etc.
1643 ***************************************************************************/
1644 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1646 char tar_clipfl='\0';
1648 /* Reset back to defaults - could be from interactive version
1649 * reset mode and archive mode left as they are though
1651 tar_type='\0';
1652 tar_excl=True;
1653 dry_run=False;
1655 while (*Optarg)
1656 switch(*Optarg++) {
1657 case 'c':
1658 tar_type='c';
1659 break;
1660 case 'x':
1661 if (tar_type=='c') {
1662 printf("Tar must be followed by only one of c or x.\n");
1663 return 0;
1665 tar_type='x';
1666 break;
1667 case 'b':
1668 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1669 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1670 return 0;
1671 } else {
1672 Optind++;
1674 break;
1675 case 'g':
1676 tar_inc=True;
1677 break;
1678 case 'N':
1679 if (Optind>=argc) {
1680 DEBUG(0,("Option N must be followed by valid file name\n"));
1681 return 0;
1682 } else {
1683 SMB_STRUCT_STAT stbuf;
1684 extern time_t newer_than;
1686 if (sys_stat(argv[Optind], &stbuf) == 0) {
1687 newer_than = stbuf.st_mtime;
1688 DEBUG(1,("Getting files newer than %s",
1689 asctime(LocalTime(&newer_than))));
1690 Optind++;
1691 } else {
1692 DEBUG(0,("Error setting newer-than time\n"));
1693 return 0;
1696 break;
1697 case 'a':
1698 tar_reset=True;
1699 break;
1700 case 'q':
1701 tar_noisy=False;
1702 break;
1703 case 'I':
1704 if (tar_clipfl) {
1705 DEBUG(0,("Only one of I,X,F must be specified\n"));
1706 return 0;
1708 tar_clipfl='I';
1709 break;
1710 case 'X':
1711 if (tar_clipfl) {
1712 DEBUG(0,("Only one of I,X,F must be specified\n"));
1713 return 0;
1715 tar_clipfl='X';
1716 break;
1717 case 'F':
1718 if (tar_clipfl) {
1719 DEBUG(0,("Only one of I,X,F must be specified\n"));
1720 return 0;
1722 tar_clipfl='F';
1723 break;
1724 case 'r':
1725 DEBUG(0, ("tar_re_search set\n"));
1726 tar_re_search = True;
1727 break;
1728 case 'n':
1729 if (tar_type == 'c') {
1730 DEBUG(0, ("dry_run set\n"));
1731 dry_run = True;
1732 } else {
1733 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1734 return 0;
1736 break;
1737 default:
1738 DEBUG(0,("Unknown tar option\n"));
1739 return 0;
1742 if (!tar_type) {
1743 printf("Option T must be followed by one of c or x.\n");
1744 return 0;
1747 /* tar_excl is true if cliplist lists files to be included.
1748 * Both 'I' and 'F' mean include. */
1749 tar_excl=tar_clipfl!='X';
1751 if (tar_clipfl=='F') {
1752 if (argc-Optind-1 != 1) {
1753 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1754 return 0;
1756 if (! read_inclusion_file(argv[Optind+1])) {
1757 return 0;
1759 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1760 char *tmpstr;
1761 char **tmplist;
1762 int clipcount;
1764 cliplist=argv+Optind+1;
1765 clipn=argc-Optind-1;
1766 clipcount = clipn;
1768 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1769 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1770 clipn)
1772 return 0;
1775 for (clipcount = 0; clipcount < clipn; clipcount++) {
1777 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1779 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1780 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1781 clipcount)
1783 return 0;
1785 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1786 tmplist[clipcount] = tmpstr;
1787 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1789 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1791 cliplist = tmplist;
1792 must_free_cliplist = True;
1795 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1796 #ifdef HAVE_REGEX_H
1797 int errcode;
1799 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1801 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1802 return;
1806 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1807 char errstr[1024];
1808 size_t errlen;
1810 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1812 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1813 return;
1816 #endif
1818 clipn=argc-Optind-1;
1819 cliplist=argv+Optind+1;
1823 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1824 /* Sets tar handle to either 0 or 1, as appropriate */
1825 tarhandle=(tar_type=='c');
1827 * Make sure that dbf points to stderr if we are using stdout for
1828 * tar output
1830 if (tarhandle == 1)
1831 dbf = x_stderr;
1832 } else {
1833 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1835 if (!dry_run) {
1836 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1837 dry_run = True;
1839 tarhandle=-1;
1840 } else
1841 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1842 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1844 DEBUG(0,("Error opening local file %s - %s\n",
1845 argv[Optind], strerror(errno)));
1846 return(0);
1850 return 1;