This commit was manufactured by cvs2svn to create branch 'SAMBA_TNG'.
[Samba.git] / source / client / clitar.c
blobee1f97835c096be802269c126e71e7b1c897345e
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;
74 extern FILE *dbf;
76 /* These defines are for the do_setrattr routine, to indicate
77 * setting and reseting of file attributes in the function call */
78 #define ATTRSET 1
79 #define ATTRRESET 0
81 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
83 #ifndef CLIENT_TIMEOUT
84 #define CLIENT_TIMEOUT (30*1000)
85 #endif
87 static char *tarbuf, *buffer_p;
88 static int tp, ntarf, tbufsiz;
89 static double ttarf;
90 /* Incremental mode */
91 BOOL tar_inc=False;
92 /* Reset archive bit */
93 BOOL tar_reset=False;
94 /* Include / exclude mode (true=include, false=exclude) */
95 BOOL tar_excl=True;
96 /* use regular expressions for search on file names */
97 BOOL tar_re_search=False;
98 #ifdef HAVE_REGEX_H
99 regex_t *preg;
100 #endif
101 /* Do not dump anything, just calculate sizes */
102 BOOL dry_run=False;
103 /* Dump files with System attribute */
104 BOOL tar_system=True;
105 /* Dump files with Hidden attribute */
106 BOOL tar_hidden=True;
107 /* Be noisy - make a catalogue */
108 BOOL tar_noisy=True;
109 BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
111 char tar_type='\0';
112 static char **cliplist=NULL;
113 static int clipn=0;
114 static BOOL must_free_cliplist = False;
116 extern file_info def_finfo;
117 extern BOOL lowercase;
118 extern uint16 cnum;
119 extern BOOL readbraw_supported;
120 extern int max_xmit;
121 extern pstring cur_dir;
122 extern int get_total_time_ms;
123 extern int get_total_size;
124 extern int Protocol;
126 int blocksize=20;
127 int tarhandle;
129 static void writetarheader(int f, char *aname, int size, time_t mtime,
130 char *amode, unsigned char ftype);
131 static void do_atar(char *rname,char *lname,file_info *finfo1);
132 static void do_tar(file_info *finfo);
133 static void oct_it(long value, int ndgs, char *p);
134 static void fixtarname(char *tptr, char *fp, int l);
135 static int dotarbuf(int f, char *b, int n);
136 static void dozerobuf(int f, int n);
137 static void dotareof(int f);
138 static void initarbuf(void);
140 /* restore functions */
141 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
142 static long unoct(char *p, int ndgs);
143 static void do_tarput(void);
144 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
147 * tar specific utitlities
150 /*******************************************************************
151 Create a string of size size+1 (for the null)
152 *******************************************************************/
153 static char *string_create_s(int size)
155 char *tmp;
157 tmp = (char *)malloc(size+1);
159 if (tmp == NULL) {
161 DEBUG(0, ("Out of memory in string_create_s\n"));
165 return(tmp);
169 /****************************************************************************
170 Write a tar header to buffer
171 ****************************************************************************/
172 static void writetarheader(int f, char *aname, int size, time_t mtime,
173 char *amode, unsigned char ftype)
175 union hblock hb;
176 int i, chk, l;
177 char *jp;
179 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
181 memset(hb.dummy, 0, sizeof(hb.dummy));
183 l=strlen(aname);
184 if (l >= NAMSIZ) {
185 /* write a GNU tar style long header */
186 char *b;
187 b = (char *)malloc(l+TBLOCK+100);
188 if (!b) {
189 DEBUG(0,("out of memory\n"));
190 exit(1);
192 writetarheader(f, "/./@LongLink", l+1, 0, " 0 \0", 'L');
193 memset(b, 0, l+TBLOCK+100);
194 fixtarname(b, aname, l);
195 i = strlen(b)+1;
196 DEBUG(5, ("File name in tar file: %s, size=%i, \n", b, strlen(b)));
197 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
198 free(b);
201 /* use l + 1 to do the null too */
202 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
204 if (lowercase)
205 strlower(hb.dbuf.name);
207 /* write out a "standard" tar format header */
209 hb.dbuf.name[NAMSIZ-1]='\0';
210 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
211 oct_it(0L, 8, hb.dbuf.uid);
212 oct_it(0L, 8, hb.dbuf.gid);
213 oct_it((long) size, 13, hb.dbuf.size);
214 oct_it((long) mtime, 13, hb.dbuf.mtime);
215 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
216 memset(hb.dbuf.linkname, 0, NAMSIZ);
217 hb.dbuf.linkflag=ftype;
219 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
221 oct_it((long) chk, 8, hb.dbuf.chksum);
222 hb.dbuf.chksum[6] = '\0';
224 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
227 /****************************************************************************
228 Read a tar header into a hblock structure, and validate
229 ***************************************************************************/
230 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
232 long chk, fchk;
233 int i;
234 char *jp;
237 * read in a "standard" tar format header - we're not that interested
238 * in that many fields, though
241 /* check the checksum */
242 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
244 if (chk == 0)
245 return chk;
247 /* compensate for blanks in chksum header */
248 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
249 chk-=(0xFF & *jp++);
251 chk += ' ' * sizeof(hb->dbuf.chksum);
253 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
255 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
256 chk, fchk, hb->dbuf.chksum));
258 if (fchk != chk)
260 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
261 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
262 return -1;
265 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
267 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
268 return(-1);
272 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
274 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
275 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
276 strlen(hb->dbuf.name) + 1, True);
278 /* can't handle some links at present */
279 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
280 if (hb->dbuf.linkflag == 0) {
281 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
282 finfo->name));
283 } else {
284 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
285 /* Do nothing here at the moment. do_tarput will handle this
286 as long as the longlink gets back to it, as it has to advance
287 the buffer pointer, etc */
289 } else {
290 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
291 return -2;
296 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
297 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
299 finfo->mode=aDIR;
301 else
302 finfo->mode=0; /* we don't care about mode at the moment, we'll
303 * just make it a regular file */
305 * Bug fix by richard@sj.co.uk
307 * REC: restore times correctly (as does tar)
308 * We only get the modification time of the file; set the creation time
309 * from the mod. time, and the access time to current time
311 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
312 finfo->atime = time(NULL);
313 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
315 return True;
318 /****************************************************************************
319 Write out the tar buffer to tape or wherever
320 ****************************************************************************/
321 static int dotarbuf(int f, char *b, int n)
323 int fail=1, writ=n;
325 if (dry_run) {
326 return writ;
328 /* This routine and the next one should be the only ones that do write()s */
329 if (tp + n >= tbufsiz)
331 int diff;
333 diff=tbufsiz-tp;
334 memcpy(tarbuf + tp, b, diff);
335 fail=fail && (1+write(f, tarbuf, tbufsiz));
336 n-=diff;
337 b+=diff;
338 tp=0;
340 while (n >= tbufsiz)
342 fail=fail && (1 + write(f, b, tbufsiz));
343 n-=tbufsiz;
344 b+=tbufsiz;
347 if (n>0) {
348 memcpy(tarbuf+tp, b, n);
349 tp+=n;
352 return(fail ? writ : 0);
355 /****************************************************************************
356 Write zeros to buffer / tape
357 ****************************************************************************/
358 static void dozerobuf(int f, int n)
360 /* short routine just to write out n zeros to buffer -
361 * used to round files to nearest block
362 * and to do tar EOFs */
364 if (dry_run)
365 return;
367 if (n+tp >= tbufsiz)
369 memset(tarbuf+tp, 0, tbufsiz-tp);
371 write(f, tarbuf, tbufsiz);
372 memset(tarbuf, 0, (tp+=n-tbufsiz));
374 else
376 memset(tarbuf+tp, 0, n);
377 tp+=n;
381 /****************************************************************************
382 Malloc tape buffer
383 ****************************************************************************/
384 static void initarbuf(void)
386 /* initialize tar buffer */
387 tbufsiz=blocksize*TBLOCK;
388 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
390 /* reset tar buffer pointer and tar file counter and total dumped */
391 tp=0; ntarf=0; ttarf=0;
394 /****************************************************************************
395 Write two zero blocks at end of file
396 ****************************************************************************/
397 static void dotareof(int f)
399 SMB_STRUCT_STAT stbuf;
400 /* Two zero blocks at end of file, write out full buffer */
402 if (dry_run)
403 return;
405 (void) dozerobuf(f, TBLOCK);
406 (void) dozerobuf(f, TBLOCK);
408 if (sys_fstat(f, &stbuf) == -1)
410 DEBUG(0, ("Couldn't stat file handle\n"));
411 return;
414 /* Could be a pipe, in which case S_ISREG should fail,
415 * and we should write out at full size */
416 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
419 /****************************************************************************
420 (Un)mangle DOS pathname, make nonabsolute
421 ****************************************************************************/
422 static void fixtarname(char *tptr, char *fp, int l)
424 /* add a '.' to start of file name, convert from ugly dos \'s in path
425 * to lovely unix /'s :-} */
427 *tptr++='.';
429 while (l > 0) {
430 int skip;
431 if((skip = skip_multibyte_char( *fp)) != 0) {
432 if (skip == 2) {
433 *tptr++ = *fp++;
434 *tptr++ = *fp++;
435 l -= 2;
436 } else if (skip == 1) {
437 *tptr++ = *fp++;
438 l--;
440 } else if (*fp == '\\') {
441 *tptr++ = '/';
442 fp++;
443 l--;
444 } else {
445 *tptr++ = *fp++;
446 l--;
451 /****************************************************************************
452 Convert from decimal to octal string
453 ****************************************************************************/
454 static void oct_it (long value, int ndgs, char *p)
456 /* Converts long to octal string, pads with leading zeros */
458 /* skip final null, but do final space */
459 --ndgs;
460 p[--ndgs] = ' ';
462 /* Loop does at least one digit */
463 do {
464 p[--ndgs] = '0' + (char) (value & 7);
465 value >>= 3;
467 while (ndgs > 0 && value != 0);
469 /* Do leading zeros */
470 while (ndgs > 0)
471 p[--ndgs] = '0';
474 /****************************************************************************
475 Convert from octal string to long
476 ***************************************************************************/
477 static long unoct(char *p, int ndgs)
479 long value=0;
480 /* Converts octal string to long, ignoring any non-digit */
482 while (--ndgs)
484 if (isdigit((int)*p))
485 value = (value << 3) | (long) (*p - '0');
487 p++;
490 return value;
493 /****************************************************************************
494 Compare two strings in a slash insensitive way, allowing s1 to match s2
495 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
496 a file in any subdirectory of s1, declare a match.
497 ***************************************************************************/
498 static int strslashcmp(char *s1, char *s2)
500 char *s1_0=s1;
502 while(*s1 && *s2 &&
503 (*s1 == *s2
504 || tolower(*s1) == tolower(*s2)
505 || (*s1 == '\\' && *s2=='/')
506 || (*s1 == '/' && *s2=='\\'))) {
507 s1++; s2++;
510 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
511 string of s2.
513 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
515 /* ignore trailing slash on s1 */
516 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
518 /* check for s1 is an "initial" string of s2 */
519 if (*s2 == '/' || *s2 == '\\') return 0;
521 return *s1-*s2;
525 /****************************************************************************
526 Ensure a remote path exists (make if necessary)
527 ***************************************************************************/
528 static BOOL ensurepath(char *fname)
530 /* *must* be called with buffer ready malloc'ed */
531 /* ensures path exists */
533 char *partpath, *ffname;
534 char *p=fname, *basehack;
536 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
538 partpath = string_create_s(strlen(fname));
539 ffname = string_create_s(strlen(fname));
541 if ((partpath == NULL) || (ffname == NULL)){
543 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
544 return(False);
548 *partpath = 0;
550 /* fname copied to ffname so can strtok */
552 safe_strcpy(ffname, fname, strlen(fname));
554 /* do a `basename' on ffname, so don't try and make file name directory */
555 if ((basehack=strrchr(ffname, '\\')) == NULL)
556 return True;
557 else
558 *basehack='\0';
560 p=strtok(ffname, "\\");
562 while (p)
564 safe_strcat(partpath, p, strlen(fname) + 1);
566 if (!cli_chkpath(cli, partpath)) {
567 if (!cli_mkdir(cli, partpath))
569 DEBUG(0, ("Error mkdirhiering\n"));
570 return False;
572 else
573 DEBUG(3, ("mkdirhiering %s\n", partpath));
577 safe_strcat(partpath, "\\", strlen(fname) + 1);
578 p = strtok(NULL,"/\\");
581 return True;
584 static int padit(char *buf, int bufsize, int padsize)
586 int berr= 0;
587 int bytestowrite;
589 DEBUG(5, ("Padding with %d zeros\n", padsize));
590 memset(buf, 0, bufsize);
591 while( !berr && padsize > 0 ) {
592 bytestowrite= MIN(bufsize, padsize);
593 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
594 padsize -= bytestowrite;
597 return berr;
601 static void do_setrattr(char *name, uint16 attr, int set)
603 uint16 oldattr;
605 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
607 if (set == ATTRSET) {
608 attr |= oldattr;
609 } else {
610 attr = oldattr & ~attr;
613 if (!cli_setatr(cli, name, attr, 0)) {
614 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
619 /****************************************************************************
620 append one remote file to the tar file
621 ***************************************************************************/
622 static void do_atar(char *rname,char *lname,file_info *finfo1)
624 int fnum;
625 uint32 nread=0;
626 char ftype;
627 file_info2 finfo;
628 BOOL close_done = False;
629 BOOL shallitime=True;
630 char data[65520];
631 int read_size = 65520;
632 int datalen=0;
634 struct timeval tp_start;
635 GetTimeOfDay(&tp_start);
637 ftype = '0'; /* An ordinary file ... */
639 if (finfo1) {
640 finfo.size = finfo1 -> size;
641 finfo.mode = finfo1 -> mode;
642 finfo.uid = finfo1 -> uid;
643 finfo.gid = finfo1 -> gid;
644 finfo.mtime = finfo1 -> mtime;
645 finfo.atime = finfo1 -> atime;
646 finfo.ctime = finfo1 -> ctime;
648 else {
649 finfo.size = def_finfo.size;
650 finfo.mode = def_finfo.mode;
651 finfo.uid = def_finfo.uid;
652 finfo.gid = def_finfo.gid;
653 finfo.mtime = def_finfo.mtime;
654 finfo.atime = def_finfo.atime;
655 finfo.ctime = def_finfo.ctime;
658 if (dry_run)
660 DEBUG(3,("skipping file %s of size %d bytes\n",
661 finfo.name,
662 finfo.size));
663 shallitime=0;
664 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
665 ntarf++;
666 return;
669 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
671 dos_clean_name(rname);
673 if (fnum == -1) {
674 DEBUG(0,("%s opening remote file %s (%s)\n",
675 cli_errstr(cli),rname, cur_dir));
676 return;
679 finfo.name = string_create_s(strlen(rname));
680 if (finfo.name == NULL) {
681 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
682 return;
685 safe_strcpy(finfo.name,rname, strlen(rname));
686 if (!finfo1) {
687 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
688 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
689 return;
691 finfo.ctime = finfo.mtime;
694 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
696 if (tar_inc && !(finfo.mode & aARCH))
698 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
699 shallitime=0;
701 else if (!tar_system && (finfo.mode & aSYSTEM))
703 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
704 shallitime=0;
706 else if (!tar_hidden && (finfo.mode & aHIDDEN))
708 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
709 shallitime=0;
711 else
713 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
714 finfo.name,
715 finfo.size,
716 lname));
718 /* write a tar header, don't bother with mode - just set to 100644 */
719 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
721 while (nread < finfo.size && !close_done) {
723 DEBUG(3,("nread=%d\n",nread));
725 datalen = cli_read(cli, fnum, data, nread, read_size, True);
727 if (datalen == -1) {
728 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
729 break;
732 /* add received bits of file to buffer - dotarbuf will
733 * write out in 512 byte intervals */
734 if (dotarbuf(tarhandle,data,datalen) != datalen) {
735 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
736 break;
739 nread += datalen;
740 if (datalen == 0) {
741 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
742 break;
745 datalen=0;
748 /* pad tar file with zero's if we couldn't get entire file */
749 if (nread < finfo.size) {
750 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
751 if (padit(data, sizeof(data), finfo.size - nread))
752 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
755 /* round tar file to nearest block */
756 if (finfo.size % TBLOCK)
757 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
759 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
760 ntarf++;
763 cli_close(cli, fnum);
765 if (shallitime)
767 struct timeval tp_end;
768 int this_time;
770 /* if shallitime is true then we didn't skip */
771 if (tar_reset && !dry_run)
772 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
774 GetTimeOfDay(&tp_end);
775 this_time =
776 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
777 (tp_end.tv_usec - tp_start.tv_usec)/1000;
778 get_total_time_ms += this_time;
779 get_total_size += finfo.size;
781 if (tar_noisy)
783 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
784 finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
785 finfo.name));
788 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
789 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
790 finfo.size / MAX(0.001, (1.024*this_time)),
791 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
795 /****************************************************************************
796 Append single file to tar file (or not)
797 ***************************************************************************/
798 static void do_tar(file_info *finfo)
800 pstring rname;
802 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
803 return;
805 /* Is it on the exclude list ? */
806 if (!tar_excl && clipn) {
807 pstring exclaim;
809 DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir)));
811 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
812 *(exclaim+strlen(exclaim)-1)='\0';
814 safe_strcat(exclaim, "\\", sizeof(pstring));
815 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
817 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
819 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
820 #ifdef HAVE_REGEX_H
821 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
822 #else
823 (tar_re_search && mask_match(exclaim, cliplist[0], True, False))) {
824 #endif
825 DEBUG(3,("Skipping file %s\n", exclaim));
826 return;
830 if (finfo->mode & aDIR)
832 pstring saved_curdir;
833 pstring mtar_mask;
835 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
837 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));
839 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
840 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
842 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
844 /* write a tar directory, don't bother with mode - just set it to
845 * 40755 */
846 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
847 if (tar_noisy) {
848 DEBUG(0,(" directory %s\n", cur_dir));
850 ntarf++; /* Make sure we have a file on there */
851 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
852 safe_strcat(mtar_mask,"*", sizeof(pstring));
853 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
854 do_list(mtar_mask, attribute, do_tar, False, True);
855 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
857 else
859 safe_strcpy(rname,cur_dir, sizeof(pstring));
860 safe_strcat(rname,finfo->name, sizeof(pstring));
861 do_atar(rname,finfo->name,finfo);
865 /****************************************************************************
866 Convert from UNIX to DOS file names
867 ***************************************************************************/
868 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
870 /* remove '.' from start of file name, convert from unix /'s to
871 * dos \'s in path. Kill any absolute path names. But only if first!
874 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
876 if (first) {
877 if (*fp == '.') {
878 fp++;
879 l--;
881 if (*fp == '\\' || *fp == '/') {
882 fp++;
883 l--;
887 while (l > 0) {
888 int skip;
889 if(( skip = skip_multibyte_char( *fp )) != 0) {
890 if (skip == 2) {
891 *tptr++ = *fp++;
892 *tptr++ = *fp++;
893 l -= 2;
894 } else if (skip == 1) {
895 *tptr++ = *fp++;
896 l--;
898 } else if (*fp == '/') {
899 *tptr++ = '\\';
900 fp++;
901 l--;
902 } else {
903 *tptr++ = *fp++;
904 l--;
910 /****************************************************************************
911 Move to the next block in the buffer, which may mean read in another set of
912 blocks. FIXME, we should allow more than one block to be skipped.
913 ****************************************************************************/
914 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
916 int bufread, total = 0;
918 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
919 *bufferp += TBLOCK;
920 total = TBLOCK;
922 if (*bufferp >= (ltarbuf + bufsiz)) {
924 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
926 total = 0;
928 for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
930 if (bufread <= 0) { /* An error, return false */
931 return (total > 0 ? -2 : bufread);
936 DEBUG(5, ("Total bytes read ... %i\n", total));
938 *bufferp = ltarbuf;
942 return(total);
946 /* Skip a file, even if it includes a long file name? */
947 static int skip_file(int skipsize)
949 int dsize = skipsize;
951 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
953 /* FIXME, we should skip more than one block at a time */
955 while (dsize > 0) {
957 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
959 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
960 return(False);
964 dsize -= TBLOCK;
968 return(True);
971 /* We get a file from the tar file and store it */
972 static int get_file(file_info2 finfo)
974 int fsize = finfo.size;
975 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
977 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
979 if (ensurepath(finfo.name) &&
980 (fnum=cli_open(cli, finfo.name, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE)) == -1)
982 DEBUG(0, ("abandoning restore\n"));
983 return(False);
986 /* read the blocks from the tar file and write to the remote file */
988 rsize = fsize; /* This is how much to write */
990 while (rsize > 0) {
992 /* We can only write up to the end of the buffer */
994 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
995 dsize = MIN(dsize, rsize); /* Should be only what is left */
996 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
998 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize, dsize) != dsize) {
999 DEBUG(0, ("Error writing remote file\n"));
1000 return 0;
1003 rsize -= dsize;
1004 pos += dsize;
1006 /* Now figure out how much to move in the buffer */
1008 /* FIXME, we should skip more than one block at a time */
1010 /* First, skip any initial part of the part written that is left over */
1011 /* from the end of the first TBLOCK */
1013 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1015 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1016 bpos = 0;
1018 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1019 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1020 return False;
1026 while (dsize >= TBLOCK) {
1028 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1030 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1031 return False;
1035 dsize -= TBLOCK;
1039 bpos = dsize;
1043 /* Now close the file ... */
1045 if (!cli_close(cli, fnum)) {
1046 DEBUG(0, ("Error closing remote file\n"));
1047 return(False);
1050 /* Now we update the creation date ... */
1052 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1054 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1055 if (tar_real_noisy) {
1056 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1057 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1061 ntarf++;
1063 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
1065 return(True);
1068 /* Create a directory. We just ensure that the path exists and return as there
1069 is no file associated with a directory
1071 static int get_dir(file_info2 finfo)
1074 DEBUG(5, ("Creating directory: %s\n", finfo.name));
1076 if (!ensurepath(finfo.name)) {
1078 DEBUG(0, ("Problems creating directory\n"));
1079 return(False);
1082 return(True);
1085 /* Get a file with a long file name ... first file has file name, next file
1086 has the data. We only want the long file name, as the loop in do_tarput
1087 will deal with the rest.
1089 static char * get_longfilename(file_info2 finfo)
1091 int namesize = finfo.size + strlen(cur_dir) + 2;
1092 char *longname = malloc(namesize);
1093 int offset = 0, left = finfo.size;
1094 BOOL first = True;
1096 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1097 DEBUG(5, ("Len = %i\n", finfo.size));
1099 if (longname == NULL) {
1101 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1102 finfo.size + strlen(cur_dir) + 2));
1103 return(NULL);
1106 /* First, add cur_dir to the long file name */
1108 if (strlen(cur_dir) > 0) {
1109 strncpy(longname, cur_dir, namesize);
1110 offset = strlen(cur_dir);
1113 /* Loop through the blocks picking up the name */
1115 while (left > 0) {
1117 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1119 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1120 return(NULL);
1124 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1125 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1127 offset += TBLOCK;
1128 left -= TBLOCK;
1132 return(longname);
1136 static void do_tarput(void)
1138 file_info2 finfo;
1139 struct timeval tp_start;
1140 char *longfilename = NULL, linkflag;
1141 int skip = False;
1143 GetTimeOfDay(&tp_start);
1145 DEBUG(5, ("RJS do_tarput called ...\n"));
1147 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1149 /* Now read through those files ... */
1151 while (True) {
1153 /* Get us to the next block, or the first block first time around */
1155 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1157 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1159 return;
1163 DEBUG(5, ("Reading the next header ...\n"));
1165 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1167 case -2: /* Hmm, not good, but not fatal */
1168 DEBUG(0, ("Skipping %s...\n", finfo.name));
1169 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1170 !skip_file(finfo.size)) {
1172 DEBUG(0, ("Short file, bailing out...\n"));
1173 return;
1177 break;
1179 case -1:
1180 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1181 return;
1183 case 0: /* chksum is zero - looks like an EOF */
1184 DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
1185 return; /* Hmmm, bad here ... */
1187 default:
1188 /* No action */
1190 break;
1194 /* Now, do we have a long file name? */
1196 if (longfilename != NULL) {
1198 free(finfo.name); /* Free the space already allocated */
1199 finfo.name = longfilename;
1200 longfilename = NULL;
1204 /* Well, now we have a header, process the file ... */
1206 /* Should we skip the file? We have the long name as well here */
1208 skip = clipn &&
1209 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1210 #ifdef HAVE_REGEX_H
1211 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1212 #else
1213 || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
1214 #endif
1216 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1218 if (skip) {
1220 skip_file(finfo.size);
1221 continue;
1225 /* We only get this far if we should process the file */
1226 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1228 switch (linkflag) {
1230 case '0': /* Should use symbolic names--FIXME */
1232 /* Skip to the next block first, so we can get the file, FIXME, should
1233 be in get_file ... */
1235 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1236 DEBUG(0, ("Short file, bailing out...\n"));
1237 return;
1239 if (!get_file(finfo)) {
1240 DEBUG(0, ("Abandoning restore\n"));
1241 return;
1244 break;
1246 case '5':
1247 if (!get_dir(finfo)) {
1248 DEBUG(0, ("Abandoning restore \n"));
1249 return;
1251 break;
1253 case 'L':
1254 longfilename = get_longfilename(finfo);
1255 if (!longfilename) {
1256 DEBUG(0, ("abandoning restore\n"));
1257 return;
1260 DEBUG(5, ("Long file name: %s\n", longfilename));
1261 break;
1263 default:
1264 skip_file(finfo.size); /* Don't handle these yet */
1265 break;
1276 * samba interactive commands
1279 /****************************************************************************
1280 Blocksize command
1281 ***************************************************************************/
1282 void cmd_block(void)
1284 fstring buf;
1285 int block;
1287 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1289 DEBUG(0, ("blocksize <n>\n"));
1290 return;
1293 block=atoi(buf);
1294 if (block < 0 || block > 65535)
1296 DEBUG(0, ("blocksize out of range"));
1297 return;
1300 blocksize=block;
1301 DEBUG(2,("blocksize is now %d\n", blocksize));
1304 /****************************************************************************
1305 command to set incremental / reset mode
1306 ***************************************************************************/
1307 void cmd_tarmode(void)
1309 fstring buf;
1311 while (next_token(NULL,buf,NULL,sizeof(buf))) {
1312 if (strequal(buf, "full"))
1313 tar_inc=False;
1314 else if (strequal(buf, "inc"))
1315 tar_inc=True;
1316 else if (strequal(buf, "reset"))
1317 tar_reset=True;
1318 else if (strequal(buf, "noreset"))
1319 tar_reset=False;
1320 else if (strequal(buf, "system"))
1321 tar_system=True;
1322 else if (strequal(buf, "nosystem"))
1323 tar_system=False;
1324 else if (strequal(buf, "hidden"))
1325 tar_hidden=True;
1326 else if (strequal(buf, "nohidden"))
1327 tar_hidden=False;
1328 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1329 tar_noisy=True;
1330 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1331 tar_noisy=False;
1332 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1335 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1336 tar_inc ? "incremental" : "full",
1337 tar_system ? "system" : "nosystem",
1338 tar_hidden ? "hidden" : "nohidden",
1339 tar_reset ? "reset" : "noreset",
1340 tar_noisy ? "verbose" : "quiet"));
1344 /****************************************************************************
1345 Feeble attrib command
1346 ***************************************************************************/
1347 void cmd_setmode(void)
1349 char *q;
1350 fstring buf;
1351 pstring fname;
1352 uint16 attra[2];
1353 int direct=1;
1355 attra[0] = attra[1] = 0;
1357 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1359 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1360 return;
1363 safe_strcpy(fname, cur_dir, sizeof(pstring));
1364 safe_strcat(fname, buf, sizeof(pstring));
1366 while (next_token(NULL,buf,NULL,sizeof(buf))) {
1367 q=buf;
1369 while(*q)
1370 switch (*q++) {
1371 case '+': direct=1;
1372 break;
1373 case '-': direct=0;
1374 break;
1375 case 'r': attra[direct]|=aRONLY;
1376 break;
1377 case 'h': attra[direct]|=aHIDDEN;
1378 break;
1379 case 's': attra[direct]|=aSYSTEM;
1380 break;
1381 case 'a': attra[direct]|=aARCH;
1382 break;
1383 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1384 return;
1388 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1390 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1391 return;
1394 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1395 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1396 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1399 /****************************************************************************
1400 Principal command for creating / extracting
1401 ***************************************************************************/
1402 void cmd_tar(void)
1404 fstring buf;
1405 char **argl;
1406 int argcl;
1408 if (!next_token(NULL,buf,NULL,sizeof(buf)))
1410 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1411 return;
1414 argl=toktocliplist(&argcl, NULL);
1415 if (!tar_parseargs(argcl, argl, buf, 0))
1416 return;
1418 process_tar();
1420 free(argl);
1423 /****************************************************************************
1424 Command line (option) version
1425 ***************************************************************************/
1426 int process_tar(void)
1428 initarbuf();
1429 switch(tar_type) {
1430 case 'x':
1432 #if 0
1433 do_tarput2();
1434 #else
1435 do_tarput();
1436 #endif
1437 free(tarbuf);
1438 close(tarhandle);
1439 break;
1440 case 'r':
1441 case 'c':
1442 if (clipn && tar_excl) {
1443 int i;
1444 pstring tarmac;
1446 for (i=0; i<clipn; i++) {
1447 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1449 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1450 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1453 if (strrchr(cliplist[i], '\\')) {
1454 pstring saved_dir;
1456 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1458 if (*cliplist[i]=='\\') {
1459 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1460 } else {
1461 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1462 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1464 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1465 *(strrchr(cur_dir, '\\')+1)='\0';
1467 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1468 do_list(tarmac,attribute,do_tar, False, True);
1469 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1470 } else {
1471 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1472 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1473 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1474 do_list(tarmac,attribute,do_tar, False, True);
1477 } else {
1478 pstring mask;
1479 safe_strcpy(mask,cur_dir, sizeof(pstring));
1480 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1481 safe_strcat(mask,"\\*", sizeof(pstring));
1482 do_list(mask,attribute,do_tar,False, True);
1485 if (ntarf) dotareof(tarhandle);
1486 close(tarhandle);
1487 free(tarbuf);
1489 DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1490 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1491 break;
1494 if (must_free_cliplist) {
1495 int i;
1496 for (i = 0; i < clipn; ++i) {
1497 free(cliplist[i]);
1499 free(cliplist);
1500 cliplist = NULL;
1501 clipn = 0;
1502 must_free_cliplist = False;
1505 return(0);
1508 /****************************************************************************
1509 Find a token (filename) in a clip list
1510 ***************************************************************************/
1511 static int clipfind(char **aret, int ret, char *tok)
1513 if (aret==NULL) return 0;
1515 /* ignore leading slashes or dots in token */
1516 while(strchr("/\\.", *tok)) tok++;
1518 while(ret--) {
1519 char *pkey=*aret++;
1521 /* ignore leading slashes or dots in list */
1522 while(strchr("/\\.", *pkey)) pkey++;
1524 if (!strslashcmp(pkey, tok)) return 1;
1527 return 0;
1530 /****************************************************************************
1531 Read list of files to include from the file and initialize cliplist
1532 accordingly.
1533 ***************************************************************************/
1534 static int read_inclusion_file(char *filename)
1536 FILE *inclusion = NULL;
1537 char buf[MAXPATHLEN + 1];
1538 char *inclusion_buffer = NULL;
1539 int inclusion_buffer_size = 0;
1540 int inclusion_buffer_sofar = 0;
1541 char *p;
1542 char *tmpstr;
1543 int i;
1544 int error = 0;
1546 clipn = 0;
1547 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1548 if ((inclusion = sys_fopen(filename, "r")) == NULL) {
1549 /* XXX It would be better to include a reason for failure, but without
1550 * autoconf, it's hard to use strerror, sys_errlist, etc.
1552 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1553 return 0;
1556 while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1557 if (inclusion_buffer == NULL) {
1558 inclusion_buffer_size = 1024;
1559 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1560 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1561 error = 1;
1562 break;
1566 if (buf[strlen(buf)-1] == '\n') {
1567 buf[strlen(buf)-1] = '\0';
1570 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1571 inclusion_buffer_size *= 2;
1572 inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
1573 if (! inclusion_buffer) {
1574 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1575 inclusion_buffer_size));
1576 error = 1;
1577 break;
1581 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1582 inclusion_buffer_sofar += strlen(buf) + 1;
1583 clipn++;
1585 fclose(inclusion);
1587 if (! error) {
1588 /* Allocate an array of clipn + 1 char*'s for cliplist */
1589 cliplist = malloc((clipn + 1) * sizeof(char *));
1590 if (cliplist == NULL) {
1591 DEBUG(0,("failure allocating memory for cliplist\n"));
1592 error = 1;
1593 } else {
1594 cliplist[clipn] = NULL;
1595 p = inclusion_buffer;
1596 for (i = 0; (! error) && (i < clipn); i++) {
1597 /* set current item to NULL so array will be null-terminated even if
1598 * malloc fails below. */
1599 cliplist[i] = NULL;
1600 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1601 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1602 error = 1;
1603 } else {
1604 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1605 cliplist[i] = tmpstr;
1606 if ((p = strchr(p, '\000')) == NULL) {
1607 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1608 abort();
1611 ++p;
1613 must_free_cliplist = True;
1617 if (inclusion_buffer) {
1618 free(inclusion_buffer);
1620 if (error) {
1621 if (cliplist) {
1622 char **pp;
1623 /* We know cliplist is always null-terminated */
1624 for (pp = cliplist; *pp; ++pp) {
1625 free(*pp);
1627 free(cliplist);
1628 cliplist = NULL;
1629 must_free_cliplist = False;
1631 return 0;
1634 /* cliplist and its elements are freed at the end of process_tar. */
1635 return 1;
1638 /****************************************************************************
1639 Parse tar arguments. Sets tar_type, tar_excl, etc.
1640 ***************************************************************************/
1641 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1643 char tar_clipfl='\0';
1645 /* Reset back to defaults - could be from interactive version
1646 * reset mode and archive mode left as they are though
1648 tar_type='\0';
1649 tar_excl=True;
1650 dry_run=False;
1652 while (*Optarg)
1653 switch(*Optarg++) {
1654 case 'c':
1655 tar_type='c';
1656 break;
1657 case 'x':
1658 if (tar_type=='c') {
1659 printf("Tar must be followed by only one of c or x.\n");
1660 return 0;
1662 tar_type='x';
1663 break;
1664 case 'b':
1665 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1666 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1667 return 0;
1668 } else {
1669 Optind++;
1671 break;
1672 case 'g':
1673 tar_inc=True;
1674 break;
1675 case 'N':
1676 if (Optind>=argc) {
1677 DEBUG(0,("Option N must be followed by valid file name\n"));
1678 return 0;
1679 } else {
1680 SMB_STRUCT_STAT stbuf;
1681 extern time_t newer_than;
1683 if (dos_stat(argv[Optind], &stbuf) == 0) {
1684 newer_than = stbuf.st_mtime;
1685 DEBUG(1,("Getting files newer than %s",
1686 asctime(LocalTime(&newer_than))));
1687 Optind++;
1688 } else {
1689 DEBUG(0,("Error setting newer-than time\n"));
1690 return 0;
1693 break;
1694 case 'a':
1695 tar_reset=True;
1696 break;
1697 case 'q':
1698 tar_noisy=False;
1699 break;
1700 case 'I':
1701 if (tar_clipfl) {
1702 DEBUG(0,("Only one of I,X,F must be specified\n"));
1703 return 0;
1705 tar_clipfl='I';
1706 break;
1707 case 'X':
1708 if (tar_clipfl) {
1709 DEBUG(0,("Only one of I,X,F must be specified\n"));
1710 return 0;
1712 tar_clipfl='X';
1713 break;
1714 case 'F':
1715 if (tar_clipfl) {
1716 DEBUG(0,("Only one of I,X,F must be specified\n"));
1717 return 0;
1719 tar_clipfl='F';
1720 break;
1721 case 'r':
1722 DEBUG(0, ("tar_re_search set\n"));
1723 tar_re_search = True;
1724 break;
1725 case 'n':
1726 if (tar_type == 'c') {
1727 DEBUG(0, ("dry_run set\n"));
1728 dry_run = True;
1729 } else {
1730 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1731 return 0;
1733 break;
1734 default:
1735 DEBUG(0,("Unknown tar option\n"));
1736 return 0;
1739 if (!tar_type) {
1740 printf("Option T must be followed by one of c or x.\n");
1741 return 0;
1744 /* tar_excl is true if cliplist lists files to be included.
1745 * Both 'I' and 'F' mean include. */
1746 tar_excl=tar_clipfl!='X';
1748 if (tar_clipfl=='F') {
1749 if (argc-Optind-1 != 1) {
1750 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1751 return 0;
1753 if (! read_inclusion_file(argv[Optind+1])) {
1754 return 0;
1756 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1757 char *tmpstr;
1758 char **tmplist;
1759 int clipcount;
1761 cliplist=argv+Optind+1;
1762 clipn=argc-Optind-1;
1763 clipcount = clipn;
1765 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1766 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1767 clipn)
1769 return 0;
1772 for (clipcount = 0; clipcount < clipn; clipcount++) {
1774 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1776 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1777 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1778 clipcount)
1780 return 0;
1782 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1783 tmplist[clipcount] = tmpstr;
1784 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1786 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1788 cliplist = tmplist;
1789 must_free_cliplist = True;
1792 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1793 #ifdef HAVE_REGEX_H
1794 int errcode;
1796 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1798 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1799 return;
1803 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1804 char errstr[1024];
1805 size_t errlen;
1807 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1809 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1810 return;
1813 #endif
1815 clipn=argc-Optind-1;
1816 cliplist=argv+Optind+1;
1820 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1821 /* Sets tar handle to either 0 or 1, as appropriate */
1822 tarhandle=(tar_type=='c');
1824 * Make sure that dbf points to stderr if we are using stdout for
1825 * tar output
1827 if (tarhandle == 1)
1828 dbf = stderr;
1829 } else {
1830 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1832 if (!dry_run) {
1833 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1834 dry_run = True;
1836 tarhandle=-1;
1837 } else
1838 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1839 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1841 DEBUG(0,("Error opening local file %s - %s\n",
1842 argv[Optind], strerror(errno)));
1843 return(0);
1847 return 1;