More janitorial duties, fixing the BIG_UINT changes for large offsets.
[Samba/gbeck.git] / source3 / client / clitar.c
blob612a383ce07a3b15a247828afb2f276ed6e2e3a3
1 /*
2 Unix SMB/CIFS implementation.
3 Tar Extensions
4 Copyright (C) Ricky Poulten 1995-1998
5 Copyright (C) Richard Sharpe 1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* The following changes developed by Richard Sharpe for Canon Information
22 Systems Research Australia (CISRA)
24 1. Restore can now restore files with long file names
25 2. Save now saves directory information so that we can restore
26 directory creation times
27 3. tar now accepts both UNIX path names and DOS path names. I prefer
28 those lovely /'s to those UGLY \'s :-)
29 4. the files to exclude can be specified as a regular expression by adding
30 an r flag to the other tar flags. Eg:
32 -TcrX file.tar "*.(obj|exe)"
34 will skip all .obj and .exe files
38 #include "includes.h"
39 #include "clitar.h"
40 #include "../client/client_proto.h"
42 static int clipfind(char **aret, int ret, char *tok);
44 typedef struct file_info_struct file_info2;
46 struct file_info_struct
48 SMB_BIG_UINT size;
49 uint16 mode;
50 uid_t uid;
51 gid_t gid;
52 /* These times are normally kept in GMT */
53 time_t mtime;
54 time_t atime;
55 time_t ctime;
56 char *name; /* This is dynamically allocate */
58 file_info2 *next, *prev; /* Used in the stack ... */
62 typedef struct
64 file_info2 *top;
65 int items;
67 } stack;
69 #define SEPARATORS " \t\n\r"
70 extern struct cli_state *cli;
72 /* These defines are for the do_setrattr routine, to indicate
73 * setting and reseting of file attributes in the function call */
74 #define ATTRSET 1
75 #define ATTRRESET 0
77 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
79 #ifndef CLIENT_TIMEOUT
80 #define CLIENT_TIMEOUT (30*1000)
81 #endif
83 static char *tarbuf, *buffer_p;
84 static int tp, ntarf, tbufsiz;
85 static double ttarf;
86 /* Incremental mode */
87 static BOOL tar_inc=False;
88 /* Reset archive bit */
89 static BOOL tar_reset=False;
90 /* Include / exclude mode (true=include, false=exclude) */
91 static BOOL tar_excl=True;
92 /* use regular expressions for search on file names */
93 static BOOL tar_re_search=False;
94 #ifdef HAVE_REGEX_H
95 regex_t *preg;
96 #endif
97 /* Do not dump anything, just calculate sizes */
98 static BOOL dry_run=False;
99 /* Dump files with System attribute */
100 static BOOL tar_system=True;
101 /* Dump files with Hidden attribute */
102 static BOOL tar_hidden=True;
103 /* Be noisy - make a catalogue */
104 static BOOL tar_noisy=True;
105 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
107 char tar_type='\0';
108 static char **cliplist=NULL;
109 static int clipn=0;
110 static BOOL must_free_cliplist = False;
112 extern file_info def_finfo;
113 extern BOOL lowercase;
114 extern uint16 cnum;
115 extern BOOL readbraw_supported;
116 extern int max_xmit;
117 extern pstring cur_dir;
118 extern int get_total_time_ms;
119 extern int get_total_size;
121 static int blocksize=20;
122 static int tarhandle;
124 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
125 const char *amode, unsigned char ftype);
126 static void do_atar(char *rname,char *lname,file_info *finfo1);
127 static void do_tar(file_info *finfo);
128 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
129 static void fixtarname(char *tptr, const char *fp, int l);
130 static int dotarbuf(int f, char *b, int n);
131 static void dozerobuf(int f, int n);
132 static void dotareof(int f);
133 static void initarbuf(void);
135 /* restore functions */
136 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
137 static long unoct(char *p, int ndgs);
138 static void do_tarput(void);
139 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
142 * tar specific utitlities
145 /*******************************************************************
146 Create a string of size size+1 (for the null)
147 *******************************************************************/
148 static char *string_create_s(int size)
150 char *tmp;
152 tmp = (char *)malloc(size+1);
154 if (tmp == NULL) {
156 DEBUG(0, ("Out of memory in string_create_s\n"));
160 return(tmp);
164 /****************************************************************************
165 Write a tar header to buffer
166 ****************************************************************************/
167 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
168 const char *amode, unsigned char ftype)
170 union hblock hb;
171 int i, chk, l;
172 char *jp;
174 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
176 memset(hb.dummy, 0, sizeof(hb.dummy));
178 l=strlen(aname);
179 if (l >= NAMSIZ - 1) {
180 /* write a GNU tar style long header */
181 char *b;
182 b = (char *)malloc(l+TBLOCK+100);
183 if (!b) {
184 DEBUG(0,("out of memory\n"));
185 exit(1);
187 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
188 memset(b, 0, l+TBLOCK+100);
189 fixtarname(b, aname, l);
190 i = strlen(b)+1;
191 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
192 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
193 SAFE_FREE(b);
196 /* use l + 1 to do the null too */
197 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
199 if (lowercase)
200 strlower(hb.dbuf.name);
202 /* write out a "standard" tar format header */
204 hb.dbuf.name[NAMSIZ-1]='\0';
205 safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
206 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
207 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
208 oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
209 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
210 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
211 memset(hb.dbuf.linkname, 0, NAMSIZ);
212 hb.dbuf.linkflag=ftype;
214 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
216 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
217 hb.dbuf.chksum[6] = '\0';
219 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
222 /****************************************************************************
223 Read a tar header into a hblock structure, and validate
224 ***************************************************************************/
225 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
227 long chk, fchk;
228 int i;
229 char *jp;
232 * read in a "standard" tar format header - we're not that interested
233 * in that many fields, though
236 /* check the checksum */
237 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
239 if (chk == 0)
240 return chk;
242 /* compensate for blanks in chksum header */
243 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
244 chk-=(0xFF & *jp++);
246 chk += ' ' * sizeof(hb->dbuf.chksum);
248 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
250 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
251 chk, fchk, hb->dbuf.chksum));
253 if (fchk != chk)
255 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
256 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
257 return -1;
260 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
262 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
263 return(-1);
267 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
269 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
270 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
271 strlen(hb->dbuf.name) + 1, True);
273 /* can't handle some links at present */
274 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
275 if (hb->dbuf.linkflag == 0) {
276 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
277 finfo->name));
278 } else {
279 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
280 /* Do nothing here at the moment. do_tarput will handle this
281 as long as the longlink gets back to it, as it has to advance
282 the buffer pointer, etc */
284 } else {
285 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
286 return -2;
291 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
292 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
294 finfo->mode=aDIR;
296 else
297 finfo->mode=0; /* we don't care about mode at the moment, we'll
298 * just make it a regular file */
300 * Bug fix by richard@sj.co.uk
302 * REC: restore times correctly (as does tar)
303 * We only get the modification time of the file; set the creation time
304 * from the mod. time, and the access time to current time
306 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
307 finfo->atime = time(NULL);
308 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
310 return True;
313 /****************************************************************************
314 Write out the tar buffer to tape or wherever
315 ****************************************************************************/
316 static int dotarbuf(int f, char *b, int n)
318 int fail=1, writ=n;
320 if (dry_run) {
321 return writ;
323 /* This routine and the next one should be the only ones that do write()s */
324 if (tp + n >= tbufsiz)
326 int diff;
328 diff=tbufsiz-tp;
329 memcpy(tarbuf + tp, b, diff);
330 fail=fail && (1+write(f, tarbuf, tbufsiz));
331 n-=diff;
332 b+=diff;
333 tp=0;
335 while (n >= tbufsiz)
337 fail=fail && (1 + write(f, b, tbufsiz));
338 n-=tbufsiz;
339 b+=tbufsiz;
342 if (n>0) {
343 memcpy(tarbuf+tp, b, n);
344 tp+=n;
347 return(fail ? writ : 0);
350 /****************************************************************************
351 Write zeros to buffer / tape
352 ****************************************************************************/
353 static void dozerobuf(int f, int n)
355 /* short routine just to write out n zeros to buffer -
356 * used to round files to nearest block
357 * and to do tar EOFs */
359 if (dry_run)
360 return;
362 if (n+tp >= tbufsiz)
364 memset(tarbuf+tp, 0, tbufsiz-tp);
366 write(f, tarbuf, tbufsiz);
367 memset(tarbuf, 0, (tp+=n-tbufsiz));
369 else
371 memset(tarbuf+tp, 0, n);
372 tp+=n;
376 /****************************************************************************
377 Malloc tape buffer
378 ****************************************************************************/
379 static void initarbuf(void)
381 /* initialize tar buffer */
382 tbufsiz=blocksize*TBLOCK;
383 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
385 /* reset tar buffer pointer and tar file counter and total dumped */
386 tp=0; ntarf=0; ttarf=0;
389 /****************************************************************************
390 Write two zero blocks at end of file
391 ****************************************************************************/
392 static void dotareof(int f)
394 SMB_STRUCT_STAT stbuf;
395 /* Two zero blocks at end of file, write out full buffer */
397 if (dry_run)
398 return;
400 (void) dozerobuf(f, TBLOCK);
401 (void) dozerobuf(f, TBLOCK);
403 if (sys_fstat(f, &stbuf) == -1)
405 DEBUG(0, ("Couldn't stat file handle\n"));
406 return;
409 /* Could be a pipe, in which case S_ISREG should fail,
410 * and we should write out at full size */
411 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
414 /****************************************************************************
415 (Un)mangle DOS pathname, make nonabsolute
416 ****************************************************************************/
417 static void fixtarname(char *tptr, const char *fp, int l)
419 /* add a '.' to start of file name, convert from ugly dos \'s in path
420 * to lovely unix /'s :-} */
421 *tptr++='.';
423 safe_strcpy(tptr, fp, l);
424 string_replace(tptr, '\\', '/');
427 /****************************************************************************
428 Convert from decimal to octal string
429 ****************************************************************************/
430 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
432 /* Converts long to octal string, pads with leading zeros */
434 /* skip final null, but do final space */
435 --ndgs;
436 p[--ndgs] = ' ';
438 /* Loop does at least one digit */
439 do {
440 p[--ndgs] = '0' + (char) (value & 7);
441 value >>= 3;
443 while (ndgs > 0 && value != 0);
445 /* Do leading zeros */
446 while (ndgs > 0)
447 p[--ndgs] = '0';
450 /****************************************************************************
451 Convert from octal string to long
452 ***************************************************************************/
453 static long unoct(char *p, int ndgs)
455 long value=0;
456 /* Converts octal string to long, ignoring any non-digit */
458 while (--ndgs)
460 if (isdigit((int)*p))
461 value = (value << 3) | (long) (*p - '0');
463 p++;
466 return value;
469 /****************************************************************************
470 Compare two strings in a slash insensitive way, allowing s1 to match s2
471 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
472 a file in any subdirectory of s1, declare a match.
473 ***************************************************************************/
474 static int strslashcmp(char *s1, char *s2)
476 char *s1_0=s1;
478 while(*s1 && *s2 &&
479 (*s1 == *s2
480 || tolower(*s1) == tolower(*s2)
481 || (*s1 == '\\' && *s2=='/')
482 || (*s1 == '/' && *s2=='\\'))) {
483 s1++; s2++;
486 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
487 string of s2.
489 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
491 /* ignore trailing slash on s1 */
492 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
494 /* check for s1 is an "initial" string of s2 */
495 if ((*s2 == '/' || *s2 == '\\') && !*s1) return 0;
497 return *s1-*s2;
501 /****************************************************************************
502 Ensure a remote path exists (make if necessary)
503 ***************************************************************************/
504 static BOOL ensurepath(char *fname)
506 /* *must* be called with buffer ready malloc'ed */
507 /* ensures path exists */
509 char *partpath, *ffname;
510 char *p=fname, *basehack;
512 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
514 partpath = string_create_s(strlen(fname));
515 ffname = string_create_s(strlen(fname));
517 if ((partpath == NULL) || (ffname == NULL)){
519 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
520 return(False);
524 *partpath = 0;
526 /* fname copied to ffname so can strtok */
528 safe_strcpy(ffname, fname, strlen(fname));
530 /* do a `basename' on ffname, so don't try and make file name directory */
531 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
532 return True;
533 else
534 *basehack='\0';
536 p=strtok(ffname, "\\");
538 while (p)
540 safe_strcat(partpath, p, strlen(fname) + 1);
542 if (!cli_chkpath(cli, partpath)) {
543 if (!cli_mkdir(cli, partpath))
545 DEBUG(0, ("Error mkdirhiering\n"));
546 return False;
548 else
549 DEBUG(3, ("mkdirhiering %s\n", partpath));
553 safe_strcat(partpath, "\\", strlen(fname) + 1);
554 p = strtok(NULL,"/\\");
557 return True;
560 static int padit(char *buf, int bufsize, int padsize)
562 int berr= 0;
563 int bytestowrite;
565 DEBUG(5, ("Padding with %d zeros\n", padsize));
566 memset(buf, 0, bufsize);
567 while( !berr && padsize > 0 ) {
568 bytestowrite= MIN(bufsize, padsize);
569 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
570 padsize -= bytestowrite;
573 return berr;
577 static void do_setrattr(char *name, uint16 attr, int set)
579 uint16 oldattr;
581 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
583 if (set == ATTRSET) {
584 attr |= oldattr;
585 } else {
586 attr = oldattr & ~attr;
589 if (!cli_setatr(cli, name, attr, 0)) {
590 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
595 /****************************************************************************
596 append one remote file to the tar file
597 ***************************************************************************/
598 static void do_atar(char *rname,char *lname,file_info *finfo1)
600 int fnum;
601 SMB_BIG_UINT nread=0;
602 char ftype;
603 file_info2 finfo;
604 BOOL close_done = False;
605 BOOL shallitime=True;
606 char data[65520];
607 int read_size = 65520;
608 int datalen=0;
610 struct timeval tp_start;
611 GetTimeOfDay(&tp_start);
613 ftype = '0'; /* An ordinary file ... */
615 if (finfo1) {
616 finfo.size = finfo1 -> size;
617 finfo.mode = finfo1 -> mode;
618 finfo.uid = finfo1 -> uid;
619 finfo.gid = finfo1 -> gid;
620 finfo.mtime = finfo1 -> mtime;
621 finfo.atime = finfo1 -> atime;
622 finfo.ctime = finfo1 -> ctime;
623 finfo.name = finfo1 -> name;
625 else {
626 finfo.size = def_finfo.size;
627 finfo.mode = def_finfo.mode;
628 finfo.uid = def_finfo.uid;
629 finfo.gid = def_finfo.gid;
630 finfo.mtime = def_finfo.mtime;
631 finfo.atime = def_finfo.atime;
632 finfo.ctime = def_finfo.ctime;
633 finfo.name = def_finfo.name;
636 if (dry_run)
638 DEBUG(3,("skipping file %s of size %12.0f bytes\n",
639 finfo.name,
640 (double)finfo.size));
641 shallitime=0;
642 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
643 ntarf++;
644 return;
647 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
649 dos_clean_name(rname);
651 if (fnum == -1) {
652 DEBUG(0,("%s opening remote file %s (%s)\n",
653 cli_errstr(cli),rname, cur_dir));
654 return;
657 finfo.name = string_create_s(strlen(rname));
658 if (finfo.name == NULL) {
659 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
660 return;
663 safe_strcpy(finfo.name,rname, strlen(rname));
664 if (!finfo1) {
665 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
666 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
667 return;
669 finfo.ctime = finfo.mtime;
672 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
674 if (tar_inc && !(finfo.mode & aARCH))
676 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
677 shallitime=0;
679 else if (!tar_system && (finfo.mode & aSYSTEM))
681 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
682 shallitime=0;
684 else if (!tar_hidden && (finfo.mode & aHIDDEN))
686 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
687 shallitime=0;
689 else
691 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
692 finfo.name,
693 (double)finfo.size,
694 lname));
696 /* write a tar header, don't bother with mode - just set to 100644 */
697 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
699 while (nread < finfo.size && !close_done) {
701 DEBUG(3,("nread=%.0f\n",(double)nread));
703 datalen = cli_read(cli, fnum, data, nread, read_size);
705 if (datalen == -1) {
706 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
707 break;
710 nread += datalen;
712 /* if file size has increased since we made file size query, truncate
713 read so tar header for this file will be correct.
716 if (nread > finfo.size) {
717 datalen -= nread - finfo.size;
718 DEBUG(0,("File size change - truncating %s to %.0f bytes\n", finfo.name, (double)finfo.size));
721 /* add received bits of file to buffer - dotarbuf will
722 * write out in 512 byte intervals */
723 if (dotarbuf(tarhandle,data,datalen) != datalen) {
724 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
725 break;
728 if (datalen == 0) {
729 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
730 break;
733 datalen=0;
736 /* pad tar file with zero's if we couldn't get entire file */
737 if (nread < finfo.size) {
738 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n", (double)finfo.size, (int)nread));
739 if (padit(data, sizeof(data), finfo.size - nread))
740 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
743 /* round tar file to nearest block */
744 if (finfo.size % TBLOCK)
745 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
747 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
748 ntarf++;
751 cli_close(cli, fnum);
753 if (shallitime)
755 struct timeval tp_end;
756 int this_time;
758 /* if shallitime is true then we didn't skip */
759 if (tar_reset && !dry_run)
760 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
762 GetTimeOfDay(&tp_end);
763 this_time =
764 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
765 (tp_end.tv_usec - tp_start.tv_usec)/1000;
766 get_total_time_ms += this_time;
767 get_total_size += finfo.size;
769 if (tar_noisy)
771 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
772 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
773 finfo.name));
776 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
777 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
778 finfo.size / MAX(0.001, (1.024*this_time)),
779 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
783 /****************************************************************************
784 Append single file to tar file (or not)
785 ***************************************************************************/
786 static void do_tar(file_info *finfo)
788 pstring rname;
790 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
791 return;
793 /* Is it on the exclude list ? */
794 if (!tar_excl && clipn) {
795 pstring exclaim;
797 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
799 safe_strcpy(exclaim, cur_dir, sizeof(pstring));
800 *(exclaim+strlen(exclaim)-1)='\0';
802 safe_strcat(exclaim, "\\", sizeof(pstring));
803 safe_strcat(exclaim, finfo->name, sizeof(exclaim));
805 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
807 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
808 #ifdef HAVE_REGEX_H
809 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
810 #else
811 (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
812 #endif
813 DEBUG(3,("Skipping file %s\n", exclaim));
814 return;
818 if (finfo->mode & aDIR)
820 pstring saved_curdir;
821 pstring mtar_mask;
823 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
825 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));
827 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
828 safe_strcat(cur_dir,"\\", sizeof(cur_dir));
830 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
832 /* write a tar directory, don't bother with mode - just set it to
833 * 40755 */
834 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
835 if (tar_noisy) {
836 DEBUG(0,(" directory %s\n", cur_dir));
838 ntarf++; /* Make sure we have a file on there */
839 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
840 safe_strcat(mtar_mask,"*", sizeof(pstring));
841 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
842 do_list(mtar_mask, attribute, do_tar, False, True);
843 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
845 else
847 safe_strcpy(rname,cur_dir, sizeof(pstring));
848 safe_strcat(rname,finfo->name, sizeof(pstring));
849 do_atar(rname,finfo->name,finfo);
853 /****************************************************************************
854 Convert from UNIX to DOS file names
855 ***************************************************************************/
856 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
858 /* remove '.' from start of file name, convert from unix /'s to
859 * dos \'s in path. Kill any absolute path names. But only if first!
862 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
864 if (first) {
865 if (*fp == '.') {
866 fp++;
867 l--;
869 if (*fp == '\\' || *fp == '/') {
870 fp++;
871 l--;
875 safe_strcpy(tptr, fp, l);
876 string_replace(tptr, '/', '\\');
880 /****************************************************************************
881 Move to the next block in the buffer, which may mean read in another set of
882 blocks. FIXME, we should allow more than one block to be skipped.
883 ****************************************************************************/
884 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
886 int bufread, total = 0;
888 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
889 *bufferp += TBLOCK;
890 total = TBLOCK;
892 if (*bufferp >= (ltarbuf + bufsiz)) {
894 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
897 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
898 * Fixes bug where read can return short if coming from
899 * a pipe.
902 bufread = read(tarhandle, ltarbuf, bufsiz);
903 total = bufread;
905 while (total < bufsiz) {
906 if (bufread < 0) { /* An error, return false */
907 return (total > 0 ? -2 : bufread);
909 if (bufread == 0) {
910 if (total <= 0) {
911 return -2;
913 break;
915 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
916 total += bufread;
919 DEBUG(5, ("Total bytes read ... %i\n", total));
921 *bufferp = ltarbuf;
925 return(total);
929 /* Skip a file, even if it includes a long file name? */
930 static int skip_file(int skipsize)
932 int dsize = skipsize;
934 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
936 /* FIXME, we should skip more than one block at a time */
938 while (dsize > 0) {
940 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
942 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
943 return(False);
947 dsize -= TBLOCK;
951 return(True);
954 /*************************************************************
955 Get a file from the tar file and store it.
956 When this is called, tarbuf already contains the first
957 file block. This is a bit broken & needs fixing.
958 **************************************************************/
960 static int get_file(file_info2 finfo)
962 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
963 SMB_BIG_UINT rsize = 0;
965 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
967 if (ensurepath(finfo.name) &&
968 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
969 DEBUG(0, ("abandoning restore\n"));
970 return(False);
973 /* read the blocks from the tar file and write to the remote file */
975 rsize = finfo.size; /* This is how much to write */
977 while (rsize > 0) {
979 /* We can only write up to the end of the buffer */
981 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
982 dsize = MIN(dsize, rsize); /* Should be only what is left */
983 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
985 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
986 DEBUG(0, ("Error writing remote file\n"));
987 return 0;
990 rsize -= dsize;
991 pos += dsize;
993 /* Now figure out how much to move in the buffer */
995 /* FIXME, we should skip more than one block at a time */
997 /* First, skip any initial part of the part written that is left over */
998 /* from the end of the first TBLOCK */
1000 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1002 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1003 bpos = 0;
1005 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1006 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1007 return False;
1014 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1015 * If the file being extracted is an exact multiple of
1016 * TBLOCK bytes then we don't want to extract the next
1017 * block from the tarfile here, as it will be done in
1018 * the caller of get_file().
1021 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1022 ((rsize == 0) && (dsize > TBLOCK))) {
1024 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1025 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1026 return False;
1029 dsize -= TBLOCK;
1032 bpos = dsize;
1036 /* Now close the file ... */
1038 if (!cli_close(cli, fnum)) {
1039 DEBUG(0, ("Error closing remote file\n"));
1040 return(False);
1043 /* Now we update the creation date ... */
1045 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1047 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1048 if (tar_real_noisy) {
1049 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1050 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1054 ntarf++;
1056 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1058 return(True);
1061 /* Create a directory. We just ensure that the path exists and return as there
1062 is no file associated with a directory
1064 static int get_dir(file_info2 finfo)
1067 DEBUG(0, ("restore directory %s\n", finfo.name));
1069 if (!ensurepath(finfo.name)) {
1071 DEBUG(0, ("Problems creating directory\n"));
1072 return(False);
1076 ntarf++;
1077 return(True);
1080 /* Get a file with a long file name ... first file has file name, next file
1081 has the data. We only want the long file name, as the loop in do_tarput
1082 will deal with the rest.
1084 static char * get_longfilename(file_info2 finfo)
1086 int namesize = strlen(finfo.name) + strlen(cur_dir) + 2;
1087 char *longname = malloc(namesize);
1088 int offset = 0, left = finfo.size;
1089 BOOL first = True;
1091 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1092 DEBUG(5, ("Len = %d\n", (int)finfo.size));
1094 if (longname == NULL) {
1096 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1097 namesize));
1098 return(NULL);
1101 /* First, add cur_dir to the long file name */
1103 if (strlen(cur_dir) > 0) {
1104 strncpy(longname, cur_dir, namesize);
1105 offset = strlen(cur_dir);
1108 /* Loop through the blocks picking up the name */
1110 while (left > 0) {
1112 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1114 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1115 return(NULL);
1119 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1120 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1122 offset += TBLOCK;
1123 left -= TBLOCK;
1127 return(longname);
1131 static void do_tarput(void)
1133 file_info2 finfo;
1134 struct timeval tp_start;
1135 char *longfilename = NULL, linkflag;
1136 int skip = False;
1138 GetTimeOfDay(&tp_start);
1140 DEBUG(5, ("RJS do_tarput called ...\n"));
1142 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1144 /* Now read through those files ... */
1146 while (True) {
1148 /* Get us to the next block, or the first block first time around */
1150 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1152 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1154 return;
1158 DEBUG(5, ("Reading the next header ...\n"));
1160 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1162 case -2: /* Hmm, not good, but not fatal */
1163 DEBUG(0, ("Skipping %s...\n", finfo.name));
1164 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1165 !skip_file(finfo.size)) {
1167 DEBUG(0, ("Short file, bailing out...\n"));
1168 return;
1172 break;
1174 case -1:
1175 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1176 return;
1178 case 0: /* chksum is zero - looks like an EOF */
1179 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1180 return; /* Hmmm, bad here ... */
1182 default:
1183 /* No action */
1185 break;
1189 /* Now, do we have a long file name? */
1191 if (longfilename != NULL) {
1193 SAFE_FREE(finfo.name); /* Free the space already allocated */
1194 finfo.name = longfilename;
1195 longfilename = NULL;
1199 /* Well, now we have a header, process the file ... */
1201 /* Should we skip the file? We have the long name as well here */
1203 skip = clipn &&
1204 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1205 #ifdef HAVE_REGEX_H
1206 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1207 #else
1208 || (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
1209 #endif
1211 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1213 if (skip) {
1215 skip_file(finfo.size);
1216 continue;
1220 /* We only get this far if we should process the file */
1221 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1223 switch (linkflag) {
1225 case '0': /* Should use symbolic names--FIXME */
1228 * Skip to the next block first, so we can get the file, FIXME, should
1229 * be in get_file ...
1230 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1231 * Fixes bug where file size in tarfile is zero.
1234 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1235 DEBUG(0, ("Short file, bailing out...\n"));
1236 return;
1238 if (!get_file(finfo)) {
1239 DEBUG(0, ("Abandoning restore\n"));
1240 return;
1243 break;
1245 case '5':
1246 if (!get_dir(finfo)) {
1247 DEBUG(0, ("Abandoning restore \n"));
1248 return;
1250 break;
1252 case 'L':
1253 longfilename = get_longfilename(finfo);
1254 if (!longfilename) {
1255 DEBUG(0, ("abandoning restore\n"));
1256 return;
1259 DEBUG(5, ("Long file name: %s\n", longfilename));
1260 break;
1262 default:
1263 skip_file(finfo.size); /* Don't handle these yet */
1264 break;
1275 * samba interactive commands
1278 /****************************************************************************
1279 Blocksize command
1280 ***************************************************************************/
1281 int cmd_block(void)
1283 fstring buf;
1284 int block;
1286 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1288 DEBUG(0, ("blocksize <n>\n"));
1289 return 1;
1292 block=atoi(buf);
1293 if (block < 0 || block > 65535)
1295 DEBUG(0, ("blocksize out of range"));
1296 return 1;
1299 blocksize=block;
1300 DEBUG(2,("blocksize is now %d\n", blocksize));
1302 return 0;
1305 /****************************************************************************
1306 command to set incremental / reset mode
1307 ***************************************************************************/
1308 int 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"));
1343 return 0;
1346 /****************************************************************************
1347 Feeble attrib command
1348 ***************************************************************************/
1349 int cmd_setmode(void)
1351 char *q;
1352 fstring buf;
1353 pstring fname;
1354 uint16 attra[2];
1355 int direct=1;
1357 attra[0] = attra[1] = 0;
1359 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1361 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1362 return 1;
1365 safe_strcpy(fname, cur_dir, sizeof(pstring));
1366 safe_strcat(fname, buf, sizeof(pstring));
1368 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1369 q=buf;
1371 while(*q)
1372 switch (*q++) {
1373 case '+': direct=1;
1374 break;
1375 case '-': direct=0;
1376 break;
1377 case 'r': attra[direct]|=aRONLY;
1378 break;
1379 case 'h': attra[direct]|=aHIDDEN;
1380 break;
1381 case 's': attra[direct]|=aSYSTEM;
1382 break;
1383 case 'a': attra[direct]|=aARCH;
1384 break;
1385 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1386 return 1;
1390 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1392 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1393 return 1;
1396 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1397 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1398 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1400 return 0;
1403 /****************************************************************************
1404 Principal command for creating / extracting
1405 ***************************************************************************/
1406 int cmd_tar(void)
1408 fstring buf;
1409 char **argl;
1410 int argcl;
1412 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
1414 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1415 return 1;
1418 argl=toktocliplist(&argcl, NULL);
1419 if (!tar_parseargs(argcl, argl, buf, 0))
1420 return 1;
1422 process_tar();
1424 SAFE_FREE(argl);
1426 return 0;
1429 /****************************************************************************
1430 Command line (option) version
1431 ***************************************************************************/
1432 int process_tar(void)
1434 initarbuf();
1435 switch(tar_type) {
1436 case 'x':
1438 #if 0
1439 do_tarput2();
1440 #else
1441 do_tarput();
1442 #endif
1443 SAFE_FREE(tarbuf);
1444 close(tarhandle);
1445 break;
1446 case 'r':
1447 case 'c':
1448 if (clipn && tar_excl) {
1449 int i;
1450 pstring tarmac;
1452 for (i=0; i<clipn; i++) {
1453 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1455 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1456 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1459 if (strrchr_m(cliplist[i], '\\')) {
1460 pstring saved_dir;
1462 safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1464 if (*cliplist[i]=='\\') {
1465 safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1466 } else {
1467 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1468 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1470 safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1471 *(strrchr_m(cur_dir, '\\')+1)='\0';
1473 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1474 do_list(tarmac,attribute,do_tar, False, True);
1475 safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1476 } else {
1477 safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1478 safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1479 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1480 do_list(tarmac,attribute,do_tar, False, True);
1483 } else {
1484 pstring mask;
1485 safe_strcpy(mask,cur_dir, sizeof(pstring));
1486 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1487 safe_strcat(mask,"\\*", sizeof(pstring));
1488 do_list(mask,attribute,do_tar,False, True);
1491 if (ntarf) dotareof(tarhandle);
1492 close(tarhandle);
1493 SAFE_FREE(tarbuf);
1495 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1496 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1497 break;
1500 if (must_free_cliplist) {
1501 int i;
1502 for (i = 0; i < clipn; ++i) {
1503 SAFE_FREE(cliplist[i]);
1505 SAFE_FREE(cliplist);
1506 cliplist = NULL;
1507 clipn = 0;
1508 must_free_cliplist = False;
1511 return(0);
1514 /****************************************************************************
1515 Find a token (filename) in a clip list
1516 ***************************************************************************/
1517 static int clipfind(char **aret, int ret, char *tok)
1519 if (aret==NULL) return 0;
1521 /* ignore leading slashes or dots in token */
1522 while(strchr_m("/\\.", *tok)) tok++;
1524 while(ret--) {
1525 char *pkey=*aret++;
1527 /* ignore leading slashes or dots in list */
1528 while(strchr_m("/\\.", *pkey)) pkey++;
1530 if (!strslashcmp(pkey, tok)) return 1;
1533 return 0;
1536 /****************************************************************************
1537 Read list of files to include from the file and initialize cliplist
1538 accordingly.
1539 ***************************************************************************/
1540 static int read_inclusion_file(char *filename)
1542 XFILE *inclusion = NULL;
1543 char buf[MAXPATHLEN + 1];
1544 char *inclusion_buffer = NULL;
1545 int inclusion_buffer_size = 0;
1546 int inclusion_buffer_sofar = 0;
1547 char *p;
1548 char *tmpstr;
1549 int i;
1550 int error = 0;
1552 clipn = 0;
1553 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1554 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1555 /* XXX It would be better to include a reason for failure, but without
1556 * autoconf, it's hard to use strerror, sys_errlist, etc.
1558 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1559 return 0;
1562 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1563 if (inclusion_buffer == NULL) {
1564 inclusion_buffer_size = 1024;
1565 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1566 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1567 error = 1;
1568 break;
1572 if (buf[strlen(buf)-1] == '\n') {
1573 buf[strlen(buf)-1] = '\0';
1576 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1577 char *ib;
1578 inclusion_buffer_size *= 2;
1579 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1580 if (! ib) {
1581 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1582 inclusion_buffer_size));
1583 error = 1;
1584 break;
1586 else inclusion_buffer = ib;
1589 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1590 inclusion_buffer_sofar += strlen(buf) + 1;
1591 clipn++;
1593 x_fclose(inclusion);
1595 if (! error) {
1596 /* Allocate an array of clipn + 1 char*'s for cliplist */
1597 cliplist = malloc((clipn + 1) * sizeof(char *));
1598 if (cliplist == NULL) {
1599 DEBUG(0,("failure allocating memory for cliplist\n"));
1600 error = 1;
1601 } else {
1602 cliplist[clipn] = NULL;
1603 p = inclusion_buffer;
1604 for (i = 0; (! error) && (i < clipn); i++) {
1605 /* set current item to NULL so array will be null-terminated even if
1606 * malloc fails below. */
1607 cliplist[i] = NULL;
1608 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1609 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1610 error = 1;
1611 } else {
1612 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1613 cliplist[i] = tmpstr;
1614 if ((p = strchr_m(p, '\000')) == NULL) {
1615 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1616 abort();
1619 ++p;
1621 must_free_cliplist = True;
1625 SAFE_FREE(inclusion_buffer);
1626 if (error) {
1627 if (cliplist) {
1628 char **pp;
1629 /* We know cliplist is always null-terminated */
1630 for (pp = cliplist; *pp; ++pp) {
1631 SAFE_FREE(*pp);
1633 SAFE_FREE(cliplist);
1634 cliplist = NULL;
1635 must_free_cliplist = False;
1637 return 0;
1640 /* cliplist and its elements are freed at the end of process_tar. */
1641 return 1;
1644 /****************************************************************************
1645 Parse tar arguments. Sets tar_type, tar_excl, etc.
1646 ***************************************************************************/
1647 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1649 char tar_clipfl='\0';
1651 /* Reset back to defaults - could be from interactive version
1652 * reset mode and archive mode left as they are though
1654 tar_type='\0';
1655 tar_excl=True;
1656 dry_run=False;
1658 while (*Optarg)
1659 switch(*Optarg++) {
1660 case 'c':
1661 tar_type='c';
1662 break;
1663 case 'x':
1664 if (tar_type=='c') {
1665 printf("Tar must be followed by only one of c or x.\n");
1666 return 0;
1668 tar_type='x';
1669 break;
1670 case 'b':
1671 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1672 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1673 return 0;
1674 } else {
1675 Optind++;
1677 break;
1678 case 'g':
1679 tar_inc=True;
1680 break;
1681 case 'N':
1682 if (Optind>=argc) {
1683 DEBUG(0,("Option N must be followed by valid file name\n"));
1684 return 0;
1685 } else {
1686 SMB_STRUCT_STAT stbuf;
1687 extern time_t newer_than;
1689 if (sys_stat(argv[Optind], &stbuf) == 0) {
1690 newer_than = stbuf.st_mtime;
1691 DEBUG(1,("Getting files newer than %s",
1692 asctime(LocalTime(&newer_than))));
1693 Optind++;
1694 } else {
1695 DEBUG(0,("Error setting newer-than time\n"));
1696 return 0;
1699 break;
1700 case 'a':
1701 tar_reset=True;
1702 break;
1703 case 'q':
1704 tar_noisy=False;
1705 break;
1706 case 'I':
1707 if (tar_clipfl) {
1708 DEBUG(0,("Only one of I,X,F must be specified\n"));
1709 return 0;
1711 tar_clipfl='I';
1712 break;
1713 case 'X':
1714 if (tar_clipfl) {
1715 DEBUG(0,("Only one of I,X,F must be specified\n"));
1716 return 0;
1718 tar_clipfl='X';
1719 break;
1720 case 'F':
1721 if (tar_clipfl) {
1722 DEBUG(0,("Only one of I,X,F must be specified\n"));
1723 return 0;
1725 tar_clipfl='F';
1726 break;
1727 case 'r':
1728 DEBUG(0, ("tar_re_search set\n"));
1729 tar_re_search = True;
1730 break;
1731 case 'n':
1732 if (tar_type == 'c') {
1733 DEBUG(0, ("dry_run set\n"));
1734 dry_run = True;
1735 } else {
1736 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1737 return 0;
1739 break;
1740 default:
1741 DEBUG(0,("Unknown tar option\n"));
1742 return 0;
1745 if (!tar_type) {
1746 printf("Option T must be followed by one of c or x.\n");
1747 return 0;
1750 /* tar_excl is true if cliplist lists files to be included.
1751 * Both 'I' and 'F' mean include. */
1752 tar_excl=tar_clipfl!='X';
1754 if (tar_clipfl=='F') {
1755 if (argc-Optind-1 != 1) {
1756 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1757 return 0;
1759 if (! read_inclusion_file(argv[Optind+1])) {
1760 return 0;
1762 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1763 char *tmpstr;
1764 char **tmplist;
1765 int clipcount;
1767 cliplist=argv+Optind+1;
1768 clipn=argc-Optind-1;
1769 clipcount = clipn;
1771 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1772 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1773 clipn)
1775 return 0;
1778 for (clipcount = 0; clipcount < clipn; clipcount++) {
1780 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1782 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1783 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1784 clipcount)
1786 return 0;
1788 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1789 tmplist[clipcount] = tmpstr;
1790 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1792 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1794 cliplist = tmplist;
1795 must_free_cliplist = True;
1798 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1799 #ifdef HAVE_REGEX_H
1800 int errcode;
1802 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1804 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1805 return;
1809 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1810 char errstr[1024];
1811 size_t errlen;
1813 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1815 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1816 return;
1819 #endif
1821 clipn=argc-Optind-1;
1822 cliplist=argv+Optind+1;
1826 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1827 /* Sets tar handle to either 0 or 1, as appropriate */
1828 tarhandle=(tar_type=='c');
1830 * Make sure that dbf points to stderr if we are using stdout for
1831 * tar output
1833 if (tarhandle == 1)
1834 dbf = x_stderr;
1835 } else {
1836 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1838 if (!dry_run) {
1839 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1840 dry_run = True;
1842 tarhandle=-1;
1843 } else
1844 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1845 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
1847 DEBUG(0,("Error opening local file %s - %s\n",
1848 argv[Optind], strerror(errno)));
1849 return(0);
1853 return 1;