• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 package org.apache.commons.compress.archivers.cpio;
20 
21 import java.io.File;
22 import java.nio.charset.Charset;
23 import java.util.Date;
24 
25 import org.apache.commons.compress.archivers.ArchiveEntry;
26 
27 /**
28  * A cpio archive consists of a sequence of files. There are several types of
29  * headers defided in two categories of new and old format. The headers are
30  * recognized by magic numbers:
31  *
32  * <ul>
33  * <li>"070701" ASCII for new portable format</li>
34  * <li>"070702" ASCII for new portable format with CRC</li>
35  * <li>"070707" ASCII for old ascii (also known as Portable ASCII, odc or old
36  * character format</li>
37  * <li>070707 binary for old binary</li>
38  * </ul>
39  *
40  * <p>The old binary format is limited to 16 bits for user id, group
41  * id, device, and inode numbers. It is limited to 4 gigabyte file
42  * sizes.
43  *
44  * The old ASCII format is limited to 18 bits for the user id, group
45  * id, device, and inode numbers. It is limited to 8 gigabyte file
46  * sizes.
47  *
48  * The new ASCII format is limited to 4 gigabyte file sizes.
49  *
50  * CPIO 2.5 knows also about tar, but it is not recognized here.</p>
51  *
52  *
53  * <h3>OLD FORMAT</h3>
54  *
55  * <p>Each file has a 76 (ascii) / 26 (binary) byte header, a variable
56  * length, NUL terminated filename, and variable length file data. A
57  * header for a filename "TRAILER!!!" indicates the end of the
58  * archive.</p>
59  *
60  * <p>All the fields in the header are ISO 646 (approximately ASCII)
61  * strings of octal numbers, left padded, not NUL terminated.</p>
62  *
63  * <pre>
64  * FIELDNAME        NOTES
65  * c_magic          The integer value octal 070707.  This value can be used to deter-
66  *                  mine whether this archive is written with little-endian or big-
67  *                  endian integers.
68  * c_dev            Device that contains a directory entry for this file
69  * c_ino            I-node number that identifies the input file to the file system
70  * c_mode           The mode specifies both the regular permissions and the file type.
71  * c_uid            Numeric User ID of the owner of the input file
72  * c_gid            Numeric Group ID of the owner of the input file
73  * c_nlink          Number of links that are connected to the input file
74  * c_rdev           For block special and character special entries, this field
75  *                  contains the associated device number.  For all other entry types,
76  *                  it should be set to zero by writers and ignored by readers.
77  * c_mtime[2]       Modification time of the file, indicated as the number of seconds
78  *                  since the start of the epoch, 00:00:00 UTC January 1, 1970.  The
79  *                  four-byte integer is stored with the most-significant 16 bits
80  *                  first followed by the least-significant 16 bits.  Each of the two
81  *                  16 bit values are stored in machine-native byte order.
82  * c_namesize       Length of the path name, including the terminating null byte
83  * c_filesize[2]    Length of the file in bytes. This is the length of the data
84  *                  section that follows the header structure. Must be 0 for
85  *                  FIFOs and directories
86  *
87  * All fields are unsigned short fields with 16-bit integer values
88  * apart from c_mtime and c_filesize which are 32-bit integer values
89  * </pre>
90  *
91  * <p>If necessary, the filename and file data are padded with a NUL byte to an even length</p>
92  *
93  * <p>Special files, directories, and the trailer are recorded with
94  * the h_filesize field equal to 0.</p>
95  *
96  * <p>In the ASCII version of this format, the 16-bit entries are represented as 6-byte octal numbers,
97  * and the 32-bit entries are represented as 11-byte octal numbers. No padding is added.</p>
98  *
99  * <h3>NEW FORMAT</h3>
100  *
101  * <p>Each file has a 110 byte header, a variable length, NUL
102  * terminated filename, and variable length file data. A header for a
103  * filename "TRAILER!!!" indicates the end of the archive. All the
104  * fields in the header are ISO 646 (approximately ASCII) strings of
105  * hexadecimal numbers, left padded, not NUL terminated.</p>
106  *
107  * <pre>
108  * FIELDNAME        NOTES
109  * c_magic[6]       The string 070701 for new ASCII, the string 070702 for new ASCII with CRC
110  * c_ino[8]
111  * c_mode[8]
112  * c_uid[8]
113  * c_gid[8]
114  * c_nlink[8]
115  * c_mtim[8]
116  * c_filesize[8]    must be 0 for FIFOs and directories
117  * c_maj[8]
118  * c_min[8]
119  * c_rmaj[8]        only valid for chr and blk special files
120  * c_rmin[8]        only valid for chr and blk special files
121  * c_namesize[8]    count includes terminating NUL in pathname
122  * c_check[8]       0 for "new" portable format; for CRC format
123  *                  the sum of all the bytes in the file
124  * </pre>
125  *
126  * <p>New ASCII Format The "new" ASCII format uses 8-byte hexadecimal
127  * fields for all numbers and separates device numbers into separate
128  * fields for major and minor numbers.</p>
129  *
130  * <p>The pathname is followed by NUL bytes so that the total size of
131  * the fixed header plus pathname is a multiple of four. Likewise, the
132  * file data is padded to a multiple of four bytes.</p>
133  *
134  * <p>This class uses mutable fields and is not considered to be
135  * threadsafe.</p>
136  *
137  * <p>Based on code from the jRPM project (http://jrpm.sourceforge.net).</p>
138  *
139  * <p>The MAGIC numbers and other constants are defined in {@link CpioConstants}</p>
140  *
141  * <p>
142  * N.B. does not handle the cpio "tar" format
143  * </p>
144  * @NotThreadSafe
145  * @see <a href="https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt">https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt</a>
146  */
147 public class CpioArchiveEntry implements CpioConstants, ArchiveEntry {
148 
149     // Header description fields - should be same throughout an archive
150 
151     /**
152      * See constructor documenation for possible values.
153      */
154     private final short fileFormat;
155 
156     /** The number of bytes in each header record; depends on the file format */
157     private final int headerSize;
158 
159     /** The boundary to which the header and data elements are aligned: 0, 2 or 4 bytes */
160     private final int alignmentBoundary;
161 
162     // Header fields
163 
164     private long chksum = 0;
165 
166     /** Number of bytes in the file */
167     private long filesize = 0;
168 
169     private long gid = 0;
170 
171     private long inode = 0;
172 
173     private long maj = 0;
174 
175     private long min = 0;
176 
177     private long mode = 0;
178 
179     private long mtime = 0;
180 
181     private String name;
182 
183     private long nlink = 0;
184 
185     private long rmaj = 0;
186 
187     private long rmin = 0;
188 
189     private long uid = 0;
190 
191     /**
192      * Creates a CpioArchiveEntry with a specified format.
193      *
194      * @param format
195      *            The cpio format for this entry.
196      * <p>
197      * Possible format values are:
198      * <pre>
199      * CpioConstants.FORMAT_NEW
200      * CpioConstants.FORMAT_NEW_CRC
201      * CpioConstants.FORMAT_OLD_BINARY
202      * CpioConstants.FORMAT_OLD_ASCII
203      * </pre>
204      */
CpioArchiveEntry(final short format)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      */
CpioArchiveEntry(final String name)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      */
CpioArchiveEntry(final short format, final String name)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      */
CpioArchiveEntry(final String name, final long size)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      */
CpioArchiveEntry(final short format, final String name, final long size)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      */
CpioArchiveEntry(final File inputFile, final String entryName)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      */
CpioArchiveEntry(final short format, final File inputFile, final String entryName)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      */
checkNewFormat()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      */
checkOldFormat()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      */
getChksum()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      */
getDevice()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      */
getDeviceMaj()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      */
getDeviceMin()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
getSize()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      */
getFormat()436     public short getFormat() {
437         return this.fileFormat;
438     }
439 
440     /**
441      * Get the group id.
442      *
443      * @return Returns the group id.
444      */
getGID()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      */
getHeaderSize()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      */
getAlignmentBoundary()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
getHeaderPadCount()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      */
getHeaderPadCount(Charset charset)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      */
getHeaderPadCount(long namesize)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      */
getDataPadCount()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      */
getInode()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      */
getMode()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
getName()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      */
getNumberOfLinks()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      */
getRemoteDevice()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      */
getRemoteDeviceMaj()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      */
getRemoteDeviceMin()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      */
getTime()621     public long getTime() {
622         return this.mtime;
623     }
624 
625     @Override
getLastModifiedDate()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      */
getUID()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      */
isBlockDevice()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      */
isCharacterDevice()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
isDirectory()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      */
isNetwork()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      */
isPipe()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      */
isRegularFile()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      */
isSocket()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      */
isSymbolicLink()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      */
setChksum(final long chksum)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      */
setDevice(final long device)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      */
setDeviceMaj(final long maj)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      */
setDeviceMin(final long min)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      */
setSize(final long size)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      */
setGID(final long gid)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      */
setInode(final long inode)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      */
setMode(final long mode)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      */
setName(final String name)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      */
setNumberOfLinks(final long nlink)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      */
setRemoteDevice(final long device)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      */
setRemoteDeviceMaj(final long rmaj)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      */
setRemoteDeviceMin(final long rmin)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      */
setTime(final long time)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      */
setUID(final long uid)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
hashCode()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
equals(final Object obj)919     public boolean equals(final Object obj) {
920         if (this == obj) {
921             return true;
922         }
923         if (obj == null || getClass() != obj.getClass()) {
924             return false;
925         }
926         final CpioArchiveEntry other = (CpioArchiveEntry) obj;
927         if (name == null) {
928             return other.name == null;
929         } else {
930             return name.equals(other.name);
931         }
932     }
933 }
934