me stupid.
[Samba.git] / source / client / clitar.c
blobd28e652b35e974230deadc963853e44ee4f8d627
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 - 1) {
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+2, 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=%d, \n", b, (int)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 :-} */
426 *tptr++='.';
428 safe_strcpy(tptr, fp, l);
429 string_replace(tptr, '\\', '/');
432 /****************************************************************************
433 Convert from decimal to octal string
434 ****************************************************************************/
435 static void oct_it (long value, int ndgs, char *p)
437 /* Converts long to octal string, pads with leading zeros */
439 /* skip final null, but do final space */
440 --ndgs;
441 p[--ndgs] = ' ';
443 /* Loop does at least one digit */
444 do {
445 p[--ndgs] = '0' + (char) (value & 7);
446 value >>= 3;
448 while (ndgs > 0 && value != 0);
450 /* Do leading zeros */
451 while (ndgs > 0)
452 p[--ndgs] = '0';
455 /****************************************************************************
456 Convert from octal string to long
457 ***************************************************************************/
458 static long unoct(char *p, int ndgs)
460 long value=0;
461 /* Converts octal string to long, ignoring any non-digit */
463 while (--ndgs)
465 if (isdigit((int)*p))
466 value = (value << 3) | (long) (*p - '0');
468 p++;
471 return value;
474 /****************************************************************************
475 Compare two strings in a slash insensitive way, allowing s1 to match s2
476 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
477 a file in any subdirectory of s1, declare a match.
478 ***************************************************************************/
479 static int strslashcmp(char *s1, char *s2)
481 char *s1_0=s1;
483 while(*s1 && *s2 &&
484 (*s1 == *s2
485 || tolower(*s1) == tolower(*s2)
486 || (*s1 == '\\' && *s2=='/')
487 || (*s1 == '/' && *s2=='\\'))) {
488 s1++; s2++;
491 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
492 string of s2.
494 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
496 /* ignore trailing slash on s1 */
497 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
499 /* check for s1 is an "initial" string of s2 */
500 if (*s2 == '/' || *s2 == '\\') return 0;
502 return *s1-*s2;
506 /****************************************************************************
507 Ensure a remote path exists (make if necessary)
508 ***************************************************************************/
509 static BOOL ensurepath(char *fname)
511 /* *must* be called with buffer ready malloc'ed */
512 /* ensures path exists */
514 char *partpath, *ffname;
515 char *p=fname, *basehack;
517 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
519 partpath = string_create_s(strlen(fname));
520 ffname = string_create_s(strlen(fname));
522 if ((partpath == NULL) || (ffname == NULL)){
524 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
525 return(False);
529 *partpath = 0;
531 /* fname copied to ffname so can strtok */
533 safe_strcpy(ffname, fname, strlen(fname));
535 /* do a `basename' on ffname, so don't try and make file name directory */
536 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
537 return True;
538 else
539 *basehack='\0';
541 p=strtok(ffname, "\\");
543 while (p)
545 safe_strcat(partpath, p, strlen(fname) + 1);
547 if (!cli_chkpath(cli, partpath)) {
548 if (!cli_mkdir(cli, partpath))
550 DEBUG(0, ("Error mkdirhiering\n"));
551 return False;
553 else
554 DEBUG(3, ("mkdirhiering %s\n", partpath));
558 safe_strcat(partpath, "\\", strlen(fname) + 1);
559 p = strtok(NULL,"/\\");
562 return True;
565 static int padit(char *buf, int bufsize, int padsize)
567 int berr= 0;
568 int bytestowrite;
570 DEBUG(5, ("Padding with %d zeros\n", padsize));
571 memset(buf, 0, bufsize);
572 while( !berr && padsize > 0 ) {
573 bytestowrite= MIN(bufsize, padsize);
574 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
575 padsize -= bytestowrite;
578 return berr;
582 static void do_setrattr(char *name, uint16 attr, int set)
584 uint16 oldattr;
586 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
588 if (set == ATTRSET) {
589 attr |= oldattr;
590 } else {
591 attr = oldattr & ~attr;
594 if (!cli_setatr(cli, name, attr, 0)) {
595 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
600 /****************************************************************************
601 append one remote file to the tar file
602 ***************************************************************************/
603 static void do_atar(char *rname,char *lname,file_info *finfo1)
605 int fnum;
606 uint32 nread=0;
607 char ftype;
608 file_info2 finfo;
609 BOOL close_done = False;
610 BOOL shallitime=True;
611 char data[65520];
612 int read_size = 65520;
613 int datalen=0;
615 struct timeval tp_start;
616 GetTimeOfDay(&tp_start);
618 ftype = '0'; /* An ordinary file ... */
620 if (finfo1) {
621 finfo.size = finfo1 -> size;
622 finfo.mode = finfo1 -> mode;
623 finfo.uid = finfo1 -> uid;
624 finfo.gid = finfo1 -> gid;
625 finfo.mtime = finfo1 -> mtime;
626 finfo.atime = finfo1 -> atime;
627 finfo.ctime = finfo1 -> ctime;
629 else {
630 finfo.size = def_finfo.size;
631 finfo.mode = def_finfo.mode;
632 finfo.uid = def_finfo.uid;
633 finfo.gid = def_finfo.gid;
634 finfo.mtime = def_finfo.mtime;
635 finfo.atime = def_finfo.atime;
636 finfo.ctime = def_finfo.ctime;
639 if (dry_run)
641 DEBUG(3,("skipping file %s of size %d bytes\n",
642 finfo.name,
643 (int)finfo.size));
644 shallitime=0;
645 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
646 ntarf++;
647 return;
650 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
652 dos_clean_name(rname);
654 if (fnum == -1) {
655 DEBUG(0,("%s opening remote file %s (%s)\n",
656 cli_errstr(cli),rname, cur_dir));
657 return;
660 finfo.name = string_create_s(strlen(rname));
661 if (finfo.name == NULL) {
662 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
663 return;
666 safe_strcpy(finfo.name,rname, strlen(rname));
667 if (!finfo1) {
668 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
669 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
670 return;
672 finfo.ctime = finfo.mtime;
675 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
677 if (tar_inc && !(finfo.mode & aARCH))
679 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
680 shallitime=0;
682 else if (!tar_system && (finfo.mode & aSYSTEM))
684 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
685 shallitime=0;
687 else if (!tar_hidden && (finfo.mode & aHIDDEN))
689 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
690 shallitime=0;
692 else
694 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
695 finfo.name,
696 (int)finfo.size,
697 lname));
699 /* write a tar header, don't bother with mode - just set to 100644 */
700 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
702 while (nread < finfo.size && !close_done) {
704 DEBUG(3,("nread=%d\n",nread));
706 datalen = cli_read(cli, fnum, data, nread, read_size);
708 if (datalen == -1) {
709 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
710 break;
713 nread += datalen;
715 /* if file size has increased since we made file size query, truncate
716 read so tar header for this file will be correct.
719 if (nread > finfo.size) {
720 datalen -= nread - finfo.size;
721 DEBUG(0,("File size change - truncating %s to %d bytes\n", finfo.name, (int)finfo.size));
724 /* add received bits of file to buffer - dotarbuf will
725 * write out in 512 byte intervals */
726 if (dotarbuf(tarhandle,data,datalen) != datalen) {
727 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
728 break;
731 if (datalen == 0) {
732 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
733 break;
736 datalen=0;
739 /* pad tar file with zero's if we couldn't get entire file */
740 if (nread < finfo.size) {
741 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", (int)finfo.size, (int)nread));
742 if (padit(data, sizeof(data), finfo.size - nread))
743 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
746 /* round tar file to nearest block */
747 if (finfo.size % TBLOCK)
748 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
750 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
751 ntarf++;
754 cli_close(cli, fnum);
756 if (shallitime)
758 struct timeval tp_end;
759 int this_time;
761 /* if shallitime is true then we didn't skip */
762 if (tar_reset && !dry_run)
763 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
765 GetTimeOfDay(&tp_end);
766 this_time =
767 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
768 (tp_end.tv_usec - tp_start.tv_usec)/1000;
769 get_total_time_ms += this_time;
770 get_total_size += finfo.size;
772 if (tar_noisy)
774 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
775 (int)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
776 finfo.name));
779 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
780 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
781 finfo.size / MAX(0.001, (1.024*this_time)),
782 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
786 /****************************************************************************
787 Append single file to tar file (or not)
788 ***************************************************************************/
789 static void do_tar(file_info *finfo)
791 pstring rname;
793 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
794 return;
796 /* Is it on the exclude list ? */
797 if (!tar_excl && clipn) {
798 pstring exclaim;
800 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
802 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
803 *(exclaim+strlen(exclaim)-1)='\0';
805 safe_strcat(exclaim, "\\", sizeof(pstring));
806 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
808 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
810 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
811 #ifdef HAVE_REGEX_H
812 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
813 #else
814 (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
815 #endif
816 DEBUG(3,("Skipping file %s\n", exclaim));
817 return;
821 if (finfo->mode & aDIR)
823 pstring saved_curdir;
824 pstring mtar_mask;
826 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
828 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", (int)sizeof(cur_dir), (int)strlen(cur_dir), (int)strlen(finfo->name), finfo->name, cur_dir));
830 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
831 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
833 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
835 /* write a tar directory, don't bother with mode - just set it to
836 * 40755 */
837 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
838 if (tar_noisy) {
839 DEBUG(0,(" directory %s\n", cur_dir));
841 ntarf++; /* Make sure we have a file on there */
842 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
843 safe_strcat(mtar_mask,"*", sizeof(pstring));
844 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
845 do_list(mtar_mask, attribute, do_tar, False, True);
846 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
848 else
850 safe_strcpy(rname,cur_dir, sizeof(pstring));
851 safe_strcat(rname,finfo->name, sizeof(pstring));
852 do_atar(rname,finfo->name,finfo);
856 /****************************************************************************
857 Convert from UNIX to DOS file names
858 ***************************************************************************/
859 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
861 /* remove '.' from start of file name, convert from unix /'s to
862 * dos \'s in path. Kill any absolute path names. But only if first!
865 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
867 if (first) {
868 if (*fp == '.') {
869 fp++;
870 l--;
872 if (*fp == '\\' || *fp == '/') {
873 fp++;
874 l--;
878 safe_strcpy(tptr, fp, l);
879 string_replace(tptr, '/', '\\');
883 /****************************************************************************
884 Move to the next block in the buffer, which may mean read in another set of
885 blocks. FIXME, we should allow more than one block to be skipped.
886 ****************************************************************************/
887 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
889 int bufread, total = 0;
891 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
892 *bufferp += TBLOCK;
893 total = TBLOCK;
895 if (*bufferp >= (ltarbuf + bufsiz)) {
897 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
900 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
901 * Fixes bug where read can return short if coming from
902 * a pipe.
905 bufread = read(tarhandle, ltarbuf, bufsiz);
906 total = bufread;
908 while (total < bufsiz) {
909 if (bufread < 0) { /* An error, return false */
910 return (total > 0 ? -2 : bufread);
912 if (bufread == 0) {
913 if (total <= 0) {
914 return -2;
916 break;
918 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
919 total += bufread;
922 DEBUG(5, ("Total bytes read ... %i\n", total));
924 *bufferp = ltarbuf;
928 return(total);
932 /* Skip a file, even if it includes a long file name? */
933 static int skip_file(int skipsize)
935 int dsize = skipsize;
937 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
939 /* FIXME, we should skip more than one block at a time */
941 while (dsize > 0) {
943 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
945 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
946 return(False);
950 dsize -= TBLOCK;
954 return(True);
957 /*************************************************************
958 Get a file from the tar file and store it.
959 When this is called, tarbuf already contains the first
960 file block. This is a bit broken & needs fixing.
961 **************************************************************/
963 static int get_file(file_info2 finfo)
965 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
967 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
969 if (ensurepath(finfo.name) &&
970 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
971 DEBUG(0, ("abandoning restore\n"));
972 return(False);
975 /* read the blocks from the tar file and write to the remote file */
977 rsize = finfo.size; /* This is how much to write */
979 while (rsize > 0) {
981 /* We can only write up to the end of the buffer */
983 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
984 dsize = MIN(dsize, rsize); /* Should be only what is left */
985 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
987 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
988 DEBUG(0, ("Error writing remote file\n"));
989 return 0;
992 rsize -= dsize;
993 pos += dsize;
995 /* Now figure out how much to move in the buffer */
997 /* FIXME, we should skip more than one block at a time */
999 /* First, skip any initial part of the part written that is left over */
1000 /* from the end of the first TBLOCK */
1002 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1004 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1005 bpos = 0;
1007 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1008 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1009 return False;
1016 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1017 * If the file being extracted is an exact multiple of
1018 * TBLOCK bytes then we don't want to extract the next
1019 * block from the tarfile here, as it will be done in
1020 * the caller of get_file().
1023 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1024 ((rsize == 0) && (dsize > TBLOCK))) {
1026 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1027 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1028 return False;
1031 dsize -= TBLOCK;
1034 bpos = dsize;
1038 /* Now close the file ... */
1040 if (!cli_close(cli, fnum)) {
1041 DEBUG(0, ("Error closing remote file\n"));
1042 return(False);
1045 /* Now we update the creation date ... */
1047 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1049 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1050 if (tar_real_noisy) {
1051 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1052 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1056 ntarf++;
1058 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
1060 return(True);
1063 /* Create a directory. We just ensure that the path exists and return as there
1064 is no file associated with a directory
1066 static int get_dir(file_info2 finfo)
1069 DEBUG(0, ("restore directory %s\n", finfo.name));
1071 if (!ensurepath(finfo.name)) {
1073 DEBUG(0, ("Problems creating directory\n"));
1074 return(False);
1078 ntarf++;
1079 return(True);
1082 /* Get a file with a long file name ... first file has file name, next file
1083 has the data. We only want the long file name, as the loop in do_tarput
1084 will deal with the rest.
1086 static char * get_longfilename(file_info2 finfo)
1088 int namesize = finfo.size + strlen(cur_dir) + 2;
1089 char *longname = malloc(namesize);
1090 int offset = 0, left = finfo.size;
1091 BOOL first = True;
1093 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1094 DEBUG(5, ("Len = %d\n", (int)finfo.size));
1096 if (longname == NULL) {
1098 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1099 (int)(finfo.size + strlen(cur_dir) + 2)));
1100 return(NULL);
1103 /* First, add cur_dir to the long file name */
1105 if (strlen(cur_dir) > 0) {
1106 strncpy(longname, cur_dir, namesize);
1107 offset = strlen(cur_dir);
1110 /* Loop through the blocks picking up the name */
1112 while (left > 0) {
1114 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1116 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1117 return(NULL);
1121 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1122 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1124 offset += TBLOCK;
1125 left -= TBLOCK;
1129 return(longname);
1133 static void do_tarput(void)
1135 file_info2 finfo;
1136 struct timeval tp_start;
1137 char *longfilename = NULL, linkflag;
1138 int skip = False;
1140 GetTimeOfDay(&tp_start);
1142 DEBUG(5, ("RJS do_tarput called ...\n"));
1144 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1146 /* Now read through those files ... */
1148 while (True) {
1150 /* Get us to the next block, or the first block first time around */
1152 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1154 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1156 return;
1160 DEBUG(5, ("Reading the next header ...\n"));
1162 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1164 case -2: /* Hmm, not good, but not fatal */
1165 DEBUG(0, ("Skipping %s...\n", finfo.name));
1166 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1167 !skip_file(finfo.size)) {
1169 DEBUG(0, ("Short file, bailing out...\n"));
1170 return;
1174 break;
1176 case -1:
1177 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1178 return;
1180 case 0: /* chksum is zero - looks like an EOF */
1181 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1182 return; /* Hmmm, bad here ... */
1184 default:
1185 /* No action */
1187 break;
1191 /* Now, do we have a long file name? */
1193 if (longfilename != NULL) {
1195 free(finfo.name); /* Free the space already allocated */
1196 finfo.name = longfilename;
1197 longfilename = NULL;
1201 /* Well, now we have a header, process the file ... */
1203 /* Should we skip the file? We have the long name as well here */
1205 skip = clipn &&
1206 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1207 #ifdef HAVE_REGEX_H
1208 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1209 #else
1210 || (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
1211 #endif
1213 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1215 if (skip) {
1217 skip_file(finfo.size);
1218 continue;
1222 /* We only get this far if we should process the file */
1223 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1225 switch (linkflag) {
1227 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 ...
1232 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1233 * Fixes bug where file size in tarfile is zero.
1236 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1237 DEBUG(0, ("Short file, bailing out...\n"));
1238 return;
1240 if (!get_file(finfo)) {
1241 DEBUG(0, ("Abandoning restore\n"));
1242 return;
1245 break;
1247 case '5':
1248 if (!get_dir(finfo)) {
1249 DEBUG(0, ("Abandoning restore \n"));
1250 return;
1252 break;
1254 case 'L':
1255 longfilename = get_longfilename(finfo);
1256 if (!longfilename) {
1257 DEBUG(0, ("abandoning restore\n"));
1258 return;
1261 DEBUG(5, ("Long file name: %s\n", longfilename));
1262 break;
1264 default:
1265 skip_file(finfo.size); /* Don't handle these yet */
1266 break;
1277 * samba interactive commands
1280 /****************************************************************************
1281 Blocksize command
1282 ***************************************************************************/
1283 void cmd_block(void)
1285 fstring buf;
1286 int block;
1288 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1290 DEBUG(0, ("blocksize <n>\n"));
1291 return;
1294 block=atoi(buf);
1295 if (block < 0 || block > 65535)
1297 DEBUG(0, ("blocksize out of range"));
1298 return;
1301 blocksize=block;
1302 DEBUG(2,("blocksize is now %d\n", blocksize));
1305 /****************************************************************************
1306 command to set incremental / reset mode
1307 ***************************************************************************/
1308 void cmd_tarmode(void)
1310 fstring buf;
1312 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1313 if (strequal(buf, "full"))
1314 tar_inc=False;
1315 else if (strequal(buf, "inc"))
1316 tar_inc=True;
1317 else if (strequal(buf, "reset"))
1318 tar_reset=True;
1319 else if (strequal(buf, "noreset"))
1320 tar_reset=False;
1321 else if (strequal(buf, "system"))
1322 tar_system=True;
1323 else if (strequal(buf, "nosystem"))
1324 tar_system=False;
1325 else if (strequal(buf, "hidden"))
1326 tar_hidden=True;
1327 else if (strequal(buf, "nohidden"))
1328 tar_hidden=False;
1329 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1330 tar_noisy=True;
1331 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1332 tar_noisy=False;
1333 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1336 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1337 tar_inc ? "incremental" : "full",
1338 tar_system ? "system" : "nosystem",
1339 tar_hidden ? "hidden" : "nohidden",
1340 tar_reset ? "reset" : "noreset",
1341 tar_noisy ? "verbose" : "quiet"));
1345 /****************************************************************************
1346 Feeble attrib command
1347 ***************************************************************************/
1348 void cmd_setmode(void)
1350 char *q;
1351 fstring buf;
1352 pstring fname;
1353 uint16 attra[2];
1354 int direct=1;
1356 attra[0] = attra[1] = 0;
1358 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1360 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1361 return;
1364 safe_strcpy(fname, cur_dir, sizeof(pstring));
1365 safe_strcat(fname, buf, sizeof(pstring));
1367 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1368 q=buf;
1370 while(*q)
1371 switch (*q++) {
1372 case '+': direct=1;
1373 break;
1374 case '-': direct=0;
1375 break;
1376 case 'r': attra[direct]|=aRONLY;
1377 break;
1378 case 'h': attra[direct]|=aHIDDEN;
1379 break;
1380 case 's': attra[direct]|=aSYSTEM;
1381 break;
1382 case 'a': attra[direct]|=aARCH;
1383 break;
1384 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1385 return;
1389 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1391 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1392 return;
1395 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1396 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1397 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1400 /****************************************************************************
1401 Principal command for creating / extracting
1402 ***************************************************************************/
1403 void cmd_tar(void)
1405 fstring buf;
1406 char **argl;
1407 int argcl;
1409 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1411 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1412 return;
1415 argl=toktocliplist(&argcl, NULL);
1416 if (!tar_parseargs(argcl, argl, buf, 0))
1417 return;
1419 process_tar();
1421 free(argl);
1424 /****************************************************************************
1425 Command line (option) version
1426 ***************************************************************************/
1427 int process_tar(void)
1429 initarbuf();
1430 switch(tar_type) {
1431 case 'x':
1433 #if 0
1434 do_tarput2();
1435 #else
1436 do_tarput();
1437 #endif
1438 free(tarbuf);
1439 close(tarhandle);
1440 break;
1441 case 'r':
1442 case 'c':
1443 if (clipn && tar_excl) {
1444 int i;
1445 pstring tarmac;
1447 for (i=0; i<clipn; i++) {
1448 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1450 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1451 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1454 if (strrchr_m(cliplist[i], '\\')) {
1455 pstring saved_dir;
1457 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1459 if (*cliplist[i]=='\\') {
1460 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1461 } else {
1462 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1463 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1465 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1466 *(strrchr_m(cur_dir, '\\')+1)='\0';
1468 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1469 do_list(tarmac,attribute,do_tar, False, True);
1470 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1471 } else {
1472 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1473 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1474 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1475 do_list(tarmac,attribute,do_tar, False, True);
1478 } else {
1479 pstring mask;
1480 safe_strcpy(mask,cur_dir, sizeof(pstring));
1481 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1482 safe_strcat(mask,"\\*", sizeof(pstring));
1483 do_list(mask,attribute,do_tar,False, True);
1486 if (ntarf) dotareof(tarhandle);
1487 close(tarhandle);
1488 free(tarbuf);
1490 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1491 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1492 break;
1495 if (must_free_cliplist) {
1496 int i;
1497 for (i = 0; i < clipn; ++i) {
1498 free(cliplist[i]);
1500 free(cliplist);
1501 cliplist = NULL;
1502 clipn = 0;
1503 must_free_cliplist = False;
1506 return(0);
1509 /****************************************************************************
1510 Find a token (filename) in a clip list
1511 ***************************************************************************/
1512 static int clipfind(char **aret, int ret, char *tok)
1514 if (aret==NULL) return 0;
1516 /* ignore leading slashes or dots in token */
1517 while(strchr_m("/\\.", *tok)) tok++;
1519 while(ret--) {
1520 char *pkey=*aret++;
1522 /* ignore leading slashes or dots in list */
1523 while(strchr_m("/\\.", *pkey)) pkey++;
1525 if (!strslashcmp(pkey, tok)) return 1;
1528 return 0;
1531 /****************************************************************************
1532 Read list of files to include from the file and initialize cliplist
1533 accordingly.
1534 ***************************************************************************/
1535 static int read_inclusion_file(char *filename)
1537 FILE *inclusion = NULL;
1538 char buf[MAXPATHLEN + 1];
1539 char *inclusion_buffer = NULL;
1540 int inclusion_buffer_size = 0;
1541 int inclusion_buffer_sofar = 0;
1542 char *p;
1543 char *tmpstr;
1544 int i;
1545 int error = 0;
1547 clipn = 0;
1548 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1549 if ((inclusion = sys_fopen(filename, "r")) == NULL) {
1550 /* XXX It would be better to include a reason for failure, but without
1551 * autoconf, it's hard to use strerror, sys_errlist, etc.
1553 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1554 return 0;
1557 while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1558 if (inclusion_buffer == NULL) {
1559 inclusion_buffer_size = 1024;
1560 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1561 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1562 error = 1;
1563 break;
1567 if (buf[strlen(buf)-1] == '\n') {
1568 buf[strlen(buf)-1] = '\0';
1571 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1572 inclusion_buffer_size *= 2;
1573 inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
1574 if (! inclusion_buffer) {
1575 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1576 inclusion_buffer_size));
1577 error = 1;
1578 break;
1582 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1583 inclusion_buffer_sofar += strlen(buf) + 1;
1584 clipn++;
1586 fclose(inclusion);
1588 if (! error) {
1589 /* Allocate an array of clipn + 1 char*'s for cliplist */
1590 cliplist = malloc((clipn + 1) * sizeof(char *));
1591 if (cliplist == NULL) {
1592 DEBUG(0,("failure allocating memory for cliplist\n"));
1593 error = 1;
1594 } else {
1595 cliplist[clipn] = NULL;
1596 p = inclusion_buffer;
1597 for (i = 0; (! error) && (i < clipn); i++) {
1598 /* set current item to NULL so array will be null-terminated even if
1599 * malloc fails below. */
1600 cliplist[i] = NULL;
1601 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1602 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1603 error = 1;
1604 } else {
1605 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1606 cliplist[i] = tmpstr;
1607 if ((p = strchr_m(p, '\000')) == NULL) {
1608 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1609 abort();
1612 ++p;
1614 must_free_cliplist = True;
1618 if (inclusion_buffer) {
1619 free(inclusion_buffer);
1621 if (error) {
1622 if (cliplist) {
1623 char **pp;
1624 /* We know cliplist is always null-terminated */
1625 for (pp = cliplist; *pp; ++pp) {
1626 free(*pp);
1628 free(cliplist);
1629 cliplist = NULL;
1630 must_free_cliplist = False;
1632 return 0;
1635 /* cliplist and its elements are freed at the end of process_tar. */
1636 return 1;
1639 /****************************************************************************
1640 Parse tar arguments. Sets tar_type, tar_excl, etc.
1641 ***************************************************************************/
1642 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1644 char tar_clipfl='\0';
1646 /* Reset back to defaults - could be from interactive version
1647 * reset mode and archive mode left as they are though
1649 tar_type='\0';
1650 tar_excl=True;
1651 dry_run=False;
1653 while (*Optarg)
1654 switch(*Optarg++) {
1655 case 'c':
1656 tar_type='c';
1657 break;
1658 case 'x':
1659 if (tar_type=='c') {
1660 printf("Tar must be followed by only one of c or x.\n");
1661 return 0;
1663 tar_type='x';
1664 break;
1665 case 'b':
1666 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1667 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1668 return 0;
1669 } else {
1670 Optind++;
1672 break;
1673 case 'g':
1674 tar_inc=True;
1675 break;
1676 case 'N':
1677 if (Optind>=argc) {
1678 DEBUG(0,("Option N must be followed by valid file name\n"));
1679 return 0;
1680 } else {
1681 SMB_STRUCT_STAT stbuf;
1682 extern time_t newer_than;
1684 if (sys_stat(argv[Optind], &stbuf) == 0) {
1685 newer_than = stbuf.st_mtime;
1686 DEBUG(1,("Getting files newer than %s",
1687 asctime(LocalTime(&newer_than))));
1688 Optind++;
1689 } else {
1690 DEBUG(0,("Error setting newer-than time\n"));
1691 return 0;
1694 break;
1695 case 'a':
1696 tar_reset=True;
1697 break;
1698 case 'q':
1699 tar_noisy=False;
1700 break;
1701 case 'I':
1702 if (tar_clipfl) {
1703 DEBUG(0,("Only one of I,X,F must be specified\n"));
1704 return 0;
1706 tar_clipfl='I';
1707 break;
1708 case 'X':
1709 if (tar_clipfl) {
1710 DEBUG(0,("Only one of I,X,F must be specified\n"));
1711 return 0;
1713 tar_clipfl='X';
1714 break;
1715 case 'F':
1716 if (tar_clipfl) {
1717 DEBUG(0,("Only one of I,X,F must be specified\n"));
1718 return 0;
1720 tar_clipfl='F';
1721 break;
1722 case 'r':
1723 DEBUG(0, ("tar_re_search set\n"));
1724 tar_re_search = True;
1725 break;
1726 case 'n':
1727 if (tar_type == 'c') {
1728 DEBUG(0, ("dry_run set\n"));
1729 dry_run = True;
1730 } else {
1731 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1732 return 0;
1734 break;
1735 default:
1736 DEBUG(0,("Unknown tar option\n"));
1737 return 0;
1740 if (!tar_type) {
1741 printf("Option T must be followed by one of c or x.\n");
1742 return 0;
1745 /* tar_excl is true if cliplist lists files to be included.
1746 * Both 'I' and 'F' mean include. */
1747 tar_excl=tar_clipfl!='X';
1749 if (tar_clipfl=='F') {
1750 if (argc-Optind-1 != 1) {
1751 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1752 return 0;
1754 if (! read_inclusion_file(argv[Optind+1])) {
1755 return 0;
1757 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1758 char *tmpstr;
1759 char **tmplist;
1760 int clipcount;
1762 cliplist=argv+Optind+1;
1763 clipn=argc-Optind-1;
1764 clipcount = clipn;
1766 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1767 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1768 clipn)
1770 return 0;
1773 for (clipcount = 0; clipcount < clipn; clipcount++) {
1775 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1777 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1778 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1779 clipcount)
1781 return 0;
1783 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1784 tmplist[clipcount] = tmpstr;
1785 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1787 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1789 cliplist = tmplist;
1790 must_free_cliplist = True;
1793 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1794 #ifdef HAVE_REGEX_H
1795 int errcode;
1797 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1799 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1800 return;
1804 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1805 char errstr[1024];
1806 size_t errlen;
1808 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1810 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1811 return;
1814 #endif
1816 clipn=argc-Optind-1;
1817 cliplist=argv+Optind+1;
1821 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1822 /* Sets tar handle to either 0 or 1, as appropriate */
1823 tarhandle=(tar_type=='c');
1825 * Make sure that dbf points to stderr if we are using stdout for
1826 * tar output
1828 if (tarhandle == 1)
1829 dbf = stderr;
1830 } else {
1831 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1833 if (!dry_run) {
1834 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1835 dry_run = True;
1837 tarhandle=-1;
1838 } else
1839 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1840 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1842 DEBUG(0,("Error opening local file %s - %s\n",
1843 argv[Optind], strerror(errno)));
1844 return(0);
1848 return 1;