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.util.Date; 023 024import 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</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 <a href="https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt">https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt</a> 145 */ 146public 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 * <p> 196 * Possible format values are: 197 * <pre> 198 * CpioConstants.FORMAT_NEW 199 * CpioConstants.FORMAT_NEW_CRC 200 * CpioConstants.FORMAT_OLD_BINARY 201 * CpioConstants.FORMAT_OLD_ASCII 202 * </pre> 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 * <p> 247 * Possible format values are: 248 * <pre> 249 * CpioConstants.FORMAT_NEW 250 * CpioConstants.FORMAT_NEW_CRC 251 * CpioConstants.FORMAT_OLD_BINARY 252 * CpioConstants.FORMAT_OLD_ASCII 253 * </pre> 254 * 255 * @since 1.1 256 */ 257 public CpioArchiveEntry(final short format, final String name) { 258 this(format); 259 this.name = name; 260 } 261 262 /** 263 * Creates a CpioArchiveEntry with a specified name. The format of 264 * this entry will be the new format. 265 * 266 * @param name 267 * The name of this entry. 268 * @param size 269 * The size of this entry 270 */ 271 public CpioArchiveEntry(final String name, final long size) { 272 this(name); 273 this.setSize(size); 274 } 275 276 /** 277 * Creates a CpioArchiveEntry with a specified name. 278 * 279 * @param format 280 * The cpio format for this entry. 281 * @param name 282 * The name of this entry. 283 * @param size 284 * The size of this entry 285 * <p> 286 * Possible format values are: 287 * <pre> 288 * CpioConstants.FORMAT_NEW 289 * CpioConstants.FORMAT_NEW_CRC 290 * CpioConstants.FORMAT_OLD_BINARY 291 * CpioConstants.FORMAT_OLD_ASCII 292 * </pre> 293 * 294 * @since 1.1 295 */ 296 public CpioArchiveEntry(final short format, final String name, 297 final long size) { 298 this(format, name); 299 this.setSize(size); 300 } 301 302 /** 303 * Creates a CpioArchiveEntry with a specified name for a 304 * specified file. The format of this entry will be the new 305 * format. 306 * 307 * @param inputFile 308 * The file to gather information from. 309 * @param entryName 310 * The name of this entry. 311 */ 312 public CpioArchiveEntry(final File inputFile, final String entryName) { 313 this(FORMAT_NEW, inputFile, entryName); 314 } 315 316 /** 317 * Creates a CpioArchiveEntry with a specified name for a 318 * specified file. 319 * 320 * @param format 321 * The cpio format for this entry. 322 * @param inputFile 323 * The file to gather information from. 324 * @param entryName 325 * The name of this entry. 326 * <p> 327 * Possible format values are: 328 * <pre> 329 * CpioConstants.FORMAT_NEW 330 * CpioConstants.FORMAT_NEW_CRC 331 * CpioConstants.FORMAT_OLD_BINARY 332 * CpioConstants.FORMAT_OLD_ASCII 333 * </pre> 334 * 335 * @since 1.1 336 */ 337 public CpioArchiveEntry(final short format, final File inputFile, 338 final String entryName) { 339 this(format, entryName, inputFile.isFile() ? inputFile.length() : 0); 340 if (inputFile.isDirectory()){ 341 setMode(C_ISDIR); 342 } else if (inputFile.isFile()){ 343 setMode(C_ISREG); 344 } else { 345 throw new IllegalArgumentException("Cannot determine type of file " 346 + inputFile.getName()); 347 } 348 // TODO set other fields as needed 349 setTime(inputFile.lastModified() / 1000); 350 } 351 352 /** 353 * Check if the method is allowed for the defined format. 354 */ 355 private void checkNewFormat() { 356 if ((this.fileFormat & FORMAT_NEW_MASK) == 0) { 357 throw new UnsupportedOperationException(); 358 } 359 } 360 361 /** 362 * Check if the method is allowed for the defined format. 363 */ 364 private void checkOldFormat() { 365 if ((this.fileFormat & FORMAT_OLD_MASK) == 0) { 366 throw new UnsupportedOperationException(); 367 } 368 } 369 370 /** 371 * Get the checksum. 372 * Only supported for the new formats. 373 * 374 * @return Returns the checksum. 375 * @throws UnsupportedOperationException if the format is not a new format 376 */ 377 public long getChksum() { 378 checkNewFormat(); 379 return this.chksum & 0xFFFFFFFFL; 380 } 381 382 /** 383 * Get the device id. 384 * 385 * @return Returns the device id. 386 * @throws UnsupportedOperationException 387 * if this method is called for a CpioArchiveEntry with a new 388 * format. 389 */ 390 public long getDevice() { 391 checkOldFormat(); 392 return this.min; 393 } 394 395 /** 396 * Get the major device id. 397 * 398 * @return Returns the major device id. 399 * @throws UnsupportedOperationException 400 * if this method is called for a CpioArchiveEntry with an old 401 * format. 402 */ 403 public long getDeviceMaj() { 404 checkNewFormat(); 405 return this.maj; 406 } 407 408 /** 409 * Get the minor device id 410 * 411 * @return Returns the minor device id. 412 * @throws UnsupportedOperationException if format is not a new format 413 */ 414 public long getDeviceMin() { 415 checkNewFormat(); 416 return this.min; 417 } 418 419 /** 420 * Get the filesize. 421 * 422 * @return Returns the filesize. 423 * @see org.apache.commons.compress.archivers.ArchiveEntry#getSize() 424 */ 425 @Override 426 public long getSize() { 427 return this.filesize; 428 } 429 430 /** 431 * Get the format for this entry. 432 * 433 * @return Returns the format. 434 */ 435 public short getFormat() { 436 return this.fileFormat; 437 } 438 439 /** 440 * Get the group id. 441 * 442 * @return Returns the group id. 443 */ 444 public long getGID() { 445 return this.gid; 446 } 447 448 /** 449 * Get the header size for this CPIO format 450 * 451 * @return Returns the header size in bytes. 452 */ 453 public int getHeaderSize() { 454 return this.headerSize; 455 } 456 457 /** 458 * Get the alignment boundary for this CPIO format 459 * 460 * @return Returns the aligment boundary (0, 2, 4) in bytes 461 */ 462 public int getAlignmentBoundary() { 463 return this.alignmentBoundary; 464 } 465 466 /** 467 * Get the number of bytes needed to pad the header to the alignment boundary. 468 * 469 * @return the number of bytes needed to pad the header (0,1,2,3) 470 */ 471 public int getHeaderPadCount(){ 472 if (this.alignmentBoundary == 0) { return 0; } 473 int size = this.headerSize + 1; // Name has terminating null 474 if (name != null) { 475 size += name.length(); 476 } 477 final int remain = size % this.alignmentBoundary; 478 if (remain > 0){ 479 return this.alignmentBoundary - remain; 480 } 481 return 0; 482 } 483 484 /** 485 * Get the number of bytes needed to pad the data to the alignment boundary. 486 * 487 * @return the number of bytes needed to pad the data (0,1,2,3) 488 */ 489 public int getDataPadCount(){ 490 if (this.alignmentBoundary == 0) { return 0; } 491 final long size = this.filesize; 492 final int remain = (int) (size % this.alignmentBoundary); 493 if (remain > 0){ 494 return this.alignmentBoundary - remain; 495 } 496 return 0; 497 } 498 499 /** 500 * Set the inode. 501 * 502 * @return Returns the inode. 503 */ 504 public long getInode() { 505 return this.inode; 506 } 507 508 /** 509 * Get the mode of this entry (e.g. directory, regular file). 510 * 511 * @return Returns the mode. 512 */ 513 public long getMode() { 514 return mode == 0 && !CPIO_TRAILER.equals(name) ? C_ISREG : mode; 515 } 516 517 /** 518 * Get the name. 519 * 520 * <p>This method returns the raw name as it is stored inside of the archive.</p> 521 * 522 * @return Returns the name. 523 */ 524 @Override 525 public String getName() { 526 return this.name; 527 } 528 529 /** 530 * Get the number of links. 531 * 532 * @return Returns the number of links. 533 */ 534 public long getNumberOfLinks() { 535 return nlink == 0 ? 536 isDirectory() ? 2 : 1 537 : nlink; 538 } 539 540 /** 541 * Get the remote device id. 542 * 543 * @return Returns the remote device id. 544 * @throws UnsupportedOperationException 545 * if this method is called for a CpioArchiveEntry with a new 546 * format. 547 */ 548 public long getRemoteDevice() { 549 checkOldFormat(); 550 return this.rmin; 551 } 552 553 /** 554 * Get the remote major device id. 555 * 556 * @return Returns the remote major device id. 557 * @throws UnsupportedOperationException 558 * if this method is called for a CpioArchiveEntry with an old 559 * format. 560 */ 561 public long getRemoteDeviceMaj() { 562 checkNewFormat(); 563 return this.rmaj; 564 } 565 566 /** 567 * Get the remote minor device id. 568 * 569 * @return Returns the remote minor device id. 570 * @throws UnsupportedOperationException 571 * if this method is called for a CpioArchiveEntry with an old 572 * format. 573 */ 574 public long getRemoteDeviceMin() { 575 checkNewFormat(); 576 return this.rmin; 577 } 578 579 /** 580 * Get the time in seconds. 581 * 582 * @return Returns the time. 583 */ 584 public long getTime() { 585 return this.mtime; 586 } 587 588 @Override 589 public Date getLastModifiedDate() { 590 return new Date(1000 * getTime()); 591 } 592 593 /** 594 * Get the user id. 595 * 596 * @return Returns the user id. 597 */ 598 public long getUID() { 599 return this.uid; 600 } 601 602 /** 603 * Check if this entry represents a block device. 604 * 605 * @return TRUE if this entry is a block device. 606 */ 607 public boolean isBlockDevice() { 608 return CpioUtil.fileType(mode) == C_ISBLK; 609 } 610 611 /** 612 * Check if this entry represents a character device. 613 * 614 * @return TRUE if this entry is a character device. 615 */ 616 public boolean isCharacterDevice() { 617 return CpioUtil.fileType(mode) == C_ISCHR; 618 } 619 620 /** 621 * Check if this entry represents a directory. 622 * 623 * @return TRUE if this entry is a directory. 624 */ 625 @Override 626 public boolean isDirectory() { 627 return CpioUtil.fileType(mode) == C_ISDIR; 628 } 629 630 /** 631 * Check if this entry represents a network device. 632 * 633 * @return TRUE if this entry is a network device. 634 */ 635 public boolean isNetwork() { 636 return CpioUtil.fileType(mode) == C_ISNWK; 637 } 638 639 /** 640 * Check if this entry represents a pipe. 641 * 642 * @return TRUE if this entry is a pipe. 643 */ 644 public boolean isPipe() { 645 return CpioUtil.fileType(mode) == C_ISFIFO; 646 } 647 648 /** 649 * Check if this entry represents a regular file. 650 * 651 * @return TRUE if this entry is a regular file. 652 */ 653 public boolean isRegularFile() { 654 return CpioUtil.fileType(mode) == C_ISREG; 655 } 656 657 /** 658 * Check if this entry represents a socket. 659 * 660 * @return TRUE if this entry is a socket. 661 */ 662 public boolean isSocket() { 663 return CpioUtil.fileType(mode) == C_ISSOCK; 664 } 665 666 /** 667 * Check if this entry represents a symbolic link. 668 * 669 * @return TRUE if this entry is a symbolic link. 670 */ 671 public boolean isSymbolicLink() { 672 return CpioUtil.fileType(mode) == C_ISLNK; 673 } 674 675 /** 676 * Set the checksum. The checksum is calculated by adding all bytes of a 677 * file to transfer (crc += buf[pos] & 0xFF). 678 * 679 * @param chksum 680 * The checksum to set. 681 */ 682 public void setChksum(final long chksum) { 683 checkNewFormat(); 684 this.chksum = chksum & 0xFFFFFFFFL; 685 } 686 687 /** 688 * Set the device id. 689 * 690 * @param device 691 * The device id to set. 692 * @throws UnsupportedOperationException 693 * if this method is called for a CpioArchiveEntry with a new 694 * format. 695 */ 696 public void setDevice(final long device) { 697 checkOldFormat(); 698 this.min = device; 699 } 700 701 /** 702 * Set major device id. 703 * 704 * @param maj 705 * The major device id to set. 706 */ 707 public void setDeviceMaj(final long maj) { 708 checkNewFormat(); 709 this.maj = maj; 710 } 711 712 /** 713 * Set the minor device id 714 * 715 * @param min 716 * The minor device id to set. 717 */ 718 public void setDeviceMin(final long min) { 719 checkNewFormat(); 720 this.min = min; 721 } 722 723 /** 724 * Set the filesize. 725 * 726 * @param size 727 * The filesize to set. 728 */ 729 public void setSize(final long size) { 730 if (size < 0 || size > 0xFFFFFFFFL) { 731 throw new IllegalArgumentException("invalid entry size <" + size 732 + ">"); 733 } 734 this.filesize = size; 735 } 736 737 /** 738 * Set the group id. 739 * 740 * @param gid 741 * The group id to set. 742 */ 743 public void setGID(final long gid) { 744 this.gid = gid; 745 } 746 747 /** 748 * Set the inode. 749 * 750 * @param inode 751 * The inode to set. 752 */ 753 public void setInode(final long inode) { 754 this.inode = inode; 755 } 756 757 /** 758 * Set the mode of this entry (e.g. directory, regular file). 759 * 760 * @param mode 761 * The mode to set. 762 */ 763 public void setMode(final long mode) { 764 final long maskedMode = mode & S_IFMT; 765 switch ((int) maskedMode) { 766 case C_ISDIR: 767 case C_ISLNK: 768 case C_ISREG: 769 case C_ISFIFO: 770 case C_ISCHR: 771 case C_ISBLK: 772 case C_ISSOCK: 773 case C_ISNWK: 774 break; 775 default: 776 throw new IllegalArgumentException( 777 "Unknown mode. " 778 + "Full: " + Long.toHexString(mode) 779 + " Masked: " + Long.toHexString(maskedMode)); 780 } 781 782 this.mode = mode; 783 } 784 785 /** 786 * Set the name. 787 * 788 * @param name 789 * The name to set. 790 */ 791 public void setName(final String name) { 792 this.name = name; 793 } 794 795 /** 796 * Set the number of links. 797 * 798 * @param nlink 799 * The number of links to set. 800 */ 801 public void setNumberOfLinks(final long nlink) { 802 this.nlink = nlink; 803 } 804 805 /** 806 * Set the remote device id. 807 * 808 * @param device 809 * The remote device id to set. 810 * @throws UnsupportedOperationException 811 * if this method is called for a CpioArchiveEntry with a new 812 * format. 813 */ 814 public void setRemoteDevice(final long device) { 815 checkOldFormat(); 816 this.rmin = device; 817 } 818 819 /** 820 * Set the remote major device id. 821 * 822 * @param rmaj 823 * The remote major device id to set. 824 * @throws UnsupportedOperationException 825 * if this method is called for a CpioArchiveEntry with an old 826 * format. 827 */ 828 public void setRemoteDeviceMaj(final long rmaj) { 829 checkNewFormat(); 830 this.rmaj = rmaj; 831 } 832 833 /** 834 * Set the remote minor device id. 835 * 836 * @param rmin 837 * The remote minor device id to set. 838 * @throws UnsupportedOperationException 839 * if this method is called for a CpioArchiveEntry with an old 840 * format. 841 */ 842 public void setRemoteDeviceMin(final long rmin) { 843 checkNewFormat(); 844 this.rmin = rmin; 845 } 846 847 /** 848 * Set the time in seconds. 849 * 850 * @param time 851 * The time to set. 852 */ 853 public void setTime(final long time) { 854 this.mtime = time; 855 } 856 857 /** 858 * Set the user id. 859 * 860 * @param uid 861 * The user id to set. 862 */ 863 public void setUID(final long uid) { 864 this.uid = uid; 865 } 866 867 /* (non-Javadoc) 868 * @see java.lang.Object#hashCode() 869 */ 870 @Override 871 public int hashCode() { 872 final int prime = 31; 873 int result = 1; 874 result = prime * result + (name == null ? 0 : name.hashCode()); 875 return result; 876 } 877 878 /* (non-Javadoc) 879 * @see java.lang.Object#equals(java.lang.Object) 880 */ 881 @Override 882 public boolean equals(final Object obj) { 883 if (this == obj) { 884 return true; 885 } 886 if (obj == null || getClass() != obj.getClass()) { 887 return false; 888 } 889 final CpioArchiveEntry other = (CpioArchiveEntry) obj; 890 if (name == null) { 891 return other.name == null; 892 } else { 893 return name.equals(other.name); 894 } 895 } 896}