Fixed problems in debug code because I did not compile
[Samba/gebeck_regimport.git] / source3 / client / clitar.c
blob4978a4dec154ca39dba8adf787e41a52c9ade438
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Tar Extensions
5 Copyright (C) Ricky Poulten 1995-1998
6 Copyright (C) Richard Sharpe 1998
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* The following changes developed by Richard Sharpe for Canon Information
23 Systems Research Australia (CISRA)
25 1. Restore can now restore files with long file names
26 2. Save now saves directory information so that we can restore
27 directory creation times
28 3. tar now accepts both UNIX path names and DOS path names. I prefer
29 those lovely /'s to those UGLY \'s :-)
30 4. the files to exclude can be specified as a regular expression by adding
31 an r flag to the other tar flags. Eg:
33 -TcrX file.tar "*.(obj|exe)"
35 will skip all .obj and .exe files
39 #include "includes.h"
40 #include "clitar.h"
42 static int clipfind(char **aret, int ret, char *tok);
44 typedef struct file_info_struct file_info2;
46 struct file_info_struct
48 size_t size;
49 uint16 mode;
50 int uid;
51 int gid;
52 /* These times are normally kept in GMT */
53 time_t mtime;
54 time_t atime;
55 time_t ctime;
56 char *name; /* This is dynamically allocate */
58 file_info2 *next, *prev; /* Used in the stack ... */
62 typedef struct
64 file_info2 *top;
65 int items;
67 } stack;
69 stack dir_stack = {NULL, 0}; /* Want an empty stack */
71 #define SEPARATORS " \t\n\r"
72 extern int DEBUGLEVEL;
73 extern struct cli_state *cli;
75 /* These defines are for the do_setrattr routine, to indicate
76 * setting and reseting of file attributes in the function call */
77 #define ATTRSET 1
78 #define ATTRRESET 0
80 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
82 #ifndef CLIENT_TIMEOUT
83 #define CLIENT_TIMEOUT (30*1000)
84 #endif
86 static char *tarbuf, *buffer_p;
87 static int tp, ntarf, tbufsiz, ttarf;
88 /* Incremental mode */
89 BOOL tar_inc=False;
90 /* Reset archive bit */
91 BOOL tar_reset=False;
92 /* Include / exclude mode (true=include, false=exclude) */
93 BOOL tar_excl=True;
94 /* use regular expressions for search on file names */
95 BOOL tar_re_search=False;
96 #ifdef HAVE_REGEX_H
97 regex_t *preg;
98 #endif
99 /* Do not dump anything, just calculate sizes */
100 BOOL dry_run=False;
101 /* Dump files with System attribute */
102 BOOL tar_system=True;
103 /* Dump files with Hidden attribute */
104 BOOL tar_hidden=True;
105 /* Be noisy - make a catalogue */
106 BOOL tar_noisy=True;
107 BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
109 char tar_type='\0';
110 static char **cliplist=NULL;
111 static int clipn=0;
112 static BOOL must_free_cliplist = False;
114 extern file_info def_finfo;
115 extern BOOL lowercase;
116 extern uint16 cnum;
117 extern BOOL readbraw_supported;
118 extern int max_xmit;
119 extern pstring cur_dir;
120 extern int get_total_time_ms;
121 extern int get_total_size;
122 extern int Protocol;
124 int blocksize=20;
125 int tarhandle;
127 static void writetarheader(int f, char *aname, int size, time_t mtime,
128 char *amode, unsigned char ftype);
129 static void do_atar(char *rname,char *lname,file_info *finfo1);
130 static void do_tar(file_info *finfo);
131 static void oct_it(long value, int ndgs, char *p);
132 static void fixtarname(char *tptr, char *fp, int l);
133 static int dotarbuf(int f, char *b, int n);
134 static void dozerobuf(int f, int n);
135 static void dotareof(int f);
136 static void initarbuf(void);
138 /* restore functions */
139 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
140 static long unoct(char *p, int ndgs);
141 static void do_tarput(void);
142 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
145 * tar specific utitlities
148 /*******************************************************************
149 Create a string of size size+1 (for the null)
150 *******************************************************************/
151 static char *string_create_s(int size)
153 char *tmp;
155 tmp = (char *)malloc(size+1);
157 if (tmp == NULL) {
159 DEBUG(0, ("Out of memory in string_create_s\n"));
163 return(tmp);
167 /****************************************************************************
168 Write a tar header to buffer
169 ****************************************************************************/
170 static void writetarheader(int f, char *aname, int size, time_t mtime,
171 char *amode, unsigned char ftype)
173 union hblock hb;
174 int i, chk, l;
175 char *jp;
177 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
179 memset(hb.dummy, 0, sizeof(hb.dummy));
181 l=strlen(aname);
182 if (l >= NAMSIZ) {
183 /* write a GNU tar style long header */
184 char *b;
185 b = (char *)malloc(l+TBLOCK+100);
186 if (!b) {
187 DEBUG(0,("out of memory\n"));
188 exit(1);
190 writetarheader(f, "/./@LongLink", l+1, 0, " 0 \0", 'L');
191 memset(b, 0, l+TBLOCK+100);
192 fixtarname(b, aname, l);
193 i = strlen(b)+1;
194 DEBUG(5, ("File name in tar file: %s, size=%i, \n", b, strlen(b)));
195 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
196 free(b);
199 /* use l + 1 to do the null too */
200 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
202 if (lowercase)
203 strlower(hb.dbuf.name);
205 /* write out a "standard" tar format header */
207 hb.dbuf.name[NAMSIZ-1]='\0';
208 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
209 oct_it(0L, 8, hb.dbuf.uid);
210 oct_it(0L, 8, hb.dbuf.gid);
211 oct_it((long) size, 13, hb.dbuf.size);
212 oct_it((long) mtime, 13, hb.dbuf.mtime);
213 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
214 memset(hb.dbuf.linkname, 0, NAMSIZ);
215 hb.dbuf.linkflag=ftype;
217 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
219 oct_it((long) chk, 8, hb.dbuf.chksum);
220 hb.dbuf.chksum[6] = '\0';
222 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
225 /****************************************************************************
226 Read a tar header into a hblock structure, and validate
227 ***************************************************************************/
228 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
230 long chk, fchk;
231 int i;
232 char *jp;
235 * read in a "standard" tar format header - we're not that interested
236 * in that many fields, though
239 /* check the checksum */
240 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
242 if (chk == 0)
243 return chk;
245 /* compensate for blanks in chksum header */
246 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
247 chk-=(0xFF & *jp++);
249 chk += ' ' * sizeof(hb->dbuf.chksum);
251 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
253 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
254 chk, fchk, hb->dbuf.chksum));
256 if (fchk != chk)
258 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
259 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
260 return -1;
263 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
265 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
266 return(-1);
270 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
272 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
273 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
274 strlen(hb->dbuf.name) + 1, True);
276 /* can't handle some links at present */
277 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
278 if (hb->dbuf.linkflag == 0) {
279 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
280 finfo->name));
281 } else {
282 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
283 /* Do nothing here at the moment. do_tarput will handle this
284 as long as the longlink gets back to it, as it has to advance
285 the buffer pointer, etc */
287 } else {
288 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
289 return -2;
294 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
295 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
297 finfo->mode=aDIR;
299 else
300 finfo->mode=0; /* we don't care about mode at the moment, we'll
301 * just make it a regular file */
303 * Bug fix by richard@sj.co.uk
305 * REC: restore times correctly (as does tar)
306 * We only get the modification time of the file; set the creation time
307 * from the mod. time, and the access time to current time
309 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
310 finfo->atime = time(NULL);
311 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
313 return True;
316 /****************************************************************************
317 Write out the tar buffer to tape or wherever
318 ****************************************************************************/
319 static int dotarbuf(int f, char *b, int n)
321 int fail=1, writ=n;
323 if (dry_run) {
324 return writ;
326 /* This routine and the next one should be the only ones that do write()s */
327 if (tp + n >= tbufsiz)
329 int diff;
331 diff=tbufsiz-tp;
332 memcpy(tarbuf + tp, b, diff);
333 fail=fail && (1+write(f, tarbuf, tbufsiz));
334 n-=diff;
335 b+=diff;
336 tp=0;
338 while (n >= tbufsiz)
340 fail=fail && (1 + write(f, b, tbufsiz));
341 n-=tbufsiz;
342 b+=tbufsiz;
345 if (n>0) {
346 memcpy(tarbuf+tp, b, n);
347 tp+=n;
350 return(fail ? writ : 0);
353 /****************************************************************************
354 Write zeros to buffer / tape
355 ****************************************************************************/
356 static void dozerobuf(int f, int n)
358 /* short routine just to write out n zeros to buffer -
359 * used to round files to nearest block
360 * and to do tar EOFs */
362 if (dry_run)
363 return;
365 if (n+tp >= tbufsiz)
367 memset(tarbuf+tp, 0, tbufsiz-tp);
369 write(f, tarbuf, tbufsiz);
370 memset(tarbuf, 0, (tp+=n-tbufsiz));
372 else
374 memset(tarbuf+tp, 0, n);
375 tp+=n;
379 /****************************************************************************
380 Malloc tape buffer
381 ****************************************************************************/
382 static void initarbuf(void)
384 /* initialize tar buffer */
385 tbufsiz=blocksize*TBLOCK;
386 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
388 /* reset tar buffer pointer and tar file counter and total dumped */
389 tp=0; ntarf=0; ttarf=0;
392 /****************************************************************************
393 Write two zero blocks at end of file
394 ****************************************************************************/
395 static void dotareof(int f)
397 SMB_STRUCT_STAT stbuf;
398 /* Two zero blocks at end of file, write out full buffer */
400 if (dry_run)
401 return;
403 (void) dozerobuf(f, TBLOCK);
404 (void) dozerobuf(f, TBLOCK);
406 if (sys_fstat(f, &stbuf) == -1)
408 DEBUG(0, ("Couldn't stat file handle\n"));
409 return;
412 /* Could be a pipe, in which case S_ISREG should fail,
413 * and we should write out at full size */
414 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
417 /****************************************************************************
418 (Un)mangle DOS pathname, make nonabsolute
419 ****************************************************************************/
420 static void fixtarname(char *tptr, char *fp, int l)
422 /* add a '.' to start of file name, convert from ugly dos \'s in path
423 * to lovely unix /'s :-} */
425 *tptr++='.';
427 while (l > 0) {
428 int skip;
429 if((skip = skip_multibyte_char( *fp)) != 0) {
430 if (skip == 2) {
431 *tptr++ = *fp++;
432 *tptr++ = *fp++;
433 l -= 2;
434 } else if (skip == 1) {
435 *tptr++ = *fp++;
436 l--;
438 } else if (*fp == '\\') {
439 *tptr++ = '/';
440 fp++;
441 l--;
442 } else {
443 *tptr++ = *fp++;
444 l--;
449 /****************************************************************************
450 Convert from decimal to octal string
451 ****************************************************************************/
452 static void oct_it (long value, int ndgs, char *p)
454 /* Converts long to octal string, pads with leading zeros */
456 /* skip final null, but do final space */
457 --ndgs;
458 p[--ndgs] = ' ';
460 /* Loop does at least one digit */
461 do {
462 p[--ndgs] = '0' + (char) (value & 7);
463 value >>= 3;
465 while (ndgs > 0 && value != 0);
467 /* Do leading zeros */
468 while (ndgs > 0)
469 p[--ndgs] = '0';
472 /****************************************************************************
473 Convert from octal string to long
474 ***************************************************************************/
475 static long unoct(char *p, int ndgs)
477 long value=0;
478 /* Converts octal string to long, ignoring any non-digit */
480 while (--ndgs)
482 if (isdigit((int)*p))
483 value = (value << 3) | (long) (*p - '0');
485 p++;
488 return value;
491 /****************************************************************************
492 Compare two strings in a slash insensitive way, allowing s1 to match s2
493 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
494 a file in any subdirectory of s1, declare a match.
495 ***************************************************************************/
496 static int strslashcmp(char *s1, char *s2)
498 char *s1_0=s1;
500 while(*s1 && *s2 &&
501 (*s1 == *s2
502 || tolower(*s1) == tolower(*s2)
503 || (*s1 == '\\' && *s2=='/')
504 || (*s1 == '/' && *s2=='\\'))) {
505 s1++; s2++;
508 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
509 string of s2.
511 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
513 /* ignore trailing slash on s1 */
514 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
516 /* check for s1 is an "initial" string of s2 */
517 if (*s2 == '/' || *s2 == '\\') return 0;
519 return *s1-*s2;
523 /****************************************************************************
524 Ensure a remote path exists (make if necessary)
525 ***************************************************************************/
526 static BOOL ensurepath(char *fname)
528 /* *must* be called with buffer ready malloc'ed */
529 /* ensures path exists */
531 char *partpath, *ffname;
532 char *p=fname, *basehack;
534 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
536 partpath = string_create_s(strlen(fname));
537 ffname = string_create_s(strlen(fname));
539 if ((partpath == NULL) || (ffname == NULL)){
541 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
542 return(False);
546 *partpath = 0;
548 /* fname copied to ffname so can strtok */
550 safe_strcpy(ffname, fname, strlen(fname));
552 /* do a `basename' on ffname, so don't try and make file name directory */
553 if ((basehack=strrchr(ffname, '\\')) == NULL)
554 return True;
555 else
556 *basehack='\0';
558 p=strtok(ffname, "\\");
560 while (p)
562 safe_strcat(partpath, p, strlen(fname) + 1);
564 if (!cli_chkpath(cli, partpath)) {
565 if (!cli_mkdir(cli, partpath))
567 DEBUG(0, ("Error mkdirhiering\n"));
568 return False;
570 else
571 DEBUG(3, ("mkdirhiering %s\n", partpath));
575 safe_strcat(partpath, "\\", strlen(fname) + 1);
576 p = strtok(NULL,"/\\");
579 return True;
582 static int padit(char *buf, int bufsize, int padsize)
584 int berr= 0;
585 int bytestowrite;
587 DEBUG(5, ("Padding with %d zeros\n", padsize));
588 memset(buf, 0, bufsize);
589 while( !berr && padsize > 0 ) {
590 bytestowrite= MIN(bufsize, padsize);
591 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
592 padsize -= bytestowrite;
595 return berr;
599 static void do_setrattr(char *name, uint16 attr, int set)
601 uint16 oldattr;
603 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
605 if (set == ATTRSET) {
606 attr |= oldattr;
607 } else {
608 attr = oldattr & ~attr;
611 if (!cli_setatr(cli, name, attr, 0)) {
612 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
617 /****************************************************************************
618 append one remote file to the tar file
619 ***************************************************************************/
620 static void do_atar(char *rname,char *lname,file_info *finfo1)
622 int fnum;
623 uint32 nread=0;
624 char ftype;
625 file_info2 finfo;
626 BOOL close_done = False;
627 BOOL shallitime=True;
628 char data[65520];
629 int read_size = 65520;
630 int datalen=0;
632 struct timeval tp_start;
633 GetTimeOfDay(&tp_start);
635 ftype = '0'; /* An ordinary file ... */
637 if (finfo1) {
638 finfo.size = finfo1 -> size;
639 finfo.mode = finfo1 -> mode;
640 finfo.uid = finfo1 -> uid;
641 finfo.gid = finfo1 -> gid;
642 finfo.mtime = finfo1 -> mtime;
643 finfo.atime = finfo1 -> atime;
644 finfo.ctime = finfo1 -> ctime;
646 else {
647 finfo.size = def_finfo.size;
648 finfo.mode = def_finfo.mode;
649 finfo.uid = def_finfo.uid;
650 finfo.gid = def_finfo.gid;
651 finfo.mtime = def_finfo.mtime;
652 finfo.atime = def_finfo.atime;
653 finfo.ctime = def_finfo.ctime;
656 if (dry_run)
658 DEBUG(3,("skipping file %s of size %d bytes\n",
659 finfo.name,
660 finfo.size));
661 shallitime=0;
662 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
663 ntarf++;
664 return;
667 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
669 dos_clean_name(rname);
671 if (fnum == -1) {
672 DEBUG(0,("%s opening remote file %s (%s)\n",
673 cli_errstr(cli),rname, cur_dir));
674 return;
677 finfo.name = string_create_s(strlen(rname));
678 if (finfo.name == NULL) {
679 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
680 return;
683 safe_strcpy(finfo.name,rname, strlen(rname));
684 if (!finfo1) {
685 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
686 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
687 return;
689 finfo.ctime = finfo.mtime;
692 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
694 if (tar_inc && !(finfo.mode & aARCH))
696 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
697 shallitime=0;
699 else if (!tar_system && (finfo.mode & aSYSTEM))
701 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
702 shallitime=0;
704 else if (!tar_hidden && (finfo.mode & aHIDDEN))
706 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
707 shallitime=0;
709 else
711 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
712 finfo.name,
713 finfo.size,
714 lname));
716 /* write a tar header, don't bother with mode - just set to 100644 */
717 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
719 while (nread < finfo.size && !close_done) {
721 DEBUG(3,("nread=%d\n",nread));
723 datalen = cli_read(cli, fnum, data, nread, read_size);
725 if (datalen == -1) {
726 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
727 break;
730 /* add received bits of file to buffer - dotarbuf will
731 * write out in 512 byte intervals */
732 if (dotarbuf(tarhandle,data,datalen) != datalen) {
733 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
734 break;
737 nread += datalen;
738 if (datalen == 0) {
739 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
740 break;
743 datalen=0;
746 /* pad tar file with zero's if we couldn't get entire file */
747 if (nread < finfo.size) {
748 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
749 if (padit(data, sizeof(data), finfo.size - nread))
750 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
753 /* round tar file to nearest block */
754 if (finfo.size % TBLOCK)
755 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
757 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
758 ntarf++;
761 cli_close(cli, fnum);
763 if (shallitime)
765 struct timeval tp_end;
766 int this_time;
768 /* if shallitime is true then we didn't skip */
769 if (tar_reset && !dry_run)
770 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
772 GetTimeOfDay(&tp_end);
773 this_time =
774 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
775 (tp_end.tv_usec - tp_start.tv_usec)/1000;
776 get_total_time_ms += this_time;
777 get_total_size += finfo.size;
779 if (tar_noisy)
781 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
782 finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
783 finfo.name));
786 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
787 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
788 finfo.size / MAX(0.001, (1.024*this_time)),
789 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
793 /****************************************************************************
794 Append single file to tar file (or not)
795 ***************************************************************************/
796 static void do_tar(file_info *finfo)
798 pstring rname;
800 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
801 return;
803 /* Is it on the exclude list ? */
804 if (!tar_excl && clipn) {
805 pstring exclaim;
807 DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir)));
809 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
810 *(exclaim+strlen(exclaim)-1)='\0';
812 safe_strcat(exclaim, "\\", sizeof(pstring));
813 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
815 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
817 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
818 #ifdef HAVE_REGEX_H
819 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
820 #else
821 (tar_re_search && mask_match(exclaim, cliplist[0], True, False))) {
822 #endif
823 DEBUG(3,("Skipping file %s\n", exclaim));
824 return;
828 if (finfo->mode & aDIR)
830 pstring saved_curdir;
831 pstring mtar_mask;
833 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
835 DEBUG(5, ("Sizeof(cur_dir)=%i, strlen(cur_dir)=%i, strlen(finfo->name)=%i\nname=%s,cur_dir=%s\n", sizeof(cur_dir), strlen(cur_dir), strlen(finfo->name), finfo->name, cur_dir));
837 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
838 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
840 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
842 /* write a tar directory, don't bother with mode - just set it to
843 * 40755 */
844 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
845 if (tar_noisy) {
846 DEBUG(0,(" directory %s\n", cur_dir));
848 ntarf++; /* Make sure we have a file on there */
849 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
850 safe_strcat(mtar_mask,"*", sizeof(pstring));
851 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
852 do_list(mtar_mask, attribute, do_tar, False, True);
853 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
855 else
857 safe_strcpy(rname,cur_dir, sizeof(pstring));
858 safe_strcat(rname,finfo->name, sizeof(pstring));
859 do_atar(rname,finfo->name,finfo);
863 /****************************************************************************
864 Convert from UNIX to DOS file names
865 ***************************************************************************/
866 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
868 /* remove '.' from start of file name, convert from unix /'s to
869 * dos \'s in path. Kill any absolute path names. But only if first!
872 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
874 if (first) {
875 if (*fp == '.') {
876 fp++;
877 l--;
879 if (*fp == '\\' || *fp == '/') {
880 fp++;
881 l--;
885 while (l > 0) {
886 int skip;
887 if(( skip = skip_multibyte_char( *fp )) != 0) {
888 if (skip == 2) {
889 *tptr++ = *fp++;
890 *tptr++ = *fp++;
891 l -= 2;
892 } else if (skip == 1) {
893 *tptr++ = *fp++;
894 l--;
896 } else if (*fp == '/') {
897 *tptr++ = '\\';
898 fp++;
899 l--;
900 } else {
901 *tptr++ = *fp++;
902 l--;
908 /****************************************************************************
909 Move to the next block in the buffer, which may mean read in another set of
910 blocks. FIXME, we should allow more than one block to be skipped.
911 ****************************************************************************/
912 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
914 int bufread, total = 0;
916 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
917 *bufferp += TBLOCK;
918 total = TBLOCK;
920 if (*bufferp >= (ltarbuf + bufsiz)) {
922 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
924 total = 0;
926 for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
928 if (bufread <= 0) { /* An error, return false */
929 return (total > 0 ? -2 : bufread);
934 DEBUG(5, ("Total bytes read ... %i\n", total));
936 *bufferp = ltarbuf;
940 return(total);
944 /* Skip a file, even if it includes a long file name? */
945 static int skip_file(int skipsize)
947 int dsize = skipsize;
949 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
951 /* FIXME, we should skip more than one block at a time */
953 while (dsize > 0) {
955 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
957 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
958 return(False);
962 dsize -= TBLOCK;
966 return(True);
969 /* We get a file from the tar file and store it */
970 static int get_file(file_info2 finfo)
972 int fsize = finfo.size;
973 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
975 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
977 if (ensurepath(finfo.name) &&
978 (fnum=cli_open(cli, finfo.name, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE)) == -1)
980 DEBUG(0, ("abandoning restore\n"));
981 return(False);
984 /* read the blocks from the tar file and write to the remote file */
986 rsize = fsize; /* This is how much to write */
988 while (rsize > 0) {
990 /* We can only write up to the end of the buffer */
992 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
993 dsize = MIN(dsize, rsize); /* Should be only what is left */
994 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
996 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
997 DEBUG(0, ("Error writing remote file\n"));
998 return 0;
1001 rsize -= dsize;
1002 pos += dsize;
1004 /* Now figure out how much to move in the buffer */
1006 /* FIXME, we should skip more than one block at a time */
1008 /* First, skip any initial part of the part written that is left over */
1009 /* from the end of the first TBLOCK */
1011 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1013 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1014 bpos = 0;
1016 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1017 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1018 return False;
1024 while (dsize >= TBLOCK) {
1026 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1028 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1029 return False;
1033 dsize -= TBLOCK;
1037 bpos = dsize;
1041 /* Now close the file ... */
1043 if (!cli_close(cli, fnum)) {
1044 DEBUG(0, ("Error closing remote file\n"));
1045 return(False);
1048 /* Now we update the creation date ... */
1050 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1052 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1053 if (tar_real_noisy) {
1054 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1055 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1059 ntarf++;
1061 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
1063 return(True);
1066 /* Create a directory. We just ensure that the path exists and return as there
1067 is no file associated with a directory
1069 static int get_dir(file_info2 finfo)
1072 DEBUG(5, ("Creating directory: %s\n", finfo.name));
1074 if (!ensurepath(finfo.name)) {
1076 DEBUG(0, ("Problems creating directory\n"));
1077 return(False);
1080 return(True);
1083 /* Get a file with a long file name ... first file has file name, next file
1084 has the data. We only want the long file name, as the loop in do_tarput
1085 will deal with the rest.
1087 static char * get_longfilename(file_info2 finfo)
1089 int namesize = finfo.size + strlen(cur_dir) + 2;
1090 char *longname = malloc(namesize);
1091 int offset = 0, left = finfo.size;
1092 BOOL first = True;
1094 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1095 DEBUG(5, ("Len = %i\n", finfo.size));
1097 if (longname == NULL) {
1099 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1100 finfo.size + strlen(cur_dir) + 2));
1101 return(NULL);
1104 /* First, add cur_dir to the long file name */
1106 if (strlen(cur_dir) > 0) {
1107 strncpy(longname, cur_dir, namesize);
1108 offset = strlen(cur_dir);
1111 /* Loop through the blocks picking up the name */
1113 while (left > 0) {
1115 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1117 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1118 return(NULL);
1122 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1123 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1125 offset += TBLOCK;
1126 left -= TBLOCK;
1130 return(longname);
1134 static void do_tarput(void)
1136 file_info2 finfo;
1137 struct timeval tp_start;
1138 char *longfilename = NULL, linkflag;
1139 int skip = False;
1141 GetTimeOfDay(&tp_start);
1143 DEBUG(5, ("RJS do_tarput called ...\n"));
1145 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1147 /* Now read through those files ... */
1149 while (True) {
1151 /* Get us to the next block, or the first block first time around */
1153 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1155 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1157 return;
1161 DEBUG(5, ("Reading the next header ...\n"));
1163 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1165 case -2: /* Hmm, not good, but not fatal */
1166 DEBUG(0, ("Skipping %s...\n", finfo.name));
1167 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1168 !skip_file(finfo.size)) {
1170 DEBUG(0, ("Short file, bailing out...\n"));
1171 return;
1175 break;
1177 case -1:
1178 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1179 return;
1181 case 0: /* chksum is zero - looks like an EOF */
1182 DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
1183 return; /* Hmmm, bad here ... */
1185 default:
1186 /* No action */
1188 break;
1192 /* Now, do we have a long file name? */
1194 if (longfilename != NULL) {
1196 free(finfo.name); /* Free the space already allocated */
1197 finfo.name = longfilename;
1198 longfilename = NULL;
1202 /* Well, now we have a header, process the file ... */
1204 /* Should we skip the file? We have the long name as well here */
1206 skip = clipn &&
1207 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1208 #ifdef HAVE_REGEX_H
1209 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1210 #else
1211 || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
1212 #endif
1214 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1216 if (skip) {
1218 skip_file(finfo.size);
1219 continue;
1223 /* We only get this far if we should process the file */
1224 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1226 switch (linkflag) {
1228 case '0': /* Should use symbolic names--FIXME */
1230 /* Skip to the next block first, so we can get the file, FIXME, should
1231 be in get_file ... */
1233 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1234 DEBUG(0, ("Short file, bailing out...\n"));
1235 return;
1237 if (!get_file(finfo)) {
1238 DEBUG(0, ("Abandoning restore\n"));
1239 return;
1242 break;
1244 case '5':
1245 if (!get_dir(finfo)) {
1246 DEBUG(0, ("Abandoning restore \n"));
1247 return;
1249 break;
1251 case 'L':
1252 longfilename = get_longfilename(finfo);
1253 if (!longfilename) {
1254 DEBUG(0, ("abandoning restore\n"));
1255 return;
1258 DEBUG(5, ("Long file name: %s\n", longfilename));
1259 break;
1261 default:
1262 skip_file(finfo.size); /* Don't handle these yet */
1263 break;
1274 * samba interactive commands
1277 /****************************************************************************
1278 Blocksize command
1279 ***************************************************************************/
1280 void cmd_block(void)
1282 fstring buf;
1283 int block;
1285 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1287 DEBUG(0, ("blocksize <n>\n"));
1288 return;
1291 block=atoi(buf);
1292 if (block < 0 || block > 65535)
1294 DEBUG(0, ("blocksize out of range"));
1295 return;
1298 blocksize=block;
1299 DEBUG(2,("blocksize is now %d\n", blocksize));
1302 /****************************************************************************
1303 command to set incremental / reset mode
1304 ***************************************************************************/
1305 void cmd_tarmode(void)
1307 fstring buf;
1309 while (next_token(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"));
1342 /****************************************************************************
1343 Feeble attrib command
1344 ***************************************************************************/
1345 void cmd_setmode(void)
1347 char *q;
1348 fstring buf;
1349 pstring fname;
1350 uint16 attra[2];
1351 int direct=1;
1353 attra[0] = attra[1] = 0;
1355 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1357 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1358 return;
1361 safe_strcpy(fname, cur_dir, sizeof(pstring));
1362 safe_strcat(fname, buf, sizeof(pstring));
1364 while (next_token(NULL,buf,NULL,sizeof(buf))) {
1365 q=buf;
1367 while(*q)
1368 switch (*q++) {
1369 case '+': direct=1;
1370 break;
1371 case '-': direct=0;
1372 break;
1373 case 'r': attra[direct]|=aRONLY;
1374 break;
1375 case 'h': attra[direct]|=aHIDDEN;
1376 break;
1377 case 's': attra[direct]|=aSYSTEM;
1378 break;
1379 case 'a': attra[direct]|=aARCH;
1380 break;
1381 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1382 return;
1386 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1388 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1389 return;
1392 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1393 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1394 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1397 /****************************************************************************
1398 Principal command for creating / extracting
1399 ***************************************************************************/
1400 void cmd_tar(void)
1402 fstring buf;
1403 char **argl;
1404 int argcl;
1406 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1408 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1409 return;
1412 argl=toktocliplist(&argcl, NULL);
1413 if (!tar_parseargs(argcl, argl, buf, 0))
1414 return;
1416 process_tar();
1418 free(argl);
1421 /****************************************************************************
1422 Command line (option) version
1423 ***************************************************************************/
1424 int process_tar(void)
1426 initarbuf();
1427 switch(tar_type) {
1428 case 'x':
1430 #if 0
1431 do_tarput2();
1432 #else
1433 do_tarput();
1434 #endif
1435 free(tarbuf);
1436 close(tarhandle);
1437 break;
1438 case 'r':
1439 case 'c':
1440 if (clipn && tar_excl) {
1441 int i;
1442 pstring tarmac;
1444 for (i=0; i<clipn; i++) {
1445 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1447 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1448 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1451 if (strrchr(cliplist[i], '\\')) {
1452 pstring saved_dir;
1454 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1456 if (*cliplist[i]=='\\') {
1457 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1458 } else {
1459 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1460 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1462 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1463 *(strrchr(cur_dir, '\\')+1)='\0';
1465 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1466 do_list(tarmac,attribute,do_tar, False, True);
1467 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1468 } else {
1469 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1470 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1471 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1472 do_list(tarmac,attribute,do_tar, False, True);
1475 } else {
1476 pstring mask;
1477 safe_strcpy(mask,cur_dir, sizeof(pstring));
1478 DEBUG(5, ("process_tar, do_list with mask: $s\n", mask));
1479 safe_strcat(mask,"\\*", sizeof(pstring));
1480 do_list(mask,attribute,do_tar,False, True);
1483 if (ntarf) dotareof(tarhandle);
1484 close(tarhandle);
1485 free(tarbuf);
1487 DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1488 DEBUG(0, ("Total bytes written: %d\n", ttarf));
1489 break;
1492 if (must_free_cliplist) {
1493 int i;
1494 for (i = 0; i < clipn; ++i) {
1495 free(cliplist[i]);
1497 free(cliplist);
1498 cliplist = NULL;
1499 clipn = 0;
1500 must_free_cliplist = False;
1503 return(0);
1506 /****************************************************************************
1507 Find a token (filename) in a clip list
1508 ***************************************************************************/
1509 static int clipfind(char **aret, int ret, char *tok)
1511 if (aret==NULL) return 0;
1513 /* ignore leading slashes or dots in token */
1514 while(strchr("/\\.", *tok)) tok++;
1516 while(ret--) {
1517 char *pkey=*aret++;
1519 /* ignore leading slashes or dots in list */
1520 while(strchr("/\\.", *pkey)) pkey++;
1522 if (!strslashcmp(pkey, tok)) return 1;
1525 return 0;
1528 /****************************************************************************
1529 Read list of files to include from the file and initialize cliplist
1530 accordingly.
1531 ***************************************************************************/
1532 static int read_inclusion_file(char *filename)
1534 FILE *inclusion = NULL;
1535 char buf[MAXPATHLEN + 1];
1536 char *inclusion_buffer = NULL;
1537 int inclusion_buffer_size = 0;
1538 int inclusion_buffer_sofar = 0;
1539 char *p;
1540 char *tmpstr;
1541 int i;
1542 int error = 0;
1544 clipn = 0;
1545 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1546 if ((inclusion = sys_fopen(filename, "r")) == NULL) {
1547 /* XXX It would be better to include a reason for failure, but without
1548 * autoconf, it's hard to use strerror, sys_errlist, etc.
1550 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1551 return 0;
1554 while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1555 if (inclusion_buffer == NULL) {
1556 inclusion_buffer_size = 1024;
1557 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1558 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1559 error = 1;
1560 break;
1564 if (buf[strlen(buf)-1] == '\n') {
1565 buf[strlen(buf)-1] = '\0';
1568 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1569 inclusion_buffer_size *= 2;
1570 inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
1571 if (! inclusion_buffer) {
1572 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1573 inclusion_buffer_size));
1574 error = 1;
1575 break;
1579 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1580 inclusion_buffer_sofar += strlen(buf) + 1;
1581 clipn++;
1583 fclose(inclusion);
1585 if (! error) {
1586 /* Allocate an array of clipn + 1 char*'s for cliplist */
1587 cliplist = malloc((clipn + 1) * sizeof(char *));
1588 if (cliplist == NULL) {
1589 DEBUG(0,("failure allocating memory for cliplist\n"));
1590 error = 1;
1591 } else {
1592 cliplist[clipn] = NULL;
1593 p = inclusion_buffer;
1594 for (i = 0; (! error) && (i < clipn); i++) {
1595 /* set current item to NULL so array will be null-terminated even if
1596 * malloc fails below. */
1597 cliplist[i] = NULL;
1598 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1599 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1600 error = 1;
1601 } else {
1602 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1603 cliplist[i] = tmpstr;
1604 if ((p = strchr(p, '\000')) == NULL) {
1605 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1606 abort();
1609 ++p;
1611 must_free_cliplist = True;
1615 if (inclusion_buffer) {
1616 free(inclusion_buffer);
1618 if (error) {
1619 if (cliplist) {
1620 char **pp;
1621 /* We know cliplist is always null-terminated */
1622 for (pp = cliplist; *pp; ++pp) {
1623 free(*pp);
1625 free(cliplist);
1626 cliplist = NULL;
1627 must_free_cliplist = False;
1629 return 0;
1632 /* cliplist and its elements are freed at the end of process_tar. */
1633 return 1;
1636 /****************************************************************************
1637 Parse tar arguments. Sets tar_type, tar_excl, etc.
1638 ***************************************************************************/
1639 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1641 char tar_clipfl='\0';
1643 /* Reset back to defaults - could be from interactive version
1644 * reset mode and archive mode left as they are though
1646 tar_type='\0';
1647 tar_excl=True;
1648 dry_run=False;
1650 while (*Optarg)
1651 switch(*Optarg++) {
1652 case 'c':
1653 tar_type='c';
1654 break;
1655 case 'x':
1656 if (tar_type=='c') {
1657 printf("Tar must be followed by only one of c or x.\n");
1658 return 0;
1660 tar_type='x';
1661 break;
1662 case 'b':
1663 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1664 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1665 return 0;
1666 } else {
1667 Optind++;
1669 break;
1670 case 'g':
1671 tar_inc=True;
1672 break;
1673 case 'N':
1674 if (Optind>=argc) {
1675 DEBUG(0,("Option N must be followed by valid file name\n"));
1676 return 0;
1677 } else {
1678 SMB_STRUCT_STAT stbuf;
1679 extern time_t newer_than;
1681 if (dos_stat(argv[Optind], &stbuf) == 0) {
1682 newer_than = stbuf.st_mtime;
1683 DEBUG(1,("Getting files newer than %s",
1684 asctime(LocalTime(&newer_than))));
1685 Optind++;
1686 } else {
1687 DEBUG(0,("Error setting newer-than time\n"));
1688 return 0;
1691 break;
1692 case 'a':
1693 tar_reset=True;
1694 break;
1695 case 'q':
1696 tar_noisy=False;
1697 break;
1698 case 'I':
1699 if (tar_clipfl) {
1700 DEBUG(0,("Only one of I,X,F must be specified\n"));
1701 return 0;
1703 tar_clipfl='I';
1704 break;
1705 case 'X':
1706 if (tar_clipfl) {
1707 DEBUG(0,("Only one of I,X,F must be specified\n"));
1708 return 0;
1710 tar_clipfl='X';
1711 break;
1712 case 'F':
1713 if (tar_clipfl) {
1714 DEBUG(0,("Only one of I,X,F must be specified\n"));
1715 return 0;
1717 tar_clipfl='F';
1718 break;
1719 case 'r':
1720 DEBUG(0, ("tar_re_search set\n"));
1721 tar_re_search = True;
1722 break;
1723 case 'n':
1724 if (tar_type == 'c') {
1725 DEBUG(0, ("dry_run set\n"));
1726 dry_run = True;
1727 } else {
1728 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1729 return 0;
1731 break;
1732 default:
1733 DEBUG(0,("Unknown tar option\n"));
1734 return 0;
1737 if (!tar_type) {
1738 printf("Option T must be followed by one of c or x.\n");
1739 return 0;
1742 /* tar_excl is true if cliplist lists files to be included.
1743 * Both 'I' and 'F' mean include. */
1744 tar_excl=tar_clipfl!='X';
1746 if (tar_clipfl=='F') {
1747 if (argc-Optind-1 != 1) {
1748 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1749 return 0;
1751 if (! read_inclusion_file(argv[Optind+1])) {
1752 return 0;
1754 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1755 char *tmpstr;
1756 char **tmplist;
1757 int clipcount;
1759 cliplist=argv+Optind+1;
1760 clipn=argc-Optind-1;
1761 clipcount = clipn;
1763 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1764 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1765 clipn)
1767 return 0;
1770 for (clipcount = 0; clipcount < clipn; clipcount++) {
1772 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1774 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1775 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1776 clipcount)
1778 return 0;
1780 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1781 tmplist[clipcount] = tmpstr;
1782 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1784 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1786 cliplist = tmplist;
1787 must_free_cliplist = True;
1790 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1791 #ifdef HAVE_REGEX_H
1792 int errcode;
1794 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1796 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1797 return;
1801 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1802 char errstr[1024];
1803 size_t errlen;
1805 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1807 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1808 return;
1811 #endif
1813 clipn=argc-Optind-1;
1814 cliplist=argv+Optind+1;
1818 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1819 /* Sets tar handle to either 0 or 1, as appropriate */
1820 tarhandle=(tar_type=='c');
1821 } else {
1822 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1824 if (!dry_run) {
1825 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1826 dry_run = True;
1828 tarhandle=-1;
1829 } else
1830 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1831 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1833 DEBUG(0,("Error opening local file %s - %s\n",
1834 argv[Optind], strerror(errno)));
1835 return(0);
1839 return 1;