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