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