1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.codehaus.plexus.archiver;
18
19 import javax.annotation.Nonnull;
20 import javax.inject.Inject;
21 import javax.inject.Provider;
22
23 import java.io.Closeable;
24 import java.io.File;
25 import java.io.IOException;
26 import java.lang.reflect.UndeclaredThrowableException;
27 import java.nio.charset.Charset;
28 import java.nio.file.Files;
29 import java.nio.file.attribute.FileTime;
30 import java.util.ArrayList;
31 import java.util.Comparator;
32 import java.util.Date;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.NoSuchElementException;
39 import java.util.Set;
40
41 import org.codehaus.plexus.archiver.manager.ArchiverManager;
42 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
43 import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributeUtils;
44 import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributes;
45 import org.codehaus.plexus.components.io.attributes.SimpleResourceAttributes;
46 import org.codehaus.plexus.components.io.functions.ResourceAttributeSupplier;
47 import org.codehaus.plexus.components.io.resources.AbstractPlexusIoResourceCollection;
48 import org.codehaus.plexus.components.io.resources.EncodingSupported;
49 import org.codehaus.plexus.components.io.resources.PlexusIoArchivedResourceCollection;
50 import org.codehaus.plexus.components.io.resources.PlexusIoFileResourceCollection;
51 import org.codehaus.plexus.components.io.resources.PlexusIoResource;
52 import org.codehaus.plexus.components.io.resources.PlexusIoResourceCollection;
53 import org.codehaus.plexus.components.io.resources.proxy.PlexusIoProxyResourceCollection;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 import static org.codehaus.plexus.archiver.util.DefaultArchivedFileSet.archivedFileSet;
58 import static org.codehaus.plexus.archiver.util.DefaultFileSet.fileSet;
59
60 public abstract class AbstractArchiver implements Archiver, FinalizerEnabled {
61
62 private final Logger logger = LoggerFactory.getLogger(getClass());
63
64 protected Logger getLogger() {
65 return logger;
66 }
67
68 private File destFile;
69
70
71
72
73
74
75
76
77
78
79 private final List<Object> resources = new ArrayList<>();
80
81 private boolean includeEmptyDirs = true;
82
83 private int forcedFileMode = -1;
84
85 private int forcedDirectoryMode = -1;
86
87 private int defaultFileMode = -1;
88
89 private int defaultDirectoryMode = -1;
90
91 private int umask = -1;
92
93 private boolean forced = true;
94
95 private List<ArchiveFinalizer> finalizers;
96
97 private File dotFileDirectory;
98
99 private String duplicateBehavior = Archiver.DUPLICATES_SKIP;
100
101
102 private final boolean replacePathSlashesToJavaPaths = File.separatorChar == '/';
103
104 private final List<Closeable> closeables = new ArrayList<>();
105
106
107
108
109
110
111 private boolean useJvmChmod = true;
112
113 private FileTime lastModifiedTime;
114
115
116
117
118 private Comparator<String> filenameComparator;
119
120
121
122
123 private int overrideUid = -1;
124
125
126
127
128 private String overrideUserName;
129
130
131
132
133 private int overrideGid = -1;
134
135
136
137
138 private String overrideGroupName;
139
140
141
142
143
144 @Inject
145 private Provider<ArchiverManager> archiverManagerProvider;
146
147 private static class AddedResourceCollection {
148
149 private final PlexusIoResourceCollection resources;
150
151 private final int forcedFileMode;
152
153 private final int forcedDirectoryMode;
154
155 public AddedResourceCollection(PlexusIoResourceCollection resources, int forcedFileMode, int forcedDirMode) {
156 this.resources = resources;
157 this.forcedFileMode = forcedFileMode;
158 this.forcedDirectoryMode = forcedDirMode;
159 }
160
161 private int maybeOverridden(int suggestedMode, boolean isDir) {
162 if (isDir) {
163 return forcedDirectoryMode >= 0 ? forcedDirectoryMode : suggestedMode;
164 } else {
165 return forcedFileMode >= 0 ? forcedFileMode : suggestedMode;
166 }
167 }
168 }
169
170
171
172
173 private boolean ignorePermissions = false;
174
175 @Override
176 public String getDuplicateBehavior() {
177 return duplicateBehavior;
178 }
179
180 @Override
181 public void setDuplicateBehavior(final String duplicate) {
182 if (!Archiver.DUPLICATES_VALID_BEHAVIORS.contains(duplicate)) {
183 throw new IllegalArgumentException("Invalid duplicate-file behavior: '" + duplicate
184 + "'. Please specify one of: " + Archiver.DUPLICATES_VALID_BEHAVIORS);
185 }
186
187 duplicateBehavior = duplicate;
188 }
189
190 @Override
191 public final void setFileMode(final int mode) {
192 if (mode >= 0) {
193 forcedFileMode = (mode & UnixStat.PERM_MASK) | UnixStat.FILE_FLAG;
194 } else {
195 forcedFileMode = -1;
196 }
197 }
198
199 @Override
200 public final void setDefaultFileMode(final int mode) {
201 defaultFileMode = (mode & UnixStat.PERM_MASK) | UnixStat.FILE_FLAG;
202 }
203
204 @Override
205 public final int getOverrideFileMode() {
206 return forcedFileMode;
207 }
208
209 @Override
210 public final int getFileMode() {
211 if (forcedFileMode < 0) {
212 if (defaultFileMode < 0) {
213 return DEFAULT_FILE_MODE;
214 }
215
216 return defaultFileMode;
217 }
218
219 return forcedFileMode;
220 }
221
222 @Override
223 public final int getDefaultFileMode() {
224 return defaultFileMode;
225 }
226
227
228
229
230 @Deprecated
231 public final int getRawDefaultFileMode() {
232 return getDefaultFileMode();
233 }
234
235 @Override
236 public final void setDirectoryMode(final int mode) {
237 if (mode >= 0) {
238 forcedDirectoryMode = (mode & UnixStat.PERM_MASK) | UnixStat.DIR_FLAG;
239 } else {
240 forcedDirectoryMode = -1;
241 }
242 }
243
244 @Override
245 public final void setDefaultDirectoryMode(final int mode) {
246 defaultDirectoryMode = (mode & UnixStat.PERM_MASK) | UnixStat.DIR_FLAG;
247 }
248
249 @Override
250 public final int getOverrideDirectoryMode() {
251 return forcedDirectoryMode;
252 }
253
254 @Override
255 public final int getDirectoryMode() {
256 if (forcedDirectoryMode < 0) {
257 if (defaultDirectoryMode < 0) {
258 return DEFAULT_DIR_MODE;
259 }
260
261 return defaultDirectoryMode;
262 }
263
264 return forcedDirectoryMode;
265 }
266
267 @Override
268 public final int getDefaultDirectoryMode() {
269 if (defaultDirectoryMode < 0) {
270 return DEFAULT_DIR_MODE;
271 } else {
272 return defaultDirectoryMode;
273 }
274 }
275
276 @Override
277 public boolean getIncludeEmptyDirs() {
278 return includeEmptyDirs;
279 }
280
281 @Override
282 public void setIncludeEmptyDirs(final boolean includeEmptyDirs) {
283 this.includeEmptyDirs = includeEmptyDirs;
284 }
285
286 @Override
287 @Deprecated
288 public void addDirectory(@Nonnull final File directory) throws ArchiverException {
289 addFileSet(fileSet(directory).prefixed("").includeExclude(null, null).includeEmptyDirs(includeEmptyDirs));
290 }
291
292 @Override
293 @Deprecated
294 public void addDirectory(@Nonnull final File directory, final String prefix) throws ArchiverException {
295 addFileSet(
296 fileSet(directory).prefixed(prefix).includeExclude(null, null).includeEmptyDirs(includeEmptyDirs));
297 }
298
299 @Override
300 @Deprecated
301 public void addDirectory(@Nonnull final File directory, final String[] includes, final String[] excludes)
302 throws ArchiverException {
303 addFileSet(fileSet(directory)
304 .prefixed("")
305 .includeExclude(includes, excludes)
306 .includeEmptyDirs(includeEmptyDirs));
307 }
308
309 @Override
310 @Deprecated
311 public void addDirectory(
312 @Nonnull final File directory, final String prefix, final String[] includes, final String[] excludes)
313 throws ArchiverException {
314 addFileSet(fileSet(directory)
315 .prefixed(prefix)
316 .includeExclude(includes, excludes)
317 .includeEmptyDirs(includeEmptyDirs));
318 }
319
320 @Override
321 public void addFileSet(@Nonnull final FileSet fileSet) throws ArchiverException {
322 final File directory = fileSet.getDirectory();
323 if (directory == null) {
324 throw new ArchiverException("The file sets base directory is null.");
325 }
326
327 if (!directory.isDirectory()) {
328 throw new ArchiverException(directory.getAbsolutePath() + " isn't a directory.");
329 }
330
331
332
333 final PlexusIoFileResourceCollection collection = new PlexusIoFileResourceCollection();
334 collection.setFollowingSymLinks(false);
335
336 collection.setIncludes(fileSet.getIncludes());
337 collection.setExcludes(fileSet.getExcludes());
338 collection.setBaseDir(directory);
339 collection.setFileSelectors(fileSet.getFileSelectors());
340 collection.setIncludingEmptyDirectories(fileSet.isIncludingEmptyDirectories());
341 collection.setPrefix(fileSet.getPrefix());
342 collection.setCaseSensitive(fileSet.isCaseSensitive());
343 collection.setUsingDefaultExcludes(fileSet.isUsingDefaultExcludes());
344 collection.setStreamTransformer(fileSet.getStreamTransformer());
345 collection.setFileMappers(fileSet.getFileMappers());
346 collection.setFilenameComparator(getFilenameComparator());
347
348 if (getOverrideDirectoryMode() > -1
349 || getOverrideFileMode() > -1
350 || getOverrideUid() > -1
351 || getOverrideGid() > -1
352 || getOverrideUserName() != null
353 || getOverrideGroupName() != null) {
354 collection.setOverrideAttributes(
355 getOverrideUid(),
356 getOverrideUserName(),
357 getOverrideGid(),
358 getOverrideGroupName(),
359 getOverrideFileMode(),
360 getOverrideDirectoryMode());
361 }
362
363 if (getDefaultDirectoryMode() > -1 || getDefaultFileMode() > -1) {
364 collection.setDefaultAttributes(-1, null, -1, null, getDefaultFileMode(), getDefaultDirectoryMode());
365 }
366
367 addResources(collection);
368 }
369
370 @Override
371 public void addFile(@Nonnull final File inputFile, @Nonnull final String destFileName) throws ArchiverException {
372 int permissions;
373 if (forcedFileMode > 0) {
374 permissions = forcedFileMode;
375 } else {
376 permissions = PlexusIoResourceAttributes.UNKNOWN_OCTAL_MODE;
377 try {
378 permissions = PlexusIoResourceAttributeUtils.getFileAttributes(inputFile)
379 .getOctalMode();
380 } catch (IOException ioe) {
381
382 }
383 }
384
385 addFile(inputFile, destFileName, permissions);
386 }
387
388 @Override
389 public void addSymlink(String symlinkName, String symlinkDestination) throws ArchiverException {
390 final int fileMode = getOverrideFileMode();
391
392 addSymlink(symlinkName, fileMode, symlinkDestination);
393 }
394
395 @Override
396 public void addSymlink(String symlinkName, int permissions, String symlinkDestination) throws ArchiverException {
397 doAddResource(
398 ArchiveEntry.createSymlinkEntry(symlinkName, permissions, symlinkDestination, getDirectoryMode()));
399 }
400
401 private ArchiveEntry updateArchiveEntryAttributes(ArchiveEntry entry) {
402 if (getOverrideUid() > -1
403 || getOverrideGid() > -1
404 || getOverrideUserName() != null
405 || getOverrideGroupName() != null) {
406 entry.setResourceAttributes(new SimpleResourceAttributes(
407 getOverrideUid(),
408 getOverrideUserName(),
409 getOverrideGid(),
410 getOverrideGroupName(),
411 entry.getMode()));
412 }
413 return entry;
414 }
415
416 protected ArchiveEntry asArchiveEntry(
417 @Nonnull final PlexusIoResource resource,
418 final String destFileName,
419 int permissions,
420 PlexusIoResourceCollection collection)
421 throws ArchiverException {
422 if (!resource.isExisting()) {
423 throw new ArchiverException(resource.getName() + " not found.");
424 }
425
426 if (umask > 0 && permissions != PlexusIoResourceAttributes.UNKNOWN_OCTAL_MODE) {
427 permissions &= ~umask;
428 }
429
430 ArchiveEntry entry;
431 if (resource.isFile()) {
432 entry = ArchiveEntry.createFileEntry(destFileName, resource, permissions, collection, getDirectoryMode());
433 } else {
434 entry = ArchiveEntry.createDirectoryEntry(destFileName, resource, permissions, getDirectoryMode());
435 }
436
437 return updateArchiveEntryAttributes(entry);
438 }
439
440 private ArchiveEntry asArchiveEntry(final AddedResourceCollection collection, final PlexusIoResource resource)
441 throws ArchiverException {
442 final String destFileName = collection.resources.getName(resource);
443
444 int fromResource = PlexusIoResourceAttributes.UNKNOWN_OCTAL_MODE;
445 if (resource instanceof ResourceAttributeSupplier) {
446 final PlexusIoResourceAttributes attrs = ((ResourceAttributeSupplier) resource).getAttributes();
447
448 if (attrs != null) {
449 fromResource = attrs.getOctalMode();
450 }
451 }
452
453 return asArchiveEntry(
454 resource,
455 destFileName,
456 collection.maybeOverridden(fromResource, resource.isDirectory()),
457 collection.resources);
458 }
459
460 @Override
461 public void addResource(final PlexusIoResource resource, final String destFileName, final int permissions)
462 throws ArchiverException {
463 doAddResource(asArchiveEntry(resource, destFileName, permissions, null));
464 }
465
466 @Override
467 public void addFile(@Nonnull final File inputFile, @Nonnull String destFileName, int permissions)
468 throws ArchiverException {
469 if (!inputFile.isFile() || !inputFile.exists()) {
470 throw new ArchiverException(inputFile.getAbsolutePath() + " isn't a file.");
471 }
472
473 if (replacePathSlashesToJavaPaths) {
474 destFileName = destFileName.replace('\\', '/');
475 }
476
477 if (permissions < 0) {
478 permissions = getOverrideFileMode();
479 }
480
481 if (umask > 0 && permissions != PlexusIoResourceAttributes.UNKNOWN_OCTAL_MODE) {
482 permissions &= ~umask;
483 }
484
485 try {
486
487 ArchiveEntry entry = ArchiveEntry.createFileEntry(destFileName, inputFile, permissions, getDirectoryMode());
488 doAddResource(updateArchiveEntryAttributes(entry));
489 } catch (final IOException e) {
490 throw new ArchiverException("Failed to determine inclusion status for: " + inputFile, e);
491 }
492 }
493
494 @Nonnull
495 @Override
496 public ResourceIterator getResources() throws ArchiverException {
497 return new ResourceIterator() {
498
499 private final Iterator<Object> addedResourceIter = resources.iterator();
500
501 private AddedResourceCollection currentResourceCollection;
502
503 private Iterator ioResourceIter;
504
505 private ArchiveEntry nextEntry;
506
507 private final Set<String> seenEntries = new HashSet<>();
508
509 @Override
510 public boolean hasNext() {
511 do {
512 if (nextEntry == null) {
513 if (ioResourceIter == null) {
514 if (addedResourceIter.hasNext()) {
515 final Object o = addedResourceIter.next();
516 if (o instanceof ArchiveEntry) {
517 nextEntry = (ArchiveEntry) o;
518 } else if (o instanceof AddedResourceCollection) {
519 currentResourceCollection = (AddedResourceCollection) o;
520
521 try {
522 ioResourceIter = currentResourceCollection.resources.getResources();
523 } catch (final IOException e) {
524 throw new ArchiverException(e.getMessage(), e);
525 }
526 } else {
527 return throwIllegalResourceType(o);
528 }
529 } else {
530 nextEntry = null;
531 }
532 } else {
533 if (ioResourceIter.hasNext()) {
534 final PlexusIoResource resource = (PlexusIoResource) ioResourceIter.next();
535 nextEntry = asArchiveEntry(currentResourceCollection, resource);
536 } else {
537
538
539
540
541
542 addCloseable(ioResourceIter);
543 ioResourceIter = null;
544 }
545 }
546 }
547
548 if (nextEntry != null && seenEntries.contains(normalizedForDuplicateCheck(nextEntry))) {
549 final String path = nextEntry.getName();
550
551 if (Archiver.DUPLICATES_PRESERVE.equals(duplicateBehavior)
552 || Archiver.DUPLICATES_SKIP.equals(duplicateBehavior)) {
553 if (nextEntry.getType() == ArchiveEntry.FILE) {
554 getLogger().debug(path + " already added, skipping");
555 }
556
557 nextEntry = null;
558 } else if (Archiver.DUPLICATES_FAIL.equals(duplicateBehavior)) {
559 throw new ArchiverException("Duplicate file " + path + " was found and the duplicate "
560 + "attribute is 'fail'.");
561 } else {
562
563 getLogger().debug("duplicate file " + path + " found, adding.");
564 }
565 }
566 } while (nextEntry == null && !(ioResourceIter == null && !addedResourceIter.hasNext()));
567
568 return nextEntry != null;
569 }
570
571 private boolean throwIllegalResourceType(Object o) {
572 throw new IllegalStateException(
573 "An invalid resource of type: " + o.getClass().getName() + " was added to archiver: "
574 + getClass().getName());
575 }
576
577 @Override
578 public ArchiveEntry next() {
579 if (!hasNext()) {
580 throw new NoSuchElementException();
581 }
582
583 final ArchiveEntry next = nextEntry;
584 nextEntry = null;
585
586 seenEntries.add(normalizedForDuplicateCheck(next));
587
588 return next;
589 }
590
591 @Override
592 public void remove() {
593 throw new UnsupportedOperationException("Does not support iterator");
594 }
595
596 private String normalizedForDuplicateCheck(ArchiveEntry entry) {
597 return entry.getName().replace('\\', '/');
598 }
599 };
600 }
601
602 private static void closeIfCloseable(Object resource) throws IOException {
603 if (resource == null) {
604 return;
605 }
606 if (resource instanceof Closeable) {
607 ((Closeable) resource).close();
608 }
609 }
610
611 private static void closeQuietlyIfCloseable(Object resource) {
612 try {
613 closeIfCloseable(resource);
614 } catch (IOException e) {
615 throw new RuntimeException(e);
616 }
617 }
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636 @Override
637 @Deprecated
638 public Map<String, ArchiveEntry> getFiles() {
639 try {
640 final Map<String, ArchiveEntry> map = new HashMap<>();
641 for (final ResourceIterator iter = getResources(); iter.hasNext(); ) {
642 final ArchiveEntry entry = iter.next();
643 if (includeEmptyDirs || entry.getType() == ArchiveEntry.FILE) {
644 map.put(entry.getName(), entry);
645 }
646 }
647 return map;
648 } catch (final ArchiverException e) {
649 throw new UndeclaredThrowableException(e);
650 }
651 }
652
653 @Override
654 public File getDestFile() {
655 return destFile;
656 }
657
658 @Override
659 public void setDestFile(final File destFile) {
660 this.destFile = destFile;
661
662 if (destFile != null && destFile.getParentFile() != null) {
663 destFile.getParentFile().mkdirs();
664 }
665 }
666
667 protected PlexusIoResourceCollection asResourceCollection(final ArchivedFileSet fileSet, Charset charset)
668 throws ArchiverException {
669 final File archiveFile = fileSet.getArchive();
670
671 final PlexusIoResourceCollection resources;
672 try {
673 resources = archiverManagerProvider.get().getResourceCollection(archiveFile);
674 } catch (final NoSuchArchiverException e) {
675 throw new ArchiverException(
676 "Error adding archived file-set. PlexusIoResourceCollection not found for: " + archiveFile, e);
677 }
678
679 if (resources instanceof EncodingSupported) {
680 ((EncodingSupported) resources).setEncoding(charset);
681 }
682
683 if (resources instanceof PlexusIoArchivedResourceCollection) {
684 ((PlexusIoArchivedResourceCollection) resources).setFile(fileSet.getArchive());
685 } else {
686 throw new ArchiverException("Expected " + PlexusIoArchivedResourceCollection.class.getName() + ", got "
687 + resources.getClass().getName());
688 }
689
690 if (resources instanceof AbstractPlexusIoResourceCollection) {
691 ((AbstractPlexusIoResourceCollection) resources).setStreamTransformer(fileSet.getStreamTransformer());
692 }
693 final PlexusIoProxyResourceCollection proxy = new PlexusIoProxyResourceCollection(resources);
694
695 proxy.setExcludes(fileSet.getExcludes());
696 proxy.setIncludes(fileSet.getIncludes());
697 proxy.setIncludingEmptyDirectories(fileSet.isIncludingEmptyDirectories());
698 proxy.setCaseSensitive(fileSet.isCaseSensitive());
699 proxy.setPrefix(fileSet.getPrefix());
700 proxy.setUsingDefaultExcludes(fileSet.isUsingDefaultExcludes());
701 proxy.setFileSelectors(fileSet.getFileSelectors());
702 proxy.setStreamTransformer(fileSet.getStreamTransformer());
703 proxy.setFileMappers(fileSet.getFileMappers());
704
705 if (getOverrideDirectoryMode() > -1 || getOverrideFileMode() > -1) {
706 proxy.setOverrideAttributes(-1, null, -1, null, getOverrideFileMode(), getOverrideDirectoryMode());
707 }
708
709 if (getDefaultDirectoryMode() > -1 || getDefaultFileMode() > -1) {
710 proxy.setDefaultAttributes(-1, null, -1, null, getDefaultFileMode(), getDefaultDirectoryMode());
711 }
712
713 return proxy;
714 }
715
716
717
718
719 @Override
720 public void addResources(final PlexusIoResourceCollection collection) throws ArchiverException {
721 doAddResource(new AddedResourceCollection(collection, forcedFileMode, forcedDirectoryMode));
722 }
723
724 private void doAddResource(Object item) {
725 resources.add(item);
726 }
727
728 @Override
729 public void addArchivedFileSet(final ArchivedFileSet fileSet) throws ArchiverException {
730 final PlexusIoResourceCollection resourceCollection = asResourceCollection(fileSet, null);
731 addResources(resourceCollection);
732 }
733
734 @Override
735 public void addArchivedFileSet(final ArchivedFileSet fileSet, Charset charset) throws ArchiverException {
736 final PlexusIoResourceCollection resourceCollection = asResourceCollection(fileSet, charset);
737 addResources(resourceCollection);
738 }
739
740
741
742
743 @Override
744 @Deprecated
745 public void addArchivedFileSet(
746 @Nonnull final File archiveFile, final String prefix, final String[] includes, final String[] excludes)
747 throws ArchiverException {
748 addArchivedFileSet(archivedFileSet(archiveFile)
749 .prefixed(prefix)
750 .includeExclude(includes, excludes)
751 .includeEmptyDirs(includeEmptyDirs));
752 }
753
754
755
756
757 @Override
758 @Deprecated
759 public void addArchivedFileSet(@Nonnull final File archiveFile, final String prefix) throws ArchiverException {
760 addArchivedFileSet(archivedFileSet(archiveFile).prefixed(prefix).includeEmptyDirs(includeEmptyDirs));
761 }
762
763
764
765
766 @Override
767 @Deprecated
768 public void addArchivedFileSet(@Nonnull final File archiveFile, final String[] includes, final String[] excludes)
769 throws ArchiverException {
770 addArchivedFileSet(
771 archivedFileSet(archiveFile).includeExclude(includes, excludes).includeEmptyDirs(includeEmptyDirs));
772 }
773
774
775
776
777 @Override
778 @Deprecated
779 public void addArchivedFileSet(@Nonnull final File archiveFile) throws ArchiverException {
780 addArchivedFileSet(archivedFileSet(archiveFile).includeEmptyDirs(includeEmptyDirs));
781 }
782
783 @Override
784 public boolean isForced() {
785 return forced;
786 }
787
788 @Override
789 public void setForced(final boolean forced) {
790 this.forced = forced;
791 }
792
793 @Override
794 public void addArchiveFinalizer(final ArchiveFinalizer finalizer) {
795 if (finalizers == null) {
796 finalizers = new ArrayList<>();
797 }
798
799 finalizers.add(finalizer);
800 }
801
802 @Override
803 public void setArchiveFinalizers(final List<ArchiveFinalizer> archiveFinalizers) {
804 finalizers = archiveFinalizers;
805 }
806
807 @Override
808 public void setDotFileDirectory(final File dotFileDirectory) {
809 this.dotFileDirectory = dotFileDirectory;
810 }
811
812 protected boolean isUptodate() throws ArchiverException {
813 final File zipFile = getDestFile();
814 if (!zipFile.exists()) {
815 getLogger().debug("isUp2date: false (Destination " + zipFile.getPath() + " not found.)");
816 return false;
817 }
818 final long destTimestamp = getFileLastModifiedTime(zipFile);
819
820 final Iterator<Object> it = resources.iterator();
821 if (!it.hasNext()) {
822 getLogger().debug("isUp2date: false (No input files.)");
823 return false;
824 }
825
826 while (it.hasNext()) {
827 final Object o = it.next();
828 final long l;
829 if (o instanceof ArchiveEntry) {
830 l = ((ArchiveEntry) o).getResource().getLastModified();
831 } else if (o instanceof AddedResourceCollection) {
832 try {
833 l = ((AddedResourceCollection) o).resources.getLastModified();
834 } catch (final IOException e) {
835 throw new ArchiverException(e.getMessage(), e);
836 }
837 } else {
838 throw new IllegalStateException(
839 "Invalid object type: " + o.getClass().getName());
840 }
841 if (l == PlexusIoResource.UNKNOWN_MODIFICATION_DATE) {
842
843 getLogger().debug("isUp2date: false (Resource with unknown modification date found.)");
844 return false;
845 }
846 if (l > destTimestamp) {
847 getLogger().debug("isUp2date: false (Resource with newer modification date found.)");
848 return false;
849 }
850 }
851
852 getLogger().debug("isUp2date: true");
853 return true;
854 }
855
856
857
858
859
860
861
862
863 private long getFileLastModifiedTime(File file) throws ArchiverException {
864 try {
865 return Files.getLastModifiedTime(file.toPath()).toMillis();
866 } catch (IOException e) {
867 throw new ArchiverException(e.getMessage(), e);
868 }
869 }
870
871 protected boolean checkForced() throws ArchiverException {
872 if (!isForced() && isSupportingForced() && isUptodate()) {
873 getLogger().debug("Archive " + getDestFile() + " is uptodate.");
874 return false;
875 }
876 return true;
877 }
878
879 @Override
880 public boolean isSupportingForced() {
881 return false;
882 }
883
884 protected void runArchiveFinalizers() throws ArchiverException {
885 if (finalizers != null) {
886 for (final ArchiveFinalizer finalizer : finalizers) {
887 finalizer.finalizeArchiveCreation(this);
888 }
889 }
890 }
891
892 @Override
893 public final void createArchive() throws ArchiverException, IOException {
894 validate();
895 try {
896 try {
897 if (dotFileDirectory != null) {
898 addArchiveFinalizer(new DotDirectiveArchiveFinalizer(dotFileDirectory));
899 }
900
901 runArchiveFinalizers();
902
903 execute();
904 } finally {
905 close();
906 }
907 } catch (final IOException e) {
908 String msg = "Problem creating " + getArchiveType() + ": " + e.getMessage();
909
910 final StringBuffer revertBuffer = new StringBuffer();
911 if (!revert(revertBuffer)) {
912 msg += revertBuffer.toString();
913 }
914
915 throw new ArchiverException(msg, e);
916 } finally {
917 cleanUp();
918 }
919
920 postCreateArchive();
921 }
922
923 protected boolean hasVirtualFiles() {
924 if (finalizers != null) {
925 for (final ArchiveFinalizer finalizer : finalizers) {
926 final List virtualFiles = finalizer.getVirtualFiles();
927
928 if ((virtualFiles != null) && !virtualFiles.isEmpty()) {
929 return true;
930 }
931 }
932 }
933 return false;
934 }
935
936 protected boolean revert(final StringBuffer messageBuffer) {
937 return true;
938 }
939
940 protected void validate() throws ArchiverException, IOException {}
941
942
943
944
945
946
947
948
949
950
951
952 protected void postCreateArchive() throws ArchiverException, IOException {}
953
954 protected abstract String getArchiveType();
955
956 private void addCloseable(Object maybeCloseable) {
957 if (maybeCloseable instanceof Closeable) {
958 closeables.add((Closeable) maybeCloseable);
959 }
960 }
961
962 private void closeIterators() {
963 for (Closeable closeable : closeables) {
964 closeQuietlyIfCloseable(closeable);
965 }
966 }
967
968 protected abstract void close() throws IOException;
969
970 protected void cleanUp() throws IOException {
971 closeIterators();
972
973 for (Object resource : resources) {
974 if (resource instanceof PlexusIoProxyResourceCollection) {
975 resource = ((PlexusIoProxyResourceCollection) resource).getSrc();
976 }
977
978 closeIfCloseable(resource);
979 }
980 resources.clear();
981 }
982
983 protected abstract void execute() throws ArchiverException, IOException;
984
985
986
987
988 @Override
989 @Deprecated
990 public boolean isUseJvmChmod() {
991 return useJvmChmod;
992 }
993
994
995
996
997 @Override
998 @Deprecated
999 public void setUseJvmChmod(final boolean useJvmChmod) {
1000 this.useJvmChmod = useJvmChmod;
1001 }
1002
1003
1004
1005
1006 @Override
1007 public boolean isIgnorePermissions() {
1008 return ignorePermissions;
1009 }
1010
1011
1012
1013
1014 @Override
1015 public void setIgnorePermissions(final boolean ignorePermissions) {
1016 this.ignorePermissions = ignorePermissions;
1017 }
1018
1019
1020
1021
1022 @Override
1023 @Deprecated
1024 public void setLastModifiedDate(Date lastModifiedDate) {
1025 this.lastModifiedTime = lastModifiedDate != null ? FileTime.fromMillis(lastModifiedDate.getTime()) : null;
1026 }
1027
1028
1029
1030
1031 @Override
1032 @Deprecated
1033 public Date getLastModifiedDate() {
1034 return lastModifiedTime != null ? new Date(lastModifiedTime.toMillis()) : null;
1035 }
1036
1037 @Override
1038 public void setLastModifiedTime(FileTime lastModifiedTime) {
1039 this.lastModifiedTime = lastModifiedTime;
1040 }
1041
1042 @Override
1043 public FileTime getLastModifiedTime() {
1044 return lastModifiedTime;
1045 }
1046
1047 @Override
1048 public void setFilenameComparator(Comparator<String> filenameComparator) {
1049 this.filenameComparator = filenameComparator;
1050 }
1051
1052 public Comparator<String> getFilenameComparator() {
1053 return filenameComparator;
1054 }
1055
1056 @Override
1057 public void setOverrideUid(int uid) {
1058 overrideUid = uid;
1059 }
1060
1061 @Override
1062 public void setOverrideUserName(String userName) {
1063 overrideUserName = userName;
1064 }
1065
1066 @Override
1067 public int getOverrideUid() {
1068 return overrideUid;
1069 }
1070
1071 @Override
1072 public String getOverrideUserName() {
1073 return overrideUserName;
1074 }
1075
1076 @Override
1077 public void setOverrideGid(int gid) {
1078 overrideGid = gid;
1079 }
1080
1081 @Override
1082 public void setOverrideGroupName(String groupName) {
1083 overrideGroupName = groupName;
1084 }
1085
1086 @Override
1087 public int getOverrideGid() {
1088 return overrideGid;
1089 }
1090
1091 @Override
1092 public String getOverrideGroupName() {
1093 return overrideGroupName;
1094 }
1095
1096 @Override
1097 public void setUmask(int umask) {
1098 this.umask = umask;
1099 }
1100
1101 @Override
1102 public int getUmask() {
1103 return umask;
1104 }
1105
1106
1107
1108
1109 @Override
1110 @Deprecated
1111 public void configureReproducible(Date lastModifiedDate) {
1112 configureReproducibleBuild(FileTime.fromMillis(lastModifiedDate.getTime()));
1113 }
1114
1115 @Override
1116 public void configureReproducibleBuild(FileTime lastModifiedTime) {
1117
1118 setLastModifiedTime(normalizeLastModifiedTime(lastModifiedTime));
1119
1120
1121 setFilenameComparator(String::compareTo);
1122
1123
1124 setOverrideUid(0);
1125 setOverrideUserName("root");
1126 setOverrideGid(0);
1127 setOverrideGroupName("root");
1128
1129
1130 setUmask(0_022);
1131 }
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145 protected FileTime normalizeLastModifiedTime(FileTime lastModifiedTime) {
1146 return lastModifiedTime;
1147 }
1148 }