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