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="http://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt">http://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; 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 * @return Returns the name. 521 */ 522 @Override 523 public String getName() { 524 return this.name; 525 } 526 527 /** 528 * Get the number of links. 529 * 530 * @return Returns the number of links. 531 */ 532 public long getNumberOfLinks() { 533 return nlink == 0 ? 534 isDirectory() ? 2 : 1 535 : nlink; 536 } 537 538 /** 539 * Get the remote device id. 540 * 541 * @return Returns the remote device id. 542 * @throws UnsupportedOperationException 543 * if this method is called for a CPIOArchiveEntry with a new 544 * format. 545 */ 546 public long getRemoteDevice() { 547 checkOldFormat(); 548 return this.rmin; 549 } 550 551 /** 552 * Get the remote major device id. 553 * 554 * @return Returns the remote major device id. 555 * @throws UnsupportedOperationException 556 * if this method is called for a CPIOArchiveEntry with an old 557 * format. 558 */ 559 public long getRemoteDeviceMaj() { 560 checkNewFormat(); 561 return this.rmaj; 562 } 563 564 /** 565 * Get the remote minor device id. 566 * 567 * @return Returns the remote minor device id. 568 * @throws UnsupportedOperationException 569 * if this method is called for a CPIOArchiveEntry with an old 570 * format. 571 */ 572 public long getRemoteDeviceMin() { 573 checkNewFormat(); 574 return this.rmin; 575 } 576 577 /** 578 * Get the time in seconds. 579 * 580 * @return Returns the time. 581 */ 582 public long getTime() { 583 return this.mtime; 584 } 585 586 @Override 587 public Date getLastModifiedDate() { 588 return new Date(1000 * getTime()); 589 } 590 591 /** 592 * Get the user id. 593 * 594 * @return Returns the user id. 595 */ 596 public long getUID() { 597 return this.uid; 598 } 599 600 /** 601 * Check if this entry represents a block device. 602 * 603 * @return TRUE if this entry is a block device. 604 */ 605 public boolean isBlockDevice() { 606 return CpioUtil.fileType(mode) == C_ISBLK; 607 } 608 609 /** 610 * Check if this entry represents a character device. 611 * 612 * @return TRUE if this entry is a character device. 613 */ 614 public boolean isCharacterDevice() { 615 return CpioUtil.fileType(mode) == C_ISCHR; 616 } 617 618 /** 619 * Check if this entry represents a directory. 620 * 621 * @return TRUE if this entry is a directory. 622 */ 623 @Override 624 public boolean isDirectory() { 625 return CpioUtil.fileType(mode) == C_ISDIR; 626 } 627 628 /** 629 * Check if this entry represents a network device. 630 * 631 * @return TRUE if this entry is a network device. 632 */ 633 public boolean isNetwork() { 634 return CpioUtil.fileType(mode) == C_ISNWK; 635 } 636 637 /** 638 * Check if this entry represents a pipe. 639 * 640 * @return TRUE if this entry is a pipe. 641 */ 642 public boolean isPipe() { 643 return CpioUtil.fileType(mode) == C_ISFIFO; 644 } 645 646 /** 647 * Check if this entry represents a regular file. 648 * 649 * @return TRUE if this entry is a regular file. 650 */ 651 public boolean isRegularFile() { 652 return CpioUtil.fileType(mode) == C_ISREG; 653 } 654 655 /** 656 * Check if this entry represents a socket. 657 * 658 * @return TRUE if this entry is a socket. 659 */ 660 public boolean isSocket() { 661 return CpioUtil.fileType(mode) == C_ISSOCK; 662 } 663 664 /** 665 * Check if this entry represents a symbolic link. 666 * 667 * @return TRUE if this entry is a symbolic link. 668 */ 669 public boolean isSymbolicLink() { 670 return CpioUtil.fileType(mode) == C_ISLNK; 671 } 672 673 /** 674 * Set the checksum. The checksum is calculated by adding all bytes of a 675 * file to transfer (crc += buf[pos] & 0xFF). 676 * 677 * @param chksum 678 * The checksum to set. 679 */ 680 public void setChksum(final long chksum) { 681 checkNewFormat(); 682 this.chksum = chksum; 683 } 684 685 /** 686 * Set the device id. 687 * 688 * @param device 689 * The device id to set. 690 * @throws UnsupportedOperationException 691 * if this method is called for a CPIOArchiveEntry with a new 692 * format. 693 */ 694 public void setDevice(final long device) { 695 checkOldFormat(); 696 this.min = device; 697 } 698 699 /** 700 * Set major device id. 701 * 702 * @param maj 703 * The major device id to set. 704 */ 705 public void setDeviceMaj(final long maj) { 706 checkNewFormat(); 707 this.maj = maj; 708 } 709 710 /** 711 * Set the minor device id 712 * 713 * @param min 714 * The minor device id to set. 715 */ 716 public void setDeviceMin(final long min) { 717 checkNewFormat(); 718 this.min = min; 719 } 720 721 /** 722 * Set the filesize. 723 * 724 * @param size 725 * The filesize to set. 726 */ 727 public void setSize(final long size) { 728 if (size < 0 || size > 0xFFFFFFFFL) { 729 throw new IllegalArgumentException("invalid entry size <" + size 730 + ">"); 731 } 732 this.filesize = size; 733 } 734 735 /** 736 * Set the group id. 737 * 738 * @param gid 739 * The group id to set. 740 */ 741 public void setGID(final long gid) { 742 this.gid = gid; 743 } 744 745 /** 746 * Set the inode. 747 * 748 * @param inode 749 * The inode to set. 750 */ 751 public void setInode(final long inode) { 752 this.inode = inode; 753 } 754 755 /** 756 * Set the mode of this entry (e.g. directory, regular file). 757 * 758 * @param mode 759 * The mode to set. 760 */ 761 public void setMode(final long mode) { 762 final long maskedMode = mode & S_IFMT; 763 switch ((int) maskedMode) { 764 case C_ISDIR: 765 case C_ISLNK: 766 case C_ISREG: 767 case C_ISFIFO: 768 case C_ISCHR: 769 case C_ISBLK: 770 case C_ISSOCK: 771 case C_ISNWK: 772 break; 773 default: 774 throw new IllegalArgumentException( 775 "Unknown mode. " 776 + "Full: " + Long.toHexString(mode) 777 + " Masked: " + Long.toHexString(maskedMode)); 778 } 779 780 this.mode = mode; 781 } 782 783 /** 784 * Set the name. 785 * 786 * @param name 787 * The name to set. 788 */ 789 public void setName(final String name) { 790 this.name = name; 791 } 792 793 /** 794 * Set the number of links. 795 * 796 * @param nlink 797 * The number of links to set. 798 */ 799 public void setNumberOfLinks(final long nlink) { 800 this.nlink = nlink; 801 } 802 803 /** 804 * Set the remote device id. 805 * 806 * @param device 807 * The remote device id to set. 808 * @throws UnsupportedOperationException 809 * if this method is called for a CPIOArchiveEntry with a new 810 * format. 811 */ 812 public void setRemoteDevice(final long device) { 813 checkOldFormat(); 814 this.rmin = device; 815 } 816 817 /** 818 * Set the remote major device id. 819 * 820 * @param rmaj 821 * The remote major device id to set. 822 * @throws UnsupportedOperationException 823 * if this method is called for a CPIOArchiveEntry with an old 824 * format. 825 */ 826 public void setRemoteDeviceMaj(final long rmaj) { 827 checkNewFormat(); 828 this.rmaj = rmaj; 829 } 830 831 /** 832 * Set the remote minor device id. 833 * 834 * @param rmin 835 * The remote minor device id to set. 836 * @throws UnsupportedOperationException 837 * if this method is called for a CPIOArchiveEntry with an old 838 * format. 839 */ 840 public void setRemoteDeviceMin(final long rmin) { 841 checkNewFormat(); 842 this.rmin = rmin; 843 } 844 845 /** 846 * Set the time in seconds. 847 * 848 * @param time 849 * The time to set. 850 */ 851 public void setTime(final long time) { 852 this.mtime = time; 853 } 854 855 /** 856 * Set the user id. 857 * 858 * @param uid 859 * The user id to set. 860 */ 861 public void setUID(final long uid) { 862 this.uid = uid; 863 } 864 865 /* (non-Javadoc) 866 * @see java.lang.Object#hashCode() 867 */ 868 @Override 869 public int hashCode() { 870 final int prime = 31; 871 int result = 1; 872 result = prime * result + (name == null ? 0 : name.hashCode()); 873 return result; 874 } 875 876 /* (non-Javadoc) 877 * @see java.lang.Object#equals(java.lang.Object) 878 */ 879 @Override 880 public boolean equals(final Object obj) { 881 if (this == obj) { 882 return true; 883 } 884 if (obj == null || getClass() != obj.getClass()) { 885 return false; 886 } 887 final CpioArchiveEntry other = (CpioArchiveEntry) obj; 888 if (name == null) { 889 if (other.name != null) { 890 return false; 891 } 892 } else if (!name.equals(other.name)) { 893 return false; 894 } 895 return true; 896 } 897}