r5555: current with 3.0 tree as of r5548; getting ready for 3.0.12pre1
[Samba.git] / source / client / clitar.c
blob14ebffb60ffd58d0b9417846bbfd78be35583ce8
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 {
47 SMB_BIG_UINT size;
48 uint16 mode;
49 uid_t uid;
50 gid_t gid;
51 /* These times are normally kept in GMT */
52 time_t mtime;
53 time_t atime;
54 time_t ctime;
55 char *name; /* This is dynamically allocate */
57 file_info2 *next, *prev; /* Used in the stack ... */
60 typedef struct {
61 file_info2 *top;
62 int items;
63 } stack;
65 #define SEPARATORS " \t\n\r"
66 extern struct cli_state *cli;
68 /* These defines are for the do_setrattr routine, to indicate
69 * setting and reseting of file attributes in the function call */
70 #define ATTRSET 1
71 #define ATTRRESET 0
73 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
75 #ifndef CLIENT_TIMEOUT
76 #define CLIENT_TIMEOUT (30*1000)
77 #endif
79 static char *tarbuf, *buffer_p;
80 static int tp, ntarf, tbufsiz;
81 static double ttarf;
82 /* Incremental mode */
83 static BOOL tar_inc=False;
84 /* Reset archive bit */
85 static BOOL tar_reset=False;
86 /* Include / exclude mode (true=include, false=exclude) */
87 static BOOL tar_excl=True;
88 /* use regular expressions for search on file names */
89 static BOOL tar_re_search=False;
90 /* Do not dump anything, just calculate sizes */
91 static BOOL dry_run=False;
92 /* Dump files with System attribute */
93 static BOOL tar_system=True;
94 /* Dump files with Hidden attribute */
95 static BOOL tar_hidden=True;
96 /* Be noisy - make a catalogue */
97 static BOOL tar_noisy=True;
98 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
100 char tar_type='\0';
101 static char **cliplist=NULL;
102 static int clipn=0;
103 static BOOL must_free_cliplist = False;
105 extern file_info def_finfo;
106 extern BOOL lowercase;
107 extern uint16 cnum;
108 extern BOOL readbraw_supported;
109 extern int max_xmit;
110 extern pstring cur_dir;
111 extern int get_total_time_ms;
112 extern int get_total_size;
114 static int blocksize=20;
115 static int tarhandle;
117 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
118 const char *amode, unsigned char ftype);
119 static void do_atar(char *rname,char *lname,file_info *finfo1);
120 static void do_tar(file_info *finfo);
121 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
122 static void fixtarname(char *tptr, const char *fp, size_t l);
123 static int dotarbuf(int f, char *b, int n);
124 static void dozerobuf(int f, int n);
125 static void dotareof(int f);
126 static void initarbuf(void);
128 /* restore functions */
129 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
130 static long unoct(char *p, int ndgs);
131 static void do_tarput(void);
132 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
135 * tar specific utitlities
138 /*******************************************************************
139 Create a string of size size+1 (for the null)
140 *******************************************************************/
142 static char *string_create_s(int size)
144 char *tmp;
146 tmp = (char *)SMB_MALLOC(size+1);
148 if (tmp == NULL) {
149 DEBUG(0, ("Out of memory in string_create_s\n"));
152 return(tmp);
155 /****************************************************************************
156 Write a tar header to buffer
157 ****************************************************************************/
159 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
160 const char *amode, unsigned char ftype)
162 union hblock hb;
163 int i, chk, l;
164 char *jp;
166 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
168 memset(hb.dummy, 0, sizeof(hb.dummy));
170 l=strlen(aname);
171 /* We will be prepending a '.' in fixtarheader so use +2 to
172 * take care of the . and terminating zero. JRA.
174 if (l+2 >= NAMSIZ) {
175 /* write a GNU tar style long header */
176 char *b;
177 b = (char *)SMB_MALLOC(l+TBLOCK+100);
178 if (!b) {
179 DEBUG(0,("out of memory\n"));
180 exit(1);
182 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
183 memset(b, 0, l+TBLOCK+100);
184 fixtarname(b, aname, l+2);
185 i = strlen(b)+1;
186 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
187 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
188 SAFE_FREE(b);
191 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
193 if (lowercase)
194 strlower_m(hb.dbuf.name);
196 /* write out a "standard" tar format header */
198 hb.dbuf.name[NAMSIZ-1]='\0';
199 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
200 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
201 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
202 oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
203 if (size > (SMB_BIG_UINT)077777777777LL) {
205 /* This is a non-POSIX compatible extention to store files
206 greater than 8GB. */
208 memset(hb.dbuf.size, 0, 4);
209 hb.dbuf.size[0]=128;
210 for (i = 8, jp=(char*)&size; i; i--)
211 hb.dbuf.size[i+3] = *(jp++);
213 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
214 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
215 memset(hb.dbuf.linkname, 0, NAMSIZ);
216 hb.dbuf.linkflag=ftype;
218 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
219 chk+=(0xFF & *jp++);
221 oct_it((SMB_BIG_UINT) 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 ***************************************************************************/
231 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
233 long chk, fchk;
234 int i;
235 char *jp;
238 * read in a "standard" tar format header - we're not that interested
239 * in that many fields, though
242 /* check the checksum */
243 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
244 chk+=(0xFF & *jp++);
246 if (chk == 0)
247 return chk;
249 /* compensate for blanks in chksum header */
250 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
251 chk-=(0xFF & *jp++);
253 chk += ' ' * sizeof(hb->dbuf.chksum);
255 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
257 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
258 chk, fchk, hb->dbuf.chksum));
260 if (fchk != chk) {
261 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
262 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
263 return -1;
266 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);
271 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
273 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
274 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
275 strlen(hb->dbuf.name) + 1, True);
277 /* can't handle some links at present */
278 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
279 if (hb->dbuf.linkflag == 0) {
280 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
281 finfo->name));
282 } else {
283 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
284 /* Do nothing here at the moment. do_tarput will handle this
285 as long as the longlink gets back to it, as it has to advance
286 the buffer pointer, etc */
287 } else {
288 DEBUG(0, ("this tar file appears to contain some kind \
289 of link other than a GNUtar Longlink - ignoring\n"));
290 return -2;
295 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
296 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
297 finfo->mode=aDIR;
298 } else {
299 finfo->mode=0; /* we don't care about mode at the moment, we'll
300 * just make it a regular file */
304 * Bug fix by richard@sj.co.uk
306 * REC: restore times correctly (as does tar)
307 * We only get the modification time of the file; set the creation time
308 * from the mod. time, and the access time to current time
310 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
311 finfo->atime = time(NULL);
312 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
314 return True;
317 /****************************************************************************
318 Write out the tar buffer to tape or wherever
319 ****************************************************************************/
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) {
330 int diff;
332 diff=tbufsiz-tp;
333 memcpy(tarbuf + tp, b, diff);
334 fail=fail && (1+write(f, tarbuf, tbufsiz));
335 n-=diff;
336 b+=diff;
337 tp=0;
339 while (n >= tbufsiz) {
340 fail=fail && (1 + write(f, b, tbufsiz));
341 n-=tbufsiz;
342 b+=tbufsiz;
346 if (n>0) {
347 memcpy(tarbuf+tp, b, n);
348 tp+=n;
351 return(fail ? writ : 0);
354 /****************************************************************************
355 Write zeros to buffer / tape
356 ****************************************************************************/
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) {
368 memset(tarbuf+tp, 0, tbufsiz-tp);
369 write(f, tarbuf, tbufsiz);
370 memset(tarbuf, 0, (tp+=n-tbufsiz));
371 } else {
372 memset(tarbuf+tp, 0, n);
373 tp+=n;
377 /****************************************************************************
378 Malloc tape buffer
379 ****************************************************************************/
381 static void initarbuf(void)
383 /* initialize tar buffer */
384 tbufsiz=blocksize*TBLOCK;
385 tarbuf=SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
387 /* reset tar buffer pointer and tar file counter and total dumped */
388 tp=0; ntarf=0; ttarf=0;
391 /****************************************************************************
392 Write two zero blocks at end of file
393 ****************************************************************************/
395 static void dotareof(int f)
397 SMB_STRUCT_STAT stbuf;
398 /* Two zero blocks at end of file, write out full buffer */
400 if (dry_run)
401 return;
403 (void) dozerobuf(f, TBLOCK);
404 (void) dozerobuf(f, TBLOCK);
406 if (sys_fstat(f, &stbuf) == -1) {
407 DEBUG(0, ("Couldn't stat file handle\n"));
408 return;
411 /* Could be a pipe, in which case S_ISREG should fail,
412 * and we should write out at full size */
413 if (tp > 0)
414 write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
417 /****************************************************************************
418 (Un)mangle DOS pathname, make nonabsolute
419 ****************************************************************************/
421 static void fixtarname(char *tptr, const char *fp, size_t l)
423 /* add a '.' to start of file name, convert from ugly dos \'s in path
424 * to lovely unix /'s :-} */
425 *tptr++='.';
426 l--;
428 StrnCpy(tptr, fp, l-1);
429 string_replace(tptr, '\\', '/');
432 /****************************************************************************
433 Convert from decimal to octal string
434 ****************************************************************************/
436 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
438 /* Converts long to octal string, pads with leading zeros */
440 /* skip final null, but do final space */
441 --ndgs;
442 p[--ndgs] = ' ';
444 /* Loop does at least one digit */
445 do {
446 p[--ndgs] = '0' + (char) (value & 7);
447 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 ***************************************************************************/
459 static long unoct(char *p, int ndgs)
461 long value=0;
462 /* Converts octal string to long, ignoring any non-digit */
464 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 ***************************************************************************/
480 static int strslashcmp(char *s1, char *s2)
482 char *s1_0=s1;
484 while(*s1 && *s2 && (*s1 == *s2 || tolower(*s1) == tolower(*s2) ||
485 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
486 s1++; s2++;
489 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
490 string of s2.
492 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
493 return 0;
495 /* ignore trailing slash on s1 */
496 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
497 return 0;
499 /* check for s1 is an "initial" string of s2 */
500 if ((*s2 == '/' || *s2 == '\\') && !*s1)
501 return 0;
503 return *s1-*s2;
506 /****************************************************************************
507 Ensure a remote path exists (make if necessary)
508 ***************************************************************************/
510 static BOOL ensurepath(char *fname)
512 /* *must* be called with buffer ready malloc'ed */
513 /* ensures path exists */
515 char *partpath, *ffname;
516 char *p=fname, *basehack;
518 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
520 partpath = string_create_s(strlen(fname));
521 ffname = string_create_s(strlen(fname));
523 if ((partpath == NULL) || (ffname == NULL)){
524 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
525 return(False);
528 *partpath = 0;
530 /* fname copied to ffname so can strtok */
532 safe_strcpy(ffname, fname, strlen(fname));
534 /* do a `basename' on ffname, so don't try and make file name directory */
535 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
536 return True;
537 else
538 *basehack='\0';
540 p=strtok(ffname, "\\");
542 while (p) {
543 safe_strcat(partpath, p, strlen(fname) + 1);
545 if (!cli_chkpath(cli, partpath)) {
546 if (!cli_mkdir(cli, partpath)) {
547 DEBUG(0, ("Error mkdirhiering\n"));
548 return False;
549 } else {
550 DEBUG(3, ("mkdirhiering %s\n", partpath));
554 safe_strcat(partpath, "\\", strlen(fname) + 1);
555 p = strtok(NULL,"/\\");
558 return True;
561 static int padit(char *buf, int bufsize, int padsize)
563 int berr= 0;
564 int bytestowrite;
566 DEBUG(5, ("Padding with %d zeros\n", padsize));
567 memset(buf, 0, bufsize);
568 while( !berr && padsize > 0 ) {
569 bytestowrite= MIN(bufsize, padsize);
570 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
571 padsize -= bytestowrite;
574 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)));
594 /****************************************************************************
595 append one remote file to the tar file
596 ***************************************************************************/
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;
612 GetTimeOfDay(&tp_start);
614 ftype = '0'; /* An ordinary file ... */
616 if (finfo1) {
617 finfo.size = finfo1 -> size;
618 finfo.mode = finfo1 -> mode;
619 finfo.uid = finfo1 -> uid;
620 finfo.gid = finfo1 -> gid;
621 finfo.mtime = finfo1 -> mtime;
622 finfo.atime = finfo1 -> atime;
623 finfo.ctime = finfo1 -> ctime;
624 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) {
637 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
638 (double)finfo.size));
639 shallitime=0;
640 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
641 ntarf++;
642 return;
645 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
647 dos_clean_name(rname);
649 if (fnum == -1) {
650 DEBUG(0,("%s opening remote file %s (%s)\n",
651 cli_errstr(cli),rname, cur_dir));
652 return;
655 finfo.name = string_create_s(strlen(rname));
656 if (finfo.name == NULL) {
657 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
658 return;
661 safe_strcpy(finfo.name,rname, strlen(rname));
662 if (!finfo1) {
663 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
664 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
665 return;
667 finfo.ctime = finfo.mtime;
670 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
672 if (tar_inc && !(finfo.mode & aARCH)) {
673 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
674 shallitime=0;
675 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
676 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
677 shallitime=0;
678 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
679 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
680 shallitime=0;
681 } else {
682 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
683 finfo.name, (double)finfo.size, lname));
685 /* write a tar header, don't bother with mode - just set to 100644 */
686 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
688 while (nread < finfo.size && !close_done) {
690 DEBUG(3,("nread=%.0f\n",(double)nread));
692 datalen = cli_read(cli, fnum, data, nread, read_size);
694 if (datalen == -1) {
695 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
696 break;
699 nread += datalen;
701 /* if file size has increased since we made file size query, truncate
702 read so tar header for this file will be correct.
705 if (nread > finfo.size) {
706 datalen -= nread - finfo.size;
707 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
708 finfo.name, (double)finfo.size));
711 /* add received bits of file to buffer - dotarbuf will
712 * write out in 512 byte intervals */
714 if (dotarbuf(tarhandle,data,datalen) != datalen) {
715 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
716 break;
719 if (datalen == 0) {
720 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
721 break;
724 datalen=0;
727 /* pad tar file with zero's if we couldn't get entire file */
728 if (nread < finfo.size) {
729 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
730 (double)finfo.size, (int)nread));
731 if (padit(data, sizeof(data), finfo.size - nread))
732 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
735 /* round tar file to nearest block */
736 if (finfo.size % TBLOCK)
737 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
739 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
740 ntarf++;
743 cli_close(cli, fnum);
745 if (shallitime) {
746 struct timeval tp_end;
747 int this_time;
749 /* if shallitime is true then we didn't skip */
750 if (tar_reset && !dry_run)
751 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
753 GetTimeOfDay(&tp_end);
754 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
755 get_total_time_ms += this_time;
756 get_total_size += finfo.size;
758 if (tar_noisy) {
759 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
760 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
761 finfo.name));
764 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
765 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
766 finfo.size / MAX(0.001, (1.024*this_time)),
767 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
771 /****************************************************************************
772 Append single file to tar file (or not)
773 ***************************************************************************/
775 static void do_tar(file_info *finfo)
777 pstring rname;
779 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
780 return;
782 /* Is it on the exclude list ? */
783 if (!tar_excl && clipn) {
784 pstring exclaim;
786 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
788 pstrcpy(exclaim, cur_dir);
789 *(exclaim+strlen(exclaim)-1)='\0';
791 pstrcat(exclaim, "\\");
792 pstrcat(exclaim, finfo->name);
794 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
796 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
797 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
798 DEBUG(3,("Skipping file %s\n", exclaim));
799 return;
803 if (finfo->mode & aDIR) {
804 pstring saved_curdir;
805 pstring mtar_mask;
807 pstrcpy(saved_curdir, cur_dir);
809 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
810 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
811 (int)sizeof(cur_dir), (int)strlen(cur_dir),
812 (int)strlen(finfo->name), finfo->name, cur_dir));
814 pstrcat(cur_dir,finfo->name);
815 pstrcat(cur_dir,"\\");
817 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
819 /* write a tar directory, don't bother with mode - just set it to
820 * 40755 */
821 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
822 if (tar_noisy) {
823 DEBUG(0,(" directory %s\n", cur_dir));
825 ntarf++; /* Make sure we have a file on there */
826 pstrcpy(mtar_mask,cur_dir);
827 pstrcat(mtar_mask,"*");
828 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
829 do_list(mtar_mask, attribute, do_tar, False, True);
830 pstrcpy(cur_dir,saved_curdir);
831 } else {
832 pstrcpy(rname,cur_dir);
833 pstrcat(rname,finfo->name);
834 do_atar(rname,finfo->name,finfo);
838 /****************************************************************************
839 Convert from UNIX to DOS file names
840 ***************************************************************************/
842 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
844 /* remove '.' from start of file name, convert from unix /'s to
845 * dos \'s in path. Kill any absolute path names. But only if first!
848 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
850 if (first) {
851 if (*fp == '.') {
852 fp++;
853 l--;
855 if (*fp == '\\' || *fp == '/') {
856 fp++;
857 l--;
861 safe_strcpy(tptr, fp, l);
862 string_replace(tptr, '/', '\\');
865 /****************************************************************************
866 Move to the next block in the buffer, which may mean read in another set of
867 blocks. FIXME, we should allow more than one block to be skipped.
868 ****************************************************************************/
870 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
872 int bufread, total = 0;
874 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
875 *bufferp += TBLOCK;
876 total = TBLOCK;
878 if (*bufferp >= (ltarbuf + bufsiz)) {
880 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
883 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
884 * Fixes bug where read can return short if coming from
885 * a pipe.
888 bufread = read(tarhandle, ltarbuf, bufsiz);
889 total = bufread;
891 while (total < bufsiz) {
892 if (bufread < 0) { /* An error, return false */
893 return (total > 0 ? -2 : bufread);
895 if (bufread == 0) {
896 if (total <= 0) {
897 return -2;
899 break;
901 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
902 total += bufread;
905 DEBUG(5, ("Total bytes read ... %i\n", total));
907 *bufferp = ltarbuf;
910 return(total);
913 /* Skip a file, even if it includes a long file name? */
914 static int skip_file(int skipsize)
916 int dsize = skipsize;
918 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
920 /* FIXME, we should skip more than one block at a time */
922 while (dsize > 0) {
923 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
924 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
925 return(False);
927 dsize -= TBLOCK;
930 return(True);
933 /*************************************************************
934 Get a file from the tar file and store it.
935 When this is called, tarbuf already contains the first
936 file block. This is a bit broken & needs fixing.
937 **************************************************************/
939 static int get_file(file_info2 finfo)
941 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
942 SMB_BIG_UINT rsize = 0;
944 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
946 if (ensurepath(finfo.name) &&
947 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
948 DEBUG(0, ("abandoning restore\n"));
949 return(False);
952 /* read the blocks from the tar file and write to the remote file */
954 rsize = finfo.size; /* This is how much to write */
956 while (rsize > 0) {
958 /* We can only write up to the end of the buffer */
959 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
960 dsize = MIN(dsize, rsize); /* Should be only what is left */
961 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
963 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
964 DEBUG(0, ("Error writing remote file\n"));
965 return 0;
968 rsize -= dsize;
969 pos += dsize;
971 /* Now figure out how much to move in the buffer */
973 /* FIXME, we should skip more than one block at a time */
975 /* First, skip any initial part of the part written that is left over */
976 /* from the end of the first TBLOCK */
978 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
979 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
980 bpos = 0;
982 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
983 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
984 return False;
989 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
990 * If the file being extracted is an exact multiple of
991 * TBLOCK bytes then we don't want to extract the next
992 * block from the tarfile here, as it will be done in
993 * the caller of get_file().
996 while (((rsize != 0) && (dsize >= TBLOCK)) ||
997 ((rsize == 0) && (dsize > TBLOCK))) {
999 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1000 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1001 return False;
1004 dsize -= TBLOCK;
1006 bpos = dsize;
1009 /* Now close the file ... */
1011 if (!cli_close(cli, fnum)) {
1012 DEBUG(0, ("Error closing remote file\n"));
1013 return(False);
1016 /* Now we update the creation date ... */
1017 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1019 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1020 if (tar_real_noisy) {
1021 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1022 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1026 ntarf++;
1027 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1028 return(True);
1031 /* Create a directory. We just ensure that the path exists and return as there
1032 is no file associated with a directory
1034 static int get_dir(file_info2 finfo)
1036 DEBUG(0, ("restore directory %s\n", finfo.name));
1038 if (!ensurepath(finfo.name)) {
1039 DEBUG(0, ("Problems creating directory\n"));
1040 return(False);
1042 ntarf++;
1043 return(True);
1046 /* Get a file with a long file name ... first file has file name, next file
1047 has the data. We only want the long file name, as the loop in do_tarput
1048 will deal with the rest.
1050 static char *get_longfilename(file_info2 finfo)
1052 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1053 * header call. */
1054 int namesize = finfo.size + strlen(cur_dir) + 2;
1055 char *longname = SMB_MALLOC(namesize);
1056 int offset = 0, left = finfo.size;
1057 BOOL first = True;
1059 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1060 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1062 if (longname == NULL) {
1063 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1064 return(NULL);
1067 /* First, add cur_dir to the long file name */
1069 if (strlen(cur_dir) > 0) {
1070 strncpy(longname, cur_dir, namesize);
1071 offset = strlen(cur_dir);
1074 /* Loop through the blocks picking up the name */
1076 while (left > 0) {
1077 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1078 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1079 return(NULL);
1082 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1083 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1085 offset += TBLOCK;
1086 left -= TBLOCK;
1089 return(longname);
1092 static void do_tarput(void)
1094 file_info2 finfo;
1095 struct timeval tp_start;
1096 char *longfilename = NULL, linkflag;
1097 int skip = False;
1099 GetTimeOfDay(&tp_start);
1100 DEBUG(5, ("RJS do_tarput called ...\n"));
1102 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1104 /* Now read through those files ... */
1105 while (True) {
1106 /* Get us to the next block, or the first block first time around */
1107 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1108 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1109 return;
1112 DEBUG(5, ("Reading the next header ...\n"));
1114 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1115 case -2: /* Hmm, not good, but not fatal */
1116 DEBUG(0, ("Skipping %s...\n", finfo.name));
1117 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1118 DEBUG(0, ("Short file, bailing out...\n"));
1119 return;
1121 break;
1123 case -1:
1124 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1125 return;
1127 case 0: /* chksum is zero - looks like an EOF */
1128 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1129 return; /* Hmmm, bad here ... */
1131 default:
1132 /* No action */
1133 break;
1136 /* Now, do we have a long file name? */
1137 if (longfilename != NULL) {
1138 SAFE_FREE(finfo.name); /* Free the space already allocated */
1139 finfo.name = longfilename;
1140 longfilename = NULL;
1143 /* Well, now we have a header, process the file ... */
1144 /* Should we skip the file? We have the long name as well here */
1145 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1146 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1148 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1149 if (skip) {
1150 skip_file(finfo.size);
1151 continue;
1154 /* We only get this far if we should process the file */
1155 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1156 switch (linkflag) {
1157 case '0': /* Should use symbolic names--FIXME */
1159 * Skip to the next block first, so we can get the file, FIXME, should
1160 * be in get_file ...
1161 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1162 * Fixes bug where file size in tarfile is zero.
1164 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1165 DEBUG(0, ("Short file, bailing out...\n"));
1166 return;
1168 if (!get_file(finfo)) {
1169 DEBUG(0, ("Abandoning restore\n"));
1170 return;
1172 break;
1173 case '5':
1174 if (!get_dir(finfo)) {
1175 DEBUG(0, ("Abandoning restore \n"));
1176 return;
1178 break;
1179 case 'L':
1180 longfilename = get_longfilename(finfo);
1181 if (!longfilename) {
1182 DEBUG(0, ("abandoning restore\n"));
1183 return;
1185 DEBUG(5, ("Long file name: %s\n", longfilename));
1186 break;
1188 default:
1189 skip_file(finfo.size); /* Don't handle these yet */
1190 break;
1196 * samba interactive commands
1199 /****************************************************************************
1200 Blocksize command
1201 ***************************************************************************/
1203 int cmd_block(void)
1205 fstring buf;
1206 int block;
1208 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1209 DEBUG(0, ("blocksize <n>\n"));
1210 return 1;
1213 block=atoi(buf);
1214 if (block < 0 || block > 65535) {
1215 DEBUG(0, ("blocksize out of range"));
1216 return 1;
1219 blocksize=block;
1220 DEBUG(2,("blocksize is now %d\n", blocksize));
1222 return 0;
1225 /****************************************************************************
1226 command to set incremental / reset mode
1227 ***************************************************************************/
1229 int cmd_tarmode(void)
1231 fstring buf;
1233 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1234 if (strequal(buf, "full"))
1235 tar_inc=False;
1236 else if (strequal(buf, "inc"))
1237 tar_inc=True;
1238 else if (strequal(buf, "reset"))
1239 tar_reset=True;
1240 else if (strequal(buf, "noreset"))
1241 tar_reset=False;
1242 else if (strequal(buf, "system"))
1243 tar_system=True;
1244 else if (strequal(buf, "nosystem"))
1245 tar_system=False;
1246 else if (strequal(buf, "hidden"))
1247 tar_hidden=True;
1248 else if (strequal(buf, "nohidden"))
1249 tar_hidden=False;
1250 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1251 tar_noisy=True;
1252 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1253 tar_noisy=False;
1254 else
1255 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1258 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1259 tar_inc ? "incremental" : "full",
1260 tar_system ? "system" : "nosystem",
1261 tar_hidden ? "hidden" : "nohidden",
1262 tar_reset ? "reset" : "noreset",
1263 tar_noisy ? "verbose" : "quiet"));
1264 return 0;
1267 /****************************************************************************
1268 Feeble attrib command
1269 ***************************************************************************/
1271 int cmd_setmode(void)
1273 char *q;
1274 fstring buf;
1275 pstring fname;
1276 uint16 attra[2];
1277 int direct=1;
1279 attra[0] = attra[1] = 0;
1281 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1282 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1283 return 1;
1286 pstrcpy(fname, cur_dir);
1287 pstrcat(fname, buf);
1289 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1290 q=buf;
1292 while(*q) {
1293 switch (*q++) {
1294 case '+':
1295 direct=1;
1296 break;
1297 case '-':
1298 direct=0;
1299 break;
1300 case 'r':
1301 attra[direct]|=aRONLY;
1302 break;
1303 case 'h':
1304 attra[direct]|=aHIDDEN;
1305 break;
1306 case 's':
1307 attra[direct]|=aSYSTEM;
1308 break;
1309 case 'a':
1310 attra[direct]|=aARCH;
1311 break;
1312 default:
1313 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1314 return 1;
1319 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1320 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1321 return 1;
1324 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1325 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1326 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1327 return 0;
1330 /****************************************************************************
1331 Principal command for creating / extracting
1332 ***************************************************************************/
1334 int cmd_tar(void)
1336 fstring buf;
1337 char **argl = NULL;
1338 int argcl = 0;
1339 int ret;
1341 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1342 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1343 return 1;
1346 argl=toktocliplist(&argcl, NULL);
1347 if (!tar_parseargs(argcl, argl, buf, 0))
1348 return 1;
1350 ret = process_tar();
1351 SAFE_FREE(argl);
1352 return ret;
1355 /****************************************************************************
1356 Command line (option) version
1357 ***************************************************************************/
1359 int process_tar(void)
1361 int rc = 0;
1362 initarbuf();
1363 switch(tar_type) {
1364 case 'x':
1366 #if 0
1367 do_tarput2();
1368 #else
1369 do_tarput();
1370 #endif
1371 SAFE_FREE(tarbuf);
1372 close(tarhandle);
1373 break;
1374 case 'r':
1375 case 'c':
1376 if (clipn && tar_excl) {
1377 int i;
1378 pstring tarmac;
1380 for (i=0; i<clipn; i++) {
1381 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1383 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1384 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1387 if (strrchr_m(cliplist[i], '\\')) {
1388 pstring saved_dir;
1390 pstrcpy(saved_dir, cur_dir);
1392 if (*cliplist[i]=='\\') {
1393 pstrcpy(tarmac, cliplist[i]);
1394 } else {
1395 pstrcpy(tarmac, cur_dir);
1396 pstrcat(tarmac, cliplist[i]);
1398 pstrcpy(cur_dir, tarmac);
1399 *(strrchr_m(cur_dir, '\\')+1)='\0';
1401 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1402 do_list(tarmac,attribute,do_tar, False, True);
1403 pstrcpy(cur_dir,saved_dir);
1404 } else {
1405 pstrcpy(tarmac, cur_dir);
1406 pstrcat(tarmac, cliplist[i]);
1407 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1408 do_list(tarmac,attribute,do_tar, False, True);
1411 } else {
1412 pstring mask;
1413 pstrcpy(mask,cur_dir);
1414 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1415 pstrcat(mask,"\\*");
1416 do_list(mask,attribute,do_tar,False, True);
1419 if (ntarf)
1420 dotareof(tarhandle);
1421 close(tarhandle);
1422 SAFE_FREE(tarbuf);
1424 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1425 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1426 break;
1429 if (must_free_cliplist) {
1430 int i;
1431 for (i = 0; i < clipn; ++i) {
1432 SAFE_FREE(cliplist[i]);
1434 SAFE_FREE(cliplist);
1435 cliplist = NULL;
1436 clipn = 0;
1437 must_free_cliplist = False;
1439 return rc;
1442 /****************************************************************************
1443 Find a token (filename) in a clip list
1444 ***************************************************************************/
1446 static int clipfind(char **aret, int ret, char *tok)
1448 if (aret==NULL)
1449 return 0;
1451 /* ignore leading slashes or dots in token */
1452 while(strchr_m("/\\.", *tok))
1453 tok++;
1455 while(ret--) {
1456 char *pkey=*aret++;
1458 /* ignore leading slashes or dots in list */
1459 while(strchr_m("/\\.", *pkey))
1460 pkey++;
1462 if (!strslashcmp(pkey, tok))
1463 return 1;
1465 return 0;
1468 /****************************************************************************
1469 Read list of files to include from the file and initialize cliplist
1470 accordingly.
1471 ***************************************************************************/
1473 static int read_inclusion_file(char *filename)
1475 XFILE *inclusion = NULL;
1476 char buf[PATH_MAX + 1];
1477 char *inclusion_buffer = NULL;
1478 int inclusion_buffer_size = 0;
1479 int inclusion_buffer_sofar = 0;
1480 char *p;
1481 char *tmpstr;
1482 int i;
1483 int error = 0;
1485 clipn = 0;
1486 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1487 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1488 /* XXX It would be better to include a reason for failure, but without
1489 * autoconf, it's hard to use strerror, sys_errlist, etc.
1491 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1492 return 0;
1495 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1496 if (inclusion_buffer == NULL) {
1497 inclusion_buffer_size = 1024;
1498 if ((inclusion_buffer = SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1499 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1500 error = 1;
1501 break;
1505 if (buf[strlen(buf)-1] == '\n') {
1506 buf[strlen(buf)-1] = '\0';
1509 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1510 char *ib;
1511 inclusion_buffer_size *= 2;
1512 ib = SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1513 if (! ib) {
1514 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1515 inclusion_buffer_size));
1516 error = 1;
1517 break;
1518 } else {
1519 inclusion_buffer = ib;
1523 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1524 inclusion_buffer_sofar += strlen(buf) + 1;
1525 clipn++;
1527 x_fclose(inclusion);
1529 if (! error) {
1530 /* Allocate an array of clipn + 1 char*'s for cliplist */
1531 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1532 if (cliplist == NULL) {
1533 DEBUG(0,("failure allocating memory for cliplist\n"));
1534 error = 1;
1535 } else {
1536 cliplist[clipn] = NULL;
1537 p = inclusion_buffer;
1538 for (i = 0; (! error) && (i < clipn); i++) {
1539 /* set current item to NULL so array will be null-terminated even if
1540 * malloc fails below. */
1541 cliplist[i] = NULL;
1542 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1543 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1544 error = 1;
1545 } else {
1546 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1547 cliplist[i] = tmpstr;
1548 if ((p = strchr_m(p, '\000')) == NULL) {
1549 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1550 abort();
1553 ++p;
1555 must_free_cliplist = True;
1559 SAFE_FREE(inclusion_buffer);
1560 if (error) {
1561 if (cliplist) {
1562 char **pp;
1563 /* We know cliplist is always null-terminated */
1564 for (pp = cliplist; *pp; ++pp) {
1565 SAFE_FREE(*pp);
1567 SAFE_FREE(cliplist);
1568 cliplist = NULL;
1569 must_free_cliplist = False;
1571 return 0;
1574 /* cliplist and its elements are freed at the end of process_tar. */
1575 return 1;
1578 /****************************************************************************
1579 Parse tar arguments. Sets tar_type, tar_excl, etc.
1580 ***************************************************************************/
1582 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1584 int newOptind = Optind;
1585 char tar_clipfl='\0';
1587 /* Reset back to defaults - could be from interactive version
1588 * reset mode and archive mode left as they are though
1590 tar_type='\0';
1591 tar_excl=True;
1592 dry_run=False;
1594 while (*Optarg) {
1595 switch(*Optarg++) {
1596 case 'c':
1597 tar_type='c';
1598 break;
1599 case 'x':
1600 if (tar_type=='c') {
1601 printf("Tar must be followed by only one of c or x.\n");
1602 return 0;
1604 tar_type='x';
1605 break;
1606 case 'b':
1607 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1608 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1609 return 0;
1610 } else {
1611 Optind++;
1612 newOptind++;
1614 break;
1615 case 'g':
1616 tar_inc=True;
1617 break;
1618 case 'N':
1619 if (Optind>=argc) {
1620 DEBUG(0,("Option N must be followed by valid file name\n"));
1621 return 0;
1622 } else {
1623 SMB_STRUCT_STAT stbuf;
1624 extern time_t newer_than;
1626 if (sys_stat(argv[Optind], &stbuf) == 0) {
1627 newer_than = stbuf.st_mtime;
1628 DEBUG(1,("Getting files newer than %s",
1629 asctime(LocalTime(&newer_than))));
1630 newOptind++;
1631 Optind++;
1632 } else {
1633 DEBUG(0,("Error setting newer-than time\n"));
1634 return 0;
1637 break;
1638 case 'a':
1639 tar_reset=True;
1640 break;
1641 case 'q':
1642 tar_noisy=False;
1643 break;
1644 case 'I':
1645 if (tar_clipfl) {
1646 DEBUG(0,("Only one of I,X,F must be specified\n"));
1647 return 0;
1649 tar_clipfl='I';
1650 break;
1651 case 'X':
1652 if (tar_clipfl) {
1653 DEBUG(0,("Only one of I,X,F must be specified\n"));
1654 return 0;
1656 tar_clipfl='X';
1657 break;
1658 case 'F':
1659 if (tar_clipfl) {
1660 DEBUG(0,("Only one of I,X,F must be specified\n"));
1661 return 0;
1663 tar_clipfl='F';
1664 break;
1665 case 'r':
1666 DEBUG(0, ("tar_re_search set\n"));
1667 tar_re_search = True;
1668 break;
1669 case 'n':
1670 if (tar_type == 'c') {
1671 DEBUG(0, ("dry_run set\n"));
1672 dry_run = True;
1673 } else {
1674 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1675 return 0;
1677 break;
1678 default:
1679 DEBUG(0,("Unknown tar option\n"));
1680 return 0;
1684 if (!tar_type) {
1685 printf("Option T must be followed by one of c or x.\n");
1686 return 0;
1689 /* tar_excl is true if cliplist lists files to be included.
1690 * Both 'I' and 'F' mean include. */
1691 tar_excl=tar_clipfl!='X';
1693 if (tar_clipfl=='F') {
1694 if (argc-Optind-1 != 1) {
1695 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1696 return 0;
1698 newOptind++;
1699 Optind++;
1700 if (! read_inclusion_file(argv[Optind])) {
1701 return 0;
1703 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1704 char *tmpstr;
1705 char **tmplist;
1706 int clipcount;
1708 cliplist=argv+Optind+1;
1709 clipn=argc-Optind-1;
1710 clipcount = clipn;
1712 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1713 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1714 return 0;
1717 for (clipcount = 0; clipcount < clipn; clipcount++) {
1719 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1721 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1722 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1723 return 0;
1726 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1727 tmplist[clipcount] = tmpstr;
1728 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1730 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1733 cliplist = tmplist;
1734 must_free_cliplist = True;
1736 newOptind += clipn;
1739 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1740 clipn=argc-Optind-1;
1741 cliplist=argv+Optind+1;
1742 newOptind += clipn;
1745 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1746 /* Sets tar handle to either 0 or 1, as appropriate */
1747 tarhandle=(tar_type=='c');
1749 * Make sure that dbf points to stderr if we are using stdout for
1750 * tar output
1752 if (tarhandle == 1) {
1753 dbf = x_stderr;
1755 if (!argv[Optind]) {
1756 DEBUG(0,("Must specify tar filename\n"));
1757 return 0;
1759 if (!strcmp(argv[Optind], "-")) {
1760 newOptind++;
1763 } else {
1764 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0)) {
1765 if (!dry_run) {
1766 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1767 dry_run = True;
1769 tarhandle=-1;
1770 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1771 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1772 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1773 return(0);
1775 newOptind++;
1778 return newOptind;