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