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] & 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 }