r6369: update release notes
[Samba.git] / source / client / clitar.c
blobb241bd0ec2a281aa79dd73614bc001559323c4ed
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_OFF_T 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 time_t newer_than;
67 extern struct cli_state *cli;
69 /* These defines are for the do_setrattr routine, to indicate
70 * setting and reseting of file attributes in the function call */
71 #define ATTRSET 1
72 #define ATTRRESET 0
74 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
76 #ifndef CLIENT_TIMEOUT
77 #define CLIENT_TIMEOUT (30*1000)
78 #endif
80 static char *tarbuf, *buffer_p;
81 static int tp, ntarf, tbufsiz;
82 static double ttarf;
83 /* Incremental mode */
84 static BOOL tar_inc=False;
85 /* Reset archive bit */
86 static BOOL tar_reset=False;
87 /* Include / exclude mode (true=include, false=exclude) */
88 static BOOL tar_excl=True;
89 /* use regular expressions for search on file names */
90 static BOOL tar_re_search=False;
91 /* Do not dump anything, just calculate sizes */
92 static BOOL dry_run=False;
93 /* Dump files with System attribute */
94 static BOOL tar_system=True;
95 /* Dump files with Hidden attribute */
96 static BOOL tar_hidden=True;
97 /* Be noisy - make a catalogue */
98 static BOOL tar_noisy=True;
99 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
101 char tar_type='\0';
102 static char **cliplist=NULL;
103 static int clipn=0;
104 static BOOL must_free_cliplist = False;
106 extern file_info def_finfo;
107 extern BOOL lowercase;
108 extern uint16 cnum;
109 extern BOOL readbraw_supported;
110 extern int max_xmit;
111 extern pstring cur_dir;
112 extern int get_total_time_ms;
113 extern int get_total_size;
115 static int blocksize=20;
116 static int tarhandle;
118 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
119 const char *amode, unsigned char ftype);
120 static void do_atar(char *rname,char *lname,file_info *finfo1);
121 static void do_tar(file_info *finfo);
122 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
123 static void fixtarname(char *tptr, const char *fp, size_t l);
124 static int dotarbuf(int f, char *b, int n);
125 static void dozerobuf(int f, int n);
126 static void dotareof(int f);
127 static void initarbuf(void);
129 /* restore functions */
130 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
131 static long unoct(char *p, int ndgs);
132 static void do_tarput(void);
133 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
136 * tar specific utitlities
139 /*******************************************************************
140 Create a string of size size+1 (for the null)
141 *******************************************************************/
143 static char *string_create_s(int size)
145 char *tmp;
147 tmp = (char *)SMB_MALLOC(size+1);
149 if (tmp == NULL) {
150 DEBUG(0, ("Out of memory in string_create_s\n"));
153 return(tmp);
156 /****************************************************************************
157 Write a tar header to buffer
158 ****************************************************************************/
160 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
161 const char *amode, unsigned char ftype)
163 union hblock hb;
164 int i, chk, l;
165 char *jp;
167 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
169 memset(hb.dummy, 0, sizeof(hb.dummy));
171 l=strlen(aname);
172 /* We will be prepending a '.' in fixtarheader so use +2 to
173 * take care of the . and terminating zero. JRA.
175 if (l+2 >= NAMSIZ) {
176 /* write a GNU tar style long header */
177 char *b;
178 b = (char *)SMB_MALLOC(l+TBLOCK+100);
179 if (!b) {
180 DEBUG(0,("out of memory\n"));
181 exit(1);
183 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
184 memset(b, 0, l+TBLOCK+100);
185 fixtarname(b, aname, l+2);
186 i = strlen(b)+1;
187 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
188 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
189 SAFE_FREE(b);
192 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
194 if (lowercase)
195 strlower_m(hb.dbuf.name);
197 /* write out a "standard" tar format header */
199 hb.dbuf.name[NAMSIZ-1]='\0';
200 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
201 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
202 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
203 oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
204 if (size > (SMB_BIG_UINT)077777777777LL) {
206 /* This is a non-POSIX compatible extention to store files
207 greater than 8GB. */
209 memset(hb.dbuf.size, 0, 4);
210 hb.dbuf.size[0]=128;
211 for (i = 8, jp=(char*)&size; i; i--)
212 hb.dbuf.size[i+3] = *(jp++);
214 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
215 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
216 memset(hb.dbuf.linkname, 0, NAMSIZ);
217 hb.dbuf.linkflag=ftype;
219 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
220 chk+=(0xFF & *jp++);
222 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
223 hb.dbuf.chksum[6] = '\0';
225 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
228 /****************************************************************************
229 Read a tar header into a hblock structure, and validate
230 ***************************************************************************/
232 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
234 long chk, fchk;
235 int i;
236 char *jp;
239 * read in a "standard" tar format header - we're not that interested
240 * in that many fields, though
243 /* check the checksum */
244 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
245 chk+=(0xFF & *jp++);
247 if (chk == 0)
248 return chk;
250 /* compensate for blanks in chksum header */
251 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
252 chk-=(0xFF & *jp++);
254 chk += ' ' * sizeof(hb->dbuf.chksum);
256 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
258 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
259 chk, fchk, hb->dbuf.chksum));
261 if (fchk != chk) {
262 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
263 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
264 return -1;
267 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
268 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
269 return(-1);
272 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
274 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
275 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
276 strlen(hb->dbuf.name) + 1, True);
278 /* can't handle some links at present */
279 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
280 if (hb->dbuf.linkflag == 0) {
281 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
282 finfo->name));
283 } else {
284 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
285 /* Do nothing here at the moment. do_tarput will handle this
286 as long as the longlink gets back to it, as it has to advance
287 the buffer pointer, etc */
288 } else {
289 DEBUG(0, ("this tar file appears to contain some kind \
290 of link other than a GNUtar Longlink - ignoring\n"));
291 return -2;
296 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
297 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
298 finfo->mode=aDIR;
299 } else {
300 finfo->mode=0; /* we don't care about mode at the moment, we'll
301 * just make it a regular file */
305 * Bug fix by richard@sj.co.uk
307 * REC: restore times correctly (as does tar)
308 * We only get the modification time of the file; set the creation time
309 * from the mod. time, and the access time to current time
311 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
312 finfo->atime = time(NULL);
313 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
315 return True;
318 /****************************************************************************
319 Write out the tar buffer to tape or wherever
320 ****************************************************************************/
322 static int dotarbuf(int f, char *b, int n)
324 int fail=1, writ=n;
326 if (dry_run) {
327 return writ;
329 /* This routine and the next one should be the only ones that do write()s */
330 if (tp + n >= tbufsiz) {
331 int diff;
333 diff=tbufsiz-tp;
334 memcpy(tarbuf + tp, b, diff);
335 fail=fail && (1+write(f, tarbuf, tbufsiz));
336 n-=diff;
337 b+=diff;
338 tp=0;
340 while (n >= tbufsiz) {
341 fail=fail && (1 + write(f, b, tbufsiz));
342 n-=tbufsiz;
343 b+=tbufsiz;
347 if (n>0) {
348 memcpy(tarbuf+tp, b, n);
349 tp+=n;
352 return(fail ? writ : 0);
355 /****************************************************************************
356 Write zeros to buffer / tape
357 ****************************************************************************/
359 static void dozerobuf(int f, int n)
361 /* short routine just to write out n zeros to buffer -
362 * used to round files to nearest block
363 * and to do tar EOFs */
365 if (dry_run)
366 return;
368 if (n+tp >= tbufsiz) {
369 memset(tarbuf+tp, 0, tbufsiz-tp);
370 write(f, tarbuf, tbufsiz);
371 memset(tarbuf, 0, (tp+=n-tbufsiz));
372 } else {
373 memset(tarbuf+tp, 0, n);
374 tp+=n;
378 /****************************************************************************
379 Malloc tape buffer
380 ****************************************************************************/
382 static void initarbuf(void)
384 /* initialize tar buffer */
385 tbufsiz=blocksize*TBLOCK;
386 tarbuf=SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
388 /* reset tar buffer pointer and tar file counter and total dumped */
389 tp=0; ntarf=0; ttarf=0;
392 /****************************************************************************
393 Write two zero blocks at end of file
394 ****************************************************************************/
396 static void dotareof(int f)
398 SMB_STRUCT_STAT stbuf;
399 /* Two zero blocks at end of file, write out full buffer */
401 if (dry_run)
402 return;
404 (void) dozerobuf(f, TBLOCK);
405 (void) dozerobuf(f, TBLOCK);
407 if (sys_fstat(f, &stbuf) == -1) {
408 DEBUG(0, ("Couldn't stat file handle\n"));
409 return;
412 /* Could be a pipe, in which case S_ISREG should fail,
413 * and we should write out at full size */
414 if (tp > 0)
415 write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
418 /****************************************************************************
419 (Un)mangle DOS pathname, make nonabsolute
420 ****************************************************************************/
422 static void fixtarname(char *tptr, const char *fp, size_t l)
424 /* add a '.' to start of file name, convert from ugly dos \'s in path
425 * to lovely unix /'s :-} */
426 *tptr++='.';
427 l--;
429 StrnCpy(tptr, fp, l-1);
430 string_replace(tptr, '\\', '/');
433 /****************************************************************************
434 Convert from decimal to octal string
435 ****************************************************************************/
437 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
439 /* Converts long to octal string, pads with leading zeros */
441 /* skip final null, but do final space */
442 --ndgs;
443 p[--ndgs] = ' ';
445 /* Loop does at least one digit */
446 do {
447 p[--ndgs] = '0' + (char) (value & 7);
448 value >>= 3;
449 } while (ndgs > 0 && value != 0);
451 /* Do leading zeros */
452 while (ndgs > 0)
453 p[--ndgs] = '0';
456 /****************************************************************************
457 Convert from octal string to long
458 ***************************************************************************/
460 static long unoct(char *p, int ndgs)
462 long value=0;
463 /* Converts octal string to long, ignoring any non-digit */
465 while (--ndgs) {
466 if (isdigit((int)*p))
467 value = (value << 3) | (long) (*p - '0');
469 p++;
472 return value;
475 /****************************************************************************
476 Compare two strings in a slash insensitive way, allowing s1 to match s2
477 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
478 a file in any subdirectory of s1, declare a match.
479 ***************************************************************************/
481 static int strslashcmp(char *s1, char *s2)
483 char *s1_0=s1;
485 while(*s1 && *s2 && (*s1 == *s2 || tolower(*s1) == tolower(*s2) ||
486 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
487 s1++; s2++;
490 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
491 string of s2.
493 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
494 return 0;
496 /* ignore trailing slash on s1 */
497 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
498 return 0;
500 /* check for s1 is an "initial" string of s2 */
501 if ((*s2 == '/' || *s2 == '\\') && !*s1)
502 return 0;
504 return *s1-*s2;
507 /****************************************************************************
508 Ensure a remote path exists (make if necessary)
509 ***************************************************************************/
511 static BOOL ensurepath(char *fname)
513 /* *must* be called with buffer ready malloc'ed */
514 /* ensures path exists */
516 char *partpath, *ffname;
517 char *p=fname, *basehack;
519 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
521 partpath = string_create_s(strlen(fname));
522 ffname = string_create_s(strlen(fname));
524 if ((partpath == NULL) || (ffname == NULL)){
525 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
526 return(False);
529 *partpath = 0;
531 /* fname copied to ffname so can strtok */
533 safe_strcpy(ffname, fname, strlen(fname));
535 /* do a `basename' on ffname, so don't try and make file name directory */
536 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
537 return True;
538 else
539 *basehack='\0';
541 p=strtok(ffname, "\\");
543 while (p) {
544 safe_strcat(partpath, p, strlen(fname) + 1);
546 if (!cli_chkpath(cli, partpath)) {
547 if (!cli_mkdir(cli, partpath)) {
548 DEBUG(0, ("Error mkdirhiering\n"));
549 return False;
550 } else {
551 DEBUG(3, ("mkdirhiering %s\n", partpath));
555 safe_strcat(partpath, "\\", strlen(fname) + 1);
556 p = strtok(NULL,"/\\");
559 return True;
562 static int padit(char *buf, int bufsize, int padsize)
564 int berr= 0;
565 int bytestowrite;
567 DEBUG(5, ("Padding with %d zeros\n", padsize));
568 memset(buf, 0, bufsize);
569 while( !berr && padsize > 0 ) {
570 bytestowrite= MIN(bufsize, padsize);
571 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
572 padsize -= bytestowrite;
575 return berr;
578 static void do_setrattr(char *name, uint16 attr, int set)
580 uint16 oldattr;
582 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
584 if (set == ATTRSET) {
585 attr |= oldattr;
586 } else {
587 attr = oldattr & ~attr;
590 if (!cli_setatr(cli, name, attr, 0)) {
591 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
595 /****************************************************************************
596 append one remote file to the tar file
597 ***************************************************************************/
599 static void do_atar(char *rname,char *lname,file_info *finfo1)
601 int fnum;
602 SMB_BIG_UINT nread=0;
603 char ftype;
604 file_info2 finfo;
605 BOOL close_done = False;
606 BOOL shallitime=True;
607 char data[65520];
608 int read_size = 65520;
609 int datalen=0;
611 struct timeval tp_start;
613 GetTimeOfDay(&tp_start);
615 ftype = '0'; /* An ordinary file ... */
617 if (finfo1) {
618 finfo.size = finfo1 -> size;
619 finfo.mode = finfo1 -> mode;
620 finfo.uid = finfo1 -> uid;
621 finfo.gid = finfo1 -> gid;
622 finfo.mtime = finfo1 -> mtime;
623 finfo.atime = finfo1 -> atime;
624 finfo.ctime = finfo1 -> ctime;
625 finfo.name = finfo1 -> name;
626 } else {
627 finfo.size = def_finfo.size;
628 finfo.mode = def_finfo.mode;
629 finfo.uid = def_finfo.uid;
630 finfo.gid = def_finfo.gid;
631 finfo.mtime = def_finfo.mtime;
632 finfo.atime = def_finfo.atime;
633 finfo.ctime = def_finfo.ctime;
634 finfo.name = def_finfo.name;
637 if (dry_run) {
638 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
639 (double)finfo.size));
640 shallitime=0;
641 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
642 ntarf++;
643 return;
646 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
648 dos_clean_name(rname);
650 if (fnum == -1) {
651 DEBUG(0,("%s opening remote file %s (%s)\n",
652 cli_errstr(cli),rname, cur_dir));
653 return;
656 finfo.name = string_create_s(strlen(rname));
657 if (finfo.name == NULL) {
658 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
659 return;
662 safe_strcpy(finfo.name,rname, strlen(rname));
663 if (!finfo1) {
664 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
665 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
666 return;
668 finfo.ctime = finfo.mtime;
671 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
673 if (tar_inc && !(finfo.mode & aARCH)) {
674 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
675 shallitime=0;
676 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
677 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
678 shallitime=0;
679 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
680 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
681 shallitime=0;
682 } else {
683 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
684 finfo.name, (double)finfo.size, lname));
686 /* write a tar header, don't bother with mode - just set to 100644 */
687 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
689 while (nread < finfo.size && !close_done) {
691 DEBUG(3,("nread=%.0f\n",(double)nread));
693 datalen = cli_read(cli, fnum, data, nread, read_size);
695 if (datalen == -1) {
696 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
697 break;
700 nread += datalen;
702 /* if file size has increased since we made file size query, truncate
703 read so tar header for this file will be correct.
706 if (nread > finfo.size) {
707 datalen -= nread - finfo.size;
708 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
709 finfo.name, (double)finfo.size));
712 /* add received bits of file to buffer - dotarbuf will
713 * write out in 512 byte intervals */
715 if (dotarbuf(tarhandle,data,datalen) != datalen) {
716 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
717 break;
720 if (datalen == 0) {
721 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
722 break;
725 datalen=0;
728 /* pad tar file with zero's if we couldn't get entire file */
729 if (nread < finfo.size) {
730 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
731 (double)finfo.size, (int)nread));
732 if (padit(data, sizeof(data), finfo.size - nread))
733 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
736 /* round tar file to nearest block */
737 if (finfo.size % TBLOCK)
738 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
740 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
741 ntarf++;
744 cli_close(cli, fnum);
746 if (shallitime) {
747 struct timeval tp_end;
748 int this_time;
750 /* if shallitime is true then we didn't skip */
751 if (tar_reset && !dry_run)
752 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
754 GetTimeOfDay(&tp_end);
755 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
756 get_total_time_ms += this_time;
757 get_total_size += finfo.size;
759 if (tar_noisy) {
760 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
761 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
762 finfo.name));
765 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
766 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
767 finfo.size / MAX(0.001, (1.024*this_time)),
768 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
772 /****************************************************************************
773 Append single file to tar file (or not)
774 ***************************************************************************/
776 static void do_tar(file_info *finfo)
778 pstring rname;
780 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
781 return;
783 /* Is it on the exclude list ? */
784 if (!tar_excl && clipn) {
785 pstring exclaim;
787 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
789 pstrcpy(exclaim, cur_dir);
790 *(exclaim+strlen(exclaim)-1)='\0';
792 pstrcat(exclaim, "\\");
793 pstrcat(exclaim, finfo->name);
795 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
797 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
798 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
799 DEBUG(3,("Skipping file %s\n", exclaim));
800 return;
804 if (finfo->mode & aDIR) {
805 pstring saved_curdir;
806 pstring mtar_mask;
808 pstrcpy(saved_curdir, cur_dir);
810 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
811 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
812 (int)sizeof(cur_dir), (int)strlen(cur_dir),
813 (int)strlen(finfo->name), finfo->name, cur_dir));
815 pstrcat(cur_dir,finfo->name);
816 pstrcat(cur_dir,"\\");
818 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
820 /* write a tar directory, don't bother with mode - just set it to
821 * 40755 */
822 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
823 if (tar_noisy) {
824 DEBUG(0,(" directory %s\n", cur_dir));
826 ntarf++; /* Make sure we have a file on there */
827 pstrcpy(mtar_mask,cur_dir);
828 pstrcat(mtar_mask,"*");
829 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
830 do_list(mtar_mask, attribute, do_tar, False, True);
831 pstrcpy(cur_dir,saved_curdir);
832 } else {
833 pstrcpy(rname,cur_dir);
834 pstrcat(rname,finfo->name);
835 do_atar(rname,finfo->name,finfo);
839 /****************************************************************************
840 Convert from UNIX to DOS file names
841 ***************************************************************************/
843 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
845 /* remove '.' from start of file name, convert from unix /'s to
846 * dos \'s in path. Kill any absolute path names. But only if first!
849 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
851 if (first) {
852 if (*fp == '.') {
853 fp++;
854 l--;
856 if (*fp == '\\' || *fp == '/') {
857 fp++;
858 l--;
862 safe_strcpy(tptr, fp, l);
863 string_replace(tptr, '/', '\\');
866 /****************************************************************************
867 Move to the next block in the buffer, which may mean read in another set of
868 blocks. FIXME, we should allow more than one block to be skipped.
869 ****************************************************************************/
871 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
873 int bufread, total = 0;
875 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
876 *bufferp += TBLOCK;
877 total = TBLOCK;
879 if (*bufferp >= (ltarbuf + bufsiz)) {
881 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
884 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
885 * Fixes bug where read can return short if coming from
886 * a pipe.
889 bufread = read(tarhandle, ltarbuf, bufsiz);
890 total = bufread;
892 while (total < bufsiz) {
893 if (bufread < 0) { /* An error, return false */
894 return (total > 0 ? -2 : bufread);
896 if (bufread == 0) {
897 if (total <= 0) {
898 return -2;
900 break;
902 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
903 total += bufread;
906 DEBUG(5, ("Total bytes read ... %i\n", total));
908 *bufferp = ltarbuf;
911 return(total);
914 /* Skip a file, even if it includes a long file name? */
915 static int skip_file(int skipsize)
917 int dsize = skipsize;
919 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
921 /* FIXME, we should skip more than one block at a time */
923 while (dsize > 0) {
924 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
925 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
926 return(False);
928 dsize -= TBLOCK;
931 return(True);
934 /*************************************************************
935 Get a file from the tar file and store it.
936 When this is called, tarbuf already contains the first
937 file block. This is a bit broken & needs fixing.
938 **************************************************************/
940 static int get_file(file_info2 finfo)
942 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
943 SMB_BIG_UINT rsize = 0;
945 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
947 if (ensurepath(finfo.name) &&
948 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
949 DEBUG(0, ("abandoning restore\n"));
950 return(False);
953 /* read the blocks from the tar file and write to the remote file */
955 rsize = finfo.size; /* This is how much to write */
957 while (rsize > 0) {
959 /* We can only write up to the end of the buffer */
960 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
961 dsize = MIN(dsize, rsize); /* Should be only what is left */
962 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
964 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
965 DEBUG(0, ("Error writing remote file\n"));
966 return 0;
969 rsize -= dsize;
970 pos += dsize;
972 /* Now figure out how much to move in the buffer */
974 /* FIXME, we should skip more than one block at a time */
976 /* First, skip any initial part of the part written that is left over */
977 /* from the end of the first TBLOCK */
979 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
980 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
981 bpos = 0;
983 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
984 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
985 return False;
990 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
991 * If the file being extracted is an exact multiple of
992 * TBLOCK bytes then we don't want to extract the next
993 * block from the tarfile here, as it will be done in
994 * the caller of get_file().
997 while (((rsize != 0) && (dsize >= TBLOCK)) ||
998 ((rsize == 0) && (dsize > TBLOCK))) {
1000 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1001 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1002 return False;
1005 dsize -= TBLOCK;
1007 bpos = dsize;
1010 /* Now close the file ... */
1012 if (!cli_close(cli, fnum)) {
1013 DEBUG(0, ("Error closing remote file\n"));
1014 return(False);
1017 /* Now we update the creation date ... */
1018 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1020 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1021 if (tar_real_noisy) {
1022 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1023 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1027 ntarf++;
1028 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1029 return(True);
1032 /* Create a directory. We just ensure that the path exists and return as there
1033 is no file associated with a directory
1035 static int get_dir(file_info2 finfo)
1037 DEBUG(0, ("restore directory %s\n", finfo.name));
1039 if (!ensurepath(finfo.name)) {
1040 DEBUG(0, ("Problems creating directory\n"));
1041 return(False);
1043 ntarf++;
1044 return(True);
1047 /* Get a file with a long file name ... first file has file name, next file
1048 has the data. We only want the long file name, as the loop in do_tarput
1049 will deal with the rest.
1051 static char *get_longfilename(file_info2 finfo)
1053 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1054 * header call. */
1055 int namesize = finfo.size + strlen(cur_dir) + 2;
1056 char *longname = SMB_MALLOC(namesize);
1057 int offset = 0, left = finfo.size;
1058 BOOL first = True;
1060 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1061 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1063 if (longname == NULL) {
1064 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1065 return(NULL);
1068 /* First, add cur_dir to the long file name */
1070 if (strlen(cur_dir) > 0) {
1071 strncpy(longname, cur_dir, namesize);
1072 offset = strlen(cur_dir);
1075 /* Loop through the blocks picking up the name */
1077 while (left > 0) {
1078 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1079 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1080 return(NULL);
1083 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1084 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1086 offset += TBLOCK;
1087 left -= TBLOCK;
1090 return(longname);
1093 static void do_tarput(void)
1095 file_info2 finfo;
1096 struct timeval tp_start;
1097 char *longfilename = NULL, linkflag;
1098 int skip = False;
1100 GetTimeOfDay(&tp_start);
1101 DEBUG(5, ("RJS do_tarput called ...\n"));
1103 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1105 /* Now read through those files ... */
1106 while (True) {
1107 /* Get us to the next block, or the first block first time around */
1108 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1109 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1110 return;
1113 DEBUG(5, ("Reading the next header ...\n"));
1115 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1116 case -2: /* Hmm, not good, but not fatal */
1117 DEBUG(0, ("Skipping %s...\n", finfo.name));
1118 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1119 DEBUG(0, ("Short file, bailing out...\n"));
1120 return;
1122 break;
1124 case -1:
1125 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1126 return;
1128 case 0: /* chksum is zero - looks like an EOF */
1129 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1130 return; /* Hmmm, bad here ... */
1132 default:
1133 /* No action */
1134 break;
1137 /* Now, do we have a long file name? */
1138 if (longfilename != NULL) {
1139 SAFE_FREE(finfo.name); /* Free the space already allocated */
1140 finfo.name = longfilename;
1141 longfilename = NULL;
1144 /* Well, now we have a header, process the file ... */
1145 /* Should we skip the file? We have the long name as well here */
1146 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1147 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1149 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1150 if (skip) {
1151 skip_file(finfo.size);
1152 continue;
1155 /* We only get this far if we should process the file */
1156 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1157 switch (linkflag) {
1158 case '0': /* Should use symbolic names--FIXME */
1160 * Skip to the next block first, so we can get the file, FIXME, should
1161 * be in get_file ...
1162 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1163 * Fixes bug where file size in tarfile is zero.
1165 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1166 DEBUG(0, ("Short file, bailing out...\n"));
1167 return;
1169 if (!get_file(finfo)) {
1170 DEBUG(0, ("Abandoning restore\n"));
1171 return;
1173 break;
1174 case '5':
1175 if (!get_dir(finfo)) {
1176 DEBUG(0, ("Abandoning restore \n"));
1177 return;
1179 break;
1180 case 'L':
1181 longfilename = get_longfilename(finfo);
1182 if (!longfilename) {
1183 DEBUG(0, ("abandoning restore\n"));
1184 return;
1186 DEBUG(5, ("Long file name: %s\n", longfilename));
1187 break;
1189 default:
1190 skip_file(finfo.size); /* Don't handle these yet */
1191 break;
1197 * samba interactive commands
1200 /****************************************************************************
1201 Blocksize command
1202 ***************************************************************************/
1204 int cmd_block(void)
1206 fstring buf;
1207 int block;
1209 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1210 DEBUG(0, ("blocksize <n>\n"));
1211 return 1;
1214 block=atoi(buf);
1215 if (block < 0 || block > 65535) {
1216 DEBUG(0, ("blocksize out of range"));
1217 return 1;
1220 blocksize=block;
1221 DEBUG(2,("blocksize is now %d\n", blocksize));
1223 return 0;
1226 /****************************************************************************
1227 command to set incremental / reset mode
1228 ***************************************************************************/
1230 int cmd_tarmode(void)
1232 fstring buf;
1234 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1235 if (strequal(buf, "full"))
1236 tar_inc=False;
1237 else if (strequal(buf, "inc"))
1238 tar_inc=True;
1239 else if (strequal(buf, "reset"))
1240 tar_reset=True;
1241 else if (strequal(buf, "noreset"))
1242 tar_reset=False;
1243 else if (strequal(buf, "system"))
1244 tar_system=True;
1245 else if (strequal(buf, "nosystem"))
1246 tar_system=False;
1247 else if (strequal(buf, "hidden"))
1248 tar_hidden=True;
1249 else if (strequal(buf, "nohidden"))
1250 tar_hidden=False;
1251 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1252 tar_noisy=True;
1253 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1254 tar_noisy=False;
1255 else
1256 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1259 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1260 tar_inc ? "incremental" : "full",
1261 tar_system ? "system" : "nosystem",
1262 tar_hidden ? "hidden" : "nohidden",
1263 tar_reset ? "reset" : "noreset",
1264 tar_noisy ? "verbose" : "quiet"));
1265 return 0;
1268 /****************************************************************************
1269 Feeble attrib command
1270 ***************************************************************************/
1272 int cmd_setmode(void)
1274 char *q;
1275 fstring buf;
1276 pstring fname;
1277 uint16 attra[2];
1278 int direct=1;
1280 attra[0] = attra[1] = 0;
1282 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1283 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1284 return 1;
1287 pstrcpy(fname, cur_dir);
1288 pstrcat(fname, buf);
1290 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1291 q=buf;
1293 while(*q) {
1294 switch (*q++) {
1295 case '+':
1296 direct=1;
1297 break;
1298 case '-':
1299 direct=0;
1300 break;
1301 case 'r':
1302 attra[direct]|=aRONLY;
1303 break;
1304 case 'h':
1305 attra[direct]|=aHIDDEN;
1306 break;
1307 case 's':
1308 attra[direct]|=aSYSTEM;
1309 break;
1310 case 'a':
1311 attra[direct]|=aARCH;
1312 break;
1313 default:
1314 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1315 return 1;
1320 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1321 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1322 return 1;
1325 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1326 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1327 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1328 return 0;
1331 /****************************************************************************
1332 Principal command for creating / extracting
1333 ***************************************************************************/
1335 int cmd_tar(void)
1337 fstring buf;
1338 char **argl = NULL;
1339 int argcl = 0;
1340 int ret;
1342 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1343 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1344 return 1;
1347 argl=toktocliplist(&argcl, NULL);
1348 if (!tar_parseargs(argcl, argl, buf, 0))
1349 return 1;
1351 ret = process_tar();
1352 SAFE_FREE(argl);
1353 return ret;
1356 /****************************************************************************
1357 Command line (option) version
1358 ***************************************************************************/
1360 int process_tar(void)
1362 int rc = 0;
1363 initarbuf();
1364 switch(tar_type) {
1365 case 'x':
1367 #if 0
1368 do_tarput2();
1369 #else
1370 do_tarput();
1371 #endif
1372 SAFE_FREE(tarbuf);
1373 close(tarhandle);
1374 break;
1375 case 'r':
1376 case 'c':
1377 if (clipn && tar_excl) {
1378 int i;
1379 pstring tarmac;
1381 for (i=0; i<clipn; i++) {
1382 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1384 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1385 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1388 if (strrchr_m(cliplist[i], '\\')) {
1389 pstring saved_dir;
1391 pstrcpy(saved_dir, cur_dir);
1393 if (*cliplist[i]=='\\') {
1394 pstrcpy(tarmac, cliplist[i]);
1395 } else {
1396 pstrcpy(tarmac, cur_dir);
1397 pstrcat(tarmac, cliplist[i]);
1399 pstrcpy(cur_dir, tarmac);
1400 *(strrchr_m(cur_dir, '\\')+1)='\0';
1402 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1403 do_list(tarmac,attribute,do_tar, False, True);
1404 pstrcpy(cur_dir,saved_dir);
1405 } else {
1406 pstrcpy(tarmac, cur_dir);
1407 pstrcat(tarmac, cliplist[i]);
1408 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1409 do_list(tarmac,attribute,do_tar, False, True);
1412 } else {
1413 pstring mask;
1414 pstrcpy(mask,cur_dir);
1415 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1416 pstrcat(mask,"\\*");
1417 do_list(mask,attribute,do_tar,False, True);
1420 if (ntarf)
1421 dotareof(tarhandle);
1422 close(tarhandle);
1423 SAFE_FREE(tarbuf);
1425 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1426 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1427 break;
1430 if (must_free_cliplist) {
1431 int i;
1432 for (i = 0; i < clipn; ++i) {
1433 SAFE_FREE(cliplist[i]);
1435 SAFE_FREE(cliplist);
1436 cliplist = NULL;
1437 clipn = 0;
1438 must_free_cliplist = False;
1440 return rc;
1443 /****************************************************************************
1444 Find a token (filename) in a clip list
1445 ***************************************************************************/
1447 static int clipfind(char **aret, int ret, char *tok)
1449 if (aret==NULL)
1450 return 0;
1452 /* ignore leading slashes or dots in token */
1453 while(strchr_m("/\\.", *tok))
1454 tok++;
1456 while(ret--) {
1457 char *pkey=*aret++;
1459 /* ignore leading slashes or dots in list */
1460 while(strchr_m("/\\.", *pkey))
1461 pkey++;
1463 if (!strslashcmp(pkey, tok))
1464 return 1;
1466 return 0;
1469 /****************************************************************************
1470 Read list of files to include from the file and initialize cliplist
1471 accordingly.
1472 ***************************************************************************/
1474 static int read_inclusion_file(char *filename)
1476 XFILE *inclusion = NULL;
1477 char buf[PATH_MAX + 1];
1478 char *inclusion_buffer = NULL;
1479 int inclusion_buffer_size = 0;
1480 int inclusion_buffer_sofar = 0;
1481 char *p;
1482 char *tmpstr;
1483 int i;
1484 int error = 0;
1486 clipn = 0;
1487 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1488 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1489 /* XXX It would be better to include a reason for failure, but without
1490 * autoconf, it's hard to use strerror, sys_errlist, etc.
1492 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1493 return 0;
1496 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1497 if (inclusion_buffer == NULL) {
1498 inclusion_buffer_size = 1024;
1499 if ((inclusion_buffer = SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1500 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1501 error = 1;
1502 break;
1506 if (buf[strlen(buf)-1] == '\n') {
1507 buf[strlen(buf)-1] = '\0';
1510 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1511 char *ib;
1512 inclusion_buffer_size *= 2;
1513 ib = SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1514 if (! ib) {
1515 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1516 inclusion_buffer_size));
1517 error = 1;
1518 break;
1519 } else {
1520 inclusion_buffer = ib;
1524 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1525 inclusion_buffer_sofar += strlen(buf) + 1;
1526 clipn++;
1528 x_fclose(inclusion);
1530 if (! error) {
1531 /* Allocate an array of clipn + 1 char*'s for cliplist */
1532 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1533 if (cliplist == NULL) {
1534 DEBUG(0,("failure allocating memory for cliplist\n"));
1535 error = 1;
1536 } else {
1537 cliplist[clipn] = NULL;
1538 p = inclusion_buffer;
1539 for (i = 0; (! error) && (i < clipn); i++) {
1540 /* set current item to NULL so array will be null-terminated even if
1541 * malloc fails below. */
1542 cliplist[i] = NULL;
1543 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1544 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1545 error = 1;
1546 } else {
1547 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1548 cliplist[i] = tmpstr;
1549 if ((p = strchr_m(p, '\000')) == NULL) {
1550 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1551 abort();
1554 ++p;
1556 must_free_cliplist = True;
1560 SAFE_FREE(inclusion_buffer);
1561 if (error) {
1562 if (cliplist) {
1563 char **pp;
1564 /* We know cliplist is always null-terminated */
1565 for (pp = cliplist; *pp; ++pp) {
1566 SAFE_FREE(*pp);
1568 SAFE_FREE(cliplist);
1569 cliplist = NULL;
1570 must_free_cliplist = False;
1572 return 0;
1575 /* cliplist and its elements are freed at the end of process_tar. */
1576 return 1;
1579 /****************************************************************************
1580 Parse tar arguments. Sets tar_type, tar_excl, etc.
1581 ***************************************************************************/
1583 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1585 int newOptind = Optind;
1586 char tar_clipfl='\0';
1588 /* Reset back to defaults - could be from interactive version
1589 * reset mode and archive mode left as they are though
1591 tar_type='\0';
1592 tar_excl=True;
1593 dry_run=False;
1595 while (*Optarg) {
1596 switch(*Optarg++) {
1597 case 'c':
1598 tar_type='c';
1599 break;
1600 case 'x':
1601 if (tar_type=='c') {
1602 printf("Tar must be followed by only one of c or x.\n");
1603 return 0;
1605 tar_type='x';
1606 break;
1607 case 'b':
1608 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1609 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1610 return 0;
1611 } else {
1612 Optind++;
1613 newOptind++;
1615 break;
1616 case 'g':
1617 tar_inc=True;
1618 break;
1619 case 'N':
1620 if (Optind>=argc) {
1621 DEBUG(0,("Option N must be followed by valid file name\n"));
1622 return 0;
1623 } else {
1624 SMB_STRUCT_STAT stbuf;
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) {
1765 tarhandle=-1;
1766 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1767 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1768 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1769 return(0);
1771 newOptind++;
1774 return newOptind;