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   *   https://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.io.file.attribute.FileTimes;
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  * 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      * @throws IOException if an I/O error occurs
318      * @since 1.21
319      */
320     public CpioArchiveEntry(final short format, final Path inputPath, final String entryName, final LinkOption... options) throws IOException {
321         this(format, entryName, Files.isRegularFile(inputPath, options) ? Files.size(inputPath) : 0);
322         if (Files.isDirectory(inputPath, options)) {
323             setMode(C_ISDIR);
324         } else if (Files.isRegularFile(inputPath, options)) {
325             setMode(C_ISREG);
326         } else {
327             throw new IllegalArgumentException("Cannot determine type of file " + inputPath);
328         }
329         // TODO set other fields as needed
330         setTime(Files.getLastModifiedTime(inputPath, options));
331     }
332 
333     /**
334      * Creates a CpioArchiveEntry with a specified name.
335      *
336      * @param format The cpio format for this entry.
337      * @param name   The name of this entry.
338      *               <p>
339      *               Possible format values are:
340      *
341      *               <pre>
342      * CpioConstants.FORMAT_NEW
343      * CpioConstants.FORMAT_NEW_CRC
344      * CpioConstants.FORMAT_OLD_BINARY
345      * CpioConstants.FORMAT_OLD_ASCII
346      *               </pre>
347      *
348      * @since 1.1
349      */
350     public CpioArchiveEntry(final short format, final String name) {
351         this(format);
352         this.name = name;
353     }
354 
355     /**
356      * Creates a CpioArchiveEntry with a specified name.
357      *
358      * @param format The cpio format for this entry.
359      * @param name   The name of this entry.
360      * @param size   The size of this entry
361      *               <p>
362      *               Possible format values are:
363      *
364      *               <pre>
365      * CpioConstants.FORMAT_NEW
366      * CpioConstants.FORMAT_NEW_CRC
367      * CpioConstants.FORMAT_OLD_BINARY
368      * CpioConstants.FORMAT_OLD_ASCII
369      *               </pre>
370      *
371      * @since 1.1
372      */
373     public CpioArchiveEntry(final short format, final String name, final long size) {
374         this(format, name);
375         setSize(size);
376     }
377 
378     /**
379      * Creates a CpioArchiveEntry with a specified name. The format of this entry will be the new format.
380      *
381      * @param name The name of this entry.
382      */
383     public CpioArchiveEntry(final String name) {
384         this(FORMAT_NEW, name);
385     }
386 
387     /**
388      * Creates a CpioArchiveEntry with a specified name. The format of this entry will be the new format.
389      *
390      * @param name The name of this entry.
391      * @param size The size of this entry
392      */
393     public CpioArchiveEntry(final String name, final long size) {
394         this(name);
395         setSize(size);
396     }
397 
398     /**
399      * Checks if the method is allowed for the defined format.
400      */
401     private void checkNewFormat() {
402         if ((this.fileFormat & FORMAT_NEW_MASK) == 0) {
403             throw new UnsupportedOperationException();
404         }
405     }
406 
407     /**
408      * Checks if the method is allowed for the defined format.
409      */
410     private void checkOldFormat() {
411         if ((this.fileFormat & FORMAT_OLD_MASK) == 0) {
412             throw new UnsupportedOperationException();
413         }
414     }
415 
416     /*
417      * (non-Javadoc)
418      *
419      * @see Object#equals(Object)
420      */
421     @Override
422     public boolean equals(final Object obj) {
423         if (this == obj) {
424             return true;
425         }
426         if (obj == null || getClass() != obj.getClass()) {
427             return false;
428         }
429         final CpioArchiveEntry other = (CpioArchiveEntry) obj;
430         return Objects.equals(name, other.name);
431     }
432 
433     /**
434      * Gets the alignment boundary for this CPIO format
435      *
436      * @return the alignment boundary (0, 2, 4) in bytes
437      */
438     public int getAlignmentBoundary() {
439         return this.alignmentBoundary;
440     }
441 
442     /**
443      * Gets the checksum. Only supported for the new formats.
444      *
445      * @return the checksum.
446      * @throws UnsupportedOperationException if the format is not a new format
447      */
448     public long getChksum() {
449         checkNewFormat();
450         return this.chksum & 0xFFFFFFFFL;
451     }
452 
453     /**
454      * Gets the number of bytes needed to pad the data to the alignment boundary.
455      *
456      * @return the number of bytes needed to pad the data (0,1,2,3)
457      */
458     public int getDataPadCount() {
459         if (this.alignmentBoundary == 0) {
460             return 0;
461         }
462         final long size = this.fileSize;
463         final int remain = (int) (size % this.alignmentBoundary);
464         if (remain > 0) {
465             return this.alignmentBoundary - remain;
466         }
467         return 0;
468     }
469 
470     /**
471      * Gets the device id.
472      *
473      * @return the device id.
474      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with a new format.
475      */
476     public long getDevice() {
477         checkOldFormat();
478         return this.min;
479     }
480 
481     /**
482      * Gets the major device id.
483      *
484      * @return the major device id.
485      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with an old format.
486      */
487     public long getDeviceMaj() {
488         checkNewFormat();
489         return this.maj;
490     }
491 
492     /**
493      * Gets the minor device id
494      *
495      * @return the minor device id.
496      * @throws UnsupportedOperationException if format is not a new format
497      */
498     public long getDeviceMin() {
499         checkNewFormat();
500         return this.min;
501     }
502 
503     /**
504      * Gets the format for this entry.
505      *
506      * @return the format.
507      */
508     public short getFormat() {
509         return this.fileFormat;
510     }
511 
512     /**
513      * Gets the group id.
514      *
515      * @return the group id.
516      */
517     public long getGID() {
518         return this.gid;
519     }
520 
521     /**
522      * Gets the number of bytes needed to pad the header to the alignment boundary.
523      *
524      * @deprecated This method doesn't properly work for multi-byte encodings. And creates corrupt archives. Use {@link #getHeaderPadCount(Charset)} or
525      *             {@link #getHeaderPadCount(long)} in any case.
526      * @return the number of bytes needed to pad the header (0,1,2,3)
527      */
528     @Deprecated
529     public int getHeaderPadCount() {
530         return getHeaderPadCount(null);
531     }
532 
533     /**
534      * Gets the number of bytes needed to pad the header to the alignment boundary.
535      *
536      * @param charset The character set used to encode the entry name in the stream.
537      * @return the number of bytes needed to pad the header (0,1,2,3)
538      * @since 1.18
539      */
540     public int getHeaderPadCount(final Charset charset) {
541         if (name == null) {
542             return 0;
543         }
544         if (charset == null) {
545             return getHeaderPadCount(name.length());
546         }
547         return getHeaderPadCount(name.getBytes(charset).length);
548     }
549 
550     /**
551      * Gets the number of bytes needed to pad the header to the alignment boundary.
552      *
553      * @param nameSize The length of the name in bytes, as read in the stream. Without the trailing zero byte.
554      * @return the number of bytes needed to pad the header (0,1,2,3)
555      * @since 1.18
556      */
557     public int getHeaderPadCount(final long nameSize) {
558         if (this.alignmentBoundary == 0) {
559             return 0;
560         }
561         int size = this.headerSize + 1; // Name has terminating null
562         if (name != null) {
563             size = ExactMath.add(size, nameSize);
564         }
565         final int remain = size % this.alignmentBoundary;
566         if (remain > 0) {
567             return this.alignmentBoundary - remain;
568         }
569         return 0;
570     }
571 
572     /**
573      * Gets the header size for this CPIO format
574      *
575      * @return the header size in bytes.
576      */
577     public int getHeaderSize() {
578         return this.headerSize;
579     }
580 
581     /**
582      * Sets the inode.
583      *
584      * @return the inode.
585      */
586     public long getInode() {
587         return this.inode;
588     }
589 
590     @Override
591     public Date getLastModifiedDate() {
592         return new Date(1000 * getTime());
593     }
594 
595     /**
596      * Gets the mode of this entry (for example directory, regular file).
597      *
598      * @return the mode.
599      */
600     public long getMode() {
601         return mode == 0 && !CPIO_TRAILER.equals(name) ? C_ISREG : mode;
602     }
603 
604     /**
605      * Gets the name.
606      *
607      * <p>
608      * This method returns the raw name as it is stored inside of the archive.
609      * </p>
610      *
611      * @return the name.
612      */
613     @Override
614     public String getName() {
615         return this.name;
616     }
617 
618     /**
619      * Gets the number of links.
620      *
621      * @return the number of links.
622      */
623     public long getNumberOfLinks() {
624         return nlink == 0 ? isDirectory() ? 2 : 1 : nlink;
625     }
626 
627     /**
628      * Gets the remote device id.
629      *
630      * @return the remote device id.
631      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with a new format.
632      */
633     public long getRemoteDevice() {
634         checkOldFormat();
635         return this.rmin;
636     }
637 
638     /**
639      * Gets the remote major device id.
640      *
641      * @return the remote major device id.
642      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with an old format.
643      */
644     public long getRemoteDeviceMaj() {
645         checkNewFormat();
646         return this.rmaj;
647     }
648 
649     /**
650      * Gets the remote minor device id.
651      *
652      * @return the remote minor device id.
653      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with an old format.
654      */
655     public long getRemoteDeviceMin() {
656         checkNewFormat();
657         return this.rmin;
658     }
659 
660     /**
661      * Gets the file size.
662      *
663      * @return the file size.
664      * @see org.apache.commons.compress.archivers.ArchiveEntry#getSize()
665      */
666     @Override
667     public long getSize() {
668         return this.fileSize;
669     }
670 
671     /**
672      * Gets the time in seconds.
673      *
674      * @return the time.
675      */
676     public long getTime() {
677         return this.mtime;
678     }
679 
680     /**
681      * Gets the user id.
682      *
683      * @return the user id.
684      */
685     public long getUID() {
686         return this.uid;
687     }
688 
689     /*
690      * (non-Javadoc)
691      *
692      * @see Object#hashCode()
693      */
694     @Override
695     public int hashCode() {
696         return Objects.hash(name);
697     }
698 
699     /**
700      * Checks if this entry represents a block device.
701      *
702      * @return TRUE if this entry is a block device.
703      */
704     public boolean isBlockDevice() {
705         return CpioUtil.fileType(mode) == C_ISBLK;
706     }
707 
708     /**
709      * Checks if this entry represents a character device.
710      *
711      * @return TRUE if this entry is a character device.
712      */
713     public boolean isCharacterDevice() {
714         return CpioUtil.fileType(mode) == C_ISCHR;
715     }
716 
717     /**
718      * Checks if this entry represents a directory.
719      *
720      * @return TRUE if this entry is a directory.
721      */
722     @Override
723     public boolean isDirectory() {
724         return CpioUtil.fileType(mode) == C_ISDIR;
725     }
726 
727     /**
728      * Checks if this entry represents a network device.
729      *
730      * @return TRUE if this entry is a network device.
731      */
732     public boolean isNetwork() {
733         return CpioUtil.fileType(mode) == C_ISNWK;
734     }
735 
736     /**
737      * Checks if this entry represents a pipe.
738      *
739      * @return TRUE if this entry is a pipe.
740      */
741     public boolean isPipe() {
742         return CpioUtil.fileType(mode) == C_ISFIFO;
743     }
744 
745     /**
746      * Checks if this entry represents a regular file.
747      *
748      * @return TRUE if this entry is a regular file.
749      */
750     public boolean isRegularFile() {
751         return CpioUtil.fileType(mode) == C_ISREG;
752     }
753 
754     /**
755      * Checks if this entry represents a socket.
756      *
757      * @return TRUE if this entry is a socket.
758      */
759     public boolean isSocket() {
760         return CpioUtil.fileType(mode) == C_ISSOCK;
761     }
762 
763     /**
764      * Checks if this entry represents a symbolic link.
765      *
766      * @return TRUE if this entry is a symbolic link.
767      */
768     public boolean isSymbolicLink() {
769         return CpioUtil.fileType(mode) == C_ISLNK;
770     }
771 
772     /**
773      * Sets the checksum. The checksum is calculated by adding all bytes of a file to transfer (crc += buf[pos] &amp; 0xFF).
774      *
775      * @param chksum The checksum to set.
776      */
777     public void setChksum(final long chksum) {
778         checkNewFormat();
779         this.chksum = chksum & 0xFFFFFFFFL;
780     }
781 
782     /**
783      * Sets the device id.
784      *
785      * @param device The device id to set.
786      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with a new format.
787      */
788     public void setDevice(final long device) {
789         checkOldFormat();
790         this.min = device;
791     }
792 
793     /**
794      * Sets major device id.
795      *
796      * @param maj The major device id to set.
797      */
798     public void setDeviceMaj(final long maj) {
799         checkNewFormat();
800         this.maj = maj;
801     }
802 
803     /**
804      * Sets the minor device id
805      *
806      * @param min The minor device id to set.
807      */
808     public void setDeviceMin(final long min) {
809         checkNewFormat();
810         this.min = min;
811     }
812 
813     /**
814      * Sets the group id.
815      *
816      * @param gid The group id to set.
817      */
818     public void setGID(final long gid) {
819         this.gid = gid;
820     }
821 
822     /**
823      * Sets the inode.
824      *
825      * @param inode The inode to set.
826      */
827     public void setInode(final long inode) {
828         this.inode = inode;
829     }
830 
831     /**
832      * Sets the mode of this entry (for example directory, regular file).
833      *
834      * @param mode The mode to set.
835      */
836     public void setMode(final long mode) {
837         final long maskedMode = mode & S_IFMT;
838         switch ((int) maskedMode) {
839         case C_ISDIR:
840         case C_ISLNK:
841         case C_ISREG:
842         case C_ISFIFO:
843         case C_ISCHR:
844         case C_ISBLK:
845         case C_ISSOCK:
846         case C_ISNWK:
847             break;
848         default:
849             throw new IllegalArgumentException("Unknown mode. Full: " + Long.toHexString(mode) + " Masked: " + Long.toHexString(maskedMode));
850         }
851 
852         this.mode = mode;
853     }
854 
855     /**
856      * Sets the name.
857      *
858      * @param name The name to set.
859      */
860     public void setName(final String name) {
861         this.name = name;
862     }
863 
864     /**
865      * Sets the number of links.
866      *
867      * @param nlink The number of links to set.
868      */
869     public void setNumberOfLinks(final long nlink) {
870         this.nlink = nlink;
871     }
872 
873     /**
874      * Sets the remote device id.
875      *
876      * @param device The remote device id to set.
877      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with a new format.
878      */
879     public void setRemoteDevice(final long device) {
880         checkOldFormat();
881         this.rmin = device;
882     }
883 
884     /**
885      * Sets the remote major device id.
886      *
887      * @param rmaj The remote major device id to set.
888      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with an old format.
889      */
890     public void setRemoteDeviceMaj(final long rmaj) {
891         checkNewFormat();
892         this.rmaj = rmaj;
893     }
894 
895     /**
896      * Sets the remote minor device id.
897      *
898      * @param rmin The remote minor device id to set.
899      * @throws UnsupportedOperationException if this method is called for a CpioArchiveEntry with an old format.
900      */
901     public void setRemoteDeviceMin(final long rmin) {
902         checkNewFormat();
903         this.rmin = rmin;
904     }
905 
906     /**
907      * Sets the file size.
908      *
909      * @param size The file size to set.
910      */
911     public void setSize(final long size) {
912         if (size < 0 || size > 0xFFFFFFFFL) {
913             throw new IllegalArgumentException("Invalid entry size <" + size + ">");
914         }
915         this.fileSize = size;
916     }
917 
918     /**
919      * Sets the time.
920      *
921      * @param time The time to set.
922      */
923     public void setTime(final FileTime time) {
924         this.mtime = FileTimes.toUnixTime(time);
925     }
926 
927     /**
928      * Sets the time in seconds.
929      *
930      * @param time The time to set.
931      */
932     public void setTime(final long time) {
933         this.mtime = time;
934     }
935 
936     /**
937      * Sets the user id.
938      *
939      * @param uid The user id to set.
940      */
941     public void setUID(final long uid) {
942         this.uid = uid;
943     }
944 }