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