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