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