    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 * http://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 <b>c_date</b>;             // date of this dump
    060 *   int32_t <b>c_ddate</b>;            // 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 <b>c_magic</b>;            // 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    <b>c_label[LBLSIZE]</b>;   // dump label
    078 *   int32_t <b>c_level</b>;            // level of this dump
    079 *   char    <b>c_filesys[NAMELEN]</b>; // name of dumpped file system
    080 *   char    <b>c_dev[NAMELEN]</b>;     // name of dumpped device
    081 *   char    <b>c_host[NAMELEN]</b>;    // 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 <b>bold</b> 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 &lt;ufs/ufs/dinode.h&gt; 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 =&gt; data; 0 =&gt; 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    public enum PERMISSION {
    177        // Note: The arguments are octal values
    178        // @formatter:off
    179        SETUID(04000),
    180        SETGUI(02000),
    181        STICKY(01000),
    182        USER_READ(00400),
    183        USER_WRITE(00200),
    184        USER_EXEC(00100),
    185        GROUP_READ(00040),
    186        GROUP_WRITE(00020),
    187        GROUP_EXEC(00010),
    188        WORLD_READ(00004),
    189        WORLD_WRITE(00002),
    190        WORLD_EXEC(00001);
    191        // @formatter:on
    192
    193        public static Set<PERMISSION> find(final int code) {
    194            final Set<PERMISSION> set = new HashSet<>();
    195
    196            for (final PERMISSION p : values()) {
    197                if ((code & p.code) == p.code) {
    198                    set.add(p);
    199                }
    200            }
    201
    202            if (set.isEmpty()) {
    203                return Collections.emptySet();
    204            }
    205
    206            return EnumSet.copyOf(set);
    207        }
    208
    209        private final int code;
    210
    211        PERMISSION(final int code) {
    212            this.code = code;
    213        }
    214    }
    215
    216    /**
    217     * Archive entry as stored on tape. There is one TSH for (at most) every 512k in the file.
    218     */
    219    static class TapeSegmentHeader {
    220        private DumpArchiveConstants.SEGMENT_TYPE type;
    221        private int volume;
    222        private int ino;
    223        private int count;
    224        private int holes;
    225        private final byte[] cdata = new byte[512]; // map of any 'holes'
    226
    227        public int getCdata(final int idx) {
    228            return cdata[idx];
    229        }
    230
    231        public int getCount() {
    232            return count;
    233        }
    234
    235        public int getHoles() {
    236            return holes;
    237        }
    238
    239        public int getIno() {
    240            return ino;
    241        }
    242
    243        public DumpArchiveConstants.SEGMENT_TYPE getType() {
    244            return type;
    245        }
    246
    247        public int getVolume() {
    248            return volume;
    249        }
    250
    251        void setIno(final int ino) {
    252            this.ino = ino;
    253        }
    254    }
    255
    256    public enum TYPE {
    257        WHITEOUT(14), SOCKET(12), LINK(10), FILE(8), BLKDEV(6), DIRECTORY(4), CHRDEV(2), FIFO(1), UNKNOWN(15);
    258
    259        public static TYPE find(final int code) {
    260            TYPE type = UNKNOWN;
    261
    262            for (final TYPE t : values()) {
    263                if (code == t.code) {
    264                    type = t;
    265                }
    266            }
    267
    268            return type;
    269        }
    270
    271        private final int code;
    272
    273        TYPE(final int code) {
    274            this.code = code;
    275        }
    276    }
    277
    278    /**
    279     * Populate the dump archive entry and tape segment header with the contents of the buffer.
    280     *
    281     * @param buffer buffer to read content from
    282     */
    283    static DumpArchiveEntry parse(final byte[] buffer) {
    284        final DumpArchiveEntry entry = new DumpArchiveEntry();
    285        final TapeSegmentHeader header = entry.header;
    286
    287        header.type = DumpArchiveConstants.SEGMENT_TYPE.find(DumpArchiveUtil.convert32(buffer, 0));
    288
    289        // header.dumpDate = new Date(1000L * DumpArchiveUtil.convert32(buffer, 4));
    290        // header.previousDumpDate = new Date(1000L * DumpArchiveUtil.convert32(
    291        // buffer, 8));
    292        header.volume = DumpArchiveUtil.convert32(buffer, 12);
    293        // header.tapea = DumpArchiveUtil.convert32(buffer, 16);
    294        entry.ino = header.ino = DumpArchiveUtil.convert32(buffer, 20);
    295
    296        // header.magic = DumpArchiveUtil.convert32(buffer, 24);
    297        // header.checksum = DumpArchiveUtil.convert32(buffer, 28);
    298        final int m = DumpArchiveUtil.convert16(buffer, 32);
    299
    300        // determine the type of the file.
    301        entry.setType(TYPE.find(m >> 12 & 0x0F));
    302
    303        // determine the standard permissions
    304        entry.setMode(m);
    305
    306        entry.nlink = DumpArchiveUtil.convert16(buffer, 34);
    307        // inumber, oldids?
    308        entry.setSize(DumpArchiveUtil.convert64(buffer, 40));
    309
    310        long t = 1000L * DumpArchiveUtil.convert32(buffer, 48) + DumpArchiveUtil.convert32(buffer, 52) / 1000;
    311        entry.setAccessTime(new Date(t));
    312        t = 1000L * DumpArchiveUtil.convert32(buffer, 56) + DumpArchiveUtil.convert32(buffer, 60) / 1000;
    313        entry.setLastModifiedDate(new Date(t));
    314        t = 1000L * DumpArchiveUtil.convert32(buffer, 64) + DumpArchiveUtil.convert32(buffer, 68) / 1000;
    315        entry.ctime = t;
    316
    317        // db: 72-119 - direct blocks
    318        // id: 120-131 - indirect blocks
    319        // entry.flags = DumpArchiveUtil.convert32(buffer, 132);
    320        // entry.blocks = DumpArchiveUtil.convert32(buffer, 136);
    321        entry.generation = DumpArchiveUtil.convert32(buffer, 140);
    322        entry.setUserId(DumpArchiveUtil.convert32(buffer, 144));
    323        entry.setGroupId(DumpArchiveUtil.convert32(buffer, 148));
    324        // two 32-bit spare values.
    325        header.count = DumpArchiveUtil.convert32(buffer, 160);
    326
    327        header.holes = 0;
    328
    329        for (int i = 0; i < 512 && i < header.count; i++) {
    330            if (buffer[164 + i] == 0) {
    331                header.holes++;
    332            }
    333        }
    334
    335        System.arraycopy(buffer, 164, header.cdata, 0, 512);
    336
    337        entry.volume = header.getVolume();
    338
    339        // entry.isSummaryOnly = false;
    340        return entry;
    341    }
    342
    343    private String name;
    344    private TYPE type = TYPE.UNKNOWN;
    345    private int mode;
    346    private Set<PERMISSION> permissions = Collections.emptySet();
    347    private long size;
    348
    349    private long atime;
    350
    351    private long mtime;
    352    private int uid;
    353    private int gid;
    354
    355    /**
    356     * Currently unused
    357     */
    358    private final DumpArchiveSummary summary = null;
    359
    360    /**
    361     * This value is available from the standard index.
    362     */
    363    private final TapeSegmentHeader header = new TapeSegmentHeader();
    364    private String simpleName;
    365    private String originalName;
    366
    367    /**
    368     * This value is available from the QFA index.
    369     */
    370    private int volume;
    371    private long offset;
    372    private int ino;
    373
    374    private int nlink;
    375
    376    private long ctime;
    377
    378    private int generation;
    379
    380    private boolean isDeleted;
    381
    382    /**
    383     * Constructs a default instance.
    384     */
    385    public DumpArchiveEntry() {
    386    }
    387
    388    /**
    389     * Constructs a new instance with only names.
    390     *
    391     * @param name       path name
    392     * @param simpleName actual file name.
    393     */
    394    public DumpArchiveEntry(final String name, final String simpleName) {
    395        setName(name);
    396        this.simpleName = simpleName;
    397    }
    398
    399    /**
    400     * Constructs a new instance with name, inode and type.
    401     *
    402     * @param name       the name
    403     * @param simpleName the simple name
    404     * @param ino        the ino
    405     * @param type       the type
    406     */
    407    protected DumpArchiveEntry(final String name, final String simpleName, final int ino, final TYPE type) {
    408        setType(type);
    409        setName(name);
    410        this.simpleName = simpleName;
    411        this.ino = ino;
    412        this.offset = 0;
    413    }
    414
    415    @Override
    416    public boolean equals(final Object o) {
    417        if (o == this) {
    418            return true;
    419        }
    420        if (o == null || !o.getClass().equals(getClass())) {
    421            return false;
    422        }
    423
    424        final DumpArchiveEntry rhs = (DumpArchiveEntry) o;
    425
    426        if (ino != rhs.ino) {
    427            return false;
    428        }
    429
    430        // summary is always null right now, but this may change some day
    431        if (summary == null && rhs.summary != null // NOSONAR
    432                || summary != null && !summary.equals(rhs.summary)) { // NOSONAR
    433            return false;
    434        }
    435
    436        return true;
    437    }
    438
    439    /**
    440     * Returns the time the file was last accessed.
    441     *
    442     * @return the access time
    443     */
    444    public Date getAccessTime() {
    445        return new Date(atime);
    446    }
    447
    448    /**
    449     * Gets file creation time.
    450     *
    451     * @return the creation time
    452     */
    453    public Date getCreationTime() {
    454        return new Date(ctime);
    455    }
    456
    457    /**
    458     * Returns the size of the entry as read from the archive.
    459     */
    460    long getEntrySize() {
    461        return size;
    462    }
    463
    464    /**
    465     * Gets the generation of the file.
    466     *
    467     * @return the generation
    468     */
    469    public int getGeneration() {
    470        return generation;
    471    }
    472
    473    /**
    474     * Gets the group id
    475     *
    476     * @return the group id
    477     */
    478    public int getGroupId() {
    479        return gid;
    480    }
    481
    482    /**
    483     * Gets the number of records in this segment.
    484     *
    485     * @return the number of records
    486     */
    487    public int getHeaderCount() {
    488        return header.getCount();
    489    }
    490
    491    /**
    492     * Gets the number of sparse records in this segment.
    493     *
    494     * @return the number of sparse records
    495     */
    496    public int getHeaderHoles() {
    497        return header.getHoles();
    498    }
    499
    500    /**
    501     * Gets the type of the tape segment header.
    502     *
    503     * @return the segment header
    504     */
    505    public DumpArchiveConstants.SEGMENT_TYPE getHeaderType() {
    506        return header.getType();
    507    }
    508
    509    /**
    510     * Returns the ino of the entry.
    511     *
    512     * @return the ino
    513     */
    514    public int getIno() {
    515        return header.getIno();
    516    }
    517
    518    /**
    519     * The last modified date.
    520     *
    521     * @return the last modified date
    522     */
    523    @Override
    524    public Date getLastModifiedDate() {
    525        return new Date(mtime);
    526    }
    527
    528    /**
    529     * Gets the access permissions on the entry.
    530     *
    531     * @return the access permissions
    532     */
    533    public int getMode() {
    534        return mode;
    535    }
    536
    537    /**
    538     * Returns the name of the entry.
    539     *
    540     * <p>
    541     * This method returns the raw name as it is stored inside of the archive.
    542     * </p>
    543     *
    544     * @return the name of the entry.
    545     */
    546    @Override
    547    public String getName() {
    548        return name;
    549    }
    550
    551    /**
    552     * Gets the number of hard links to the entry.
    553     *
    554     * @return the number of hard links
    555     */
    556    public int getNlink() {
    557        return nlink;
    558    }
    559
    560    /**
    561     * Gets the offset within the archive
    562     *
    563     * @return the offset
    564     */
    565    public long getOffset() {
    566        return offset;
    567    }
    568
    569    /**
    570     * Returns the unmodified name of the entry.
    571     *
    572     * @return the name of the entry.
    573     */
    574    String getOriginalName() {
    575        return originalName;
    576    }
    577
    578    /**
    579     * Returns the permissions on the entry.
    580     *
    581     * @return the permissions
    582     */
    583    public Set<PERMISSION> getPermissions() {
    584        return permissions;
    585    }
    586
    587    /**
    588     * Returns the path of the entry.
    589     *
    590     * @return the path of the entry.
    591     */
    592    public String getSimpleName() {
    593        return simpleName;
    594    }
    595
    596    /**
    597     * Returns the size of the entry.
    598     *
    599     * @return the size
    600     */
    601    @Override
    602    public long getSize() {
    603        return isDirectory() ? SIZE_UNKNOWN : size;
    604    }
    605
    606    /**
    607     * Gets the type of the entry.
    608     *
    609     * @return the type
    610     */
    611    public TYPE getType() {
    612        return type;
    613    }
    614
    615    /**
    616     * Gets the user id.
    617     *
    618     * @return the user id
    619     */
    620    public int getUserId() {
    621        return uid;
    622    }
    623
    624    /**
    625     * Gets the tape volume where this file is located.
    626     *
    627     * @return the volume
    628     */
    629    public int getVolume() {
    630        return volume;
    631    }
    632
    633    @Override
    634    public int hashCode() {
    635        return ino;
    636    }
    637
    638    /**
    639     * Is this a block device?
    640     *
    641     * @return whether this is a block device
    642     */
    643    public boolean isBlkDev() {
    644        return type == TYPE.BLKDEV;
    645    }
    646
    647    /**
    648     * Is this a character device?
    649     *
    650     * @return whether this is a character device
    651     */
    652    public boolean isChrDev() {
    653        return type == TYPE.CHRDEV;
    654    }
    655
    656    /**
    657     * Has this file been deleted? (On valid on incremental dumps.)
    658     *
    659     * @return whether the file has been deleted
    660     */
    661    public boolean isDeleted() {
    662        return isDeleted;
    663    }
    664
    665    /**
    666     * Is this a directory?
    667     *
    668     * @return whether this is a directory
    669     */
    670    @Override
    671    public boolean isDirectory() {
    672        return type == TYPE.DIRECTORY;
    673    }
    674
    675    /**
    676     * Is this a fifo/pipe?
    677     *
    678     * @return whether this is a fifo
    679     */
    680    public boolean isFifo() {
    681        return type == TYPE.FIFO;
    682    }
    683
    684    /**
    685     * Is this a regular file?
    686     *
    687     * @return whether this is a regular file
    688     */
    689    public boolean isFile() {
    690        return type == TYPE.FILE;
    691    }
    692
    693    /**
    694     * Is this a network device?
    695     *
    696     * @return whether this is a socket
    697     */
    698    public boolean isSocket() {
    699        return type == TYPE.SOCKET;
    700    }
    701
    702    /**
    703     * Is this a sparse record?
    704     *
    705     * @param idx index of the record to check
    706     * @return whether this is a sparse record
    707     */
    708    public boolean isSparseRecord(final int idx) {
    709        return (header.getCdata(idx) & 0x01) == 0;
    710    }
    711
    712    /**
    713     * Sets the time the file was last accessed.
    714     *
    715     * @param atime the access time
    716     */
    717    public void setAccessTime(final Date atime) {
    718        this.atime = atime.getTime();
    719    }
    720
    721    /**
    722     * Sets the file creation time.
    723     *
    724     * @param ctime the creation time
    725     */
    726    public void setCreationTime(final Date ctime) {
    727        this.ctime = ctime.getTime();
    728    }
    729
    730    /**
    731     * Sets whether this file has been deleted.
    732     *
    733     * @param isDeleted whether the file has been deleted
    734     */
    735    public void setDeleted(final boolean isDeleted) {
    736        this.isDeleted = isDeleted;
    737    }
    738
    739    /**
    740     * Sets the generation of the file.
    741     *
    742     * @param generation the generation
    743     */
    744    public void setGeneration(final int generation) {
    745        this.generation = generation;
    746    }
    747
    748    /**
    749     * Sets the group id.
    750     *
    751     * @param gid the group id
    752     */
    753    public void setGroupId(final int gid) {
    754        this.gid = gid;
    755    }
    756
    757    /**
    758     * Sets the time the file was last modified.
    759     *
    760     * @param mtime the last modified time
    761     */
    762    public void setLastModifiedDate(final Date mtime) {
    763        this.mtime = mtime.getTime();
    764    }
    765
    766    /**
    767     * Sets the access permissions on the entry.
    768     *
    769     * @param mode the access permissions
    770     */
    771    public void setMode(final int mode) {
    772        this.mode = mode & 07777;
    773        this.permissions = PERMISSION.find(mode);
    774    }
    775
    776    /**
    777     * Sets the name of the entry.
    778     *
    779     * @param name the name
    780     */
    781    public final void setName(String name) {
    782        this.originalName = name;
    783        if (name != null) {
    784            if (isDirectory() && !name.endsWith("/")) {
    785                name += "/";
    786            }
    787            if (name.startsWith("./")) {
    788                name = name.substring(2);
    789            }
    790        }
    791        this.name = name;
    792    }
    793
    794    /**
    795     * Sets the number of hard links.
    796     *
    797     * @param nlink the number of hard links
    798     */
    799    public void setNlink(final int nlink) {
    800        this.nlink = nlink;
    801    }
    802
    803    /**
    804     * Sets the offset within the archive.
    805     *
    806     * @param offset the offset
    807     */
    808    public void setOffset(final long offset) {
    809        this.offset = offset;
    810    }
    811
    812    /**
    813     * Sets the path of the entry.
    814     *
    815     * @param simpleName the simple name
    816     */
    817    protected void setSimpleName(final String simpleName) {
    818        this.simpleName = simpleName;
    819    }
    820
    821    /**
    822     * Sets the size of the entry.
    823     *
    824     * @param size the size
    825     */
    826    public void setSize(final long size) {
    827        this.size = size;
    828    }
    829
    830    /**
    831     * Sets the type of the entry.
    832     *
    833     * @param type the type
    834     */
    835    public void setType(final TYPE type) {
    836        this.type = type;
    837    }
    838
    839    /**
    840     * Sets the user id.
    841     *
    842     * @param uid the user id
    843     */
    844    public void setUserId(final int uid) {
    845        this.uid = uid;
    846    }
    847
    848    /**
    849     * Sets the tape volume.
    850     *
    851     * @param volume the volume
    852     */
    853    public void setVolume(final int volume) {
    854        this.volume = volume;
    855    }
    856
    857    @Override
    858    public String toString() {
    859        return getName();
    860    }
    861
    862    /**
    863     * Update entry with information from next tape segment header.
    864     */
    865    void update(final byte[] buffer) {
    866        header.volume = DumpArchiveUtil.convert32(buffer, 16);
    867        header.count = DumpArchiveUtil.convert32(buffer, 160);
    868
    869        header.holes = 0;
    870
    871        for (int i = 0; i < 512 && i < header.count; i++) {
    872            if (buffer[164 + i] == 0) {
    873                header.holes++;
    874            }
    875        }
    876
    877        System.arraycopy(buffer, 164, header.cdata, 0, 512);
    878    }
    879}