DumpArchiveEntry.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  *   https://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing,
  13.  * software distributed under the License is distributed on an
  14.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15.  * KIND, either express or implied.  See the License for the
  16.  * specific language governing permissions and limitations
  17.  * under the License.
  18.  */
  19. package org.apache.commons.compress.archivers.dump;

  20. import java.util.Collections;
  21. import java.util.Date;
  22. import java.util.EnumSet;
  23. import java.util.HashSet;
  24. import java.util.Set;

  25. import org.apache.commons.compress.archivers.ArchiveEntry;

  26. /**
  27.  * This class represents an entry in a Dump archive. It consists of the entry's header, the entry's File and any extended attributes.
  28.  * <p>
  29.  * DumpEntries that are created from the header bytes read from an archive are instantiated with the DumpArchiveEntry( byte[] ) constructor. These entries will
  30.  * 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
  31.  * to null, since they reference an archive entry not a file.
  32.  * <p>
  33.  * 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
  34.  * 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
  35.  * and the File is set to null.
  36.  *
  37.  * <p>
  38.  * The C structure for a Dump Entry's header is:
  39.  *
  40.  * <pre>
  41.  * #define TP_BSIZE    1024          // size of each file block
  42.  * #define NTREC       10            // number of blocks to write at once
  43.  * #define HIGHDENSITYTREC 32        // number of blocks to write on high-density tapes
  44.  * #define TP_NINDIR   (TP_BSIZE/2)  // number if indirect inodes in record
  45.  * #define TP_NINOS    (TP_NINDIR / sizeof (int32_t))
  46.  * #define LBLSIZE     16
  47.  * #define NAMELEN     64
  48.  *
  49.  * #define OFS_MAGIC     (int) 60011  // old format magic value
  50.  * #define NFS_MAGIC     (int) 60012  // new format magic value
  51.  * #define FS_UFS2_MAGIC (int) 0x19540119
  52.  * #define CHECKSUM      (int) 84446  // constant used in checksum algorithm
  53.  *
  54.  * struct  s_spcl {
  55.  *   int32_t c_type;             // record type (see below)
  56.  *   int32_t <strong>c_date</strong>;             // date of this dump
  57.  *   int32_t <strong>c_ddate</strong>;            // date of previous dump
  58.  *   int32_t c_volume;           // dump volume number
  59.  *   u_int32_t c_tapea;          // logical block of this record
  60.  *   dump_ino_t c_ino;           // number of inode
  61.  *   int32_t <strong>c_magic</strong>;            // magic number (see above)
  62.  *   int32_t c_checksum;         // record checksum
  63.  * #ifdef  __linux__
  64.  *   struct  new_bsd_inode c_dinode;
  65.  * #else
  66.  * #ifdef sunos
  67.  *   struct  new_bsd_inode c_dinode;
  68.  * #else
  69.  *   struct  dinode  c_dinode;   // ownership and mode of inode
  70.  * #endif
  71.  * #endif
  72.  *   int32_t c_count;            // number of valid c_addr entries
  73.  *   union u_data c_data;        // see above
  74.  *   char    <strong>c_label[LBLSIZE]</strong>;   // dump label
  75.  *   int32_t <strong>c_level</strong>;            // level of this dump
  76.  *   char    <strong>c_filesys[NAMELEN]</strong>; // name of dumpped file system
  77.  *   char    <strong>c_dev[NAMELEN]</strong>;     // name of dumpped device
  78.  *   char    <strong>c_host[NAMELEN]</strong>;    // name of dumpped host
  79.  *   int32_t c_flags;            // additional information (see below)
  80.  *   int32_t c_firstrec;         // first record on volume
  81.  *   int32_t c_ntrec;            // blocksize on volume
  82.  *   int32_t c_extattributes;    // additional inode info (see below)
  83.  *   int32_t c_spare[30];        // reserved for future uses
  84.  * } s_spcl;
  85.  *
  86.  * //
  87.  * // flag values
  88.  * //
  89.  * #define DR_NEWHEADER     0x0001  // new format tape header
  90.  * #define DR_NEWINODEFMT   0x0002  // new format inodes on tape
  91.  * #define DR_COMPRESSED    0x0080  // dump tape is compressed
  92.  * #define DR_METAONLY      0x0100  // only the metadata of the inode has been dumped
  93.  * #define DR_INODEINFO     0x0002  // [SIC] TS_END header contains c_inos information
  94.  * #define DR_EXTATTRIBUTES 0x8000
  95.  *
  96.  * //
  97.  * // extattributes inode info
  98.  * //
  99.  * #define EXT_REGULAR         0
  100.  * #define EXT_MACOSFNDRINFO   1
  101.  * #define EXT_MACOSRESFORK    2
  102.  * #define EXT_XATTR           3
  103.  *
  104.  * // used for EA on tape
  105.  * #define EXT2_GOOD_OLD_INODE_SIZE    128
  106.  * #define EXT2_XATTR_MAGIC        0xEA020000  // block EA
  107.  * #define EXT2_XATTR_MAGIC2       0xEA020001  // in inode EA
  108.  * </pre>
  109.  * <p>
  110.  * The fields in <strong>bold</strong> are the same for all blocks. (This permitted multiple dumps to be written to a single tape.)
  111.  * </p>
  112.  *
  113.  * <p>
  114.  * The C structure for the inode (file) information is:
  115.  *
  116.  * <pre>
  117.  * struct bsdtimeval {           //  **** alpha-*-linux is deviant
  118.  *   __u32   tv_sec;
  119.  *   __u32   tv_usec;
  120.  * };
  121.  *
  122.  * #define NDADDR      12
  123.  * #define NIADDR       3
  124.  *
  125.  * //
  126.  * // This is the new (4.4) BSD inode structure
  127.  * // copied from the FreeBSD 2.0 &lt;ufs/ufs/dinode.h&gt; include file
  128.  * //
  129.  * struct new_bsd_inode {
  130.  *   __u16       di_mode;           // file type, standard Unix permissions
  131.  *   __s16       di_nlink;          // number of hard links to file.
  132.  *   union {
  133.  *      __u16       oldids[2];
  134.  *      __u32       inumber;
  135.  *   }           di_u;
  136.  *   u_quad_t    di_size;           // file size
  137.  *   struct bsdtimeval   di_atime;  // time file was last accessed
  138.  *   struct bsdtimeval   di_mtime;  // time file was last modified
  139.  *   struct bsdtimeval   di_ctime;  // time file was created
  140.  *   __u32       di_db[NDADDR];
  141.  *   __u32       di_ib[NIADDR];
  142.  *   __u32       di_flags;          //
  143.  *   __s32       di_blocks;         // number of disk blocks
  144.  *   __s32       di_gen;            // generation number
  145.  *   __u32       di_uid;            // user id (see /etc/passwd)
  146.  *   __u32       di_gid;            // group id (see /etc/group)
  147.  *   __s32       di_spare[2];       // unused
  148.  * };
  149.  * </pre>
  150.  * <p>
  151.  * 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
  152.  * physical file. You must read the contents of the directory entries to learn the mapping(s) from file name to inode.
  153.  * </p>
  154.  *
  155.  * <p>
  156.  * 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:
  157.  * </p>
  158.  *
  159.  * <pre>
  160.  * #define TP_BSIZE    1024
  161.  * #define TP_NINDIR   (TP_BSIZE/2)
  162.  *
  163.  * union u_data {
  164.  *   char    s_addrs[TP_NINDIR]; // 1 =&gt; data; 0 =&gt; hole in inode
  165.  *   int32_t s_inos[TP_NINOS];   // table of first inode on each volume
  166.  * } u_data;
  167.  * </pre>
  168.  *
  169.  * @NotThreadSafe
  170.  */
  171. public class DumpArchiveEntry implements ArchiveEntry {

  172.     /**
  173.      * Enumerates permissions with values.
  174.      */
  175.     public enum PERMISSION {
  176.         // Note: The arguments are octal values

  177.         /**
  178.          * Permission SETUID (octal value 04000).
  179.          */
  180.         SETUID(04000),

  181.         /**
  182.          * Permission SETGUI (octal value 02000).
  183.          */
  184.         SETGUI(02000),

  185.         /**
  186.          * Permission STICKY (octal value 01000).
  187.          */
  188.         STICKY(01000),

  189.         /**
  190.          * Permission USER_READ (octal value 00400).
  191.          */
  192.         USER_READ(00400),

  193.         /**
  194.          * Permission USER_WRITE (octal value 00200).
  195.          */
  196.         USER_WRITE(00200),

  197.         /**
  198.          * Permission USER_EXEC (octal value 00100).
  199.          */
  200.         USER_EXEC(00100),

  201.         /**
  202.          * Permission GROUP_READ (octal value 00040).
  203.          */
  204.         GROUP_READ(00040),

  205.         /**
  206.          * Permission GROUP_WRITE (octal value 00020).
  207.          */
  208.         GROUP_WRITE(00020),

  209.         /**
  210.          * Permission 00020 (octal value 00010).
  211.          */
  212.         GROUP_EXEC(00010),

  213.         /**
  214.          * Permission WORLD_READ (octal value 00004).
  215.          */
  216.         WORLD_READ(00004),

  217.         /**
  218.          * Permission WORLD_WRITE (octal value 00002).
  219.          */
  220.         WORLD_WRITE(00002),

  221.         /**
  222.          * Permission WORLD_EXEC (octal value 00001).
  223.          */
  224.         WORLD_EXEC(00001);

  225.         /**
  226.          * Finds a matching set of enumeration values for the given code.
  227.          *
  228.          * @param code a code.
  229.          * @return a Set of values, never null.
  230.          */
  231.         public static Set<PERMISSION> find(final int code) {
  232.             final Set<PERMISSION> set = new HashSet<>();
  233.             for (final PERMISSION p : values()) {
  234.                 if ((code & p.code) == p.code) {
  235.                     set.add(p);
  236.                 }
  237.             }
  238.             if (set.isEmpty()) {
  239.                 return Collections.emptySet();
  240.             }
  241.             return EnumSet.copyOf(set);
  242.         }

  243.         private final int code;

  244.         PERMISSION(final int code) {
  245.             this.code = code;
  246.         }
  247.     }

  248.     /**
  249.      * Archive entry as stored on tape. There is one TSH for (at most) every 512k in the file.
  250.      */
  251.     static final class TapeSegmentHeader {
  252.         private DumpArchiveConstants.SEGMENT_TYPE type;
  253.         private int volume;
  254.         private int ino;
  255.         private int count;
  256.         private int holes;
  257.         private final byte[] cdata = new byte[512]; // map of any 'holes'

  258.         public int getCdata(final int idx) {
  259.             return cdata[idx];
  260.         }

  261.         public int getCount() {
  262.             return count;
  263.         }

  264.         public int getHoles() {
  265.             return holes;
  266.         }

  267.         public int getIno() {
  268.             return ino;
  269.         }

  270.         public DumpArchiveConstants.SEGMENT_TYPE getType() {
  271.             return type;
  272.         }

  273.         public int getVolume() {
  274.             return volume;
  275.         }

  276.         void setIno(final int ino) {
  277.             this.ino = ino;
  278.         }
  279.     }

  280.     /**
  281.      * Enumerates types.
  282.      */
  283.     public enum TYPE {

  284.         /**
  285.          * WHITEOUT with code 14.
  286.          */
  287.         WHITEOUT(14),

  288.         /**
  289.          * SOCKET with code 12.
  290.          */
  291.         SOCKET(12),

  292.         /**
  293.          * LINK with code 10.
  294.          */
  295.         LINK(10),

  296.         /**
  297.          * FILE with code 8.
  298.          */
  299.         FILE(8),

  300.         /**
  301.          * BLKDEV with code 6.
  302.          */
  303.         BLKDEV(6),

  304.         /**
  305.          * DIRECTORY with code 4.
  306.          */
  307.         DIRECTORY(4),

  308.         /**
  309.          * CHRDEV with code 2.
  310.          */
  311.         CHRDEV(2),

  312.         /**
  313.          * CHRDEV with code 1.
  314.          */
  315.         FIFO(1),

  316.         /**
  317.          * UNKNOWN with code 15.
  318.          */
  319.         UNKNOWN(15);

  320.         /**
  321.          * Finds a matching enumeration value for the given code.
  322.          *
  323.          * @param code a code.
  324.          * @return a value, never null.
  325.          */
  326.         public static TYPE find(final int code) {
  327.             TYPE type = UNKNOWN;
  328.             for (final TYPE t : values()) {
  329.                 if (code == t.code) {
  330.                     type = t;
  331.                 }
  332.             }
  333.             return type;
  334.         }

  335.         private final int code;

  336.         TYPE(final int code) {
  337.             this.code = code;
  338.         }
  339.     }

  340.     /**
  341.      * Populate the dump archive entry and tape segment header with the contents of the buffer.
  342.      *
  343.      * @param buffer buffer to read content from
  344.      */
  345.     static DumpArchiveEntry parse(final byte[] buffer) {
  346.         final DumpArchiveEntry entry = new DumpArchiveEntry();
  347.         final TapeSegmentHeader header = entry.header;

  348.         header.type = DumpArchiveConstants.SEGMENT_TYPE.find(DumpArchiveUtil.convert32(buffer, 0));

  349.         // header.dumpDate = new Date(1000L * DumpArchiveUtil.convert32(buffer, 4));
  350.         // header.previousDumpDate = new Date(1000L * DumpArchiveUtil.convert32(
  351.         // buffer, 8));
  352.         header.volume = DumpArchiveUtil.convert32(buffer, 12);
  353.         // header.tapea = DumpArchiveUtil.convert32(buffer, 16);
  354.         entry.ino = header.ino = DumpArchiveUtil.convert32(buffer, 20);

  355.         // header.magic = DumpArchiveUtil.convert32(buffer, 24);
  356.         // header.checksum = DumpArchiveUtil.convert32(buffer, 28);
  357.         final int m = DumpArchiveUtil.convert16(buffer, 32);

  358.         // determine the type of the file.
  359.         entry.setType(TYPE.find(m >> 12 & 0x0F));

  360.         // determine the standard permissions
  361.         entry.setMode(m);

  362.         entry.nlink = DumpArchiveUtil.convert16(buffer, 34);
  363.         // inumber, oldids?
  364.         entry.setSize(DumpArchiveUtil.convert64(buffer, 40));

  365.         long t = 1000L * DumpArchiveUtil.convert32(buffer, 48) + DumpArchiveUtil.convert32(buffer, 52) / 1000;
  366.         entry.setAccessTime(new Date(t));
  367.         t = 1000L * DumpArchiveUtil.convert32(buffer, 56) + DumpArchiveUtil.convert32(buffer, 60) / 1000;
  368.         entry.setLastModifiedDate(new Date(t));
  369.         t = 1000L * DumpArchiveUtil.convert32(buffer, 64) + DumpArchiveUtil.convert32(buffer, 68) / 1000;
  370.         entry.ctime = t;

  371.         // db: 72-119 - direct blocks
  372.         // id: 120-131 - indirect blocks
  373.         // entry.flags = DumpArchiveUtil.convert32(buffer, 132);
  374.         // entry.blocks = DumpArchiveUtil.convert32(buffer, 136);
  375.         entry.generation = DumpArchiveUtil.convert32(buffer, 140);
  376.         entry.setUserId(DumpArchiveUtil.convert32(buffer, 144));
  377.         entry.setGroupId(DumpArchiveUtil.convert32(buffer, 148));
  378.         // two 32-bit spare values.
  379.         header.count = DumpArchiveUtil.convert32(buffer, 160);

  380.         header.holes = 0;

  381.         for (int i = 0; i < 512 && i < header.count; i++) {
  382.             if (buffer[164 + i] == 0) {
  383.                 header.holes++;
  384.             }
  385.         }

  386.         System.arraycopy(buffer, 164, header.cdata, 0, 512);

  387.         entry.volume = header.getVolume();

  388.         // entry.isSummaryOnly = false;
  389.         return entry;
  390.     }

  391.     private String name;
  392.     private TYPE type = TYPE.UNKNOWN;
  393.     private int mode;
  394.     private Set<PERMISSION> permissions = Collections.emptySet();
  395.     private long size;

  396.     private long atime;

  397.     private long mtime;
  398.     private int uid;
  399.     private int gid;

  400.     /**
  401.      * Currently unused
  402.      */
  403.     private final DumpArchiveSummary summary = null;

  404.     /**
  405.      * This value is available from the standard index.
  406.      */
  407.     private final TapeSegmentHeader header = new TapeSegmentHeader();
  408.     private String simpleName;
  409.     private String originalName;

  410.     /**
  411.      * This value is available from the QFA index.
  412.      */
  413.     private int volume;
  414.     private long offset;
  415.     private int ino;

  416.     private int nlink;

  417.     private long ctime;

  418.     private int generation;

  419.     private boolean isDeleted;

  420.     /**
  421.      * Constructs a default instance.
  422.      */
  423.     public DumpArchiveEntry() {
  424.     }

  425.     /**
  426.      * Constructs a new instance with only names.
  427.      *
  428.      * @param name       path name
  429.      * @param simpleName actual file name.
  430.      */
  431.     public DumpArchiveEntry(final String name, final String simpleName) {
  432.         setName(name);
  433.         this.simpleName = simpleName;
  434.     }

  435.     /**
  436.      * Constructs a new instance with name, inode and type.
  437.      *
  438.      * @param name       the name
  439.      * @param simpleName the simple name
  440.      * @param ino        the ino
  441.      * @param type       the type
  442.      */
  443.     protected DumpArchiveEntry(final String name, final String simpleName, final int ino, final TYPE type) {
  444.         setType(type);
  445.         setName(name);
  446.         this.simpleName = simpleName;
  447.         this.ino = ino;
  448.         this.offset = 0;
  449.     }

  450.     @Override
  451.     public boolean equals(final Object o) {
  452.         if (o == this) {
  453.             return true;
  454.         }
  455.         if (o == null || !o.getClass().equals(getClass())) {
  456.             return false;
  457.         }

  458.         final DumpArchiveEntry rhs = (DumpArchiveEntry) o;

  459.         if (ino != rhs.ino) {
  460.             return false;
  461.         }

  462.         // summary is always null right now, but this may change some day
  463.         if (summary == null && rhs.summary != null // NOSONAR
  464.                 || summary != null && !summary.equals(rhs.summary)) { // NOSONAR
  465.             return false;
  466.         }

  467.         return true;
  468.     }

  469.     /**
  470.      * Returns the time the file was last accessed.
  471.      *
  472.      * @return the access time
  473.      */
  474.     public Date getAccessTime() {
  475.         return new Date(atime);
  476.     }

  477.     /**
  478.      * Gets file creation time.
  479.      *
  480.      * @return the creation time
  481.      */
  482.     public Date getCreationTime() {
  483.         return new Date(ctime);
  484.     }

  485.     /**
  486.      * Returns the size of the entry as read from the archive.
  487.      */
  488.     long getEntrySize() {
  489.         return size;
  490.     }

  491.     /**
  492.      * Gets the generation of the file.
  493.      *
  494.      * @return the generation
  495.      */
  496.     public int getGeneration() {
  497.         return generation;
  498.     }

  499.     /**
  500.      * Gets the group id
  501.      *
  502.      * @return the group id
  503.      */
  504.     public int getGroupId() {
  505.         return gid;
  506.     }

  507.     /**
  508.      * Gets the number of records in this segment.
  509.      *
  510.      * @return the number of records
  511.      */
  512.     public int getHeaderCount() {
  513.         return header.getCount();
  514.     }

  515.     /**
  516.      * Gets the number of sparse records in this segment.
  517.      *
  518.      * @return the number of sparse records
  519.      */
  520.     public int getHeaderHoles() {
  521.         return header.getHoles();
  522.     }

  523.     /**
  524.      * Gets the type of the tape segment header.
  525.      *
  526.      * @return the segment header
  527.      */
  528.     public DumpArchiveConstants.SEGMENT_TYPE getHeaderType() {
  529.         return header.getType();
  530.     }

  531.     /**
  532.      * Returns the ino of the entry.
  533.      *
  534.      * @return the ino
  535.      */
  536.     public int getIno() {
  537.         return header.getIno();
  538.     }

  539.     /**
  540.      * The last modified date.
  541.      *
  542.      * @return the last modified date
  543.      */
  544.     @Override
  545.     public Date getLastModifiedDate() {
  546.         return new Date(mtime);
  547.     }

  548.     /**
  549.      * Gets the access permissions on the entry.
  550.      *
  551.      * @return the access permissions
  552.      */
  553.     public int getMode() {
  554.         return mode;
  555.     }

  556.     /**
  557.      * Returns the name of the entry.
  558.      *
  559.      * <p>
  560.      * This method returns the raw name as it is stored inside of the archive.
  561.      * </p>
  562.      *
  563.      * @return the name of the entry.
  564.      */
  565.     @Override
  566.     public String getName() {
  567.         return name;
  568.     }

  569.     /**
  570.      * Gets the number of hard links to the entry.
  571.      *
  572.      * @return the number of hard links
  573.      */
  574.     public int getNlink() {
  575.         return nlink;
  576.     }

  577.     /**
  578.      * Gets the offset within the archive
  579.      *
  580.      * @return the offset
  581.      */
  582.     public long getOffset() {
  583.         return offset;
  584.     }

  585.     /**
  586.      * Returns the unmodified name of the entry.
  587.      *
  588.      * @return the name of the entry.
  589.      */
  590.     String getOriginalName() {
  591.         return originalName;
  592.     }

  593.     /**
  594.      * Returns the permissions on the entry.
  595.      *
  596.      * @return the permissions
  597.      */
  598.     public Set<PERMISSION> getPermissions() {
  599.         return permissions;
  600.     }

  601.     /**
  602.      * Returns the path of the entry.
  603.      *
  604.      * @return the path of the entry.
  605.      */
  606.     public String getSimpleName() {
  607.         return simpleName;
  608.     }

  609.     /**
  610.      * Returns the size of the entry.
  611.      *
  612.      * @return the size
  613.      */
  614.     @Override
  615.     public long getSize() {
  616.         return isDirectory() ? SIZE_UNKNOWN : size;
  617.     }

  618.     /**
  619.      * Gets the type of the entry.
  620.      *
  621.      * @return the type
  622.      */
  623.     public TYPE getType() {
  624.         return type;
  625.     }

  626.     /**
  627.      * Gets the user id.
  628.      *
  629.      * @return the user id
  630.      */
  631.     public int getUserId() {
  632.         return uid;
  633.     }

  634.     /**
  635.      * Gets the tape volume where this file is located.
  636.      *
  637.      * @return the volume
  638.      */
  639.     public int getVolume() {
  640.         return volume;
  641.     }

  642.     @Override
  643.     public int hashCode() {
  644.         return ino;
  645.     }

  646.     /**
  647.      * Tests whether this is a block device.
  648.      *
  649.      * @return whether this is a block device.
  650.      */
  651.     public boolean isBlkDev() {
  652.         return type == TYPE.BLKDEV;
  653.     }

  654.     /**
  655.      * Tests whether this is a character device.
  656.      *
  657.      * @return whether this is a character device
  658.      */
  659.     public boolean isChrDev() {
  660.         return type == TYPE.CHRDEV;
  661.     }

  662.     /**
  663.      * Tests whether this file been deleted.
  664.      * For valid on incremental dumps.
  665.      *
  666.      * @return whether the file has been deleted.
  667.      */
  668.     public boolean isDeleted() {
  669.         return isDeleted;
  670.     }

  671.     /**
  672.      * Tests whether this is a directory.
  673.      *
  674.      * @return whether this is a directory
  675.      */
  676.     @Override
  677.     public boolean isDirectory() {
  678.         return type == TYPE.DIRECTORY;
  679.     }

  680.     /**
  681.      * Tests whether whether this is a fifo/pipe.
  682.      *
  683.      * @return whether this is a fifo/pipe.
  684.      */
  685.     public boolean isFifo() {
  686.         return type == TYPE.FIFO;
  687.     }

  688.     /**
  689.      * Tests whether this is a regular file.
  690.      *
  691.      * @return whether this is a regular file.
  692.      */
  693.     public boolean isFile() {
  694.         return type == TYPE.FILE;
  695.     }

  696.     /**
  697.      * Tests whether this is a socket.
  698.      *
  699.      * @return whether this is a socket.
  700.      */
  701.     public boolean isSocket() {
  702.         return type == TYPE.SOCKET;
  703.     }

  704.     /**
  705.      * Tests whether this is a sparse record.
  706.      *
  707.      * @param idx index of the record to check.
  708.      * @return whether this is a sparse record.
  709.      */
  710.     public boolean isSparseRecord(final int idx) {
  711.         return (header.getCdata(idx) & 0x01) == 0;
  712.     }

  713.     /**
  714.      * Sets the time the file was last accessed.
  715.      *
  716.      * @param atime the access time
  717.      */
  718.     public void setAccessTime(final Date atime) {
  719.         this.atime = atime.getTime();
  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.      * Sets whether this file has been deleted.
  731.      *
  732.      * @param isDeleted whether the file has been deleted
  733.      */
  734.     public void setDeleted(final boolean isDeleted) {
  735.         this.isDeleted = isDeleted;
  736.     }

  737.     /**
  738.      * Sets the generation of the file.
  739.      *
  740.      * @param generation the generation
  741.      */
  742.     public void setGeneration(final int generation) {
  743.         this.generation = generation;
  744.     }

  745.     /**
  746.      * Sets the group id.
  747.      *
  748.      * @param gid the group id
  749.      */
  750.     public void setGroupId(final int gid) {
  751.         this.gid = gid;
  752.     }

  753.     /**
  754.      * Sets the time the file was last modified.
  755.      *
  756.      * @param mtime the last modified time
  757.      */
  758.     public void setLastModifiedDate(final Date mtime) {
  759.         this.mtime = mtime.getTime();
  760.     }

  761.     /**
  762.      * Sets the access permissions on the entry.
  763.      *
  764.      * @param mode the access permissions
  765.      */
  766.     public void setMode(final int mode) {
  767.         this.mode = mode & 07777;
  768.         this.permissions = PERMISSION.find(mode);
  769.     }

  770.     /**
  771.      * Sets the name of the entry.
  772.      *
  773.      * @param name the name
  774.      */
  775.     public final void setName(String name) {
  776.         this.originalName = name;
  777.         if (name != null) {
  778.             if (isDirectory() && !name.endsWith("/")) {
  779.                 name += "/";
  780.             }
  781.             if (name.startsWith("./")) {
  782.                 name = name.substring(2);
  783.             }
  784.         }
  785.         this.name = name;
  786.     }

  787.     /**
  788.      * Sets the number of hard links.
  789.      *
  790.      * @param nlink the number of hard links
  791.      */
  792.     public void setNlink(final int nlink) {
  793.         this.nlink = nlink;
  794.     }

  795.     /**
  796.      * Sets the offset within the archive.
  797.      *
  798.      * @param offset the offset
  799.      */
  800.     public void setOffset(final long offset) {
  801.         this.offset = offset;
  802.     }

  803.     /**
  804.      * Sets the path of the entry.
  805.      *
  806.      * @param simpleName the simple name
  807.      */
  808.     protected void setSimpleName(final String simpleName) {
  809.         this.simpleName = simpleName;
  810.     }

  811.     /**
  812.      * Sets the size of the entry.
  813.      *
  814.      * @param size the size
  815.      */
  816.     public void setSize(final long size) {
  817.         this.size = size;
  818.     }

  819.     /**
  820.      * Sets the type of the entry.
  821.      *
  822.      * @param type the type
  823.      */
  824.     public void setType(final TYPE type) {
  825.         this.type = type;
  826.     }

  827.     /**
  828.      * Sets the user id.
  829.      *
  830.      * @param uid the user id
  831.      */
  832.     public void setUserId(final int uid) {
  833.         this.uid = uid;
  834.     }

  835.     /**
  836.      * Sets the tape volume.
  837.      *
  838.      * @param volume the volume
  839.      */
  840.     public void setVolume(final int volume) {
  841.         this.volume = volume;
  842.     }

  843.     @Override
  844.     public String toString() {
  845.         return getName();
  846.     }

  847.     /**
  848.      * Update entry with information from next tape segment header.
  849.      */
  850.     void update(final byte[] buffer) {
  851.         header.volume = DumpArchiveUtil.convert32(buffer, 16);
  852.         header.count = DumpArchiveUtil.convert32(buffer, 160);

  853.         header.holes = 0;

  854.         for (int i = 0; i < 512 && i < header.count; i++) {
  855.             if (buffer[164 + i] == 0) {
  856.                 header.holes++;
  857.             }
  858.         }

  859.         System.arraycopy(buffer, 164, header.cdata, 0, 512);
  860.     }
  861. }