CpioArchiveEntry.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  * 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. import java.io.File;
  21. import java.io.IOException;
  22. import java.nio.charset.Charset;
  23. import java.nio.file.Files;
  24. import java.nio.file.LinkOption;
  25. import java.nio.file.Path;
  26. import java.nio.file.attribute.FileTime;
  27. import java.util.Date;
  28. import java.util.Objects;

  29. import org.apache.commons.compress.archivers.ArchiveEntry;
  30. import org.apache.commons.compress.utils.ExactMath;
  31. import org.apache.commons.compress.utils.TimeUtils;

  32. /**
  33.  * 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
  34.  * recognized by magic numbers:
  35.  *
  36.  * <ul>
  37.  * <li>"070701" ASCII for new portable format</li>
  38.  * <li>"070702" ASCII for new portable format with CRC</li>
  39.  * <li>"070707" ASCII for old ASCII (also known as Portable ASCII, odc or old character format</li>
  40.  * <li>070707 binary for old binary</li>
  41.  * </ul>
  42.  *
  43.  * <p>
  44.  * 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.
  45.  *
  46.  * 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.
  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.
  51.  * </p>
  52.  *
  53.  *
  54.  * <h2>OLD FORMAT</h2>
  55.  *
  56.  * <p>
  57.  * 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
  58.  * "TRAILER!!!" indicates the end of the archive.
  59.  * </p>
  60.  *
  61.  * <p>
  62.  * All the fields in the header are ISO 646 (approximately ASCII) strings of octal numbers, left padded, not NUL terminated.
  63.  * </p>
  64.  *
  65.  * <pre>
  66.  * FIELDNAME        NOTES
  67.  * c_magic          The integer value octal 070707.  This value can be used to deter-
  68.  *                  mine whether this archive is written with little-endian or big-
  69.  *                  endian integers.
  70.  * c_dev            Device that contains a directory entry for this file
  71.  * c_ino            I-node number that identifies the input file to the file system
  72.  * c_mode           The mode specifies both the regular permissions and the file type.
  73.  * c_uid            Numeric User ID of the owner of the input file
  74.  * c_gid            Numeric Group ID of the owner of the input file
  75.  * c_nlink          Number of links that are connected to the input file
  76.  * c_rdev           For block special and character special entries, this field
  77.  *                  contains the associated device number.  For all other entry types,
  78.  *                  it should be set to zero by writers and ignored by readers.
  79.  * c_mtime[2]       Modification time of the file, indicated as the number of seconds
  80.  *                  since the start of the epoch, 00:00:00 UTC January 1, 1970.  The
  81.  *                  four-byte integer is stored with the most-significant 16 bits
  82.  *                  first followed by the least-significant 16 bits.  Each of the two
  83.  *                  16 bit values are stored in machine-native byte order.
  84.  * c_namesize       Length of the path name, including the terminating null byte
  85.  * c_filesize[2]    Length of the file in bytes. This is the length of the data
  86.  *                  section that follows the header structure. Must be 0 for
  87.  *                  FIFOs and directories
  88.  *
  89.  * All fields are unsigned short fields with 16-bit integer values
  90.  * apart from c_mtime and c_filesize which are 32-bit integer values
  91.  * </pre>
  92.  *
  93.  * <p>
  94.  * If necessary, the file name and file data are padded with a NUL byte to an even length
  95.  * </p>
  96.  *
  97.  * <p>
  98.  * Special files, directories, and the trailer are recorded with the h_filesize field equal to 0.
  99.  * </p>
  100.  *
  101.  * <p>
  102.  * 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
  103.  * numbers. No padding is added.
  104.  * </p>
  105.  *
  106.  * <h3>NEW FORMAT</h3>
  107.  *
  108.  * <p>
  109.  * 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
  110.  * 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.
  111.  * </p>
  112.  *
  113.  * <pre>
  114.  * FIELDNAME        NOTES
  115.  * c_magic[6]       The string 070701 for new ASCII, the string 070702 for new ASCII with CRC
  116.  * c_ino[8]
  117.  * c_mode[8]
  118.  * c_uid[8]
  119.  * c_gid[8]
  120.  * c_nlink[8]
  121.  * c_mtim[8]
  122.  * c_filesize[8]    must be 0 for FIFOs and directories
  123.  * c_maj[8]
  124.  * c_min[8]
  125.  * c_rmaj[8]        only valid for chr and blk special files
  126.  * c_rmin[8]        only valid for chr and blk special files
  127.  * c_namesize[8]    count includes terminating NUL in path name
  128.  * c_check[8]       0 for "new" portable format; for CRC format
  129.  *                  the sum of all the bytes in the file
  130.  * </pre>
  131.  *
  132.  * <p>
  133.  * 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
  134.  * numbers.
  135.  * </p>
  136.  *
  137.  * <p>
  138.  * 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
  139.  * a multiple of four bytes.
  140.  * </p>
  141.  *
  142.  * <p>
  143.  * This class uses mutable fields and is not considered to be threadsafe.
  144.  * </p>
  145.  *
  146.  * <p>
  147.  * Based on code from the jRPM project (https://jrpm.sourceforge.net).
  148.  * </p>
  149.  *
  150.  * <p>
  151.  * The MAGIC numbers and other constants are defined in {@link CpioConstants}
  152.  * </p>
  153.  *
  154.  * <p>
  155.  * N.B. does not handle the cpio "tar" format
  156.  * </p>
  157.  *
  158.  * @NotThreadSafe
  159.  * @see <a href="https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt">https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt</a>
  160.  */
  161. public class CpioArchiveEntry implements CpioConstants, ArchiveEntry {

  162.     // Header description fields - should be same throughout an archive

  163.     /**
  164.      * See {@link #CpioArchiveEntry(short)} for possible values.
  165.      */
  166.     private final short fileFormat;

  167.     /** The number of bytes in each header record; depends on the file format */
  168.     private final int headerSize;

  169.     /** The boundary to which the header and data elements are aligned: 0, 2 or 4 bytes */
  170.     private final int alignmentBoundary;

  171.     // Header fields

  172.     private long chksum;

  173.     /** Number of bytes in the file */
  174.     private long filesize;

  175.     private long gid;

  176.     private long inode;

  177.     private long maj;

  178.     private long min;

  179.     private long mode;

  180.     private long mtime;

  181.     private String name;

  182.     private long nlink;

  183.     private long rmaj;

  184.     private long rmin;

  185.     private long uid;

  186.     /**
  187.      * Creates a CpioArchiveEntry with a specified name for a specified file. The format of this entry will be the new format.
  188.      *
  189.      * @param inputFile The file to gather information from.
  190.      * @param entryName The name of this entry.
  191.      */
  192.     public CpioArchiveEntry(final File inputFile, final String entryName) {
  193.         this(FORMAT_NEW, inputFile, entryName);
  194.     }

  195.     /**
  196.      * Creates a CpioArchiveEntry with a specified name for a specified file. The format of this entry will be the new format.
  197.      *
  198.      * @param inputPath The file to gather information from.
  199.      * @param entryName The name of this entry.
  200.      * @param options   options indicating how symbolic links are handled.
  201.      * @throws IOException if an I/O error occurs
  202.      * @since 1.21
  203.      */
  204.     public CpioArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException {
  205.         this(FORMAT_NEW, inputPath, entryName, options);
  206.     }

  207.     /**
  208.      * Creates a CpioArchiveEntry with a specified format.
  209.      *
  210.      * @param format The cpio format for this entry.
  211.      *               <p>
  212.      *               Possible format values are:
  213.      *
  214.      *               <pre>
  215.      * CpioConstants.FORMAT_NEW
  216.      * CpioConstants.FORMAT_NEW_CRC
  217.      * CpioConstants.FORMAT_OLD_BINARY
  218.      * CpioConstants.FORMAT_OLD_ASCII
  219.      *               </pre>
  220.      */
  221.     public CpioArchiveEntry(final short format) {
  222.         switch (format) {
  223.         case FORMAT_NEW:
  224.             this.headerSize = 110;
  225.             this.alignmentBoundary = 4;
  226.             break;
  227.         case FORMAT_NEW_CRC:
  228.             this.headerSize = 110;
  229.             this.alignmentBoundary = 4;
  230.             break;
  231.         case FORMAT_OLD_ASCII:
  232.             this.headerSize = 76;
  233.             this.alignmentBoundary = 0;
  234.             break;
  235.         case FORMAT_OLD_BINARY:
  236.             this.headerSize = 26;
  237.             this.alignmentBoundary = 2;
  238.             break;
  239.         default:
  240.             throw new IllegalArgumentException("Unknown header type " + format);
  241.         }
  242.         this.fileFormat = format;
  243.     }

  244.     /**
  245.      * Creates a CpioArchiveEntry with a specified name for a specified file.
  246.      *
  247.      * @param format    The cpio format for this entry.
  248.      * @param inputFile The file to gather information from.
  249.      * @param entryName The name of this entry.
  250.      *                  <p>
  251.      *                  Possible format values are:
  252.      *
  253.      *                  <pre>
  254.      * CpioConstants.FORMAT_NEW
  255.      * CpioConstants.FORMAT_NEW_CRC
  256.      * CpioConstants.FORMAT_OLD_BINARY
  257.      * CpioConstants.FORMAT_OLD_ASCII
  258.      *                  </pre>
  259.      *
  260.      * @since 1.1
  261.      */
  262.     public CpioArchiveEntry(final short format, final File inputFile, final String entryName) {
  263.         this(format, entryName, inputFile.isFile() ? inputFile.length() : 0);
  264.         if (inputFile.isDirectory()) {
  265.             setMode(C_ISDIR);
  266.         } else if (inputFile.isFile()) {
  267.             setMode(C_ISREG);
  268.         } else {
  269.             throw new IllegalArgumentException("Cannot determine type of file " + inputFile.getName());
  270.         }
  271.         // TODO set other fields as needed
  272.         setTime(inputFile.lastModified() / 1000);
  273.     }

  274.     /**
  275.      * Creates a CpioArchiveEntry with a specified name for a specified path.
  276.      *
  277.      * @param format    The cpio format for this entry.
  278.      * @param inputPath The file to gather information from.
  279.      * @param entryName The name of this entry.
  280.      *                  <p>
  281.      *                  Possible format values are:
  282.      *
  283.      *                  <pre>
  284.      * CpioConstants.FORMAT_NEW
  285.      * CpioConstants.FORMAT_NEW_CRC
  286.      * CpioConstants.FORMAT_OLD_BINARY
  287.      * CpioConstants.FORMAT_OLD_ASCII
  288.      *                  </pre>
  289.      *
  290.      * @param options   options indicating how symbolic links are handled.
  291.      *
  292.      * @throws IOException if an I/O error occurs
  293.      * @since 1.21
  294.      */
  295.     public CpioArchiveEntry(final short format, final Path inputPath, final String entryName, final LinkOption... options) throws IOException {
  296.         this(format, entryName, Files.isRegularFile(inputPath, options) ? Files.size(inputPath) : 0);
  297.         if (Files.isDirectory(inputPath, options)) {
  298.             setMode(C_ISDIR);
  299.         } else if (Files.isRegularFile(inputPath, options)) {
  300.             setMode(C_ISREG);
  301.         } else {
  302.             throw new IllegalArgumentException("Cannot determine type of file " + inputPath);
  303.         }
  304.         // TODO set other fields as needed
  305.         setTime(Files.getLastModifiedTime(inputPath, options));
  306.     }

  307.     /**
  308.      * Creates a CpioArchiveEntry with a specified name.
  309.      *
  310.      * @param format The cpio format for this entry.
  311.      * @param name   The name of this entry.
  312.      *               <p>
  313.      *               Possible format values are:
  314.      *
  315.      *               <pre>
  316.      * CpioConstants.FORMAT_NEW
  317.      * CpioConstants.FORMAT_NEW_CRC
  318.      * CpioConstants.FORMAT_OLD_BINARY
  319.      * CpioConstants.FORMAT_OLD_ASCII
  320.      *               </pre>
  321.      *
  322.      * @since 1.1
  323.      */
  324.     public CpioArchiveEntry(final short format, final String name) {
  325.         this(format);
  326.         this.name = name;
  327.     }

  328.     /**
  329.      * Creates a CpioArchiveEntry with a specified name.
  330.      *
  331.      * @param format The cpio format for this entry.
  332.      * @param name   The name of this entry.
  333.      * @param size   The size of this entry
  334.      *               <p>
  335.      *               Possible format values are:
  336.      *
  337.      *               <pre>
  338.      * CpioConstants.FORMAT_NEW
  339.      * CpioConstants.FORMAT_NEW_CRC
  340.      * CpioConstants.FORMAT_OLD_BINARY
  341.      * CpioConstants.FORMAT_OLD_ASCII
  342.      *               </pre>
  343.      *
  344.      * @since 1.1
  345.      */
  346.     public CpioArchiveEntry(final short format, final String name, final long size) {
  347.         this(format, name);
  348.         setSize(size);
  349.     }

  350.     /**
  351.      * Creates a CpioArchiveEntry with a specified name. The format of this entry will be the new format.
  352.      *
  353.      * @param name The name of this entry.
  354.      */
  355.     public CpioArchiveEntry(final String name) {
  356.         this(FORMAT_NEW, name);
  357.     }

  358.     /**
  359.      * Creates a CpioArchiveEntry with a specified name. The format of this entry will be the new format.
  360.      *
  361.      * @param name The name of this entry.
  362.      * @param size The size of this entry
  363.      */
  364.     public CpioArchiveEntry(final String name, final long size) {
  365.         this(name);
  366.         setSize(size);
  367.     }

  368.     /**
  369.      * Checks if the method is allowed for the defined format.
  370.      */
  371.     private void checkNewFormat() {
  372.         if ((this.fileFormat & FORMAT_NEW_MASK) == 0) {
  373.             throw new UnsupportedOperationException();
  374.         }
  375.     }

  376.     /**
  377.      * Checks if the method is allowed for the defined format.
  378.      */
  379.     private void checkOldFormat() {
  380.         if ((this.fileFormat & FORMAT_OLD_MASK) == 0) {
  381.             throw new UnsupportedOperationException();
  382.         }
  383.     }

  384.     /*
  385.      * (non-Javadoc)
  386.      *
  387.      * @see Object#equals(Object)
  388.      */
  389.     @Override
  390.     public boolean equals(final Object obj) {
  391.         if (this == obj) {
  392.             return true;
  393.         }
  394.         if (obj == null || getClass() != obj.getClass()) {
  395.             return false;
  396.         }
  397.         final CpioArchiveEntry other = (CpioArchiveEntry) obj;
  398.         return Objects.equals(name, other.name);
  399.     }

  400.     /**
  401.      * Gets the alignment boundary for this CPIO format
  402.      *
  403.      * @return the alignment boundary (0, 2, 4) in bytes
  404.      */
  405.     public int getAlignmentBoundary() {
  406.         return this.alignmentBoundary;
  407.     }

  408.     /**
  409.      * Gets the checksum. Only supported for the new formats.
  410.      *
  411.      * @return the checksum.
  412.      * @throws UnsupportedOperationException if the format is not a new format
  413.      */
  414.     public long getChksum() {
  415.         checkNewFormat();
  416.         return this.chksum & 0xFFFFFFFFL;
  417.     }

  418.     /**
  419.      * Gets the number of bytes needed to pad the data to the alignment boundary.
  420.      *
  421.      * @return the number of bytes needed to pad the data (0,1,2,3)
  422.      */
  423.     public int getDataPadCount() {
  424.         if (this.alignmentBoundary == 0) {
  425.             return 0;
  426.         }
  427.         final long size = this.filesize;
  428.         final int remain = (int) (size % this.alignmentBoundary);
  429.         if (remain > 0) {
  430.             return this.alignmentBoundary - remain;
  431.         }
  432.         return 0;
  433.     }

  434.     /**
  435.      * Gets the device id.
  436.      *
  437.      * @return the device id.
  438.      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with a new format.
  439.      */
  440.     public long getDevice() {
  441.         checkOldFormat();
  442.         return this.min;
  443.     }

  444.     /**
  445.      * Gets the major device id.
  446.      *
  447.      * @return the major device id.
  448.      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with an old format.
  449.      */
  450.     public long getDeviceMaj() {
  451.         checkNewFormat();
  452.         return this.maj;
  453.     }

  454.     /**
  455.      * Gets the minor device id
  456.      *
  457.      * @return the minor device id.
  458.      * @throws UnsupportedOperationException if format is not a new format
  459.      */
  460.     public long getDeviceMin() {
  461.         checkNewFormat();
  462.         return this.min;
  463.     }

  464.     /**
  465.      * Gets the format for this entry.
  466.      *
  467.      * @return the format.
  468.      */
  469.     public short getFormat() {
  470.         return this.fileFormat;
  471.     }

  472.     /**
  473.      * Gets the group id.
  474.      *
  475.      * @return the group id.
  476.      */
  477.     public long getGID() {
  478.         return this.gid;
  479.     }

  480.     /**
  481.      * Gets the number of bytes needed to pad the header to the alignment boundary.
  482.      *
  483.      * @deprecated This method doesn't properly work for multi-byte encodings. And creates corrupt archives. Use {@link #getHeaderPadCount(Charset)} or
  484.      *             {@link #getHeaderPadCount(long)} in any case.
  485.      * @return the number of bytes needed to pad the header (0,1,2,3)
  486.      */
  487.     @Deprecated
  488.     public int getHeaderPadCount() {
  489.         return getHeaderPadCount(null);
  490.     }

  491.     /**
  492.      * Gets the number of bytes needed to pad the header to the alignment boundary.
  493.      *
  494.      * @param charset The character set used to encode the entry name in the stream.
  495.      * @return the number of bytes needed to pad the header (0,1,2,3)
  496.      * @since 1.18
  497.      */
  498.     public int getHeaderPadCount(final Charset charset) {
  499.         if (name == null) {
  500.             return 0;
  501.         }
  502.         if (charset == null) {
  503.             return getHeaderPadCount(name.length());
  504.         }
  505.         return getHeaderPadCount(name.getBytes(charset).length);
  506.     }

  507.     /**
  508.      * Gets the number of bytes needed to pad the header to the alignment boundary.
  509.      *
  510.      * @param nameSize The length of the name in bytes, as read in the stream. Without the trailing zero byte.
  511.      * @return the number of bytes needed to pad the header (0,1,2,3)
  512.      *
  513.      * @since 1.18
  514.      */
  515.     public int getHeaderPadCount(final long nameSize) {
  516.         if (this.alignmentBoundary == 0) {
  517.             return 0;
  518.         }
  519.         int size = this.headerSize + 1; // Name has terminating null
  520.         if (name != null) {
  521.             size = ExactMath.add(size, nameSize);
  522.         }
  523.         final int remain = size % this.alignmentBoundary;
  524.         if (remain > 0) {
  525.             return this.alignmentBoundary - remain;
  526.         }
  527.         return 0;
  528.     }

  529.     /**
  530.      * Gets the header size for this CPIO format
  531.      *
  532.      * @return the header size in bytes.
  533.      */
  534.     public int getHeaderSize() {
  535.         return this.headerSize;
  536.     }

  537.     /**
  538.      * Sets the inode.
  539.      *
  540.      * @return the inode.
  541.      */
  542.     public long getInode() {
  543.         return this.inode;
  544.     }

  545.     @Override
  546.     public Date getLastModifiedDate() {
  547.         return new Date(1000 * getTime());
  548.     }

  549.     /**
  550.      * Gets the mode of this entry (e.g. directory, regular file).
  551.      *
  552.      * @return the mode.
  553.      */
  554.     public long getMode() {
  555.         return mode == 0 && !CPIO_TRAILER.equals(name) ? C_ISREG : mode;
  556.     }

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

  570.     /**
  571.      * Gets the number of links.
  572.      *
  573.      * @return the number of links.
  574.      */
  575.     public long getNumberOfLinks() {
  576.         return nlink == 0 ? isDirectory() ? 2 : 1 : nlink;
  577.     }

  578.     /**
  579.      * Gets the remote device id.
  580.      *
  581.      * @return the remote device id.
  582.      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with a new format.
  583.      */
  584.     public long getRemoteDevice() {
  585.         checkOldFormat();
  586.         return this.rmin;
  587.     }

  588.     /**
  589.      * Gets the remote major device id.
  590.      *
  591.      * @return the remote major device id.
  592.      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with an old format.
  593.      */
  594.     public long getRemoteDeviceMaj() {
  595.         checkNewFormat();
  596.         return this.rmaj;
  597.     }

  598.     /**
  599.      * Gets the remote minor device id.
  600.      *
  601.      * @return the remote minor device id.
  602.      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with an old format.
  603.      */
  604.     public long getRemoteDeviceMin() {
  605.         checkNewFormat();
  606.         return this.rmin;
  607.     }

  608.     /**
  609.      * Gets the filesize.
  610.      *
  611.      * @return the filesize.
  612.      * @see org.apache.commons.compress.archivers.ArchiveEntry#getSize()
  613.      */
  614.     @Override
  615.     public long getSize() {
  616.         return this.filesize;
  617.     }

  618.     /**
  619.      * Gets the time in seconds.
  620.      *
  621.      * @return the time.
  622.      */
  623.     public long getTime() {
  624.         return this.mtime;
  625.     }

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

  634.     /*
  635.      * (non-Javadoc)
  636.      *
  637.      * @see Object#hashCode()
  638.      */
  639.     @Override
  640.     public int hashCode() {
  641.         return Objects.hash(name);
  642.     }

  643.     /**
  644.      * Checks if this entry represents a block device.
  645.      *
  646.      * @return TRUE if this entry is a block device.
  647.      */
  648.     public boolean isBlockDevice() {
  649.         return CpioUtil.fileType(mode) == C_ISBLK;
  650.     }

  651.     /**
  652.      * Checks if this entry represents a character device.
  653.      *
  654.      * @return TRUE if this entry is a character device.
  655.      */
  656.     public boolean isCharacterDevice() {
  657.         return CpioUtil.fileType(mode) == C_ISCHR;
  658.     }

  659.     /**
  660.      * Checks if this entry represents a directory.
  661.      *
  662.      * @return TRUE if this entry is a directory.
  663.      */
  664.     @Override
  665.     public boolean isDirectory() {
  666.         return CpioUtil.fileType(mode) == C_ISDIR;
  667.     }

  668.     /**
  669.      * Checks if this entry represents a network device.
  670.      *
  671.      * @return TRUE if this entry is a network device.
  672.      */
  673.     public boolean isNetwork() {
  674.         return CpioUtil.fileType(mode) == C_ISNWK;
  675.     }

  676.     /**
  677.      * Checks 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.      * Checks if this entry represents a regular file.
  686.      *
  687.      * @return TRUE if this entry is a regular file.
  688.      */
  689.     public boolean isRegularFile() {
  690.         return CpioUtil.fileType(mode) == C_ISREG;
  691.     }

  692.     /**
  693.      * Checks if this entry represents a socket.
  694.      *
  695.      * @return TRUE if this entry is a socket.
  696.      */
  697.     public boolean isSocket() {
  698.         return CpioUtil.fileType(mode) == C_ISSOCK;
  699.     }

  700.     /**
  701.      * Checks if this entry represents a symbolic link.
  702.      *
  703.      * @return TRUE if this entry is a symbolic link.
  704.      */
  705.     public boolean isSymbolicLink() {
  706.         return CpioUtil.fileType(mode) == C_ISLNK;
  707.     }

  708.     /**
  709.      * Sets the checksum. The checksum is calculated by adding all bytes of a file to transfer (crc += buf[pos] &amp; 0xFF).
  710.      *
  711.      * @param chksum The checksum to set.
  712.      */
  713.     public void setChksum(final long chksum) {
  714.         checkNewFormat();
  715.         this.chksum = chksum & 0xFFFFFFFFL;
  716.     }

  717.     /**
  718.      * Sets the device id.
  719.      *
  720.      * @param device The device id to set.
  721.      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with a new format.
  722.      */
  723.     public void setDevice(final long device) {
  724.         checkOldFormat();
  725.         this.min = device;
  726.     }

  727.     /**
  728.      * Sets major device id.
  729.      *
  730.      * @param maj The major device id to set.
  731.      */
  732.     public void setDeviceMaj(final long maj) {
  733.         checkNewFormat();
  734.         this.maj = maj;
  735.     }

  736.     /**
  737.      * Sets the minor device id
  738.      *
  739.      * @param min The minor device id to set.
  740.      */
  741.     public void setDeviceMin(final long min) {
  742.         checkNewFormat();
  743.         this.min = min;
  744.     }

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

  753.     /**
  754.      * Sets the inode.
  755.      *
  756.      * @param inode The inode to set.
  757.      */
  758.     public void setInode(final long inode) {
  759.         this.inode = inode;
  760.     }

  761.     /**
  762.      * Sets the mode of this entry (e.g. directory, regular file).
  763.      *
  764.      * @param mode The mode to set.
  765.      */
  766.     public void setMode(final long mode) {
  767.         final long maskedMode = mode & S_IFMT;
  768.         switch ((int) maskedMode) {
  769.         case C_ISDIR:
  770.         case C_ISLNK:
  771.         case C_ISREG:
  772.         case C_ISFIFO:
  773.         case C_ISCHR:
  774.         case C_ISBLK:
  775.         case C_ISSOCK:
  776.         case C_ISNWK:
  777.             break;
  778.         default:
  779.             throw new IllegalArgumentException("Unknown mode. " + "Full: " + Long.toHexString(mode) + " Masked: " + Long.toHexString(maskedMode));
  780.         }

  781.         this.mode = mode;
  782.     }

  783.     /**
  784.      * Sets the name.
  785.      *
  786.      * @param name The name to set.
  787.      */
  788.     public void setName(final String name) {
  789.         this.name = name;
  790.     }

  791.     /**
  792.      * Sets the number of links.
  793.      *
  794.      * @param nlink The number of links to set.
  795.      */
  796.     public void setNumberOfLinks(final long nlink) {
  797.         this.nlink = nlink;
  798.     }

  799.     /**
  800.      * Sets the remote device id.
  801.      *
  802.      * @param device The remote device id to set.
  803.      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with a new format.
  804.      */
  805.     public void setRemoteDevice(final long device) {
  806.         checkOldFormat();
  807.         this.rmin = device;
  808.     }

  809.     /**
  810.      * Sets the remote major device id.
  811.      *
  812.      * @param rmaj The remote major device id to set.
  813.      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with an old format.
  814.      */
  815.     public void setRemoteDeviceMaj(final long rmaj) {
  816.         checkNewFormat();
  817.         this.rmaj = rmaj;
  818.     }

  819.     /**
  820.      * Sets the remote minor device id.
  821.      *
  822.      * @param rmin The remote minor device id to set.
  823.      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with an old format.
  824.      */
  825.     public void setRemoteDeviceMin(final long rmin) {
  826.         checkNewFormat();
  827.         this.rmin = rmin;
  828.     }

  829.     /**
  830.      * Sets the filesize.
  831.      *
  832.      * @param size The filesize to set.
  833.      */
  834.     public void setSize(final long size) {
  835.         if (size < 0 || size > 0xFFFFFFFFL) {
  836.             throw new IllegalArgumentException("Invalid entry size <" + size + ">");
  837.         }
  838.         this.filesize = size;
  839.     }

  840.     /**
  841.      * Sets the time.
  842.      *
  843.      * @param time The time to set.
  844.      */
  845.     public void setTime(final FileTime time) {
  846.         this.mtime = TimeUtils.toUnixTime(time);
  847.     }

  848.     /**
  849.      * Sets the time in seconds.
  850.      *
  851.      * @param time The time to set.
  852.      */
  853.     public void setTime(final long time) {
  854.         this.mtime = time;
  855.     }

  856.     /**
  857.      * Sets the user id.
  858.      *
  859.      * @param uid The user id to set.
  860.      */
  861.     public void setUID(final long uid) {
  862.         this.uid = uid;
  863.     }
  864. }