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