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