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