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