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