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 @Override
620 @Deprecated
621 public Map<String, ArchiveEntry> getFiles() {
622 try {
623 final Map<String, ArchiveEntry> map = new HashMap<>();
624 for (final ResourceIterator iter = getResources(); iter.hasNext(); ) {
625 final ArchiveEntry entry = iter.next();
626 if (includeEmptyDirs || entry.getType() == ArchiveEntry.FILE) {
627 map.put(entry.getName(), entry);
628 }
629 }
630 return map;
631 } catch (final ArchiverException e) {
632 throw new UndeclaredThrowableException(e);
633 }
634 }
635
636 @Override
637 public File getDestFile() {
638 return destFile;
639 }
640
641 @Override
642 public void setDestFile(final File destFile) {
643 this.destFile = destFile;
644
645 if (destFile != null && destFile.getParentFile() != null) {
646 destFile.getParentFile().mkdirs();
647 }
648 }
649
650 protected PlexusIoResourceCollection asResourceCollection(final ArchivedFileSet fileSet, Charset charset)
651 throws ArchiverException {
652 final File archiveFile = fileSet.getArchive();
653
654 final PlexusIoResourceCollection resources;
655 try {
656 resources = archiverManagerProvider.get().getResourceCollection(archiveFile);
657 } catch (final NoSuchArchiverException e) {
658 throw new ArchiverException(
659 "Error adding archived file-set. PlexusIoResourceCollection not found for: " + archiveFile, e);
660 }
661
662 if (resources instanceof EncodingSupported) {
663 ((EncodingSupported) resources).setEncoding(charset);
664 }
665
666 if (resources instanceof PlexusIoArchivedResourceCollection) {
667 ((PlexusIoArchivedResourceCollection) resources).setFile(fileSet.getArchive());
668 } else {
669 throw new ArchiverException("Expected " + PlexusIoArchivedResourceCollection.class.getName() + ", got "
670 + resources.getClass().getName());
671 }
672
673 if (resources instanceof AbstractPlexusIoResourceCollection) {
674 ((AbstractPlexusIoResourceCollection) resources).setStreamTransformer(fileSet.getStreamTransformer());
675 }
676 final PlexusIoProxyResourceCollection proxy = new PlexusIoProxyResourceCollection(resources);
677
678 proxy.setExcludes(fileSet.getExcludes());
679 proxy.setIncludes(fileSet.getIncludes());
680 proxy.setIncludingEmptyDirectories(fileSet.isIncludingEmptyDirectories());
681 proxy.setCaseSensitive(fileSet.isCaseSensitive());
682 proxy.setPrefix(fileSet.getPrefix());
683 proxy.setUsingDefaultExcludes(fileSet.isUsingDefaultExcludes());
684 proxy.setFileSelectors(fileSet.getFileSelectors());
685 proxy.setStreamTransformer(fileSet.getStreamTransformer());
686 proxy.setFileMappers(fileSet.getFileMappers());
687
688 if (getOverrideDirectoryMode() > -1 || getOverrideFileMode() > -1) {
689 proxy.setOverrideAttributes(-1, null, -1, null, getOverrideFileMode(), getOverrideDirectoryMode());
690 }
691
692 if (getDefaultDirectoryMode() > -1 || getDefaultFileMode() > -1) {
693 proxy.setDefaultAttributes(-1, null, -1, null, getDefaultFileMode(), getDefaultDirectoryMode());
694 }
695
696 return proxy;
697 }
698
699
700
701
702 @Override
703 public void addResources(final PlexusIoResourceCollection collection) throws ArchiverException {
704 doAddResource(new AddedResourceCollection(collection, forcedFileMode, forcedDirectoryMode));
705 }
706
707 private void doAddResource(Object item) {
708 resources.add(item);
709 }
710
711 @Override
712 public void addArchivedFileSet(final ArchivedFileSet fileSet) throws ArchiverException {
713 final PlexusIoResourceCollection resourceCollection = asResourceCollection(fileSet, null);
714 addResources(resourceCollection);
715 }
716
717 @Override
718 public void addArchivedFileSet(final ArchivedFileSet fileSet, Charset charset) throws ArchiverException {
719 final PlexusIoResourceCollection resourceCollection = asResourceCollection(fileSet, charset);
720 addResources(resourceCollection);
721 }
722
723
724
725
726 @Override
727 @Deprecated
728 public void addArchivedFileSet(
729 @Nonnull final File archiveFile, final String prefix, final String[] includes, final String[] excludes)
730 throws ArchiverException {
731 addArchivedFileSet(archivedFileSet(archiveFile)
732 .prefixed(prefix)
733 .includeExclude(includes, excludes)
734 .includeEmptyDirs(includeEmptyDirs));
735 }
736
737
738
739
740 @Override
741 @Deprecated
742 public void addArchivedFileSet(@Nonnull final File archiveFile, final String prefix) throws ArchiverException {
743 addArchivedFileSet(archivedFileSet(archiveFile).prefixed(prefix).includeEmptyDirs(includeEmptyDirs));
744 }
745
746
747
748
749 @Override
750 @Deprecated
751 public void addArchivedFileSet(@Nonnull final File archiveFile, final String[] includes, final String[] excludes)
752 throws ArchiverException {
753 addArchivedFileSet(
754 archivedFileSet(archiveFile).includeExclude(includes, excludes).includeEmptyDirs(includeEmptyDirs));
755 }
756
757
758
759
760 @Override
761 @Deprecated
762 public void addArchivedFileSet(@Nonnull final File archiveFile) throws ArchiverException {
763 addArchivedFileSet(archivedFileSet(archiveFile).includeEmptyDirs(includeEmptyDirs));
764 }
765
766 @Override
767 public boolean isForced() {
768 return forced;
769 }
770
771 @Override
772 public void setForced(final boolean forced) {
773 this.forced = forced;
774 }
775
776 @Override
777 public void addArchiveFinalizer(final ArchiveFinalizer finalizer) {
778 if (finalizers == null) {
779 finalizers = new ArrayList<>();
780 }
781
782 finalizers.add(finalizer);
783 }
784
785 @Override
786 public void setArchiveFinalizers(final List<ArchiveFinalizer> archiveFinalizers) {
787 finalizers = archiveFinalizers;
788 }
789
790 @Override
791 public void setDotFileDirectory(final File dotFileDirectory) {
792 this.dotFileDirectory = dotFileDirectory;
793 }
794
795 protected boolean isUptodate() throws ArchiverException {
796 final File zipFile = getDestFile();
797 if (!zipFile.exists()) {
798 getLogger().debug("isUp2date: false (Destination " + zipFile.getPath() + " not found.)");
799 return false;
800 }
801 final long destTimestamp = getFileLastModifiedTime(zipFile);
802
803 final Iterator<Object> it = resources.iterator();
804 if (!it.hasNext()) {
805 getLogger().debug("isUp2date: false (No input files.)");
806 return false;
807 }
808
809 while (it.hasNext()) {
810 final Object o = it.next();
811 final long l;
812 if (o instanceof ArchiveEntry) {
813 l = ((ArchiveEntry) o).getResource().getLastModified();
814 } else if (o instanceof AddedResourceCollection) {
815 try {
816 l = ((AddedResourceCollection) o).resources.getLastModified();
817 } catch (final IOException e) {
818 throw new ArchiverException(e.getMessage(), e);
819 }
820 } else {
821 throw new IllegalStateException(
822 "Invalid object type: " + o.getClass().getName());
823 }
824 if (l == PlexusIoResource.UNKNOWN_MODIFICATION_DATE) {
825
826 getLogger().debug("isUp2date: false (Resource with unknown modification date found.)");
827 return false;
828 }
829 if (l > destTimestamp) {
830 getLogger().debug("isUp2date: false (Resource with newer modification date found.)");
831 return false;
832 }
833 }
834
835 getLogger().debug("isUp2date: true");
836 return true;
837 }
838
839
840
841
842
843
844
845
846 private long getFileLastModifiedTime(File file) throws ArchiverException {
847 try {
848 return Files.getLastModifiedTime(file.toPath()).toMillis();
849 } catch (IOException e) {
850 throw new ArchiverException(e.getMessage(), e);
851 }
852 }
853
854 protected boolean checkForced() throws ArchiverException {
855 if (!isForced() && isSupportingForced() && isUptodate()) {
856 getLogger().debug("Archive " + getDestFile() + " is uptodate.");
857 return false;
858 }
859 return true;
860 }
861
862 @Override
863 public boolean isSupportingForced() {
864 return false;
865 }
866
867 protected void runArchiveFinalizers() throws ArchiverException {
868 if (finalizers != null) {
869 for (final ArchiveFinalizer finalizer : finalizers) {
870 finalizer.finalizeArchiveCreation(this);
871 }
872 }
873 }
874
875 @Override
876 public final void createArchive() throws ArchiverException, IOException {
877 validate();
878 try {
879 try {
880 if (dotFileDirectory != null) {
881 addArchiveFinalizer(new DotDirectiveArchiveFinalizer(dotFileDirectory));
882 }
883
884 runArchiveFinalizers();
885
886 execute();
887 } finally {
888 close();
889 }
890 } catch (final IOException e) {
891 String msg = "Problem creating " + getArchiveType() + ": " + e.getMessage();
892
893 final StringBuffer revertBuffer = new StringBuffer();
894 if (!revert(revertBuffer)) {
895 msg += revertBuffer.toString();
896 }
897
898 throw new ArchiverException(msg, e);
899 } finally {
900 cleanUp();
901 }
902
903 postCreateArchive();
904 }
905
906 protected boolean hasVirtualFiles() {
907 if (finalizers != null) {
908 for (final ArchiveFinalizer finalizer : finalizers) {
909 final List virtualFiles = finalizer.getVirtualFiles();
910
911 if ((virtualFiles != null) && !virtualFiles.isEmpty()) {
912 return true;
913 }
914 }
915 }
916 return false;
917 }
918
919 protected boolean revert(final StringBuffer messageBuffer) {
920 return true;
921 }
922
923 protected void validate() throws ArchiverException, IOException {}
924
925
926
927
928
929
930
931
932
933
934
935 protected void postCreateArchive() throws ArchiverException, IOException {}
936
937 protected abstract String getArchiveType();
938
939 private void addCloseable(Object maybeCloseable) {
940 if (maybeCloseable instanceof Closeable) {
941 closeables.add((Closeable) maybeCloseable);
942 }
943 }
944
945 private void closeIterators() {
946 for (Closeable closeable : closeables) {
947 closeQuietlyIfCloseable(closeable);
948 }
949 }
950
951 protected abstract void close() throws IOException;
952
953 protected void cleanUp() throws IOException {
954 closeIterators();
955
956 for (Object resource : resources) {
957 if (resource instanceof PlexusIoProxyResourceCollection) {
958 resource = ((PlexusIoProxyResourceCollection) resource).getSrc();
959 }
960
961 closeIfCloseable(resource);
962 }
963 resources.clear();
964 }
965
966 protected abstract void execute() throws ArchiverException, IOException;
967
968
969
970
971 @Override
972 @Deprecated
973 public boolean isUseJvmChmod() {
974 return useJvmChmod;
975 }
976
977
978
979
980 @Override
981 @Deprecated
982 public void setUseJvmChmod(final boolean useJvmChmod) {
983 this.useJvmChmod = useJvmChmod;
984 }
985
986
987
988
989 @Override
990 public boolean isIgnorePermissions() {
991 return ignorePermissions;
992 }
993
994
995
996
997 @Override
998 public void setIgnorePermissions(final boolean ignorePermissions) {
999 this.ignorePermissions = ignorePermissions;
1000 }
1001
1002
1003
1004
1005 @Override
1006 @Deprecated
1007 public void setLastModifiedDate(Date lastModifiedDate) {
1008 this.lastModifiedTime = lastModifiedDate != null ? FileTime.fromMillis(lastModifiedDate.getTime()) : null;
1009 }
1010
1011
1012
1013
1014 @Override
1015 @Deprecated
1016 public Date getLastModifiedDate() {
1017 return lastModifiedTime != null ? new Date(lastModifiedTime.toMillis()) : null;
1018 }
1019
1020 @Override
1021 public void setLastModifiedTime(FileTime lastModifiedTime) {
1022 this.lastModifiedTime = lastModifiedTime;
1023 }
1024
1025 @Override
1026 public FileTime getLastModifiedTime() {
1027 return lastModifiedTime;
1028 }
1029
1030 @Override
1031 public void setFilenameComparator(Comparator<String> filenameComparator) {
1032 this.filenameComparator = filenameComparator;
1033 }
1034
1035 public Comparator<String> getFilenameComparator() {
1036 return filenameComparator;
1037 }
1038
1039 @Override
1040 public void setOverrideUid(int uid) {
1041 overrideUid = uid;
1042 }
1043
1044 @Override
1045 public void setOverrideUserName(String userName) {
1046 overrideUserName = userName;
1047 }
1048
1049 @Override
1050 public int getOverrideUid() {
1051 return overrideUid;
1052 }
1053
1054 @Override
1055 public String getOverrideUserName() {
1056 return overrideUserName;
1057 }
1058
1059 @Override
1060 public void setOverrideGid(int gid) {
1061 overrideGid = gid;
1062 }
1063
1064 @Override
1065 public void setOverrideGroupName(String groupName) {
1066 overrideGroupName = groupName;
1067 }
1068
1069 @Override
1070 public int getOverrideGid() {
1071 return overrideGid;
1072 }
1073
1074 @Override
1075 public String getOverrideGroupName() {
1076 return overrideGroupName;
1077 }
1078
1079 @Override
1080 public void setUmask(int umask) {
1081 this.umask = umask;
1082 }
1083
1084 @Override
1085 public int getUmask() {
1086 return umask;
1087 }
1088
1089
1090
1091
1092 @Override
1093 @Deprecated
1094 public void configureReproducible(Date lastModifiedDate) {
1095 configureReproducibleBuild(FileTime.fromMillis(lastModifiedDate.getTime()));
1096 }
1097
1098 @Override
1099 public void configureReproducibleBuild(FileTime lastModifiedTime) {
1100
1101 setLastModifiedTime(normalizeLastModifiedTime(lastModifiedTime));
1102
1103
1104 setFilenameComparator(String::compareTo);
1105
1106
1107 setOverrideUid(0);
1108 setOverrideUserName("root");
1109 setOverrideGid(0);
1110 setOverrideGroupName("root");
1111
1112
1113 setUmask(0_022);
1114 }
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128 protected FileTime normalizeLastModifiedTime(FileTime lastModifiedTime) {
1129 return lastModifiedTime;
1130 }
1131 }