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 }