    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.cpio;
    020
    021import java.io.File;
    022import java.io.IOException;
    023import java.nio.charset.Charset;
    024import java.nio.file.Files;
    025import java.nio.file.LinkOption;
    026import java.nio.file.Path;
    027import java.nio.file.attribute.FileTime;
    028import java.util.Date;
    029import java.util.Objects;
    030import java.util.concurrent.TimeUnit;
    031
    032import org.apache.commons.compress.archivers.ArchiveEntry;
    033
    034/**
    035 * A cpio archive consists of a sequence of files. There are several types of
    036 * headers defined in two categories of new and old format. The headers are
    037 * recognized by magic numbers:
    038 *
    039 * <ul>
    040 * <li>"070701" ASCII for new portable format</li>
    041 * <li>"070702" ASCII for new portable format with CRC</li>
    042 * <li>"070707" ASCII for old ascii (also known as Portable ASCII, odc or old
    043 * character format</li>
    044 * <li>070707 binary for old binary</li>
    045 * </ul>
    046 *
    047 * <p>The old binary format is limited to 16 bits for user id, group
    048 * id, device, and inode numbers. It is limited to 4 gigabyte file
    049 * sizes.
    050 *
    051 * The old ASCII format is limited to 18 bits for the user id, group
    052 * id, device, and inode numbers. It is limited to 8 gigabyte file
    053 * sizes.
    054 *
    055 * The new ASCII format is limited to 4 gigabyte file sizes.
    056 *
    057 * CPIO 2.5 knows also about tar, but it is not recognized here.</p>
    058 *
    059 *
    060 * <h2>OLD FORMAT</h2>
    061 *
    062 * <p>Each file has a 76 (ascii) / 26 (binary) byte header, a variable
    063 * length, NUL terminated file name, and variable length file data. A
    064 * header for a file name "TRAILER!!!" indicates the end of the
    065 * archive.</p>
    066 *
    067 * <p>All the fields in the header are ISO 646 (approximately ASCII)
    068 * strings of octal numbers, left padded, not NUL terminated.</p>
    069 *
    070 * <pre>
    071 * FIELDNAME        NOTES
    072 * c_magic          The integer value octal 070707.  This value can be used to deter-
    073 *                  mine whether this archive is written with little-endian or big-
    074 *                  endian integers.
    075 * c_dev            Device that contains a directory entry for this file
    076 * c_ino            I-node number that identifies the input file to the file system
    077 * c_mode           The mode specifies both the regular permissions and the file type.
    078 * c_uid            Numeric User ID of the owner of the input file
    079 * c_gid            Numeric Group ID of the owner of the input file
    080 * c_nlink          Number of links that are connected to the input file
    081 * c_rdev           For block special and character special entries, this field
    082 *                  contains the associated device number.  For all other entry types,
    083 *                  it should be set to zero by writers and ignored by readers.
    084 * c_mtime[2]       Modification time of the file, indicated as the number of seconds
    085 *                  since the start of the epoch, 00:00:00 UTC January 1, 1970.  The
    086 *                  four-byte integer is stored with the most-significant 16 bits
    087 *                  first followed by the least-significant 16 bits.  Each of the two
    088 *                  16 bit values are stored in machine-native byte order.
    089 * c_namesize       Length of the path name, including the terminating null byte
    090 * c_filesize[2]    Length of the file in bytes. This is the length of the data
    091 *                  section that follows the header structure. Must be 0 for
    092 *                  FIFOs and directories
    093 *
    094 * All fields are unsigned short fields with 16-bit integer values
    095 * apart from c_mtime and c_filesize which are 32-bit integer values
    096 * </pre>
    097 *
    098 * <p>If necessary, the file name and file data are padded with a NUL byte to an even length</p>
    099 *
    100 * <p>Special files, directories, and the trailer are recorded with
    101 * the h_filesize field equal to 0.</p>
    102 *
    103 * <p>In the ASCII version of this format, the 16-bit entries are represented as 6-byte octal numbers,
    104 * and the 32-bit entries are represented as 11-byte octal numbers. No padding is added.</p>
    105 *
    106 * <h3>NEW FORMAT</h3>
    107 *
    108 * <p>Each file has a 110 byte header, a variable length, NUL
    109 * terminated file name, and variable length file data. A header for a
    110 * file name "TRAILER!!!" indicates the end of the archive. All the
    111 * fields in the header are ISO 646 (approximately ASCII) strings of
    112 * hexadecimal numbers, left padded, not NUL terminated.</p>
    113 *
    114 * <pre>
    115 * FIELDNAME        NOTES
    116 * c_magic[6]       The string 070701 for new ASCII, the string 070702 for new ASCII with CRC
    117 * c_ino[8]
    118 * c_mode[8]
    119 * c_uid[8]
    120 * c_gid[8]
    121 * c_nlink[8]
    122 * c_mtim[8]
    123 * c_filesize[8]    must be 0 for FIFOs and directories
    124 * c_maj[8]
    125 * c_min[8]
    126 * c_rmaj[8]        only valid for chr and blk special files
    127 * c_rmin[8]        only valid for chr and blk special files
    128 * c_namesize[8]    count includes terminating NUL in pathname
    129 * c_check[8]       0 for "new" portable format; for CRC format
    130 *                  the sum of all the bytes in the file
    131 * </pre>
    132 *
    133 * <p>New ASCII Format The "new" ASCII format uses 8-byte hexadecimal
    134 * fields for all numbers and separates device numbers into separate
    135 * fields for major and minor numbers.</p>
    136 *
    137 * <p>The pathname is followed by NUL bytes so that the total size of
    138 * the fixed header plus pathname is a multiple of four. Likewise, the
    139 * file data is padded to a multiple of four bytes.</p>
    140 *
    141 * <p>This class uses mutable fields and is not considered to be
    142 * threadsafe.</p>
    143 *
    144 * <p>Based on code from the jRPM project (http://jrpm.sourceforge.net).</p>
    145 *
    146 * <p>The MAGIC numbers and other constants are defined in {@link CpioConstants}</p>
    147 *
    148 * <p>
    149 * N.B. does not handle the cpio "tar" format
    150 * </p>
    151 * @NotThreadSafe
    152 * @see <a href="https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt">https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt</a>
    153 */
    154public class CpioArchiveEntry implements CpioConstants, ArchiveEntry {
    155
    156    // Header description fields - should be same throughout an archive
    157
    158    /**
    159     * See {@link #CpioArchiveEntry(short)} for possible values.
    160     */
    161    private final short fileFormat;
    162
    163    /** The number of bytes in each header record; depends on the file format */
    164    private final int headerSize;
    165
    166    /** The boundary to which the header and data elements are aligned: 0, 2 or 4 bytes */
    167    private final int alignmentBoundary;
    168
    169    // Header fields
    170
    171    private long chksum;
    172
    173    /** Number of bytes in the file */
    174    private long filesize;
    175
    176    private long gid;
    177
    178    private long inode;
    179
    180    private long maj;
    181
    182    private long min;
    183
    184    private long mode;
    185
    186    private long mtime;
    187
    188    private String name;
    189
    190    private long nlink;
    191
    192    private long rmaj;
    193
    194    private long rmin;
    195
    196    private long uid;
    197
    198    /**
    199     * Creates a CpioArchiveEntry with a specified format.
    200     *
    201     * @param format
    202     *            The cpio format for this entry.
    203     * <p>
    204     * Possible format values are:
    205     * <pre>
    206     * CpioConstants.FORMAT_NEW
    207     * CpioConstants.FORMAT_NEW_CRC
    208     * CpioConstants.FORMAT_OLD_BINARY
    209     * CpioConstants.FORMAT_OLD_ASCII
    210     * </pre>
    211     */
    212    public CpioArchiveEntry(final short format) {
    213        switch (format) {
    214        case FORMAT_NEW:
    215            this.headerSize = 110;
    216            this.alignmentBoundary = 4;
    217            break;
    218        case FORMAT_NEW_CRC:
    219            this.headerSize = 110;
    220            this.alignmentBoundary = 4;
    221            break;
    222        case FORMAT_OLD_ASCII:
    223            this.headerSize = 76;
    224            this.alignmentBoundary = 0;
    225            break;
    226        case FORMAT_OLD_BINARY:
    227            this.headerSize = 26;
    228            this.alignmentBoundary = 2;
    229            break;
    230        default:
    231            throw new IllegalArgumentException("Unknown header type");
    232        }
    233        this.fileFormat = format;
    234    }
    235
    236    /**
    237     * Creates a CpioArchiveEntry with a specified name. The format of
    238     * this entry will be the new format.
    239     *
    240     * @param name
    241     *            The name of this entry.
    242     */
    243    public CpioArchiveEntry(final String name) {
    244        this(FORMAT_NEW, name);
    245    }
    246
    247    /**
    248     * Creates a CpioArchiveEntry with a specified name.
    249     *
    250     * @param format
    251     *            The cpio format for this entry.
    252     * @param name
    253     *            The name of this entry.
    254     * <p>
    255     * Possible format values are:
    256     * <pre>
    257     * CpioConstants.FORMAT_NEW
    258     * CpioConstants.FORMAT_NEW_CRC
    259     * CpioConstants.FORMAT_OLD_BINARY
    260     * CpioConstants.FORMAT_OLD_ASCII
    261     * </pre>
    262     *
    263     * @since 1.1
    264     */
    265    public CpioArchiveEntry(final short format, final String name) {
    266        this(format);
    267        this.name = name;
    268    }
    269
    270    /**
    271     * Creates a CpioArchiveEntry with a specified name. The format of
    272     * this entry will be the new format.
    273     *
    274     * @param name
    275     *            The name of this entry.
    276     * @param size
    277     *            The size of this entry
    278     */
    279    public CpioArchiveEntry(final String name, final long size) {
    280        this(name);
    281        this.setSize(size);
    282    }
    283
    284    /**
    285     * Creates a CpioArchiveEntry with a specified name.
    286     *
    287     * @param format
    288     *            The cpio format for this entry.
    289     * @param name
    290     *            The name of this entry.
    291     * @param size
    292     *            The size of this entry
    293     * <p>
    294     * Possible format values are:
    295     * <pre>
    296     * CpioConstants.FORMAT_NEW
    297     * CpioConstants.FORMAT_NEW_CRC
    298     * CpioConstants.FORMAT_OLD_BINARY
    299     * CpioConstants.FORMAT_OLD_ASCII
    300     * </pre>
    301     *
    302     * @since 1.1
    303     */
    304    public CpioArchiveEntry(final short format, final String name,
    305                            final long size) {
    306        this(format, name);
    307        this.setSize(size);
    308    }
    309
    310    /**
    311     * Creates a CpioArchiveEntry with a specified name for a
    312     * specified file. The format of this entry will be the new
    313     * format.
    314     *
    315     * @param inputFile
    316     *            The file to gather information from.
    317     * @param entryName
    318     *            The name of this entry.
    319     */
    320    public CpioArchiveEntry(final File inputFile, final String entryName) {
    321        this(FORMAT_NEW, inputFile, entryName);
    322    }
    323
    324    /**
    325     * Creates a CpioArchiveEntry with a specified name for a
    326     * specified file. The format of this entry will be the new
    327     * format.
    328     *
    329     * @param inputPath
    330     *            The file to gather information from.
    331     * @param entryName
    332     *            The name of this entry.
    333     * @param options options indicating how symbolic links are handled.
    334     * @throws IOException if an I/O error occurs
    335     * @since 1.21
    336     */
    337    public CpioArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException {
    338        this(FORMAT_NEW, inputPath, entryName, options);
    339    }
    340
    341    /**
    342     * Creates a CpioArchiveEntry with a specified name for a
    343     * specified file.
    344     *
    345     * @param format
    346     *            The cpio format for this entry.
    347     * @param inputFile
    348     *            The file to gather information from.
    349     * @param entryName
    350     *            The name of this entry.
    351     * <p>
    352     * Possible format values are:
    353     * <pre>
    354     * CpioConstants.FORMAT_NEW
    355     * CpioConstants.FORMAT_NEW_CRC
    356     * CpioConstants.FORMAT_OLD_BINARY
    357     * CpioConstants.FORMAT_OLD_ASCII
    358     * </pre>
    359     *
    360     * @since 1.1
    361     */
    362    public CpioArchiveEntry(final short format, final File inputFile,
    363                            final String entryName) {
    364        this(format, entryName, inputFile.isFile() ? inputFile.length() : 0);
    365        if (inputFile.isDirectory()){
    366            setMode(C_ISDIR);
    367        } else if (inputFile.isFile()){
    368            setMode(C_ISREG);
    369        } else {
    370            throw new IllegalArgumentException("Cannot determine type of file "
    371                                               + inputFile.getName());
    372        }
    373        // TODO set other fields as needed
    374        setTime(inputFile.lastModified() / 1000);
    375    }
    376
    377    /**
    378     * Creates a CpioArchiveEntry with a specified name for a
    379     * specified path.
    380     *
    381     * @param format
    382     *            The cpio format for this entry.
    383     * @param inputPath
    384     *            The file to gather information from.
    385     * @param entryName
    386     *            The name of this entry.
    387     * <p>
    388     * Possible format values are:
    389     * <pre>
    390     * CpioConstants.FORMAT_NEW
    391     * CpioConstants.FORMAT_NEW_CRC
    392     * CpioConstants.FORMAT_OLD_BINARY
    393     * CpioConstants.FORMAT_OLD_ASCII
    394     * </pre>
    395     * @param options options indicating how symbolic links are handled.
    396     *
    397     * @throws IOException if an I/O error occurs
    398     * @since 1.21
    399     */
    400    public CpioArchiveEntry(final short format, final Path inputPath, final String entryName, final LinkOption... options)
    401        throws IOException {
    402        this(format, entryName, Files.isRegularFile(inputPath, options) ? Files.size(inputPath) : 0);
    403        if (Files.isDirectory(inputPath, options)) {
    404            setMode(C_ISDIR);
    405        } else if (Files.isRegularFile(inputPath, options)) {
    406            setMode(C_ISREG);
    407        } else {
    408            throw new IllegalArgumentException("Cannot determine type of file " + inputPath);
    409        }
    410        // TODO set other fields as needed
    411        setTime(Files.getLastModifiedTime(inputPath, options));
    412    }
    413
    414    /**
    415     * Checks if the method is allowed for the defined format.
    416     */
    417    private void checkNewFormat() {
    418        if ((this.fileFormat & FORMAT_NEW_MASK) == 0) {
    419            throw new UnsupportedOperationException();
    420        }
    421    }
    422
    423    /**
    424     * Checks if the method is allowed for the defined format.
    425     */
    426    private void checkOldFormat() {
    427        if ((this.fileFormat & FORMAT_OLD_MASK) == 0) {
    428            throw new UnsupportedOperationException();
    429        }
    430    }
    431
    432    /**
    433     * Gets the checksum.
    434     * Only supported for the new formats.
    435     *
    436     * @return Returns the checksum.
    437     * @throws UnsupportedOperationException if the format is not a new format
    438     */
    439    public long getChksum() {
    440        checkNewFormat();
    441        return this.chksum & 0xFFFFFFFFL;
    442    }
    443
    444    /**
    445     * Gets the device id.
    446     *
    447     * @return Returns the device id.
    448     * @throws UnsupportedOperationException
    449     *             if this method is called for a CpioArchiveEntry with a new
    450     *             format.
    451     */
    452    public long getDevice() {
    453        checkOldFormat();
    454        return this.min;
    455    }
    456
    457    /**
    458     * Gets the major device id.
    459     *
    460     * @return Returns the major device id.
    461     * @throws UnsupportedOperationException
    462     *             if this method is called for a CpioArchiveEntry with an old
    463     *             format.
    464     */
    465    public long getDeviceMaj() {
    466        checkNewFormat();
    467        return this.maj;
    468    }
    469
    470    /**
    471     * Gets the minor device id
    472     *
    473     * @return Returns the minor device id.
    474     * @throws UnsupportedOperationException if format is not a new format
    475     */
    476    public long getDeviceMin() {
    477        checkNewFormat();
    478        return this.min;
    479    }
    480
    481    /**
    482     * Gets the filesize.
    483     *
    484     * @return Returns the filesize.
    485     * @see org.apache.commons.compress.archivers.ArchiveEntry#getSize()
    486     */
    487    @Override
    488    public long getSize() {
    489        return this.filesize;
    490    }
    491
    492    /**
    493     * Gets the format for this entry.
    494     *
    495     * @return Returns the format.
    496     */
    497    public short getFormat() {
    498        return this.fileFormat;
    499    }
    500
    501    /**
    502     * Gets the group id.
    503     *
    504     * @return Returns the group id.
    505     */
    506    public long getGID() {
    507        return this.gid;
    508    }
    509
    510    /**
    511     * Gets the header size for this CPIO format
    512     *
    513     * @return Returns the header size in bytes.
    514     */
    515    public int getHeaderSize() {
    516        return this.headerSize;
    517    }
    518
    519    /**
    520     * Gets the alignment boundary for this CPIO format
    521     *
    522     * @return Returns the aligment boundary (0, 2, 4) in bytes
    523     */
    524    public int getAlignmentBoundary() {
    525        return this.alignmentBoundary;
    526    }
    527
    528    /**
    529     * Gets the number of bytes needed to pad the header to the alignment boundary.
    530     *
    531     * @deprecated This method doesn't properly work for multi-byte encodings. And
    532     *             creates corrupt archives. Use {@link #getHeaderPadCount(Charset)}
    533     *             or {@link #getHeaderPadCount(long)} in any case.
    534     * @return the number of bytes needed to pad the header (0,1,2,3)
    535     */
    536    @Deprecated
    537    public int getHeaderPadCount(){
    538        return getHeaderPadCount(null);
    539    }
    540
    541    /**
    542     * Gets the number of bytes needed to pad the header to the alignment boundary.
    543     *
    544     * @param charset
    545     *             The character set used to encode the entry name in the stream.
    546     * @return the number of bytes needed to pad the header (0,1,2,3)
    547     * @since 1.18
    548     */
    549    public int getHeaderPadCount(final Charset charset) {
    550        if (name == null) {
    551            return 0;
    552        }
    553        if (charset == null) {
    554            return getHeaderPadCount(name.length());
    555        }
    556        return getHeaderPadCount(name.getBytes(charset).length);
    557    }
    558
    559    /**
    560     * Gets the number of bytes needed to pad the header to the alignment boundary.
    561     *
    562     * @param namesize
    563     *            The length of the name in bytes, as read in the stream.
    564     *            Without the trailing zero byte.
    565     * @return the number of bytes needed to pad the header (0,1,2,3)
    566     *
    567     * @since 1.18
    568     */
    569    public int getHeaderPadCount(final long namesize) {
    570        if (this.alignmentBoundary == 0) { return 0; }
    571        int size = this.headerSize + 1;  // Name has terminating null
    572        if (name != null) {
    573            size += namesize;
    574        }
    575        final int remain = size % this.alignmentBoundary;
    576        if (remain > 0) {
    577            return this.alignmentBoundary - remain;
    578        }
    579        return 0;
    580    }
    581
    582    /**
    583     * Gets the number of bytes needed to pad the data to the alignment boundary.
    584     *
    585     * @return the number of bytes needed to pad the data (0,1,2,3)
    586     */
    587    public int getDataPadCount(){
    588        if (this.alignmentBoundary == 0) { return 0; }
    589        final long size = this.filesize;
    590        final int remain = (int) (size % this.alignmentBoundary);
    591        if (remain > 0){
    592            return this.alignmentBoundary - remain;
    593        }
    594        return 0;
    595    }
    596
    597    /**
    598     * Sets the inode.
    599     *
    600     * @return Returns the inode.
    601     */
    602    public long getInode() {
    603        return this.inode;
    604    }
    605
    606    /**
    607     * Gets the mode of this entry (e.g. directory, regular file).
    608     *
    609     * @return Returns the mode.
    610     */
    611    public long getMode() {
    612        return mode == 0 && !CPIO_TRAILER.equals(name) ? C_ISREG : mode;
    613    }
    614
    615    /**
    616     * Gets the name.
    617     *
    618     * <p>This method returns the raw name as it is stored inside of the archive.</p>
    619     *
    620     * @return Returns the name.
    621     */
    622    @Override
    623    public String getName() {
    624        return this.name;
    625    }
    626
    627    /**
    628     * Gets the number of links.
    629     *
    630     * @return Returns the number of links.
    631     */
    632    public long getNumberOfLinks() {
    633        return nlink == 0 ?
    634            isDirectory() ? 2 : 1
    635            : nlink;
    636    }
    637
    638    /**
    639     * Gets the remote device id.
    640     *
    641     * @return Returns the remote device id.
    642     * @throws UnsupportedOperationException
    643     *             if this method is called for a CpioArchiveEntry with a new
    644     *             format.
    645     */
    646    public long getRemoteDevice() {
    647        checkOldFormat();
    648        return this.rmin;
    649    }
    650
    651    /**
    652     * Gets the remote major device id.
    653     *
    654     * @return Returns the remote major device id.
    655     * @throws UnsupportedOperationException
    656     *             if this method is called for a CpioArchiveEntry with an old
    657     *             format.
    658     */
    659    public long getRemoteDeviceMaj() {
    660        checkNewFormat();
    661        return this.rmaj;
    662    }
    663
    664    /**
    665     * Gets the remote minor device id.
    666     *
    667     * @return Returns the remote minor device id.
    668     * @throws UnsupportedOperationException
    669     *             if this method is called for a CpioArchiveEntry with an old
    670     *             format.
    671     */
    672    public long getRemoteDeviceMin() {
    673        checkNewFormat();
    674        return this.rmin;
    675    }
    676
    677    /**
    678     * Gets the time in seconds.
    679     *
    680     * @return Returns the time.
    681     */
    682    public long getTime() {
    683        return this.mtime;
    684    }
    685
    686    @Override
    687    public Date getLastModifiedDate() {
    688        return new Date(1000 * getTime());
    689    }
    690
    691    /**
    692     * Gets the user id.
    693     *
    694     * @return Returns the user id.
    695     */
    696    public long getUID() {
    697        return this.uid;
    698    }
    699
    700    /**
    701     * Checks if this entry represents a block device.
    702     *
    703     * @return TRUE if this entry is a block device.
    704     */
    705    public boolean isBlockDevice() {
    706        return CpioUtil.fileType(mode) == C_ISBLK;
    707    }
    708
    709    /**
    710     * Checks if this entry represents a character device.
    711     *
    712     * @return TRUE if this entry is a character device.
    713     */
    714    public boolean isCharacterDevice() {
    715        return CpioUtil.fileType(mode) == C_ISCHR;
    716    }
    717
    718    /**
    719     * Checks if this entry represents a directory.
    720     *
    721     * @return TRUE if this entry is a directory.
    722     */
    723    @Override
    724    public boolean isDirectory() {
    725        return CpioUtil.fileType(mode) == C_ISDIR;
    726    }
    727
    728    /**
    729     * Checks if this entry represents a network device.
    730     *
    731     * @return TRUE if this entry is a network device.
    732     */
    733    public boolean isNetwork() {
    734        return CpioUtil.fileType(mode) == C_ISNWK;
    735    }
    736
    737    /**
    738     * Checks if this entry represents a pipe.
    739     *
    740     * @return TRUE if this entry is a pipe.
    741     */
    742    public boolean isPipe() {
    743        return CpioUtil.fileType(mode) == C_ISFIFO;
    744    }
    745
    746    /**
    747     * Checks if this entry represents a regular file.
    748     *
    749     * @return TRUE if this entry is a regular file.
    750     */
    751    public boolean isRegularFile() {
    752        return CpioUtil.fileType(mode) == C_ISREG;
    753    }
    754
    755    /**
    756     * Checks if this entry represents a socket.
    757     *
    758     * @return TRUE if this entry is a socket.
    759     */
    760    public boolean isSocket() {
    761        return CpioUtil.fileType(mode) == C_ISSOCK;
    762    }
    763
    764    /**
    765     * Checks if this entry represents a symbolic link.
    766     *
    767     * @return TRUE if this entry is a symbolic link.
    768     */
    769    public boolean isSymbolicLink() {
    770        return CpioUtil.fileType(mode) == C_ISLNK;
    771    }
    772
    773    /**
    774     * Sets the checksum. The checksum is calculated by adding all bytes of a
    775     * file to transfer (crc += buf[pos] &amp; 0xFF).
    776     *
    777     * @param chksum
    778     *            The checksum to set.
    779     */
    780    public void setChksum(final long chksum) {
    781        checkNewFormat();
    782        this.chksum = chksum & 0xFFFFFFFFL;
    783    }
    784
    785    /**
    786     * Sets the device id.
    787     *
    788     * @param device
    789     *            The device id to set.
    790     * @throws UnsupportedOperationException
    791     *             if this method is called for a CpioArchiveEntry with a new
    792     *             format.
    793     */
    794    public void setDevice(final long device) {
    795        checkOldFormat();
    796        this.min = device;
    797    }
    798
    799    /**
    800     * Sets major device id.
    801     *
    802     * @param maj
    803     *            The major device id to set.
    804     */
    805    public void setDeviceMaj(final long maj) {
    806        checkNewFormat();
    807        this.maj = maj;
    808    }
    809
    810    /**
    811     * Sets the minor device id
    812     *
    813     * @param min
    814     *            The minor device id to set.
    815     */
    816    public void setDeviceMin(final long min) {
    817        checkNewFormat();
    818        this.min = min;
    819    }
    820
    821    /**
    822     * Sets the filesize.
    823     *
    824     * @param size
    825     *            The filesize to set.
    826     */
    827    public void setSize(final long size) {
    828        if (size < 0 || size > 0xFFFFFFFFL) {
    829            throw new IllegalArgumentException("Invalid entry size <" + size
    830                                               + ">");
    831        }
    832        this.filesize = size;
    833    }
    834
    835    /**
    836     * Sets the group id.
    837     *
    838     * @param gid
    839     *            The group id to set.
    840     */
    841    public void setGID(final long gid) {
    842        this.gid = gid;
    843    }
    844
    845    /**
    846     * Sets the inode.
    847     *
    848     * @param inode
    849     *            The inode to set.
    850     */
    851    public void setInode(final long inode) {
    852        this.inode = inode;
    853    }
    854
    855    /**
    856     * Sets the mode of this entry (e.g. directory, regular file).
    857     *
    858     * @param mode
    859     *            The mode to set.
    860     */
    861    public void setMode(final long mode) {
    862        final long maskedMode = mode & S_IFMT;
    863        switch ((int) maskedMode) {
    864        case C_ISDIR:
    865        case C_ISLNK:
    866        case C_ISREG:
    867        case C_ISFIFO:
    868        case C_ISCHR:
    869        case C_ISBLK:
    870        case C_ISSOCK:
    871        case C_ISNWK:
    872            break;
    873        default:
    874            throw new IllegalArgumentException(
    875                                               "Unknown mode. "
    876                                               + "Full: " + Long.toHexString(mode)
    877                                               + " Masked: " + Long.toHexString(maskedMode));
    878        }
    879
    880        this.mode = mode;
    881    }
    882
    883    /**
    884     * Sets the name.
    885     *
    886     * @param name
    887     *            The name to set.
    888     */
    889    public void setName(final String name) {
    890        this.name = name;
    891    }
    892
    893    /**
    894     * Sets the number of links.
    895     *
    896     * @param nlink
    897     *            The number of links to set.
    898     */
    899    public void setNumberOfLinks(final long nlink) {
    900        this.nlink = nlink;
    901    }
    902
    903    /**
    904     * Sets the remote device id.
    905     *
    906     * @param device
    907     *            The remote device id to set.
    908     * @throws UnsupportedOperationException
    909     *             if this method is called for a CpioArchiveEntry with a new
    910     *             format.
    911     */
    912    public void setRemoteDevice(final long device) {
    913        checkOldFormat();
    914        this.rmin = device;
    915    }
    916
    917    /**
    918     * Sets the remote major device id.
    919     *
    920     * @param rmaj
    921     *            The remote major device id to set.
    922     * @throws UnsupportedOperationException
    923     *             if this method is called for a CpioArchiveEntry with an old
    924     *             format.
    925     */
    926    public void setRemoteDeviceMaj(final long rmaj) {
    927        checkNewFormat();
    928        this.rmaj = rmaj;
    929    }
    930
    931    /**
    932     * Sets the remote minor device id.
    933     *
    934     * @param rmin
    935     *            The remote minor device id to set.
    936     * @throws UnsupportedOperationException
    937     *             if this method is called for a CpioArchiveEntry with an old
    938     *             format.
    939     */
    940    public void setRemoteDeviceMin(final long rmin) {
    941        checkNewFormat();
    942        this.rmin = rmin;
    943    }
    944
    945    /**
    946     * Sets the time in seconds.
    947     *
    948     * @param time
    949     *            The time to set.
    950     */
    951    public void setTime(final long time) {
    952        this.mtime = time;
    953    }
    954
    955    /**
    956     * Sets the time.
    957     *
    958     * @param time
    959     *            The time to set.
    960     */
    961    public void setTime(final FileTime time) {
    962        this.mtime = time.to(TimeUnit.SECONDS);
    963    }
    964
    965    /**
    966     * Sets the user id.
    967     *
    968     * @param uid
    969     *            The user id to set.
    970     */
    971    public void setUID(final long uid) {
    972        this.uid = uid;
    973    }
    974
    975    /* (non-Javadoc)
    976     * @see java.lang.Object#hashCode()
    977     */
    978    @Override
    979    public int hashCode() {
    980        return Objects.hash(name);
    981    }
    982
    983    /* (non-Javadoc)
    984     * @see java.lang.Object#equals(java.lang.Object)
    985     */
    986    @Override
    987    public boolean equals(final Object obj) {
    988        if (this == obj) {
    989            return true;
    990        }
    991        if (obj == null || getClass() != obj.getClass()) {
    992            return false;
    993        }
    994        final CpioArchiveEntry other = (CpioArchiveEntry) obj;
    995        if (name == null) {
    996            return other.name == null;
    997        }
    998        return name.equals(other.name);
    999    }
    1000}