001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.compress.archivers.sevenz; 018 019import java.nio.file.attribute.FileTime; 020import java.util.Arrays; 021import java.util.Collections; 022import java.util.Date; 023import java.util.Iterator; 024import java.util.LinkedList; 025import java.util.Objects; 026 027import org.apache.commons.compress.archivers.ArchiveEntry; 028import org.apache.commons.io.file.attribute.FileTimes; 029 030/** 031 * An entry in a 7z archive. 032 * 033 * @NotThreadSafe 034 * @since 1.6 035 */ 036public class SevenZArchiveEntry implements ArchiveEntry { 037 038 static final SevenZArchiveEntry[] EMPTY_SEVEN_Z_ARCHIVE_ENTRY_ARRAY = {}; 039 040 /** 041 * Converts Java time to NTFS time. 042 * 043 * @param date the Java time 044 * @return the NTFS time 045 * @deprecated Use {@link FileTimes#toNtfsTime(Date)} instead. 046 * @see FileTimes#toNtfsTime(Date) 047 */ 048 @Deprecated 049 public static long javaTimeToNtfsTime(final Date date) { 050 return FileTimes.toNtfsTime(date); 051 } 052 053 /** 054 * Converts NTFS time (100 nanosecond units since 1 January 1601) to Java time. 055 * 056 * @param ntfsTime the NTFS time in 100 nanosecond units 057 * @return the Java time 058 * @deprecated Use {@link FileTimes#ntfsTimeToDate(long)} instead. 059 * @see FileTimes#ntfsTimeToDate(long) 060 */ 061 @Deprecated 062 public static Date ntfsTimeToJavaTime(final long ntfsTime) { 063 return FileTimes.ntfsTimeToDate(ntfsTime); 064 } 065 066 private String name; 067 private boolean hasStream; 068 private boolean isDirectory; 069 private boolean isAntiItem; 070 private boolean hasCreationDate; 071 private boolean hasLastModifiedDate; 072 private boolean hasAccessDate; 073 private FileTime creationDate; 074 private FileTime lastModifiedDate; 075 private FileTime accessDate; 076 private boolean hasWindowsAttributes; 077 private int windowsAttributes; 078 private boolean hasCrc; 079 private long crc, compressedCrc; 080 private long size, compressedSize; 081 private Iterable<? extends SevenZMethodConfiguration> contentMethods; 082 083 /** 084 * Constructs a new instance. 085 */ 086 public SevenZArchiveEntry() { 087 } 088 089 @Override 090 public boolean equals(final Object obj) { 091 if (this == obj) { 092 return true; 093 } 094 if (obj == null || getClass() != obj.getClass()) { 095 return false; 096 } 097 final SevenZArchiveEntry other = (SevenZArchiveEntry) obj; 098 return Objects.equals(name, other.name) && hasStream == other.hasStream && isDirectory == other.isDirectory && isAntiItem == other.isAntiItem 099 && hasCreationDate == other.hasCreationDate && hasLastModifiedDate == other.hasLastModifiedDate && hasAccessDate == other.hasAccessDate 100 && Objects.equals(creationDate, other.creationDate) && Objects.equals(lastModifiedDate, other.lastModifiedDate) 101 && Objects.equals(accessDate, other.accessDate) && hasWindowsAttributes == other.hasWindowsAttributes 102 && windowsAttributes == other.windowsAttributes && hasCrc == other.hasCrc && crc == other.crc && compressedCrc == other.compressedCrc 103 && size == other.size && compressedSize == other.compressedSize && equalSevenZMethods(contentMethods, other.contentMethods); 104 } 105 106 private boolean equalSevenZMethods(final Iterable<? extends SevenZMethodConfiguration> c1, final Iterable<? extends SevenZMethodConfiguration> c2) { 107 if (c1 == null) { 108 return c2 == null; 109 } 110 if (c2 == null) { 111 return false; 112 } 113 final Iterator<? extends SevenZMethodConfiguration> i2 = c2.iterator(); 114 for (final SevenZMethodConfiguration element : c1) { 115 if (!i2.hasNext()) { 116 return false; 117 } 118 if (!element.equals(i2.next())) { 119 return false; 120 } 121 } 122 return !i2.hasNext(); 123 } 124 125 /** 126 * Gets the access date. This is equivalent to {@link SevenZArchiveEntry#getAccessTime()}, but precision is truncated to milliseconds. 127 * 128 * @throws UnsupportedOperationException if the entry hasn't got an access date. 129 * @return the access date 130 * @see SevenZArchiveEntry#getAccessTime() 131 */ 132 public Date getAccessDate() { 133 return FileTimes.toDate(getAccessTime()); 134 } 135 136 /** 137 * Gets the access time. 138 * 139 * @throws UnsupportedOperationException if the entry hasn't got an access time. 140 * @return the access time 141 * @since 1.23 142 */ 143 public FileTime getAccessTime() { 144 if (hasAccessDate) { 145 return accessDate; 146 } 147 throw new UnsupportedOperationException("The entry doesn't have this timestamp"); 148 } 149 150 /** 151 * Gets the compressed CRC. 152 * 153 * @return the compressed CRC 154 * @deprecated Use {@link #getCompressedCrcValue()} instead. 155 */ 156 @Deprecated 157 int getCompressedCrc() { 158 return (int) compressedCrc; 159 } 160 161 /** 162 * Gets the compressed CRC. 163 * 164 * @since 1.7 165 * @return the CRC 166 */ 167 long getCompressedCrcValue() { 168 return compressedCrc; 169 } 170 171 /** 172 * Gets this entry's compressed file size. 173 * 174 * @return This entry's compressed file size. 175 */ 176 long getCompressedSize() { 177 return compressedSize; 178 } 179 180 /** 181 * Gets the (compression) methods to use for entry's content - the default is LZMA2. 182 * 183 * <p> 184 * Currently only {@link SevenZMethod#COPY}, {@link SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link SevenZMethod#DEFLATE} are supported when 185 * writing archives. 186 * </p> 187 * 188 * <p> 189 * The methods will be consulted in iteration order to create the final output. 190 * </p> 191 * 192 * @since 1.8 193 * @return the methods to use for the content 194 */ 195 public Iterable<? extends SevenZMethodConfiguration> getContentMethods() { 196 return contentMethods; 197 } 198 199 /** 200 * Gets the CRC. 201 * 202 * @deprecated use getCrcValue instead. 203 * @return the CRC 204 */ 205 @Deprecated 206 public int getCrc() { 207 return (int) crc; 208 } 209 210 /** 211 * Gets the CRC. 212 * 213 * @since 1.7 214 * @return the CRC 215 */ 216 public long getCrcValue() { 217 return crc; 218 } 219 220 /** 221 * Gets the creation date. This is equivalent to {@link SevenZArchiveEntry#getCreationTime()}, but precision is truncated to milliseconds. 222 * 223 * @throws UnsupportedOperationException if the entry hasn't got a creation date. 224 * @return the new creation date 225 * @see SevenZArchiveEntry#getCreationTime() 226 */ 227 public Date getCreationDate() { 228 return FileTimes.toDate(getCreationTime()); 229 } 230 231 /** 232 * Gets the creation time. 233 * 234 * @throws UnsupportedOperationException if the entry hasn't got a creation time. 235 * @return the creation time 236 * @since 1.23 237 */ 238 public FileTime getCreationTime() { 239 if (hasCreationDate) { 240 return creationDate; 241 } 242 throw new UnsupportedOperationException("The entry doesn't have this timestamp"); 243 } 244 245 /** 246 * Gets whether this entry has got an access date at all. 247 * 248 * @return whether this entry has got an access date at all. 249 */ 250 public boolean getHasAccessDate() { 251 return hasAccessDate; 252 } 253 254 /** 255 * Gets whether this entry has got a crc. 256 * 257 * <p> 258 * In general entries without streams don't have a CRC either. 259 * </p> 260 * 261 * @return whether this entry has got a crc. 262 */ 263 public boolean getHasCrc() { 264 return hasCrc; 265 } 266 267 /** 268 * Gets whether this entry has got a creation date at all. 269 * 270 * @return whether the entry has got a creation date 271 */ 272 public boolean getHasCreationDate() { 273 return hasCreationDate; 274 } 275 276 /** 277 * Gets whether this entry has got a last modified date at all. 278 * 279 * @return whether this entry has got a last modified date at all 280 */ 281 public boolean getHasLastModifiedDate() { 282 return hasLastModifiedDate; 283 } 284 285 /** 286 * Gets whether this entry has windows attributes. 287 * 288 * @return whether this entry has windows attributes. 289 */ 290 public boolean getHasWindowsAttributes() { 291 return hasWindowsAttributes; 292 } 293 294 /** 295 * Gets the last modified date. This is equivalent to {@link SevenZArchiveEntry#getLastModifiedTime()}, but precision is truncated to milliseconds. 296 * 297 * @throws UnsupportedOperationException if the entry hasn't got a last modified date. 298 * @return the last modified date 299 * @see SevenZArchiveEntry#getLastModifiedTime() 300 */ 301 @Override 302 public Date getLastModifiedDate() { 303 return FileTimes.toDate(getLastModifiedTime()); 304 } 305 306 /** 307 * Gets the last modified time. 308 * 309 * @throws UnsupportedOperationException if the entry hasn't got a last modified time. 310 * @return the last modified time 311 * @since 1.23 312 */ 313 public FileTime getLastModifiedTime() { 314 if (hasLastModifiedDate) { 315 return lastModifiedDate; 316 } 317 throw new UnsupportedOperationException("The entry doesn't have this timestamp"); 318 } 319 320 /** 321 * Gets this entry's name. 322 * 323 * <p> 324 * This method returns the raw name as it is stored inside of the archive. 325 * </p> 326 * 327 * @return This entry's name. 328 */ 329 @Override 330 public String getName() { 331 return name; 332 } 333 334 /** 335 * Gets this entry's file size. 336 * 337 * @return This entry's file size. 338 */ 339 @Override 340 public long getSize() { 341 return size; 342 } 343 344 /** 345 * Gets the windows attributes. 346 * 347 * @return the windows attributes 348 */ 349 public int getWindowsAttributes() { 350 return windowsAttributes; 351 } 352 353 @Override 354 public int hashCode() { 355 final String n = getName(); 356 return n == null ? 0 : n.hashCode(); 357 } 358 359 /** 360 * Tests whether there is any content associated with this entry. 361 * 362 * @return whether there is any content associated with this entry. 363 */ 364 public boolean hasStream() { 365 return hasStream; 366 } 367 368 /** 369 * Tests whether this is an "anti-item" used in differential backups, meaning it should delete the same file from a previous backup. 370 * 371 * @return true if it is an anti-item, false otherwise 372 */ 373 public boolean isAntiItem() { 374 return isAntiItem; 375 } 376 377 /** 378 * Tests whether or not this entry represents a directory. 379 * 380 * @return True if this entry is a directory. 381 */ 382 @Override 383 public boolean isDirectory() { 384 return isDirectory; 385 } 386 387 /** 388 * Sets the access date. 389 * 390 * @param accessDate the new access date 391 * @see SevenZArchiveEntry#setAccessTime(FileTime) 392 */ 393 public void setAccessDate(final Date accessDate) { 394 setAccessTime(FileTimes.toFileTime(accessDate)); 395 } 396 397 /** 398 * Sets the access date using NTFS time (100 nanosecond units since 1 January 1601) 399 * 400 * @param ntfsAccessDate the access date 401 */ 402 public void setAccessDate(final long ntfsAccessDate) { 403 this.accessDate = FileTimes.ntfsTimeToFileTime(ntfsAccessDate); 404 } 405 406 /** 407 * Sets the access time. 408 * 409 * @param time the new access time 410 * @since 1.23 411 */ 412 public void setAccessTime(final FileTime time) { 413 hasAccessDate = time != null; 414 if (hasAccessDate) { 415 this.accessDate = time; 416 } 417 } 418 419 /** 420 * Sets whether this is an "anti-item" used in differential backups, meaning it should delete the same file from a previous backup. 421 * 422 * @param isAntiItem true if it is an anti-item, false otherwise 423 */ 424 public void setAntiItem(final boolean isAntiItem) { 425 this.isAntiItem = isAntiItem; 426 } 427 428 /** 429 * Sets the compressed CRC. 430 * 431 * @deprecated use setCompressedCrcValue instead. 432 * @param crc the CRC 433 */ 434 @Deprecated 435 void setCompressedCrc(final int crc) { 436 this.compressedCrc = crc; 437 } 438 439 /** 440 * Sets the compressed CRC. 441 * 442 * @since 1.7 443 * @param crc the CRC 444 */ 445 void setCompressedCrcValue(final long crc) { 446 this.compressedCrc = crc; 447 } 448 449 /** 450 * Sets this entry's compressed file size. 451 * 452 * @param size This entry's new compressed file size. 453 */ 454 void setCompressedSize(final long size) { 455 this.compressedSize = size; 456 } 457 458 /** 459 * Sets the (compression) methods to use for entry's content - the default is LZMA2. 460 * 461 * <p> 462 * Currently only {@link SevenZMethod#COPY}, {@link SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link SevenZMethod#DEFLATE} are supported when 463 * writing archives. 464 * </p> 465 * 466 * <p> 467 * The methods will be consulted in iteration order to create the final output. 468 * </p> 469 * 470 * @param methods the methods to use for the content 471 * @since 1.8 472 */ 473 public void setContentMethods(final Iterable<? extends SevenZMethodConfiguration> methods) { 474 if (methods != null) { 475 final LinkedList<SevenZMethodConfiguration> l = new LinkedList<>(); 476 methods.forEach(l::addLast); 477 contentMethods = Collections.unmodifiableList(l); 478 } else { 479 contentMethods = null; 480 } 481 } 482 483 /** 484 * Sets the (compression) methods to use for entry's content - the default is LZMA2. 485 * 486 * <p> 487 * Currently only {@link SevenZMethod#COPY}, {@link SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link SevenZMethod#DEFLATE} are supported when 488 * writing archives. 489 * </p> 490 * 491 * <p> 492 * The methods will be consulted in iteration order to create the final output. 493 * </p> 494 * 495 * @param methods the methods to use for the content 496 * @since 1.22 497 */ 498 public void setContentMethods(final SevenZMethodConfiguration... methods) { 499 setContentMethods(Arrays.asList(methods)); 500 } 501 502 /** 503 * Sets the CRC. 504 * 505 * @deprecated use setCrcValue instead. 506 * @param crc the CRC 507 */ 508 @Deprecated 509 public void setCrc(final int crc) { 510 this.crc = crc; 511 } 512 513 /** 514 * Sets the CRC. 515 * 516 * @since 1.7 517 * @param crc the CRC 518 */ 519 public void setCrcValue(final long crc) { 520 this.crc = crc; 521 } 522 523 /** 524 * Sets the creation date. 525 * 526 * @param creationDate the new creation date 527 * @see SevenZArchiveEntry#setCreationTime(FileTime) 528 */ 529 public void setCreationDate(final Date creationDate) { 530 setCreationTime(FileTimes.toFileTime(creationDate)); 531 } 532 533 /** 534 * Sets the creation date using NTFS time (100 nanosecond units since 1 January 1601) 535 * 536 * @param ntfsCreationDate the creation date 537 */ 538 public void setCreationDate(final long ntfsCreationDate) { 539 this.creationDate = FileTimes.ntfsTimeToFileTime(ntfsCreationDate); 540 } 541 542 /** 543 * Sets the creation time. 544 * 545 * @param time the new creation time 546 * @since 1.23 547 */ 548 public void setCreationTime(final FileTime time) { 549 hasCreationDate = time != null; 550 if (hasCreationDate) { 551 this.creationDate = time; 552 } 553 } 554 555 /** 556 * Sets whether or not this entry represents a directory. 557 * 558 * @param isDirectory True if this entry is a directory. 559 */ 560 public void setDirectory(final boolean isDirectory) { 561 this.isDirectory = isDirectory; 562 } 563 564 /** 565 * Sets whether this entry has got an access date at all. 566 * 567 * @param hasAcessDate whether this entry has got an access date at all. 568 */ 569 public void setHasAccessDate(final boolean hasAcessDate) { 570 this.hasAccessDate = hasAcessDate; 571 } 572 573 /** 574 * Sets whether this entry has got a crc. 575 * 576 * @param hasCrc whether this entry has got a crc. 577 */ 578 public void setHasCrc(final boolean hasCrc) { 579 this.hasCrc = hasCrc; 580 } 581 582 /** 583 * Sets whether this entry has got a creation date at all. 584 * 585 * @param hasCreationDate whether the entry has got a creation date 586 */ 587 public void setHasCreationDate(final boolean hasCreationDate) { 588 this.hasCreationDate = hasCreationDate; 589 } 590 591 /** 592 * Sets whether this entry has got a last modified date at all. 593 * 594 * @param hasLastModifiedDate whether this entry has got a last modified date at all 595 */ 596 public void setHasLastModifiedDate(final boolean hasLastModifiedDate) { 597 this.hasLastModifiedDate = hasLastModifiedDate; 598 } 599 600 /** 601 * Sets whether there is any content associated with this entry. 602 * 603 * @param hasStream whether there is any content associated with this entry. 604 */ 605 public void setHasStream(final boolean hasStream) { 606 this.hasStream = hasStream; 607 } 608 609 /** 610 * Sets whether this entry has windows attributes. 611 * 612 * @param hasWindowsAttributes whether this entry has windows attributes. 613 */ 614 public void setHasWindowsAttributes(final boolean hasWindowsAttributes) { 615 this.hasWindowsAttributes = hasWindowsAttributes; 616 } 617 618 /** 619 * Sets the last modified date. 620 * 621 * @param lastModifiedDate the new last modified date 622 * @see SevenZArchiveEntry#setLastModifiedTime(FileTime) 623 */ 624 public void setLastModifiedDate(final Date lastModifiedDate) { 625 setLastModifiedTime(FileTimes.toFileTime(lastModifiedDate)); 626 } 627 628 /** 629 * Sets the last modified date using NTFS time (100 nanosecond units since 1 January 1601) 630 * 631 * @param ntfsLastModifiedDate the last modified date 632 */ 633 public void setLastModifiedDate(final long ntfsLastModifiedDate) { 634 this.lastModifiedDate = FileTimes.ntfsTimeToFileTime(ntfsLastModifiedDate); 635 } 636 637 /** 638 * Sets the last modified time. 639 * 640 * @param time the new last modified time 641 * @since 1.23 642 */ 643 public void setLastModifiedTime(final FileTime time) { 644 hasLastModifiedDate = time != null; 645 if (hasLastModifiedDate) { 646 this.lastModifiedDate = time; 647 } 648 } 649 650 /** 651 * Sets this entry's name. 652 * 653 * @param name This entry's new name. 654 */ 655 public void setName(final String name) { 656 this.name = name; 657 } 658 659 /** 660 * Sets this entry's file size. 661 * 662 * @param size This entry's new file size. 663 */ 664 public void setSize(final long size) { 665 this.size = size; 666 } 667 668 /** 669 * Sets the windows attributes. 670 * 671 * @param windowsAttributes the windows attributes 672 */ 673 public void setWindowsAttributes(final int windowsAttributes) { 674 this.windowsAttributes = windowsAttributes; 675 } 676}