1/* 2 Unix SMB/Netbios implementation. 3 Version 1.9. 4 Tar Extensions 5 Copyright (C) Ricky Poulten 1995-1998 6 Copyright (C) Richard Sharpe 1998 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22/* The following changes developed by Richard Sharpe for Canon Information 23 Systems Research Australia (CISRA) 24 25 1. Restore can now restore files with long file names 26 2. Save now saves directory information so that we can restore 27 directory creation times 28 3. tar now accepts both UNIX path names and DOS path names. I prefer 29 those lovely /'s to those UGLY \'s :-) 30 4. the files to exclude can be specified as a regular expression by adding 31 an r flag to the other tar flags. Eg: 32 33 -TcrX file.tar "*.(obj|exe)" 34 35 will skip all .obj and .exe files 36*/ 37 38 39#include "includes.h" 40#include "clitar.h" 41 42static int clipfind(char **aret, int ret, char *tok); 43 44typedef struct file_info_struct file_info2; 45 46struct file_info_struct 47{ 48 size_t size; 49 uint16 mode; 50 int uid; 51 int gid; 52 /* These times are normally kept in GMT */ 53 time_t mtime; 54 time_t atime; 55 time_t ctime; 56 char *name; /* This is dynamically allocate */ 57 58 file_info2 *next, *prev; /* Used in the stack ... */ 59 60}; 61 62typedef struct 63{ 64 file_info2 *top; 65 int items; 66 67} stack; 68 69stack dir_stack = {NULL, 0}; /* Want an empty stack */ 70 71#define SEPARATORS " \t\n\r" 72extern int DEBUGLEVEL; 73extern struct cli_state *cli; 74extern FILE *dbf; 75 76/* These defines are for the do_setrattr routine, to indicate 77 * setting and reseting of file attributes in the function call */ 78#define ATTRSET 1 79#define ATTRRESET 0 80 81static uint16 attribute = aDIR | aSYSTEM | aHIDDEN; 82 83#ifndef CLIENT_TIMEOUT 84#define CLIENT_TIMEOUT (30*1000) 85#endif 86 87static char *tarbuf, *buffer_p; 88static int tp, ntarf, tbufsiz; 89static double ttarf; 90/* Incremental mode */ 91BOOL tar_inc=False; 92/* Reset archive bit */ 93BOOL tar_reset=False; 94/* Include / exclude mode (true=include, false=exclude) */ 95BOOL tar_excl=True; 96/* use regular expressions for search on file names */ 97BOOL tar_re_search=False; 98#ifdef HAVE_REGEX_H 99regex_t *preg; 100#endif 101/* Do not dump anything, just calculate sizes */ 102BOOL dry_run=False; 103/* Dump files with System attribute */ 104BOOL tar_system=True; 105/* Dump files with Hidden attribute */ 106BOOL tar_hidden=True; 107/* Be noisy - make a catalogue */ 108BOOL tar_noisy=True; 109BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */ 110 111char tar_type='\0'; 112static char **cliplist=NULL; 113static int clipn=0; 114static BOOL must_free_cliplist = False; 115 116extern file_info def_finfo; 117extern BOOL lowercase; 118extern uint16 cnum; 119extern BOOL readbraw_supported; 120extern int max_xmit; 121extern pstring cur_dir; 122extern int get_total_time_ms; 123extern int get_total_size; 124extern int Protocol; 125 126int blocksize=20; 127int tarhandle; 128 129static void writetarheader(int f, char *aname, int size, time_t mtime, 130 char *amode, unsigned char ftype); 131static void do_atar(char *rname,char *lname,file_info *finfo1); 132static void do_tar(file_info *finfo); 133static void oct_it(long value, int ndgs, char *p); 134static void fixtarname(char *tptr, char *fp, int l); 135static int dotarbuf(int f, char *b, int n); 136static void dozerobuf(int f, int n); 137static void dotareof(int f); 138static void initarbuf(void); 139 140/* restore functions */ 141static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix); 142static long unoct(char *p, int ndgs); 143static void do_tarput(void); 144static void unfixtarname(char *tptr, char *fp, int l, BOOL first); 145 146/* 147 * tar specific utitlities 148 */ 149 150/******************************************************************* 151Create a string of size size+1 (for the null) 152*******************************************************************/ 153static char *string_create_s(int size) 154{ 155 char *tmp; 156 157 tmp = (char *)malloc(size+1); 158 159 if (tmp == NULL) { 160 161 DEBUG(0, ("Out of memory in string_create_s\n")); 162 163 } 164 165 return(tmp); 166 167} 168 169/**************************************************************************** 170Write a tar header to buffer 171****************************************************************************/ 172static void writetarheader(int f, char *aname, int size, time_t mtime, 173 char *amode, unsigned char ftype) 174{ 175 union hblock hb; 176 int i, chk, l; 177 char *jp; 178 179 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname)); 180 181 memset(hb.dummy, 0, sizeof(hb.dummy)); 182 183 l=strlen(aname); 184 if (l >= NAMSIZ) { 185 /* write a GNU tar style long header */ 186 char *b; 187 b = (char *)malloc(l+TBLOCK+100); 188 if (!b) { 189 DEBUG(0,("out of memory\n")); 190 exit(1); 191 } 192 writetarheader(f, "/./@LongLink", l+1, 0, " 0 \0", 'L'); 193 memset(b, 0, l+TBLOCK+100); 194 fixtarname(b, aname, l); 195 i = strlen(b)+1; 196 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b))); 197 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1)); 198 free(b); 199 } 200 201 /* use l + 1 to do the null too */ 202 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1); 203 204 if (lowercase) 205 strlower(hb.dbuf.name); 206 207 /* write out a "standard" tar format header */ 208 209 hb.dbuf.name[NAMSIZ-1]='\0'; 210 safe_strcpy(hb.dbuf.mode, amode, strlen(amode)); 211 oct_it(0L, 8, hb.dbuf.uid); 212 oct_it(0L, 8, hb.dbuf.gid); 213 oct_it((long) size, 13, hb.dbuf.size); 214 oct_it((long) mtime, 13, hb.dbuf.mtime); 215 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum)); 216 memset(hb.dbuf.linkname, 0, NAMSIZ); 217 hb.dbuf.linkflag=ftype; 218 219 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++); 220 221 oct_it((long) chk, 8, hb.dbuf.chksum); 222 hb.dbuf.chksum[6] = '\0'; 223 224 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy)); 225} 226 227/**************************************************************************** 228Read a tar header into a hblock structure, and validate 229***************************************************************************/ 230static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix) 231{ 232 long chk, fchk; 233 int i; 234 char *jp; 235 236 /* 237 * read in a "standard" tar format header - we're not that interested 238 * in that many fields, though 239 */ 240 241 /* check the checksum */ 242 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++); 243 244 if (chk == 0) 245 return chk; 246 247 /* compensate for blanks in chksum header */ 248 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;) 249 chk-=(0xFF & *jp++); 250 251 chk += ' ' * sizeof(hb->dbuf.chksum); 252 253 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum)); 254 255 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n", 256 chk, fchk, hb->dbuf.chksum)); 257 258 if (fchk != chk) 259 { 260 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk)); 261 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3); 262 return -1; 263 } 264 265 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) { 266 267 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name)); 268 return(-1); 269 270 } 271 272 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3); 273 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); 277 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 289 } else { 290 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n")); 291 return -2; 292 } 293 } 294 } 295 296 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) 297 || (*(finfo->name+strlen(finfo->name)-1) == '\\')) 298 { 299 finfo->mode=aDIR; 300 } 301 else 302 finfo->mode=0; /* we don't care about mode at the moment, we'll 303 * just make it a regular file */ 304 /* 305 * Bug fix by richard@sj.co.uk 306 * 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 310 */ 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)); 314 315 return True; 316} 317 318/**************************************************************************** 319Write out the tar buffer to tape or wherever 320****************************************************************************/ 321static int dotarbuf(int f, char *b, int n) 322{ 323 int fail=1, writ=n; 324 325 if (dry_run) { 326 return writ; 327 } 328 /* This routine and the next one should be the only ones that do write()s */ 329 if (tp + n >= tbufsiz) 330 { 331 int diff; 332 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; 339 340 while (n >= tbufsiz) 341 { 342 fail=fail && (1 + write(f, b, tbufsiz)); 343 n-=tbufsiz; 344 b+=tbufsiz; 345 } 346 } 347 if (n>0) { 348 memcpy(tarbuf+tp, b, n); 349 tp+=n; 350 } 351 352 return(fail ? writ : 0); 353} 354 355/**************************************************************************** 356Write zeros to buffer / tape 357****************************************************************************/ 358static void dozerobuf(int f, int n) 359{ 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 */ 363 364 if (dry_run) 365 return; 366 367 if (n+tp >= tbufsiz) 368 { 369 memset(tarbuf+tp, 0, tbufsiz-tp); 370 371 write(f, tarbuf, tbufsiz); 372 memset(tarbuf, 0, (tp+=n-tbufsiz)); 373 } 374 else 375 { 376 memset(tarbuf+tp, 0, n); 377 tp+=n; 378 } 379} 380 381/**************************************************************************** 382Malloc tape buffer 383****************************************************************************/ 384static void initarbuf(void) 385{ 386 /* initialize tar buffer */ 387 tbufsiz=blocksize*TBLOCK; 388 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */ 389 390 /* reset tar buffer pointer and tar file counter and total dumped */ 391 tp=0; ntarf=0; ttarf=0; 392} 393 394/**************************************************************************** 395Write two zero blocks at end of file 396****************************************************************************/ 397static void dotareof(int f) 398{ 399 SMB_STRUCT_STAT stbuf; 400 /* Two zero blocks at end of file, write out full buffer */ 401 402 if (dry_run) 403 return; 404 405 (void) dozerobuf(f, TBLOCK); 406 (void) dozerobuf(f, TBLOCK); 407 408 if (sys_fstat(f, &stbuf) == -1) 409 { 410 DEBUG(0, ("Couldn't stat file handle\n")); 411 return; 412 } 413 414 /* Could be a pipe, in which case S_ISREG should fail, 415 * and we should write out at full size */ 416 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz); 417} 418 419/**************************************************************************** 420(Un)mangle DOS pathname, make nonabsolute 421****************************************************************************/ 422static void fixtarname(char *tptr, char *fp, int l) 423{ 424 /* add a '.' to start of file name, convert from ugly dos \'s in path 425 * to lovely unix /'s :-} */ 426 427 *tptr++='.'; 428 429 while (l > 0) { 430 int skip = get_character_len(*fp); 431 if(skip != 0) { 432 if (skip == 2) { 433 *tptr++ = *fp++; 434 *tptr++ = *fp++; 435 l -= 2; 436 } else if (skip == 1) { 437 *tptr++ = *fp++; 438 l--; 439 } 440 } else if (*fp == '\\') { 441 *tptr++ = '/'; 442 fp++; 443 l--; 444 } else { 445 *tptr++ = *fp++; 446 l--; 447 } 448 } 449} 450 451/**************************************************************************** 452Convert from decimal to octal string 453****************************************************************************/ 454static void oct_it (long value, int ndgs, char *p) 455{ 456 /* Converts long to octal string, pads with leading zeros */ 457 458 /* skip final null, but do final space */ 459 --ndgs; 460 p[--ndgs] = ' '; 461 462 /* Loop does at least one digit */ 463 do { 464 p[--ndgs] = '0' + (char) (value & 7); 465 value >>= 3; 466 } 467 while (ndgs > 0 && value != 0); 468 469 /* Do leading zeros */ 470 while (ndgs > 0) 471 p[--ndgs] = '0'; 472} 473 474/**************************************************************************** 475Convert from octal string to long 476***************************************************************************/ 477static long unoct(char *p, int ndgs) 478{ 479 long value=0; 480 /* Converts octal string to long, ignoring any non-digit */ 481 482 while (--ndgs) 483 { 484 if (isdigit((int)*p)) 485 value = (value << 3) | (long) (*p - '0'); 486 487 p++; 488 } 489 490 return value; 491} 492 493/**************************************************************************** 494Compare two strings in a slash insensitive way, allowing s1 to match s2 495if s1 is an "initial" string (up to directory marker). Thus, if s2 is 496a file in any subdirectory of s1, declare a match. 497***************************************************************************/ 498static int strslashcmp(char *s1, char *s2) 499{ 500 char *s1_0=s1; 501 502 while(*s1 && *s2 && 503 (*s1 == *s2 504 || tolower(*s1) == tolower(*s2) 505 || (*s1 == '\\' && *s2=='/') 506 || (*s1 == '/' && *s2=='\\'))) { 507 s1++; s2++; 508 } 509 510 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" 511 string of s2. 512 */ 513 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0; 514 515 /* ignore trailing slash on s1 */ 516 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0; 517 518 /* check for s1 is an "initial" string of s2 */ 519 if (*s2 == '/' || *s2 == '\\') return 0; 520 521 return *s1-*s2; 522} 523 524 525/**************************************************************************** 526Ensure a remote path exists (make if necessary) 527***************************************************************************/ 528static BOOL ensurepath(char *fname) 529{ 530 /* *must* be called with buffer ready malloc'ed */ 531 /* ensures path exists */ 532 533 char *partpath, *ffname; 534 char *p=fname, *basehack; 535 536 DEBUG(5, ( "Ensurepath called with: %s\n", fname)); 537 538 partpath = string_create_s(strlen(fname)); 539 ffname = string_create_s(strlen(fname)); 540 541 if ((partpath == NULL) || (ffname == NULL)){ 542 543 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname)); 544 return(False); 545 546 } 547 548 *partpath = 0; 549 550 /* fname copied to ffname so can strtok */ 551 552 safe_strcpy(ffname, fname, strlen(fname)); 553 554 /* do a `basename' on ffname, so don't try and make file name directory */ 555 if ((basehack=strrchr(ffname, '\\')) == NULL) 556 return True; 557 else 558 *basehack='\0'; 559 560 p=strtok(ffname, "\\"); 561 562 while (p) 563 { 564 safe_strcat(partpath, p, strlen(fname) + 1); 565 566 if (!cli_chkpath(cli, partpath)) { 567 if (!cli_mkdir(cli, partpath)) 568 { 569 DEBUG(0, ("Error mkdirhiering\n")); 570 return False; 571 } 572 else 573 DEBUG(3, ("mkdirhiering %s\n", partpath)); 574 575 } 576 577 safe_strcat(partpath, "\\", strlen(fname) + 1); 578 p = strtok(NULL,"/\\"); 579 } 580 581 return True; 582} 583 584static int padit(char *buf, int bufsize, int padsize) 585{ 586 int berr= 0; 587 int bytestowrite; 588 589 DEBUG(5, ("Padding with %d zeros\n", padsize)); 590 memset(buf, 0, bufsize); 591 while( !berr && padsize > 0 ) { 592 bytestowrite= MIN(bufsize, padsize); 593 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite; 594 padsize -= bytestowrite; 595 } 596 597 return berr; 598} 599 600 601static void do_setrattr(char *name, uint16 attr, int set) 602{ 603 uint16 oldattr; 604 605 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return; 606 607 if (set == ATTRSET) { 608 attr |= oldattr; 609 } else { 610 attr = oldattr & ~attr; 611 } 612 613 if (!cli_setatr(cli, name, attr, 0)) { 614 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli))); 615 } 616} 617 618 619/**************************************************************************** 620append one remote file to the tar file 621***************************************************************************/ 622static void do_atar(char *rname,char *lname,file_info *finfo1) 623{ 624 int fnum; 625 uint32 nread=0; 626 char ftype; 627 file_info2 finfo; 628 BOOL close_done = False; 629 BOOL shallitime=True; 630 char data[65520]; 631 int read_size = 65520; 632 int datalen=0; 633 634 struct timeval tp_start; 635 GetTimeOfDay(&tp_start); 636 637 ftype = '0'; /* An ordinary file ... */ 638 639 if (finfo1) { 640 finfo.size = finfo1 -> size; 641 finfo.mode = finfo1 -> mode; 642 finfo.uid = finfo1 -> uid; 643 finfo.gid = finfo1 -> gid; 644 finfo.mtime = finfo1 -> mtime; 645 finfo.atime = finfo1 -> atime; 646 finfo.ctime = finfo1 -> ctime; 647 } 648 else { 649 finfo.size = def_finfo.size; 650 finfo.mode = def_finfo.mode; 651 finfo.uid = def_finfo.uid; 652 finfo.gid = def_finfo.gid; 653 finfo.mtime = def_finfo.mtime; 654 finfo.atime = def_finfo.atime; 655 finfo.ctime = def_finfo.ctime; 656 } 657 658 if (dry_run) 659 { 660 DEBUG(3,("skipping file %s of size %d bytes\n", 661 finfo.name, 662 (int)finfo.size)); 663 shallitime=0; 664 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK); 665 ntarf++; 666 return; 667 } 668 669 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE); 670 671 dos_clean_name(rname); 672 673 if (fnum == -1) { 674 DEBUG(0,("%s opening remote file %s (%s)\n", 675 cli_errstr(cli),rname, cur_dir)); 676 return; 677 } 678 679 finfo.name = string_create_s(strlen(rname)); 680 if (finfo.name == NULL) { 681 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n")); 682 return; 683 } 684 685 safe_strcpy(finfo.name,rname, strlen(rname)); 686 if (!finfo1) { 687 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) { 688 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli))); 689 return; 690 } 691 finfo.ctime = finfo.mtime; 692 } 693 694 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode)); 695 696 if (tar_inc && !(finfo.mode & aARCH)) 697 { 698 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name)); 699 shallitime=0; 700 } 701 else if (!tar_system && (finfo.mode & aSYSTEM)) 702 { 703 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name)); 704 shallitime=0; 705 } 706 else if (!tar_hidden && (finfo.mode & aHIDDEN)) 707 { 708 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name)); 709 shallitime=0; 710 } 711 else 712 { 713 DEBUG(3,("getting file %s of size %d bytes as a tar file %s", 714 finfo.name, 715 (int)finfo.size, 716 lname)); 717 718 /* write a tar header, don't bother with mode - just set to 100644 */ 719 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype); 720 721 while (nread < finfo.size && !close_done) { 722 723 DEBUG(3,("nread=%d\n",nread)); 724 725 datalen = cli_read(cli, fnum, data, nread, read_size); 726 727 if (datalen == -1) { 728 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli))); 729 break; 730 } 731 732 /* add received bits of file to buffer - dotarbuf will 733 * write out in 512 byte intervals */ 734 if (dotarbuf(tarhandle,data,datalen) != datalen) { 735 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno))); 736 break; 737 } 738 739 nread += datalen; 740 if (datalen == 0) { 741 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname)); 742 break; 743 } 744 745 datalen=0; 746 } 747 748 /* pad tar file with zero's if we couldn't get entire file */ 749 if (nread < finfo.size) { 750 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", (int)finfo.size, (int)nread)); 751 if (padit(data, sizeof(data), finfo.size - nread)) 752 DEBUG(0,("Error writing tar file - %s\n", strerror(errno))); 753 } 754 755 /* round tar file to nearest block */ 756 if (finfo.size % TBLOCK) 757 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK)); 758 759 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK); 760 ntarf++; 761 } 762 763 cli_close(cli, fnum); 764 765 if (shallitime) 766 { 767 struct timeval tp_end; 768 int this_time; 769 770 /* if shallitime is true then we didn't skip */ 771 if (tar_reset && !dry_run) 772 (void) do_setrattr(finfo.name, aARCH, ATTRRESET); 773 774 GetTimeOfDay(&tp_end); 775 this_time = 776 (tp_end.tv_sec - tp_start.tv_sec)*1000 + 777 (tp_end.tv_usec - tp_start.tv_usec)/1000; 778 get_total_time_ms += this_time; 779 get_total_size += finfo.size; 780 781 if (tar_noisy) 782 { 783 DEBUG(0, ("%10d (%7.1f kb/s) %s\n", 784 (int)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)), 785 finfo.name)); 786 } 787 788 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */ 789 DEBUG(3,("(%g kb/s) (average %g kb/s)\n", 790 finfo.size / MAX(0.001, (1.024*this_time)), 791 get_total_size / MAX(0.001, (1.024*get_total_time_ms)))); 792 } 793} 794 795/**************************************************************************** 796Append single file to tar file (or not) 797***************************************************************************/ 798static void do_tar(file_info *finfo) 799{ 800 pstring rname; 801 802 if (strequal(finfo->name,"..") || strequal(finfo->name,".")) 803 return; 804 805 /* Is it on the exclude list ? */ 806 if (!tar_excl && clipn) { 807 pstring exclaim; 808 809 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir))); 810 811 safe_strcpy(exclaim, cur_dir, sizeof(pstring)); 812 *(exclaim+strlen(exclaim)-1)='\0'; 813 814 safe_strcat(exclaim, "\\", sizeof(pstring)); 815 safe_strcat(exclaim, finfo->name, sizeof(exclaim)); 816 817 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search)); 818 819 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) || 820#ifdef HAVE_REGEX_H 821 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) { 822#else 823 (tar_re_search && mask_match(exclaim, cliplist[0], True, False))) { 824#endif 825 DEBUG(3,("Skipping file %s\n", exclaim)); 826 return; 827 } 828 } 829 830 if (finfo->mode & aDIR) 831 { 832 pstring saved_curdir; 833 pstring mtar_mask; 834 835 safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir)); 836 837 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", (int)sizeof(cur_dir), (int)strlen(cur_dir), (int)strlen(finfo->name), finfo->name, cur_dir)); 838 839 safe_strcat(cur_dir,finfo->name, sizeof(cur_dir)); 840 safe_strcat(cur_dir,"\\", sizeof(cur_dir)); 841 842 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir)); 843 844 /* write a tar directory, don't bother with mode - just set it to 845 * 40755 */ 846 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5'); 847 if (tar_noisy) { 848 DEBUG(0,(" directory %s\n", cur_dir)); 849 } 850 ntarf++; /* Make sure we have a file on there */ 851 safe_strcpy(mtar_mask,cur_dir, sizeof(pstring)); 852 safe_strcat(mtar_mask,"*", sizeof(pstring)); 853 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask)); 854 do_list(mtar_mask, attribute, do_tar, False, True); 855 safe_strcpy(cur_dir,saved_curdir, sizeof(pstring)); 856 } 857 else 858 { 859 safe_strcpy(rname,cur_dir, sizeof(pstring)); 860 safe_strcat(rname,finfo->name, sizeof(pstring)); 861 do_atar(rname,finfo->name,finfo); 862 } 863} 864 865/**************************************************************************** 866Convert from UNIX to DOS file names 867***************************************************************************/ 868static void unfixtarname(char *tptr, char *fp, int l, BOOL first) 869{ 870 /* remove '.' from start of file name, convert from unix /'s to 871 * dos \'s in path. Kill any absolute path names. But only if first! 872 */ 873 874 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l)); 875 876 if (first) { 877 if (*fp == '.') { 878 fp++; 879 l--; 880 } 881 if (*fp == '\\' || *fp == '/') { 882 fp++; 883 l--; 884 } 885 } 886 887 while (l > 0) { 888 int skip = get_character_len(*fp); 889 if(skip != 0) { 890 if (skip == 2) { 891 *tptr++ = *fp++; 892 *tptr++ = *fp++; 893 l -= 2; 894 } else if (skip == 1) { 895 *tptr++ = *fp++; 896 l--; 897 } 898 } else if (*fp == '/') { 899 *tptr++ = '\\'; 900 fp++; 901 l--; 902 } else { 903 *tptr++ = *fp++; 904 l--; 905 } 906 } 907} 908 909 910/**************************************************************************** 911Move to the next block in the buffer, which may mean read in another set of 912blocks. FIXME, we should allow more than one block to be skipped. 913****************************************************************************/ 914static int next_block(char *ltarbuf, char **bufferp, int bufsiz) 915{ 916 int bufread, total = 0; 917 918 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp)); 919 *bufferp += TBLOCK; 920 total = TBLOCK; 921 922 if (*bufferp >= (ltarbuf + bufsiz)) { 923 924 DEBUG(5, ("Reading more data into ltarbuf ...\n")); 925 926 /* 927 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net> 928 * Fixes bug where read can return short if coming from 929 * a pipe. 930 */ 931 932 bufread = read(tarhandle, ltarbuf, bufsiz); 933 total = bufread; 934 935 while (total < bufsiz) { 936 if (bufread < 0) { /* An error, return false */ 937 return (total > 0 ? -2 : bufread); 938 } 939 if (bufread == 0) { 940 if (total <= 0) { 941 return -2; 942 } 943 break; 944 } 945 bufread = read(tarhandle, <arbuf[total], bufsiz - total); 946 total += bufread; 947 } 948 949 DEBUG(5, ("Total bytes read ... %i\n", total)); 950 951 *bufferp = ltarbuf; 952 953 } 954 955 return(total); 956 957} 958 959/* Skip a file, even if it includes a long file name? */ 960static int skip_file(int skipsize) 961{ 962 int dsize = skipsize; 963 964 DEBUG(5, ("Skiping file. Size = %i\n", skipsize)); 965 966 /* FIXME, we should skip more than one block at a time */ 967 968 while (dsize > 0) { 969 970 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) { 971 972 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno))); 973 return(False); 974 975 } 976 977 dsize -= TBLOCK; 978 979 } 980 981 return(True); 982} 983 984/************************************************************* 985 Get a file from the tar file and store it. 986 When this is called, tarbuf already contains the first 987 file block. This is a bit broken & needs fixing. 988**************************************************************/ 989 990static int get_file(file_info2 finfo) 991{ 992 int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0; 993 994 DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size)); 995 996 if (ensurepath(finfo.name) && 997 (fnum=cli_open(cli, finfo.name, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE)) == -1) { 998 DEBUG(0, ("abandoning restore\n")); 999 return(False); 1000 } 1001 1002 /* read the blocks from the tar file and write to the remote file */ 1003 1004 rsize = finfo.size; /* This is how much to write */ 1005 1006 while (rsize > 0) { 1007 1008 /* We can only write up to the end of the buffer */ 1009 1010 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */ 1011 dsize = MIN(dsize, rsize); /* Should be only what is left */ 1012 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos)); 1013 1014 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) { 1015 DEBUG(0, ("Error writing remote file\n")); 1016 return 0; 1017 } 1018 1019 rsize -= dsize; 1020 pos += dsize; 1021 1022 /* Now figure out how much to move in the buffer */ 1023 1024 /* FIXME, we should skip more than one block at a time */ 1025 1026 /* First, skip any initial part of the part written that is left over */ 1027 /* from the end of the first TBLOCK */ 1028 1029 if ((bpos) && ((bpos + dsize) >= TBLOCK)) { 1030 1031 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */ 1032 bpos = 0; 1033 1034 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */ 1035 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno))); 1036 return False; 1037 1038 } 1039 1040 } 1041 1042 /* 1043 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>. 1044 * If the file being extracted is an exact multiple of 1045 * TBLOCK bytes then we don't want to extract the next 1046 * block from the tarfile here, as it will be done in 1047 * the caller of get_file(). 1048 */ 1049 1050 while (((rsize != 0) && (dsize >= TBLOCK)) || 1051 ((rsize == 0) && (dsize > TBLOCK))) { 1052 1053 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { 1054 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno))); 1055 return False; 1056 } 1057 1058 dsize -= TBLOCK; 1059 } 1060 1061 bpos = dsize; 1062 1063 } 1064 1065 /* Now close the file ... */ 1066 1067 if (!cli_close(cli, fnum)) { 1068 DEBUG(0, ("Error closing remote file\n")); 1069 return(False); 1070 } 1071 1072 /* Now we update the creation date ... */ 1073 1074 DEBUG(5, ("Updating creation date on %s\n", finfo.name)); 1075 1076 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) { 1077 if (tar_real_noisy) { 1078 DEBUG(0, ("Could not set time on file: %s\n", finfo.name)); 1079 /*return(False); */ /* Ignore, as Win95 does not allow changes */ 1080 } 1081 } 1082 1083 ntarf++; 1084 1085 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size)); 1086 1087 return(True); 1088} 1089 1090/* Create a directory. We just ensure that the path exists and return as there 1091 is no file associated with a directory 1092*/ 1093static int get_dir(file_info2 finfo) 1094{ 1095 1096 DEBUG(0, ("restore directory %s\n", finfo.name)); 1097 1098 if (!ensurepath(finfo.name)) { 1099 1100 DEBUG(0, ("Problems creating directory\n")); 1101 return(False); 1102 1103 } 1104 1105 ntarf++; 1106 return(True); 1107 1108} 1109/* Get a file with a long file name ... first file has file name, next file 1110 has the data. We only want the long file name, as the loop in do_tarput 1111 will deal with the rest. 1112*/ 1113static char * get_longfilename(file_info2 finfo) 1114{ 1115 int namesize = finfo.size + strlen(cur_dir) + 2; 1116 char *longname = malloc(namesize); 1117 int offset = 0, left = finfo.size; 1118 BOOL first = True; 1119 1120 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name)); 1121 DEBUG(5, ("Len = %d\n", (int)finfo.size)); 1122 1123 if (longname == NULL) { 1124 1125 DEBUG(0, ("could not allocate buffer of size %d for longname\n", 1126 (int)(finfo.size + strlen(cur_dir) + 2))); 1127 return(NULL); 1128 } 1129 1130 /* First, add cur_dir to the long file name */ 1131 1132 if (strlen(cur_dir) > 0) { 1133 strncpy(longname, cur_dir, namesize); 1134 offset = strlen(cur_dir); 1135 } 1136 1137 /* Loop through the blocks picking up the name */ 1138 1139 while (left > 0) { 1140 1141 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) { 1142 1143 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno))); 1144 return(NULL); 1145 1146 } 1147 1148 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--); 1149 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p)); 1150 1151 offset += TBLOCK; 1152 left -= TBLOCK; 1153 1154 } 1155 1156 return(longname); 1157 1158} 1159 1160static void do_tarput(void) 1161{ 1162 file_info2 finfo; 1163 struct timeval tp_start; 1164 char *longfilename = NULL, linkflag; 1165 int skip = False; 1166 1167 GetTimeOfDay(&tp_start); 1168 1169 DEBUG(5, ("RJS do_tarput called ...\n")); 1170 1171 buffer_p = tarbuf + tbufsiz; /* init this to force first read */ 1172 1173 /* Now read through those files ... */ 1174 1175 while (True) { 1176 1177 /* Get us to the next block, or the first block first time around */ 1178 1179 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) { 1180 1181 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno))); 1182 1183 return; 1184 1185 } 1186 1187 DEBUG(5, ("Reading the next header ...\n")); 1188 1189 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) { 1190 1191 case -2: /* Hmm, not good, but not fatal */ 1192 DEBUG(0, ("Skipping %s...\n", finfo.name)); 1193 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && 1194 !skip_file(finfo.size)) { 1195 1196 DEBUG(0, ("Short file, bailing out...\n")); 1197 return; 1198 1199 } 1200 1201 break; 1202 1203 case -1: 1204 DEBUG(0, ("abandoning restore, -1 from read tar header\n")); 1205 return; 1206 1207 case 0: /* chksum is zero - looks like an EOF */ 1208 DEBUG(0, ("tar: restored %d files and directories\n", ntarf)); 1209 return; /* Hmmm, bad here ... */ 1210 1211 default: 1212 /* No action */ 1213 1214 break; 1215 1216 } 1217 1218 /* Now, do we have a long file name? */ 1219 1220 if (longfilename != NULL) { 1221 1222 free(finfo.name); /* Free the space already allocated */ 1223 finfo.name = longfilename; 1224 longfilename = NULL; 1225 1226 } 1227 1228 /* Well, now we have a header, process the file ... */ 1229 1230 /* Should we skip the file? We have the long name as well here */ 1231 1232 skip = clipn && 1233 ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) 1234#ifdef HAVE_REGEX_H 1235 || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0))); 1236#else 1237 || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False))); 1238#endif 1239 1240 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name)); 1241 1242 if (skip) { 1243 1244 skip_file(finfo.size); 1245 continue; 1246 1247 } 1248 1249 /* We only get this far if we should process the file */ 1250 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag; 1251 1252 switch (linkflag) { 1253 1254 case '0': /* Should use symbolic names--FIXME */ 1255 1256 /* 1257 * Skip to the next block first, so we can get the file, FIXME, should 1258 * be in get_file ... 1259 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net> 1260 * Fixes bug where file size in tarfile is zero. 1261 */ 1262 1263 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) { 1264 DEBUG(0, ("Short file, bailing out...\n")); 1265 return; 1266 } 1267 if (!get_file(finfo)) { 1268 DEBUG(0, ("Abandoning restore\n")); 1269 return; 1270 1271 } 1272 break; 1273 1274 case '5': 1275 if (!get_dir(finfo)) { 1276 DEBUG(0, ("Abandoning restore \n")); 1277 return; 1278 } 1279 break; 1280 1281 case 'L': 1282 longfilename = get_longfilename(finfo); 1283 if (!longfilename) { 1284 DEBUG(0, ("abandoning restore\n")); 1285 return; 1286 1287 } 1288 DEBUG(5, ("Long file name: %s\n", longfilename)); 1289 break; 1290 1291 default: 1292 skip_file(finfo.size); /* Don't handle these yet */ 1293 break; 1294 1295 } 1296 1297 } 1298 1299 1300} 1301 1302 1303/* 1304 * samba interactive commands 1305 */ 1306 1307/**************************************************************************** 1308Blocksize command 1309***************************************************************************/ 1310void cmd_block(void) 1311{ 1312 fstring buf; 1313 int block; 1314 1315 if (!next_token(NULL,buf,NULL,sizeof(buf))) 1316 { 1317 DEBUG(0, ("blocksize <n>\n")); 1318 return; 1319 } 1320 1321 block=atoi(buf); 1322 if (block < 0 || block > 65535) 1323 { 1324 DEBUG(0, ("blocksize out of range")); 1325 return; 1326 } 1327 1328 blocksize=block; 1329 DEBUG(2,("blocksize is now %d\n", blocksize)); 1330} 1331 1332/**************************************************************************** 1333command to set incremental / reset mode 1334***************************************************************************/ 1335void cmd_tarmode(void) 1336{ 1337 fstring buf; 1338 1339 while (next_token(NULL,buf,NULL,sizeof(buf))) { 1340 if (strequal(buf, "full")) 1341 tar_inc=False; 1342 else if (strequal(buf, "inc")) 1343 tar_inc=True; 1344 else if (strequal(buf, "reset")) 1345 tar_reset=True; 1346 else if (strequal(buf, "noreset")) 1347 tar_reset=False; 1348 else if (strequal(buf, "system")) 1349 tar_system=True; 1350 else if (strequal(buf, "nosystem")) 1351 tar_system=False; 1352 else if (strequal(buf, "hidden")) 1353 tar_hidden=True; 1354 else if (strequal(buf, "nohidden")) 1355 tar_hidden=False; 1356 else if (strequal(buf, "verbose") || strequal(buf, "noquiet")) 1357 tar_noisy=True; 1358 else if (strequal(buf, "quiet") || strequal(buf, "noverbose")) 1359 tar_noisy=False; 1360 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf)); 1361 } 1362 1363 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n", 1364 tar_inc ? "incremental" : "full", 1365 tar_system ? "system" : "nosystem", 1366 tar_hidden ? "hidden" : "nohidden", 1367 tar_reset ? "reset" : "noreset", 1368 tar_noisy ? "verbose" : "quiet")); 1369 1370} 1371 1372/**************************************************************************** 1373Feeble attrib command 1374***************************************************************************/ 1375void cmd_setmode(void) 1376{ 1377 char *q; 1378 fstring buf; 1379 pstring fname; 1380 uint16 attra[2]; 1381 int direct=1; 1382 1383 attra[0] = attra[1] = 0; 1384 1385 if (!next_token(NULL,buf,NULL,sizeof(buf))) 1386 { 1387 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n")); 1388 return; 1389 } 1390 1391 safe_strcpy(fname, cur_dir, sizeof(pstring)); 1392 safe_strcat(fname, buf, sizeof(pstring)); 1393 1394 while (next_token(NULL,buf,NULL,sizeof(buf))) { 1395 q=buf; 1396 1397 while(*q) 1398 switch (*q++) { 1399 case '+': direct=1; 1400 break; 1401 case '-': direct=0; 1402 break; 1403 case 'r': attra[direct]|=aRONLY; 1404 break; 1405 case 'h': attra[direct]|=aHIDDEN; 1406 break; 1407 case 's': attra[direct]|=aSYSTEM; 1408 break; 1409 case 'a': attra[direct]|=aARCH; 1410 break; 1411 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n")); 1412 return; 1413 } 1414 } 1415 1416 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) 1417 { 1418 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n")); 1419 return; 1420 } 1421 1422 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET])); 1423 do_setrattr(fname, attra[ATTRSET], ATTRSET); 1424 do_setrattr(fname, attra[ATTRRESET], ATTRRESET); 1425} 1426 1427/**************************************************************************** 1428Principal command for creating / extracting 1429***************************************************************************/ 1430void cmd_tar(void) 1431{ 1432 fstring buf; 1433 char **argl; 1434 int argcl; 1435 1436 if (!next_token(NULL,buf,NULL,sizeof(buf))) 1437 { 1438 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n")); 1439 return; 1440 } 1441 1442 argl=toktocliplist(&argcl, NULL); 1443 if (!tar_parseargs(argcl, argl, buf, 0)) 1444 return; 1445 1446 process_tar(); 1447 1448 free(argl); 1449} 1450 1451/**************************************************************************** 1452Command line (option) version 1453***************************************************************************/ 1454int process_tar(void) 1455{ 1456 initarbuf(); 1457 switch(tar_type) { 1458 case 'x': 1459 1460#if 0 1461 do_tarput2(); 1462#else 1463 do_tarput(); 1464#endif 1465 free(tarbuf); 1466 close(tarhandle); 1467 break; 1468 case 'r': 1469 case 'c': 1470 if (clipn && tar_excl) { 1471 int i; 1472 pstring tarmac; 1473 1474 for (i=0; i<clipn; i++) { 1475 DEBUG(5,("arg %d = %s\n", i, cliplist[i])); 1476 1477 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') { 1478 *(cliplist[i]+strlen(cliplist[i])-1)='\0'; 1479 } 1480 1481 if (strrchr(cliplist[i], '\\')) { 1482 pstring saved_dir; 1483 1484 safe_strcpy(saved_dir, cur_dir, sizeof(pstring)); 1485 1486 if (*cliplist[i]=='\\') { 1487 safe_strcpy(tarmac, cliplist[i], sizeof(pstring)); 1488 } else { 1489 safe_strcpy(tarmac, cur_dir, sizeof(pstring)); 1490 safe_strcat(tarmac, cliplist[i], sizeof(pstring)); 1491 } 1492 safe_strcpy(cur_dir, tarmac, sizeof(pstring)); 1493 *(strrchr(cur_dir, '\\')+1)='\0'; 1494 1495 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac)); 1496 do_list(tarmac,attribute,do_tar, False, True); 1497 safe_strcpy(cur_dir,saved_dir, sizeof(pstring)); 1498 } else { 1499 safe_strcpy(tarmac, cur_dir, sizeof(pstring)); 1500 safe_strcat(tarmac, cliplist[i], sizeof(pstring)); 1501 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac)); 1502 do_list(tarmac,attribute,do_tar, False, True); 1503 } 1504 } 1505 } else { 1506 pstring mask; 1507 safe_strcpy(mask,cur_dir, sizeof(pstring)); 1508 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask)); 1509 safe_strcat(mask,"\\*", sizeof(pstring)); 1510 do_list(mask,attribute,do_tar,False, True); 1511 } 1512 1513 if (ntarf) dotareof(tarhandle); 1514 close(tarhandle); 1515 free(tarbuf); 1516 1517 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf)); 1518 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf)); 1519 break; 1520 } 1521 1522 if (must_free_cliplist) { 1523 int i; 1524 for (i = 0; i < clipn; ++i) { 1525 free(cliplist[i]); 1526 } 1527 free(cliplist); 1528 cliplist = NULL; 1529 clipn = 0; 1530 must_free_cliplist = False; 1531 } 1532 1533 return(0); 1534} 1535 1536/**************************************************************************** 1537Find a token (filename) in a clip list 1538***************************************************************************/ 1539static int clipfind(char **aret, int ret, char *tok) 1540{ 1541 if (aret==NULL) return 0; 1542 1543 /* ignore leading slashes or dots in token */ 1544 while(strchr("/\\.", *tok)) tok++; 1545 1546 while(ret--) { 1547 char *pkey=*aret++; 1548 1549 /* ignore leading slashes or dots in list */ 1550 while(strchr("/\\.", *pkey)) pkey++; 1551 1552 if (!strslashcmp(pkey, tok)) return 1; 1553 } 1554 1555 return 0; 1556} 1557 1558/**************************************************************************** 1559Read list of files to include from the file and initialize cliplist 1560accordingly. 1561***************************************************************************/ 1562static int read_inclusion_file(char *filename) 1563{ 1564 FILE *inclusion = NULL; 1565 char buf[MAXPATHLEN + 1]; 1566 char *inclusion_buffer = NULL; 1567 int inclusion_buffer_size = 0; 1568 int inclusion_buffer_sofar = 0; 1569 char *p; 1570 char *tmpstr; 1571 int i; 1572 int error = 0; 1573 1574 clipn = 0; 1575 buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */ 1576 if ((inclusion = sys_fopen(filename, "r")) == NULL) { 1577 /* XXX It would be better to include a reason for failure, but without 1578 * autoconf, it's hard to use strerror, sys_errlist, etc. 1579 */ 1580 DEBUG(0,("Unable to open inclusion file %s\n", filename)); 1581 return 0; 1582 } 1583 1584 while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) { 1585 if (inclusion_buffer == NULL) { 1586 inclusion_buffer_size = 1024; 1587 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) { 1588 DEBUG(0,("failure allocating buffer to read inclusion file\n")); 1589 error = 1; 1590 break; 1591 } 1592 } 1593 1594 if (buf[strlen(buf)-1] == '\n') { 1595 buf[strlen(buf)-1] = '\0'; 1596 } 1597 1598 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) { 1599 inclusion_buffer_size *= 2; 1600 inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size); 1601 if (! inclusion_buffer) { 1602 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n", 1603 inclusion_buffer_size)); 1604 error = 1; 1605 break; 1606 } 1607 } 1608 1609 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar); 1610 inclusion_buffer_sofar += strlen(buf) + 1; 1611 clipn++; 1612 } 1613 fclose(inclusion); 1614 1615 if (! error) { 1616 /* Allocate an array of clipn + 1 char*'s for cliplist */ 1617 cliplist = malloc((clipn + 1) * sizeof(char *)); 1618 if (cliplist == NULL) { 1619 DEBUG(0,("failure allocating memory for cliplist\n")); 1620 error = 1; 1621 } else { 1622 cliplist[clipn] = NULL; 1623 p = inclusion_buffer; 1624 for (i = 0; (! error) && (i < clipn); i++) { 1625 /* set current item to NULL so array will be null-terminated even if 1626 * malloc fails below. */ 1627 cliplist[i] = NULL; 1628 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) { 1629 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i)); 1630 error = 1; 1631 } else { 1632 unfixtarname(tmpstr, p, strlen(p) + 1, True); 1633 cliplist[i] = tmpstr; 1634 if ((p = strchr(p, '\000')) == NULL) { 1635 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n")); 1636 abort(); 1637 } 1638 } 1639 ++p; 1640 } 1641 must_free_cliplist = True; 1642 } 1643 } 1644 1645 if (inclusion_buffer) { 1646 free(inclusion_buffer); 1647 } 1648 if (error) { 1649 if (cliplist) { 1650 char **pp; 1651 /* We know cliplist is always null-terminated */ 1652 for (pp = cliplist; *pp; ++pp) { 1653 free(*pp); 1654 } 1655 free(cliplist); 1656 cliplist = NULL; 1657 must_free_cliplist = False; 1658 } 1659 return 0; 1660 } 1661 1662 /* cliplist and its elements are freed at the end of process_tar. */ 1663 return 1; 1664} 1665 1666/**************************************************************************** 1667Parse tar arguments. Sets tar_type, tar_excl, etc. 1668***************************************************************************/ 1669int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind) 1670{ 1671 char tar_clipfl='\0'; 1672 1673 /* Reset back to defaults - could be from interactive version 1674 * reset mode and archive mode left as they are though 1675 */ 1676 tar_type='\0'; 1677 tar_excl=True; 1678 dry_run=False; 1679 1680 while (*Optarg) 1681 switch(*Optarg++) { 1682 case 'c': 1683 tar_type='c'; 1684 break; 1685 case 'x': 1686 if (tar_type=='c') { 1687 printf("Tar must be followed by only one of c or x.\n"); 1688 return 0; 1689 } 1690 tar_type='x'; 1691 break; 1692 case 'b': 1693 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) { 1694 DEBUG(0,("Option b must be followed by valid blocksize\n")); 1695 return 0; 1696 } else { 1697 Optind++; 1698 } 1699 break; 1700 case 'g': 1701 tar_inc=True; 1702 break; 1703 case 'N': 1704 if (Optind>=argc) { 1705 DEBUG(0,("Option N must be followed by valid file name\n")); 1706 return 0; 1707 } else { 1708 SMB_STRUCT_STAT stbuf; 1709 extern time_t newer_than; 1710 1711 if (dos_stat(argv[Optind], &stbuf) == 0) { 1712 newer_than = stbuf.st_mtime; 1713 DEBUG(1,("Getting files newer than %s", 1714 asctime(LocalTime(&newer_than)))); 1715 Optind++; 1716 } else { 1717 DEBUG(0,("Error setting newer-than time\n")); 1718 return 0; 1719 } 1720 } 1721 break; 1722 case 'a': 1723 tar_reset=True; 1724 break; 1725 case 'q': 1726 tar_noisy=False; 1727 break; 1728 case 'I': 1729 if (tar_clipfl) { 1730 DEBUG(0,("Only one of I,X,F must be specified\n")); 1731 return 0; 1732 } 1733 tar_clipfl='I'; 1734 break; 1735 case 'X': 1736 if (tar_clipfl) { 1737 DEBUG(0,("Only one of I,X,F must be specified\n")); 1738 return 0; 1739 } 1740 tar_clipfl='X'; 1741 break; 1742 case 'F': 1743 if (tar_clipfl) { 1744 DEBUG(0,("Only one of I,X,F must be specified\n")); 1745 return 0; 1746 } 1747 tar_clipfl='F'; 1748 break; 1749 case 'r': 1750 DEBUG(0, ("tar_re_search set\n")); 1751 tar_re_search = True; 1752 break; 1753 case 'n': 1754 if (tar_type == 'c') { 1755 DEBUG(0, ("dry_run set\n")); 1756 dry_run = True; 1757 } else { 1758 DEBUG(0, ("n is only meaningful when creating a tar-file\n")); 1759 return 0; 1760 } 1761 break; 1762 default: 1763 DEBUG(0,("Unknown tar option\n")); 1764 return 0; 1765 } 1766 1767 if (!tar_type) { 1768 printf("Option T must be followed by one of c or x.\n"); 1769 return 0; 1770 } 1771 1772 /* tar_excl is true if cliplist lists files to be included. 1773 * Both 'I' and 'F' mean include. */ 1774 tar_excl=tar_clipfl!='X'; 1775 1776 if (tar_clipfl=='F') { 1777 if (argc-Optind-1 != 1) { 1778 DEBUG(0,("Option F must be followed by exactly one filename.\n")); 1779 return 0; 1780 } 1781 if (! read_inclusion_file(argv[Optind+1])) { 1782 return 0; 1783 } 1784 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */ 1785 char *tmpstr; 1786 char **tmplist; 1787 int clipcount; 1788 1789 cliplist=argv+Optind+1; 1790 clipn=argc-Optind-1; 1791 clipcount = clipn; 1792 1793 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) { 1794 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 1795 clipn) 1796 ); 1797 return 0; 1798 } 1799 1800 for (clipcount = 0; clipcount < clipn; clipcount++) { 1801 1802 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount])); 1803 1804 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) { 1805 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", 1806 clipcount) 1807 ); 1808 return 0; 1809 } 1810 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True); 1811 tmplist[clipcount] = tmpstr; 1812 DEBUG(5, ("Processed an item, %s\n", tmpstr)); 1813 1814 DEBUG(5, ("Cliplist is: %s\n", cliplist[0])); 1815 } 1816 cliplist = tmplist; 1817 must_free_cliplist = True; 1818 } 1819 1820 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */ 1821#ifdef HAVE_REGEX_H 1822 int errcode; 1823 1824 if ((preg = (regex_t *)malloc(65536)) == NULL) { 1825 1826 DEBUG(0, ("Could not allocate buffer for regular expression search\n")); 1827 return; 1828 1829 } 1830 1831 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) { 1832 char errstr[1024]; 1833 size_t errlen; 1834 1835 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1); 1836 1837 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr)); 1838 return; 1839 1840 } 1841#endif 1842 1843 clipn=argc-Optind-1; 1844 cliplist=argv+Optind+1; 1845 1846 } 1847 1848 if (Optind>=argc || !strcmp(argv[Optind], "-")) { 1849 /* Sets tar handle to either 0 or 1, as appropriate */ 1850 tarhandle=(tar_type=='c'); 1851 /* 1852 * Make sure that dbf points to stderr if we are using stdout for 1853 * tar output 1854 */ 1855 if (tarhandle == 1) 1856 dbf = stderr; 1857 } else { 1858 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0)) 1859 { 1860 if (!dry_run) { 1861 DEBUG(0,("Output is /dev/null, assuming dry_run")); 1862 dry_run = True; 1863 } 1864 tarhandle=-1; 1865 } else 1866 if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1) 1867 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) 1868 { 1869 DEBUG(0,("Error opening local file %s - %s\n", 1870 argv[Optind], strerror(errno))); 1871 return(0); 1872 } 1873 } 1874 1875 return 1; 1876} 1877