001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.commons.compress.archivers.dump; 020 021import java.util.Collections; 022import java.util.Date; 023import java.util.EnumSet; 024import java.util.HashSet; 025import java.util.Set; 026 027import org.apache.commons.compress.archivers.ArchiveEntry; 028 029/** 030 * This class represents an entry in a Dump archive. It consists of the entry's header, the entry's File and any extended attributes. 031 * <p> 032 * DumpEntries that are created from the header bytes read from an archive are instantiated with the DumpArchiveEntry( byte[] ) constructor. These entries will 033 * be used when extracting from or listing the contents of an archive. These entries have their header filled in using the header bytes. They also set the File 034 * to null, since they reference an archive entry not a file. 035 * <p> 036 * DumpEntries can also be constructed from nothing but a name. This allows the programmer to construct the entry by hand, for instance when only an InputStream 037 * is available for writing to the archive, and the header information is constructed from other information. In this case the header fields are set to defaults 038 * and the File is set to null. 039 * 040 * <p> 041 * The C structure for a Dump Entry's header is: 042 * 043 * <pre> 044 * #define TP_BSIZE 1024 // size of each file block 045 * #define NTREC 10 // number of blocks to write at once 046 * #define HIGHDENSITYTREC 32 // number of blocks to write on high-density tapes 047 * #define TP_NINDIR (TP_BSIZE/2) // number if indirect inodes in record 048 * #define TP_NINOS (TP_NINDIR / sizeof (int32_t)) 049 * #define LBLSIZE 16 050 * #define NAMELEN 64 051 * 052 * #define OFS_MAGIC (int) 60011 // old format magic value 053 * #define NFS_MAGIC (int) 60012 // new format magic value 054 * #define FS_UFS2_MAGIC (int) 0x19540119 055 * #define CHECKSUM (int) 84446 // constant used in checksum algorithm 056 * 057 * struct s_spcl { 058 * int32_t c_type; // record type (see below) 059 * int32_t <strong>c_date</strong>; // date of this dump 060 * int32_t <strong>c_ddate</strong>; // date of previous dump 061 * int32_t c_volume; // dump volume number 062 * u_int32_t c_tapea; // logical block of this record 063 * dump_ino_t c_ino; // number of inode 064 * int32_t <strong>c_magic</strong>; // magic number (see above) 065 * int32_t c_checksum; // record checksum 066 * #ifdef __linux__ 067 * struct new_bsd_inode c_dinode; 068 * #else 069 * #ifdef sunos 070 * struct new_bsd_inode c_dinode; 071 * #else 072 * struct dinode c_dinode; // ownership and mode of inode 073 * #endif 074 * #endif 075 * int32_t c_count; // number of valid c_addr entries 076 * union u_data c_data; // see above 077 * char <strong>c_label[LBLSIZE]</strong>; // dump label 078 * int32_t <strong>c_level</strong>; // level of this dump 079 * char <strong>c_filesys[NAMELEN]</strong>; // name of dumpped file system 080 * char <strong>c_dev[NAMELEN]</strong>; // name of dumpped device 081 * char <strong>c_host[NAMELEN]</strong>; // name of dumpped host 082 * int32_t c_flags; // additional information (see below) 083 * int32_t c_firstrec; // first record on volume 084 * int32_t c_ntrec; // blocksize on volume 085 * int32_t c_extattributes; // additional inode info (see below) 086 * int32_t c_spare[30]; // reserved for future uses 087 * } s_spcl; 088 * 089 * // 090 * // flag values 091 * // 092 * #define DR_NEWHEADER 0x0001 // new format tape header 093 * #define DR_NEWINODEFMT 0x0002 // new format inodes on tape 094 * #define DR_COMPRESSED 0x0080 // dump tape is compressed 095 * #define DR_METAONLY 0x0100 // only the metadata of the inode has been dumped 096 * #define DR_INODEINFO 0x0002 // [SIC] TS_END header contains c_inos information 097 * #define DR_EXTATTRIBUTES 0x8000 098 * 099 * // 100 * // extattributes inode info 101 * // 102 * #define EXT_REGULAR 0 103 * #define EXT_MACOSFNDRINFO 1 104 * #define EXT_MACOSRESFORK 2 105 * #define EXT_XATTR 3 106 * 107 * // used for EA on tape 108 * #define EXT2_GOOD_OLD_INODE_SIZE 128 109 * #define EXT2_XATTR_MAGIC 0xEA020000 // block EA 110 * #define EXT2_XATTR_MAGIC2 0xEA020001 // in inode EA 111 * </pre> 112 * <p> 113 * The fields in <strong>bold</strong> are the same for all blocks. (This permitted multiple dumps to be written to a single tape.) 114 * </p> 115 * 116 * <p> 117 * The C structure for the inode (file) information is: 118 * 119 * <pre> 120 * struct bsdtimeval { // **** alpha-*-linux is deviant 121 * __u32 tv_sec; 122 * __u32 tv_usec; 123 * }; 124 * 125 * #define NDADDR 12 126 * #define NIADDR 3 127 * 128 * // 129 * // This is the new (4.4) BSD inode structure 130 * // copied from the FreeBSD 2.0 <ufs/ufs/dinode.h> include file 131 * // 132 * struct new_bsd_inode { 133 * __u16 di_mode; // file type, standard Unix permissions 134 * __s16 di_nlink; // number of hard links to file. 135 * union { 136 * __u16 oldids[2]; 137 * __u32 inumber; 138 * } di_u; 139 * u_quad_t di_size; // file size 140 * struct bsdtimeval di_atime; // time file was last accessed 141 * struct bsdtimeval di_mtime; // time file was last modified 142 * struct bsdtimeval di_ctime; // time file was created 143 * __u32 di_db[NDADDR]; 144 * __u32 di_ib[NIADDR]; 145 * __u32 di_flags; // 146 * __s32 di_blocks; // number of disk blocks 147 * __s32 di_gen; // generation number 148 * __u32 di_uid; // user id (see /etc/passwd) 149 * __u32 di_gid; // group id (see /etc/group) 150 * __s32 di_spare[2]; // unused 151 * }; 152 * </pre> 153 * <p> 154 * It is important to note that the header DOES NOT have the name of the file. It can't since hard links mean that you may have multiple file names for a single 155 * physical file. You must read the contents of the directory entries to learn the mapping(s) from file name to inode. 156 * </p> 157 * 158 * <p> 159 * The C structure that indicates if a specific block is a real block that contains data or is a sparse block that is not persisted to the disk is: 160 * </p> 161 * 162 * <pre> 163 * #define TP_BSIZE 1024 164 * #define TP_NINDIR (TP_BSIZE/2) 165 * 166 * union u_data { 167 * char s_addrs[TP_NINDIR]; // 1 => data; 0 => hole in inode 168 * int32_t s_inos[TP_NINOS]; // table of first inode on each volume 169 * } u_data; 170 * </pre> 171 * 172 * @NotThreadSafe 173 */ 174public class DumpArchiveEntry implements ArchiveEntry { 175 176 /** 177 * Enumerates permissions with values. 178 */ 179 public enum PERMISSION { 180 // Note: The arguments are octal values 181 182 /** 183 * Permission SETUID (octal value 04000). 184 */ 185 SETUID(04000), 186 187 /** 188 * Permission SETGUI (octal value 02000). 189 */ 190 SETGUI(02000), 191 192 /** 193 * Permission STICKY (octal value 01000). 194 */ 195 STICKY(01000), 196 197 /** 198 * Permission USER_READ (octal value 00400). 199 */ 200 USER_READ(00400), 201 202 /** 203 * Permission USER_WRITE (octal value 00200). 204 */ 205 USER_WRITE(00200), 206 207 /** 208 * Permission USER_EXEC (octal value 00100). 209 */ 210 USER_EXEC(00100), 211 212 /** 213 * Permission GROUP_READ (octal value 00040). 214 */ 215 GROUP_READ(00040), 216 217 /** 218 * Permission GROUP_WRITE (octal value 00020). 219 */ 220 GROUP_WRITE(00020), 221 222 /** 223 * Permission 00020 (octal value 00010). 224 */ 225 GROUP_EXEC(00010), 226 227 /** 228 * Permission WORLD_READ (octal value 00004). 229 */ 230 WORLD_READ(00004), 231 232 /** 233 * Permission WORLD_WRITE (octal value 00002). 234 */ 235 WORLD_WRITE(00002), 236 237 /** 238 * Permission WORLD_EXEC (octal value 00001). 239 */ 240 WORLD_EXEC(00001); 241 242 /** 243 * Finds a matching set of enumeration values for the given code. 244 * 245 * @param code a code. 246 * @return a Set of values, never null. 247 */ 248 public static Set<PERMISSION> find(final int code) { 249 final Set<PERMISSION> set = new HashSet<>(); 250 for (final PERMISSION p : values()) { 251 if ((code & p.code) == p.code) { 252 set.add(p); 253 } 254 } 255 if (set.isEmpty()) { 256 return Collections.emptySet(); 257 } 258 return EnumSet.copyOf(set); 259 } 260 261 private final int code; 262 263 PERMISSION(final int code) { 264 this.code = code; 265 } 266 } 267 268 /** 269 * Archive entry as stored on tape. There is one TSH for (at most) every 512k in the file. 270 */ 271 static final class TapeSegmentHeader { 272 private DumpArchiveConstants.SEGMENT_TYPE type; 273 private int volume; 274 private int ino; 275 private int count; 276 private int holes; 277 private final byte[] cdata = new byte[512]; // map of any 'holes' 278 279 public int getCdata(final int idx) { 280 return cdata[idx]; 281 } 282 283 public int getCount() { 284 return count; 285 } 286 287 public int getHoles() { 288 return holes; 289 } 290 291 public int getIno() { 292 return ino; 293 } 294 295 public DumpArchiveConstants.SEGMENT_TYPE getType() { 296 return type; 297 } 298 299 public int getVolume() { 300 return volume; 301 } 302 303 void setIno(final int ino) { 304 this.ino = ino; 305 } 306 } 307 308 /** 309 * Enumerates types. 310 */ 311 public enum TYPE { 312 313 /** 314 * WHITEOUT with code 14. 315 */ 316 WHITEOUT(14), 317 318 /** 319 * SOCKET with code 12. 320 */ 321 SOCKET(12), 322 323 /** 324 * LINK with code 10. 325 */ 326 LINK(10), 327 328 /** 329 * FILE with code 8. 330 */ 331 FILE(8), 332 333 /** 334 * BLKDEV with code 6. 335 */ 336 BLKDEV(6), 337 338 /** 339 * DIRECTORY with code 4. 340 */ 341 DIRECTORY(4), 342 343 /** 344 * CHRDEV with code 2. 345 */ 346 CHRDEV(2), 347 348 /** 349 * CHRDEV with code 1. 350 */ 351 FIFO(1), 352 353 /** 354 * UNKNOWN with code 15. 355 */ 356 UNKNOWN(15); 357 358 /** 359 * Finds a matching enumeration value for the given code. 360 * 361 * @param code a code. 362 * @return a value, never null. 363 */ 364 public static TYPE find(final int code) { 365 TYPE type = UNKNOWN; 366 for (final TYPE t : values()) { 367 if (code == t.code) { 368 type = t; 369 } 370 } 371 return type; 372 } 373 374 private final int code; 375 376 TYPE(final int code) { 377 this.code = code; 378 } 379 } 380 381 /** 382 * Populate the dump archive entry and tape segment header with the contents of the buffer. 383 * 384 * @param buffer buffer to read content from 385 */ 386 static DumpArchiveEntry parse(final byte[] buffer) { 387 final DumpArchiveEntry entry = new DumpArchiveEntry(); 388 final TapeSegmentHeader header = entry.header; 389 390 header.type = DumpArchiveConstants.SEGMENT_TYPE.find(DumpArchiveUtil.convert32(buffer, 0)); 391 392 // header.dumpDate = new Date(1000L * DumpArchiveUtil.convert32(buffer, 4)); 393 // header.previousDumpDate = new Date(1000L * DumpArchiveUtil.convert32( 394 // buffer, 8)); 395 header.volume = DumpArchiveUtil.convert32(buffer, 12); 396 // header.tapea = DumpArchiveUtil.convert32(buffer, 16); 397 entry.ino = header.ino = DumpArchiveUtil.convert32(buffer, 20); 398 399 // header.magic = DumpArchiveUtil.convert32(buffer, 24); 400 // header.checksum = DumpArchiveUtil.convert32(buffer, 28); 401 final int m = DumpArchiveUtil.convert16(buffer, 32); 402 403 // determine the type of the file. 404 entry.setType(TYPE.find(m >> 12 & 0x0F)); 405 406 // determine the standard permissions 407 entry.setMode(m); 408 409 entry.nlink = DumpArchiveUtil.convert16(buffer, 34); 410 // inumber, oldids? 411 entry.setSize(DumpArchiveUtil.convert64(buffer, 40)); 412 413 long t = 1000L * DumpArchiveUtil.convert32(buffer, 48) + DumpArchiveUtil.convert32(buffer, 52) / 1000; 414 entry.setAccessTime(new Date(t)); 415 t = 1000L * DumpArchiveUtil.convert32(buffer, 56) + DumpArchiveUtil.convert32(buffer, 60) / 1000; 416 entry.setLastModifiedDate(new Date(t)); 417 t = 1000L * DumpArchiveUtil.convert32(buffer, 64) + DumpArchiveUtil.convert32(buffer, 68) / 1000; 418 entry.ctime = t; 419 420 // db: 72-119 - direct blocks 421 // id: 120-131 - indirect blocks 422 // entry.flags = DumpArchiveUtil.convert32(buffer, 132); 423 // entry.blocks = DumpArchiveUtil.convert32(buffer, 136); 424 entry.generation = DumpArchiveUtil.convert32(buffer, 140); 425 entry.setUserId(DumpArchiveUtil.convert32(buffer, 144)); 426 entry.setGroupId(DumpArchiveUtil.convert32(buffer, 148)); 427 // two 32-bit spare values. 428 header.count = DumpArchiveUtil.convert32(buffer, 160); 429 430 header.holes = 0; 431 432 for (int i = 0; i < 512 && i < header.count; i++) { 433 if (buffer[164 + i] == 0) { 434 header.holes++; 435 } 436 } 437 438 System.arraycopy(buffer, 164, header.cdata, 0, 512); 439 440 entry.volume = header.getVolume(); 441 442 // entry.isSummaryOnly = false; 443 return entry; 444 } 445 446 private String name; 447 private TYPE type = TYPE.UNKNOWN; 448 private int mode; 449 private Set<PERMISSION> permissions = Collections.emptySet(); 450 private long size; 451 452 private long atime; 453 454 private long mtime; 455 private int uid; 456 private int gid; 457 458 /** 459 * Currently unused 460 */ 461 private final DumpArchiveSummary summary = null; 462 463 /** 464 * This value is available from the standard index. 465 */ 466 private final TapeSegmentHeader header = new TapeSegmentHeader(); 467 private String simpleName; 468 private String originalName; 469 470 /** 471 * This value is available from the QFA index. 472 */ 473 private int volume; 474 private long offset; 475 private int ino; 476 477 private int nlink; 478 479 private long ctime; 480 481 private int generation; 482 483 private boolean isDeleted; 484 485 /** 486 * Constructs a default instance. 487 */ 488 public DumpArchiveEntry() { 489 } 490 491 /** 492 * Constructs a new instance with only names. 493 * 494 * @param name path name 495 * @param simpleName actual file name. 496 */ 497 public DumpArchiveEntry(final String name, final String simpleName) { 498 setName(name); 499 this.simpleName = simpleName; 500 } 501 502 /** 503 * Constructs a new instance with name, inode and type. 504 * 505 * @param name the name 506 * @param simpleName the simple name 507 * @param ino the ino 508 * @param type the type 509 */ 510 protected DumpArchiveEntry(final String name, final String simpleName, final int ino, final TYPE type) { 511 setType(type); 512 setName(name); 513 this.simpleName = simpleName; 514 this.ino = ino; 515 this.offset = 0; 516 } 517 518 @Override 519 public boolean equals(final Object o) { 520 if (o == this) { 521 return true; 522 } 523 if (o == null || !o.getClass().equals(getClass())) { 524 return false; 525 } 526 527 final DumpArchiveEntry rhs = (DumpArchiveEntry) o; 528 529 if (ino != rhs.ino) { 530 return false; 531 } 532 533 // summary is always null right now, but this may change some day 534 if (summary == null && rhs.summary != null // NOSONAR 535 || summary != null && !summary.equals(rhs.summary)) { // NOSONAR 536 return false; 537 } 538 539 return true; 540 } 541 542 /** 543 * Returns the time the file was last accessed. 544 * 545 * @return the access time 546 */ 547 public Date getAccessTime() { 548 return new Date(atime); 549 } 550 551 /** 552 * Gets file creation time. 553 * 554 * @return the creation time 555 */ 556 public Date getCreationTime() { 557 return new Date(ctime); 558 } 559 560 /** 561 * Returns the size of the entry as read from the archive. 562 */ 563 long getEntrySize() { 564 return size; 565 } 566 567 /** 568 * Gets the generation of the file. 569 * 570 * @return the generation 571 */ 572 public int getGeneration() { 573 return generation; 574 } 575 576 /** 577 * Gets the group id 578 * 579 * @return the group id 580 */ 581 public int getGroupId() { 582 return gid; 583 } 584 585 /** 586 * Gets the number of records in this segment. 587 * 588 * @return the number of records 589 */ 590 public int getHeaderCount() { 591 return header.getCount(); 592 } 593 594 /** 595 * Gets the number of sparse records in this segment. 596 * 597 * @return the number of sparse records 598 */ 599 public int getHeaderHoles() { 600 return header.getHoles(); 601 } 602 603 /** 604 * Gets the type of the tape segment header. 605 * 606 * @return the segment header 607 */ 608 public DumpArchiveConstants.SEGMENT_TYPE getHeaderType() { 609 return header.getType(); 610 } 611 612 /** 613 * Returns the ino of the entry. 614 * 615 * @return the ino 616 */ 617 public int getIno() { 618 return header.getIno(); 619 } 620 621 /** 622 * The last modified date. 623 * 624 * @return the last modified date 625 */ 626 @Override 627 public Date getLastModifiedDate() { 628 return new Date(mtime); 629 } 630 631 /** 632 * Gets the access permissions on the entry. 633 * 634 * @return the access permissions 635 */ 636 public int getMode() { 637 return mode; 638 } 639 640 /** 641 * Returns the name of the entry. 642 * 643 * <p> 644 * This method returns the raw name as it is stored inside of the archive. 645 * </p> 646 * 647 * @return the name of the entry. 648 */ 649 @Override 650 public String getName() { 651 return name; 652 } 653 654 /** 655 * Gets the number of hard links to the entry. 656 * 657 * @return the number of hard links 658 */ 659 public int getNlink() { 660 return nlink; 661 } 662 663 /** 664 * Gets the offset within the archive 665 * 666 * @return the offset 667 */ 668 public long getOffset() { 669 return offset; 670 } 671 672 /** 673 * Returns the unmodified name of the entry. 674 * 675 * @return the name of the entry. 676 */ 677 String getOriginalName() { 678 return originalName; 679 } 680 681 /** 682 * Returns the permissions on the entry. 683 * 684 * @return the permissions 685 */ 686 public Set<PERMISSION> getPermissions() { 687 return permissions; 688 } 689 690 /** 691 * Returns the path of the entry. 692 * 693 * @return the path of the entry. 694 */ 695 public String getSimpleName() { 696 return simpleName; 697 } 698 699 /** 700 * Returns the size of the entry. 701 * 702 * @return the size 703 */ 704 @Override 705 public long getSize() { 706 return isDirectory() ? SIZE_UNKNOWN : size; 707 } 708 709 /** 710 * Gets the type of the entry. 711 * 712 * @return the type 713 */ 714 public TYPE getType() { 715 return type; 716 } 717 718 /** 719 * Gets the user id. 720 * 721 * @return the user id 722 */ 723 public int getUserId() { 724 return uid; 725 } 726 727 /** 728 * Gets the tape volume where this file is located. 729 * 730 * @return the volume 731 */ 732 public int getVolume() { 733 return volume; 734 } 735 736 @Override 737 public int hashCode() { 738 return ino; 739 } 740 741 /** 742 * Tests whether this is a block device. 743 * 744 * @return whether this is a block device. 745 */ 746 public boolean isBlkDev() { 747 return type == TYPE.BLKDEV; 748 } 749 750 /** 751 * Tests whether this is a character device. 752 * 753 * @return whether this is a character device 754 */ 755 public boolean isChrDev() { 756 return type == TYPE.CHRDEV; 757 } 758 759 /** 760 * Tests whether this file been deleted. 761 * For valid on incremental dumps. 762 * 763 * @return whether the file has been deleted. 764 */ 765 public boolean isDeleted() { 766 return isDeleted; 767 } 768 769 /** 770 * Tests whether this is a directory. 771 * 772 * @return whether this is a directory 773 */ 774 @Override 775 public boolean isDirectory() { 776 return type == TYPE.DIRECTORY; 777 } 778 779 /** 780 * Tests whether whether this is a fifo/pipe. 781 * 782 * @return whether this is a fifo/pipe. 783 */ 784 public boolean isFifo() { 785 return type == TYPE.FIFO; 786 } 787 788 /** 789 * Tests whether this is a regular file. 790 * 791 * @return whether this is a regular file. 792 */ 793 public boolean isFile() { 794 return type == TYPE.FILE; 795 } 796 797 /** 798 * Tests whether this is a socket. 799 * 800 * @return whether this is a socket. 801 */ 802 public boolean isSocket() { 803 return type == TYPE.SOCKET; 804 } 805 806 /** 807 * Tests whether this is a sparse record. 808 * 809 * @param idx index of the record to check. 810 * @return whether this is a sparse record. 811 */ 812 public boolean isSparseRecord(final int idx) { 813 return (header.getCdata(idx) & 0x01) == 0; 814 } 815 816 /** 817 * Sets the time the file was last accessed. 818 * 819 * @param atime the access time 820 */ 821 public void setAccessTime(final Date atime) { 822 this.atime = atime.getTime(); 823 } 824 825 /** 826 * Sets the file creation time. 827 * 828 * @param ctime the creation time 829 */ 830 public void setCreationTime(final Date ctime) { 831 this.ctime = ctime.getTime(); 832 } 833 834 /** 835 * Sets whether this file has been deleted. 836 * 837 * @param isDeleted whether the file has been deleted 838 */ 839 public void setDeleted(final boolean isDeleted) { 840 this.isDeleted = isDeleted; 841 } 842 843 /** 844 * Sets the generation of the file. 845 * 846 * @param generation the generation 847 */ 848 public void setGeneration(final int generation) { 849 this.generation = generation; 850 } 851 852 /** 853 * Sets the group id. 854 * 855 * @param gid the group id 856 */ 857 public void setGroupId(final int gid) { 858 this.gid = gid; 859 } 860 861 /** 862 * Sets the time the file was last modified. 863 * 864 * @param mtime the last modified time 865 */ 866 public void setLastModifiedDate(final Date mtime) { 867 this.mtime = mtime.getTime(); 868 } 869 870 /** 871 * Sets the access permissions on the entry. 872 * 873 * @param mode the access permissions 874 */ 875 public void setMode(final int mode) { 876 this.mode = mode & 07777; 877 this.permissions = PERMISSION.find(mode); 878 } 879 880 /** 881 * Sets the name of the entry. 882 * 883 * @param name the name 884 */ 885 public final void setName(String name) { 886 this.originalName = name; 887 if (name != null) { 888 if (isDirectory() && !name.endsWith("/")) { 889 name += "/"; 890 } 891 if (name.startsWith("./")) { 892 name = name.substring(2); 893 } 894 } 895 this.name = name; 896 } 897 898 /** 899 * Sets the number of hard links. 900 * 901 * @param nlink the number of hard links 902 */ 903 public void setNlink(final int nlink) { 904 this.nlink = nlink; 905 } 906 907 /** 908 * Sets the offset within the archive. 909 * 910 * @param offset the offset 911 */ 912 public void setOffset(final long offset) { 913 this.offset = offset; 914 } 915 916 /** 917 * Sets the path of the entry. 918 * 919 * @param simpleName the simple name 920 */ 921 protected void setSimpleName(final String simpleName) { 922 this.simpleName = simpleName; 923 } 924 925 /** 926 * Sets the size of the entry. 927 * 928 * @param size the size 929 */ 930 public void setSize(final long size) { 931 this.size = size; 932 } 933 934 /** 935 * Sets the type of the entry. 936 * 937 * @param type the type 938 */ 939 public void setType(final TYPE type) { 940 this.type = type; 941 } 942 943 /** 944 * Sets the user id. 945 * 946 * @param uid the user id 947 */ 948 public void setUserId(final int uid) { 949 this.uid = uid; 950 } 951 952 /** 953 * Sets the tape volume. 954 * 955 * @param volume the volume 956 */ 957 public void setVolume(final int volume) { 958 this.volume = volume; 959 } 960 961 @Override 962 public String toString() { 963 return getName(); 964 } 965 966 /** 967 * Update entry with information from next tape segment header. 968 */ 969 void update(final byte[] buffer) { 970 header.volume = DumpArchiveUtil.convert32(buffer, 16); 971 header.count = DumpArchiveUtil.convert32(buffer, 160); 972 973 header.holes = 0; 974 975 for (int i = 0; i < 512 && i < header.count; i++) { 976 if (buffer[164 + i] == 0) { 977 header.holes++; 978 } 979 } 980 981 System.arraycopy(buffer, 164, header.cdata, 0, 512); 982 } 983}