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