View Javadoc
1   /*
2    * The MIT License
3    *
4    * Copyright (c) 2004, The Codehaus
5    *
6    * Permission is hereby granted, free of charge, to any person obtaining a copy of
7    * this software and associated documentation files (the "Software"), to deal in
8    * the Software without restriction, including without limitation the rights to
9    * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10   * of the Software, and to permit persons to whom the Software is furnished to do
11   * so, subject to the following conditions:
12   *
13   * The above copyright notice and this permission notice shall be included in all
14   * copies or substantial portions of the Software.
15   *
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22   * SOFTWARE.
23   */
24  package org.codehaus.plexus.archiver.zip;
25  
26  import java.io.ByteArrayInputStream;
27  import java.io.ByteArrayOutputStream;
28  import java.io.File;
29  import java.io.FileInputStream;
30  import java.io.FileWriter;
31  import java.io.IOException;
32  import java.io.InputStream;
33  import java.nio.file.Files;
34  import java.nio.file.attribute.FileTime;
35  import java.util.Arrays;
36  import java.util.Date;
37  import java.util.Enumeration;
38  import java.util.Map;
39  import java.util.zip.ZipEntry;
40  import java.util.zip.ZipInputStream;
41  import java.util.zip.ZipOutputStream;
42  import javax.annotation.Nonnull;
43  import org.apache.commons.compress.archivers.zip.ExtraFieldUtils;
44  import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
45  import org.apache.commons.compress.archivers.zip.ZipExtraField;
46  import org.apache.commons.compress.archivers.zip.ZipFile;
47  import org.apache.commons.compress.utils.BoundedInputStream;
48  import org.codehaus.plexus.archiver.Archiver;
49  import org.codehaus.plexus.archiver.ArchiverException;
50  import org.codehaus.plexus.archiver.BasePlexusArchiverTest;
51  import org.codehaus.plexus.archiver.UnArchiver;
52  import org.codehaus.plexus.archiver.UnixStat;
53  import org.codehaus.plexus.archiver.exceptions.EmptyArchiveException;
54  import org.codehaus.plexus.archiver.tar.TarArchiver;
55  import org.codehaus.plexus.archiver.tar.TarFile;
56  import org.codehaus.plexus.archiver.util.ArchiveEntryUtils;
57  import org.codehaus.plexus.archiver.util.DefaultArchivedFileSet;
58  import org.codehaus.plexus.archiver.util.DefaultFileSet;
59  import org.codehaus.plexus.archiver.util.Streams;
60  import org.codehaus.plexus.components.io.attributes.FileAttributes;
61  import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributeUtils;
62  import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributes;
63  import org.codehaus.plexus.components.io.attributes.SimpleResourceAttributes;
64  import org.codehaus.plexus.components.io.filemappers.FileMapper;
65  import org.codehaus.plexus.components.io.filemappers.PrefixFileMapper;
66  import org.codehaus.plexus.components.io.functions.InputStreamTransformer;
67  import org.codehaus.plexus.components.io.resources.PlexusIoFileResourceCollection;
68  import org.codehaus.plexus.components.io.resources.PlexusIoResource;
69  import org.codehaus.plexus.components.io.resources.ResourceFactory;
70  import org.codehaus.plexus.util.FileUtils;
71  import org.codehaus.plexus.util.IOUtil;
72  import org.codehaus.plexus.util.Os;
73  
74  /**
75   * @author Emmanuel Venisse
76   */
77  @SuppressWarnings( "OctalInteger" )
78  public class ZipArchiverTest
79      extends BasePlexusArchiverTest
80  {
81  
82      public void testImplicitPermissions()
83          throws IOException
84      {
85          File zipFile = getTestFile( "target/output/zip-with-implicit-dirmode.zip" );
86  
87          ZipArchiver archiver = getZipArchiver( zipFile );
88  
89          archiver.setDefaultDirectoryMode( 0777 );
90          archiver.setDirectoryMode( 0641 );
91          archiver.setFileMode( 0222 );
92          archiver.addFile( new File( "pom.xml" ), "fizz/buzz/pom.xml" );
93          archiver.setDefaultDirectoryMode( 0530 );
94          archiver.setDirectoryMode( -1 ); // Not forced mode
95          archiver.setFileMode( 0111 );
96          archiver.addFile( new File( "pom.xml" ), "fazz/bazz/pam.xml" );
97          archiver.createArchive();
98  
99          assertTrue( zipFile.exists() );
100         ZipFile zf = new ZipFile( zipFile );
101         ZipArchiveEntry fizz = zf.getEntry( "fizz/" );
102         assertEquals( 040641, fizz.getUnixMode() );
103         ZipArchiveEntry pom = zf.getEntry( "fizz/buzz/pom.xml" );
104         assertEquals( 0100222, pom.getUnixMode() );
105 
106         ZipArchiveEntry fazz = zf.getEntry( "fazz/" );
107         assertEquals( 040530, fazz.getUnixMode() );
108         ZipArchiveEntry pam = zf.getEntry( "fazz/bazz/pam.xml" );
109         assertEquals( 0100111, pam.getUnixMode() );
110     }
111 
112     public void testOveriddenPermissions()
113         throws IOException
114     {
115         if ( !Os.isFamily( Os.FAMILY_WINDOWS ) )
116         {
117             File zipFile = getTestFile( "target/output/zip-with-overriden-modes.zip" );
118 
119             ZipArchiver archiver = getZipArchiver( zipFile );
120             archiver.setDefaultDirectoryMode( 0777 );
121             archiver.setDirectoryMode( 0641 );
122             archiver.setFileMode( 0777 );
123             archiver.addDirectory( new File( "src/test/resources/symlinks/src" ) );
124             archiver.createArchive();
125 
126             assertTrue( zipFile.exists() );
127             ZipFile zf = new ZipFile( zipFile );
128             ZipArchiveEntry fizz = zf.getEntry( "symDir" );
129             assertTrue( fizz.isUnixSymlink() );
130             ZipArchiveEntry symR = zf.getEntry( "symR" );
131             assertTrue( symR.isUnixSymlink() );
132         }
133     }
134 
135     public void testCreateArchiveWithDetectedModes()
136         throws Exception
137     {
138 
139         String[] executablePaths =
140         {
141             "path/to/executable", "path/to/executable.bat"
142         };
143 
144         String[] confPaths =
145         {
146             "path/to/etc/file", "path/to/etc/file2"
147         };
148 
149         String[] logPaths =
150         {
151             "path/to/logs/log.txt"
152         };
153 
154         int exeMode = 0777;
155         int confMode = 0600;
156         int logMode = 0640;
157 
158         if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
159         {
160             StackTraceElement e = new Throwable().getStackTrace()[0];
161             System.out.println(
162                 "Cannot execute test: " + e.getMethodName() + " on " + System.getProperty( "os.name" ) );
163             return;
164         }
165 
166         File tmpDir = null;
167         try
168         {
169             tmpDir = File.createTempFile( "zip-with-chmod.", ".dir" );
170             tmpDir.delete();
171 
172             tmpDir.mkdirs();
173 
174             for ( String executablePath : executablePaths )
175             {
176                 writeFile( tmpDir, executablePath, exeMode );
177             }
178 
179             for ( String confPath : confPaths )
180             {
181                 writeFile( tmpDir, confPath, confMode );
182             }
183 
184             for ( String logPath : logPaths )
185             {
186                 writeFile( tmpDir, logPath, logMode );
187             }
188 
189             {
190                 Map<String, PlexusIoResourceAttributes> attributesByPath =
191                     PlexusIoResourceAttributeUtils.getFileAttributesByPath( tmpDir );
192                 for ( String path : executablePaths )
193                 {
194                     PlexusIoResourceAttributes attrs = attributesByPath.get( path );
195                     if ( attrs == null )
196                     {
197                         attrs = attributesByPath.get( new File( tmpDir, path ).getAbsolutePath() );
198                     }
199 
200                     assertNotNull( attrs );
201                     assertEquals( "Wrong mode for: " + path + "; expected: " + exeMode, exeMode, attrs.getOctalMode() );
202                 }
203 
204                 for ( String path : confPaths )
205                 {
206                     PlexusIoResourceAttributes attrs = attributesByPath.get( path );
207                     if ( attrs == null )
208                     {
209                         attrs = attributesByPath.get( new File( tmpDir, path ).getAbsolutePath() );
210                     }
211 
212                     assertNotNull( attrs );
213                     assertEquals( "Wrong mode for: " + path + "; expected: " + confMode, confMode,
214                                   attrs.getOctalMode() );
215                 }
216 
217                 for ( String path : logPaths )
218                 {
219                     PlexusIoResourceAttributes attrs = attributesByPath.get( path );
220                     if ( attrs == null )
221                     {
222                         attrs = attributesByPath.get( new File( tmpDir, path ).getAbsolutePath() );
223                     }
224 
225                     assertNotNull( attrs );
226                     assertEquals( "Wrong mode for: " + path + "; expected: " + logMode, logMode, attrs.getOctalMode() );
227                 }
228             }
229 
230             File zipFile = getTestFile( "target/output/zip-with-modes.zip" );
231 
232             ZipArchiver archiver = getZipArchiver( zipFile );
233 
234             archiver.addDirectory( tmpDir );
235             archiver.createArchive();
236 
237             assertTrue( zipFile.exists() );
238 
239             File zipFile2 = getTestFile( "target/output/zip-with-modes-L2.zip" );
240 
241             archiver = getZipArchiver();
242             archiver.setDestFile( zipFile2 );
243 
244             archiver.addArchivedFileSet( zipFile );
245             archiver.createArchive();
246 
247             ZipFile zf = new ZipFile( zipFile2 );
248 
249             for ( String path : executablePaths )
250             {
251                 ZipArchiveEntry ze = zf.getEntry( path );
252 
253                 int mode = ze.getUnixMode() & UnixStat.PERM_MASK;
254 
255                 assertEquals( "Wrong mode for: " + path + "; expected: " + exeMode, exeMode, mode );
256             }
257 
258             for ( String path : confPaths )
259             {
260                 ZipArchiveEntry ze = zf.getEntry( path );
261 
262                 int mode = ze.getUnixMode() & UnixStat.PERM_MASK;
263 
264                 assertEquals( "Wrong mode for: " + path + "; expected: " + confMode, confMode, mode );
265             }
266 
267             for ( String path : logPaths )
268             {
269                 ZipArchiveEntry ze = zf.getEntry( path );
270 
271                 int mode = ze.getUnixMode() & UnixStat.PERM_MASK;
272 
273                 assertEquals( "Wrong mode for: " + path + "; expected: " + logMode, logMode, mode );
274             }
275         }
276         finally
277         {
278             if ( tmpDir != null && tmpDir.exists() )
279             {
280                 try
281                 {
282                     FileUtils.forceDelete( tmpDir );
283                 }
284                 catch ( IOException e )
285                 {
286                     e.printStackTrace();
287                 }
288             }
289         }
290     }
291 
292     public void testCreateEmptyArchive()
293         throws Exception
294     {
295         ZipArchiver archiver = getZipArchiver();
296         archiver.setDestFile( getTestFile( "target/output/empty.zip" ) );
297         try
298         {
299             archiver.createArchive();
300 
301             fail( "Creating empty archive should throw EmptyArchiveException" );
302         }
303         catch ( EmptyArchiveException ignore )
304         {
305         }
306     }
307 
308     private ZipArchiver getZipArchiver()
309     {
310         try
311         {
312             return (ZipArchiver) lookup( Archiver.ROLE, "zip" );
313         }
314         catch ( Exception e )
315         {
316             throw new RuntimeException( e );
317         }
318     }
319 
320     private ZipArchiver getZipArchiver( File destFile )
321     {
322         final ZipArchiver zipArchiver = getZipArchiver();
323         zipArchiver.setDestFile( destFile );
324         return zipArchiver;
325     }
326 
327     private ZipUnArchiver getZipUnArchiver( File testJar )
328         throws Exception
329     {
330         ZipUnArchiver zu = (ZipUnArchiver) lookup( UnArchiver.ROLE, "zip" );
331         zu.setSourceFile( testJar );
332         return zu;
333     }
334 
335     private void writeFile( File dir, String fname, int mode )
336         throws IOException, ArchiverException
337     {
338         File file = new File( dir, fname );
339         FileWriter writer = null;
340 
341         try
342         {
343             if ( file.getParentFile() != null )
344             {
345                 file.getParentFile().mkdirs();
346             }
347 
348             writer = new FileWriter( file );
349             writer.write( "This is a test file." );
350             writer.close();
351             writer = null;
352         }
353         finally
354         {
355             IOUtil.close( writer );
356         }
357 
358         ArchiveEntryUtils.chmod( file, mode );
359     }
360 
361     public void testCreateArchive()
362         throws Exception
363     {
364         ZipArchiver archiver = newArchiver( "archive1.zip" );
365 
366         createArchive( archiver );
367     }
368 
369     public void testRecompressAddedZips() throws Exception
370     {
371         // check that by default the zip archives are re-compressed
372 
373         final File zipFileRecompress = getTestFile( "target/output/recompress-added-zips.zip" );
374         final ZipArchiver zipArchiverRecompress = getZipArchiver( zipFileRecompress );
375         zipArchiverRecompress.addDirectory( getTestFile( "src/test/jars" ) );
376         FileUtils.removePath( zipFileRecompress.getPath() );
377         zipArchiverRecompress.createArchive();
378 
379         final ZipFile zfRecompress = new ZipFile( zipFileRecompress );
380         assertEquals( ZipEntry.DEFLATED, zfRecompress.getEntry( "test.zip" ).getMethod() );
381         assertEquals( ZipEntry.DEFLATED, zfRecompress.getEntry( "test.jar" ).getMethod() );
382         assertEquals( ZipEntry.DEFLATED, zfRecompress.getEntry( "test.rar" ).getMethod() );
383         assertEquals( ZipEntry.DEFLATED, zfRecompress.getEntry( "test.tar.gz" ).getMethod() );
384         zfRecompress.close();
385 
386         // make sure the zip files are not re-compressed when recompressAddedZips is set to false
387 
388         final File zipFileDontRecompress = getTestFile( "target/output/dont-recompress-added-zips.zip" );
389         ZipArchiver zipArchiver = getZipArchiver( zipFileDontRecompress );
390         zipArchiver.addDirectory( getTestFile( "src/test/jars" ) );
391         zipArchiver.setRecompressAddedZips( false );
392         FileUtils.removePath( zipFileDontRecompress.getPath() );
393         zipArchiver.createArchive();
394 
395         final ZipFile zfDontRecompress = new ZipFile( zipFileDontRecompress );
396         final ZipArchiveEntry zipEntry = zfDontRecompress.getEntry( "test.zip" );
397         final ZipArchiveEntry jarEntry = zfDontRecompress.getEntry( "test.jar" );
398         final ZipArchiveEntry rarEntry = zfDontRecompress.getEntry( "test.rar" );
399         final ZipArchiveEntry tarEntry = zfDontRecompress.getEntry( "test.tar.gz" );
400         // check if only zip files are not compressed...
401         assertEquals( ZipEntry.STORED, zipEntry.getMethod() );
402         assertEquals( ZipEntry.STORED, jarEntry.getMethod() );
403         assertEquals( ZipEntry.STORED, rarEntry.getMethod() );
404         assertEquals( ZipEntry.DEFLATED, tarEntry.getMethod() );
405         // ...and no file is corrupted in the process
406         assertTrue( IOUtil.contentEquals( new FileInputStream( getTestFile( "src/test/jars/test.zip" ) ),
407                     zfDontRecompress.getInputStream( zipEntry ) ) );
408         assertTrue( IOUtil.contentEquals( new FileInputStream( getTestFile( "src/test/jars/test.jar" ) ),
409                 zfDontRecompress.getInputStream( jarEntry ) ) );
410         assertTrue( IOUtil.contentEquals( new FileInputStream( getTestFile( "src/test/jars/test.rar" ) ),
411                 zfDontRecompress.getInputStream( rarEntry ) ) );
412         assertTrue( IOUtil.contentEquals( new FileInputStream( getTestFile( "src/test/jars/test.tar.gz" ) ),
413                 zfDontRecompress.getInputStream( tarEntry ) ) );
414         zfDontRecompress.close();
415     }
416 
417     public void testAddArchivedFileSet()
418         throws Exception
419     {
420         File toBeAdded = new File( "src/test/resources/test.zip" );
421         DefaultArchivedFileSet sfd = DefaultArchivedFileSet.archivedFileSet( toBeAdded );
422         File zipFIle = getTestFile( "target/output/withZip.zip" );
423         final ZipArchiver zipArchiver = getZipArchiver( zipFIle );
424         InputStreamTransformer is = new InputStreamTransformer()
425         {
426 
427             @Nonnull
428             public InputStream transform( @Nonnull PlexusIoResource resource, @Nonnull InputStream inputStream )
429                 throws IOException
430             {
431                 return new BoundedInputStream( inputStream, 3 );
432             }
433 
434         };
435         sfd.setStreamTransformer( is );
436         PrefixFileMapper mapper = new PrefixFileMapper();
437         mapper.setPrefix( "prefix" );
438         sfd.setFileMappers( new FileMapper[] { mapper } );
439         zipArchiver.addArchivedFileSet( sfd );
440         zipArchiver.createArchive();
441 
442         final ZipUnArchiver zipUnArchiver = getZipUnArchiver( zipFIle );
443         File destFile = new File( "target/output/withZip" );
444         destFile.mkdirs();
445         zipUnArchiver.setDestFile( destFile );
446         zipUnArchiver.extract();
447         File a3byteFile = new File( destFile,
448                                     "prefixUsers/kristian/lsrc/plexus/plexus-archiver/src/main/java/org/codehaus/plexus/archiver/zip/ZipArchiver.java" );
449         assertTrue( a3byteFile.exists() );
450         assertTrue( a3byteFile.length() == 3 );
451     }
452 
453     public void testCreateArchiveWithStreamTransformer()
454         throws IOException
455     {
456         InputStreamTransformer is = new InputStreamTransformer()
457         {
458 
459             @Nonnull
460             @Override
461             public InputStream transform( @Nonnull PlexusIoResource resource, @Nonnull InputStream inputStream )
462                 throws IOException
463             {
464                 return new BoundedInputStream( inputStream, 3 );
465             }
466 
467         };
468 
469         final ZipArchiver zipArchiver = getZipArchiver( getTestFile( "target/output/all3bytes.zip" ) );
470         File zipFIle = new File( "src/test/resources/test.zip" );
471         DefaultArchivedFileSet afs = new DefaultArchivedFileSet( zipFIle );
472         afs.setStreamTransformer( is );
473         afs.setPrefix( "azip/" );
474         zipArchiver.addArchivedFileSet( afs );
475 
476         DefaultFileSet dfs = new DefaultFileSet( new File( "src/test/resources/mjar179" ) );
477         dfs.setStreamTransformer( is );
478         dfs.setPrefix( "mj179/" );
479         zipArchiver.addFileSet( dfs );
480 
481         PlexusIoFileResourceCollection files = new PlexusIoFileResourceCollection();
482         files.setBaseDir( new File( "src/test/resources" ) );
483         files.setStreamTransformer( is );
484         files.setPrefix( "plexus/" );
485         zipArchiver.addResources( files );
486 
487         zipArchiver.createArchive();
488 
489     }
490 
491     private ZipArchiver newArchiver( String name )
492         throws Exception
493     {
494         ZipArchiver archiver = getZipArchiver( getTestFile( "target/output/" + name ) );
495 
496         archiver.setFileMode( 0640 );
497         archiver.addFile( getTestFile( "src/test/resources/manifests/manifest1.mf" ), "one.txt" );
498         archiver.addFile( getTestFile( "src/test/resources/manifests/manifest2.mf" ), "two.txt", 0664 );
499 
500         // reset default file mode for files included from now on
501         archiver.setFileMode( 0400 );
502         archiver.setDirectoryMode( 0777 );
503         archiver.addDirectory( getTestFile( "src/test/resources/world-writable/" ), "worldwritable/" );
504 
505         archiver.setDirectoryMode( 0070 );
506         archiver.addDirectory( getTestFile( "src/test/resources/group-writable/" ), "groupwritable/" );
507 
508         archiver.setDirectoryMode( 0500 );
509         archiver.setFileMode( 0400 );
510         archiver.addDirectory( getTestFile( "src" ) );
511 
512         return archiver;
513     }
514 
515     private void fileModeAssert( int expected, int actual )
516     {
517         assertEquals( Integer.toString( expected, 8 ), Integer.toString( actual, 8 ) );
518     }
519 
520     private void createArchive( ZipArchiver archiver )
521         throws ArchiverException, IOException
522     {
523         archiver.createArchive();
524 
525         ZipFile zf = new ZipFile( archiver.getDestFile() );
526 
527         Enumeration e = zf.getEntries();
528 
529         while ( e.hasMoreElements() )
530         {
531             ZipArchiveEntry ze = (ZipArchiveEntry) e.nextElement();
532             if ( ze.isDirectory() )
533             {
534                 if ( ze.getName().startsWith( "worldwritable" ) )
535                 {
536                     fileModeAssert( 0777, UnixStat.PERM_MASK & ze.getUnixMode() );
537                 }
538                 else if ( ze.getName().startsWith( "groupwritable" ) )
539                 {
540                     fileModeAssert( 0070, UnixStat.PERM_MASK & ze.getUnixMode() );
541                 }
542                 else
543                 {
544                     fileModeAssert( 0500, UnixStat.PERM_MASK & ze.getUnixMode() );
545                 }
546             }
547             else
548             {
549                 if ( ze.getName().equals( "one.txt" ) )
550                 {
551                     fileModeAssert( 0640, UnixStat.PERM_MASK & ze.getUnixMode() );
552                 }
553                 else if ( ze.getName().equals( "two.txt" ) )
554                 {
555                     fileModeAssert( 0664, UnixStat.PERM_MASK & ze.getUnixMode() );
556                 }
557                 else if ( ze.isUnixSymlink() )
558                 {
559                     //         assertEquals( ze.getName(), 0500, UnixStat.PERM_MASK & ze.getUnixMode() );
560                 }
561                 else
562                 {
563                     fileModeAssert( 0400, UnixStat.PERM_MASK & ze.getUnixMode() );
564                 }
565             }
566 
567         }
568     }
569 
570     public void testSymlinkZip()
571         throws Exception
572     {
573         if ( !Os.isFamily( Os.FAMILY_WINDOWS ) )
574         {
575             final File zipFile = getTestFile( "target/output/pasymlinks.zip" );
576             final ZipArchiver zipArchiver = getZipArchiver( zipFile );
577             PlexusIoFileResourceCollection files = new PlexusIoFileResourceCollection();
578             files.setFollowingSymLinks( false );
579             files.setBaseDir( new File( "src/test/resources/symlinks" ) );
580             files.setPrefix( "plexus/" );
581             zipArchiver.addResources( files );
582             zipArchiver.createArchive();
583             final File output = getTestFile( "target/output/unzipped" );
584             output.mkdirs();
585             final ZipUnArchiver zipUnArchiver = getZipUnArchiver( zipFile );
586             zipUnArchiver.setDestFile( output );
587             zipUnArchiver.extract();
588             File symDir = new File( "target/output/unzipped/plexus/src/symDir" );
589             PlexusIoResourceAttributes fa = FileAttributes.uncached( symDir );
590             assertTrue( fa.isSymbolicLink() );
591         }
592     }
593 
594     @SuppressWarnings( "ResultOfMethodCallIgnored" )
595     public void testSymlinkFileSet()
596         throws Exception
597     {
598         if ( !Os.isFamily( Os.FAMILY_WINDOWS ) )
599         {
600             final File zipFile = getTestFile( "target/output/pasymlinks-fileset.zip" );
601             final ZipArchiver zipArchiver = getZipArchiver( zipFile );
602             final DefaultFileSet fs = new DefaultFileSet();
603             fs.setPrefix( "bzz/" );
604             fs.setDirectory( new File( "src/test/resources/symlinks/src" ) );
605             zipArchiver.addFileSet( fs );
606             zipArchiver.createArchive();
607             final File output = getTestFile( "target/output/unzipped/symlFs" );
608             output.mkdirs();
609             final ZipUnArchiver zipUnArchiver = getZipUnArchiver( zipFile );
610             zipUnArchiver.setDestFile( output );
611             zipUnArchiver.extract();
612             File symDir = new File( output, "bzz/symDir" );
613             PlexusIoResourceAttributes fa = FileAttributes.uncached( symDir );
614             assertTrue( fa.isSymbolicLink() );
615         }
616     }
617 
618     public void testSymlinkArchivedFileSet()
619         throws Exception
620     {
621         final File zipFile = getTestFile( "src/test/resources/symlinks/symlinks.zip" );
622         final File zipFile2 = getTestFile( "target/output/pasymlinks-archivedFileset.zip" );
623         final ZipArchiver zipArchiver = getZipArchiver( zipFile2 );
624         zipArchiver.addArchivedFileSet( zipFile );
625         zipArchiver.createArchive();
626 
627         final ZipFile cmp1 = new ZipFile( zipFile );
628         final ZipFile cmp2 = new ZipFile( zipFile2 );
629         ArchiveFileComparator.assertEquals( cmp1, cmp2, "" );
630     }
631 
632     /*
633      * Zip archives store file modification times with a granularity of two seconds.
634      * Verify that ZipArchiver rounds up the last modified time.
635      */
636     public void testLastModifiedTimeRounding()
637         throws Exception
638     {
639         File oddSecondsTimestampFile = File.createTempFile( "odd-seconds-timestamp", null );
640         oddSecondsTimestampFile.deleteOnExit();
641         // The milliseconds part is set to zero as not all filesystem support timestamp more granular than second.
642         Files.setLastModifiedTime( oddSecondsTimestampFile.toPath(), FileTime.fromMillis( 1534189011_000L ) );
643         File evenSecondsTimestampFile = File.createTempFile( "even-seconds-timestamp", null );
644         evenSecondsTimestampFile.deleteOnExit();
645         Files.setLastModifiedTime( evenSecondsTimestampFile.toPath(), FileTime.fromMillis( 1534189012_000L ) );
646 
647         File destFile = getTestFile( "target/output/last-modified-time.zip" );
648         ZipArchiver archiver = getZipArchiver( destFile );
649         archiver.addFile( oddSecondsTimestampFile, "odd-seconds" );
650         archiver.addFile( evenSecondsTimestampFile, "even-seconds" );
651         archiver.createArchive();
652 
653         // verify that the last modified time of the entry is equal or newer than the original file
654         ZipFile resultingZipFile = new ZipFile( destFile );
655         assertEquals( 1534189012_000L, resultingZipFile.getEntry( "odd-seconds" ).getTime() );
656         assertEquals( 1534189012_000L, resultingZipFile.getEntry( "even-seconds" ).getTime() );
657     }
658 
659     /*
660      */
661     public void testForced()
662         throws Exception
663     {
664         ZipArchiver archiver = newArchiver( "archive2.zip" );
665 
666         assertTrue( archiver.isForced() );
667         File f = archiver.getDestFile();
668         if ( f.exists() )
669         {
670             FileUtils.fileDelete( f.getPath() );
671         }
672         assertFalse( f.exists() );
673         createArchive( archiver );
674         long l1 = f.lastModified();
675         assertTrue( f.exists() );
676 
677         archiver = newArchiver( "archive2.zip" );
678         waitUntilNewTimestamp( archiver.getDestFile(), l1 );
679         createArchive( archiver );
680         long l2 = f.lastModified();
681         assertTrue( f.exists() );
682         assertTrue( l2 > l1 );
683 
684         archiver = newArchiver( "archive2.zip" );
685         assertTrue( archiver.isSupportingForced() );
686         archiver.setForced( false );
687         assertFalse( archiver.isForced() );
688 
689         createArchive( archiver );
690         long l3 = f.lastModified();
691         assertTrue( f.exists() );
692         assertEquals( l2, l3 );
693     }
694 
695     // Used to investigate extrafields
696     public void testLookAtExtraZipFields_from_macos()
697         throws IOException
698     {
699         InputStream fis = Streams.fileInputStream( new File( "src/test/resources/zip-timestamp/macOsZipFile.zip" ) );
700         ZipInputStream zis = new ZipInputStream( fis );
701         final java.util.zip.ZipEntry evenEntry = zis.getNextEntry();
702         final ZipExtraField[] parse = ExtraFieldUtils.parse( evenEntry.getExtra() );
703         System.out.println( Arrays.asList( parse ) );
704         final java.util.zip.ZipEntry oddEntry = zis.getNextEntry();
705 
706         System.out.println( Arrays.asList( ExtraFieldUtils.parse( oddEntry.getExtra() ) ) );
707 
708         System.out.println( "oddEntry.getTime() = " + new Date( oddEntry.getTime() ).toString() );
709         System.out.println( "oddEntry.getName() = " + oddEntry.getName() );
710         System.out.println( "new String(oddEntry.getExtra()) = " + new String( oddEntry.getExtra() ) );
711         System.out.println( "evenEntry.getName() = " + evenEntry.getName() );
712         System.out.println( "evenEntry.getTime() = " + new Date( evenEntry.getTime() ).toString() );
713         System.out.println( "new String(evenEntry.getExtra()) = " + new String( evenEntry.getExtra() ) );
714 
715     }
716 
717     // Used to investigate date roundtrip behaviour across zip versions
718     public void testZipStuff()
719         throws IOException
720     {
721         ByteArrayOutputStream baos = new ByteArrayOutputStream();
722         ZipOutputStream zos = new ZipOutputStream( baos );
723         // name the file inside the zip  file
724         final File oddFile = new File( "src/test/resources/zip-timestamp/file-with-odd-time.txt" );
725         final File evenFile = new File( "src/test/resources/zip-timestamp/file-with-even-time.txt" );
726         final ZipEntry oddZe = new ZipEntry( oddFile.getName() );
727         oddZe.setTime( oddFile.lastModified() );
728         zos.putNextEntry( oddZe );
729         final ZipEntry evenZe = new ZipEntry( evenFile.getName() );
730         evenZe.setTime( evenFile.lastModified() );
731         zos.putNextEntry( evenZe );
732         zos.close();
733 
734         ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() );
735         ZipInputStream zipInputStream = new ZipInputStream( bais );
736         final java.util.zip.ZipEntry oddEntry = zipInputStream.getNextEntry();
737         System.out.println( "oddEntry.getTime() = " + new Date( oddEntry.getTime() ).toString() );
738         System.out.println( "oddEntry.getName() = " + oddEntry.getName() );
739         final java.util.zip.ZipEntry evenEntry = zipInputStream.getNextEntry();
740         System.out.println( "evenEntry.getName() = " + evenEntry.getName() );
741         System.out.println( "evenEntry.getTime() = " + new Date( evenEntry.getTime() ).toString() );
742     }
743 
744     public void notestJustThatOne()
745         throws Exception
746     {
747         final File srcDir = new File( "src" );
748         String[] inc =
749         {
750             "test/java/org/codehaus/plexus/archiver/zip/ZipShortTest.java"
751         };
752         final File zipFile = new File( "target/output/zz1.zip" );
753 
754         final File zipFile2 = new File( "target/output/zz2.zip" );
755         ZipArchiver zipArchiver2 = getZipArchiver( zipFile2 );
756 
757         // Bugbug: This does not work on 1.8....?
758         zipArchiver2.addArchivedFileSet( zipFile );
759         FileUtils.removePath( zipFile2.getPath() );
760         zipArchiver2.createArchive();
761     }
762 
763     public void testCreateResourceCollection()
764         throws Exception
765     {
766         final File srcDir = new File( "src" );
767         final File zipFile = new File( "target/output/src.zip" );
768         ZipArchiver zipArchiver = getZipArchiver( zipFile );
769         zipArchiver.addDirectory( srcDir, null, FileUtils.getDefaultExcludes() );
770         zipArchiver.setEncoding( "UTF-8" );
771         FileUtils.removePath( zipFile.getPath() );
772         zipArchiver.createArchive();
773 
774         final File zipFile2 = new File( "target/output/src2.zip" );
775         ZipArchiver zipArchiver2 = getZipArchiver( zipFile2 );
776         zipArchiver2.addArchivedFileSet( zipFile, "prfx/" );
777         zipArchiver2.setEncoding( "UTF-8" );
778         FileUtils.removePath( zipFile2.getPath() );
779         zipArchiver2.createArchive();
780 
781         final ZipFile cmp1 = new ZipFile( zipFile );
782         final ZipFile cmp2 = new ZipFile( zipFile2 );
783         ArchiveFileComparator.assertEquals( cmp1, cmp2, "prfx/" );
784         cmp1.close();
785         cmp2.close();
786     }
787 
788     public void testZipNonConcurrentResourceCollection()
789         throws Exception
790     {
791         final File tarFile = getTestFile( "target/output/zip-non-concurrent.tar" );
792         TarArchiver tarArchiver = (TarArchiver) lookup( Archiver.ROLE, "tar" );
793         tarArchiver.setDestFile( tarFile );
794         // We're testing concurrency issue so we need large amount of files
795         for ( int i = 0; i < 100; i++ )
796         {
797             tarArchiver.addFile( getTestFile( "src/test/resources/manifests/manifest1.mf" ),
798                                  "manifest1.mf" + i );
799             // Directories are added separately so let's test them too
800             tarArchiver.addFile( getTestFile( "src/test/resources/manifests/manifest2.mf" ),
801                                  "subdir" + i + "/manifest2.mf" );
802         }
803         tarArchiver.createArchive();
804 
805         final File zipFile = new File( "target/output/zip-non-concurrent.zip" );
806         ZipArchiver zipArchive = getZipArchiver( zipFile );
807         zipArchive.addArchivedFileSet( tarFile, "prfx/" );
808         zipArchive.setEncoding( "UTF-8" );
809         zipArchive.createArchive();
810 
811         final TarFile cmp1 = new TarFile( tarFile );
812         final ZipFile cmp2 = new ZipFile( zipFile );
813         ArchiveFileComparator.assertEquals( cmp1, cmp2, "prfx/" );
814         cmp1.close();
815         cmp2.close();
816     }
817 
818     public void testDefaultUTF8()
819         throws IOException
820     {
821         final ZipArchiver zipArchiver = getZipArchiver( new File( "target/output/utf8-default.zip" ) );
822         zipArchiver.addDirectory( new File( "src/test/resources/miscUtf8" ) );
823         zipArchiver.createArchive();
824     }
825 
826     public void testDefaultUTF8withUTF8()
827         throws IOException
828     {
829         final ZipArchiver zipArchiver = getZipArchiver( new File( "target/output/utf8-with_utf.zip" ) );
830         zipArchiver.setEncoding( "UTF-8" );
831         zipArchiver.addDirectory( new File( "src/test/resources/miscUtf8" ) );
832         zipArchiver.createArchive();
833     }
834 
835     public void testForcedFileModes()
836         throws IOException
837     {
838         File step1file = new File( "target/output/forced-file-mode.zip" );
839         {
840             final ZipArchiver zipArchiver = getZipArchiver( step1file );
841             zipArchiver.setFileMode( 0077 );
842             zipArchiver.setDirectoryMode( 0007 );
843             PlexusIoResourceAttributes attrs = new SimpleResourceAttributes( 123, "fred", 22, "filntstones", 0111 );
844             PlexusIoResource resource =
845                 ResourceFactory.createResource( new File( "src/test/resources/folders/File.txt" ), "Test.txt", null,
846                                                 attrs );
847             zipArchiver.addResource( resource, "Test2.txt", 0707 );
848             PlexusIoFileResourceCollection files = new PlexusIoFileResourceCollection();
849             files.setBaseDir( new File( "src/test/resources/folders" ) );
850             files.setPrefix( "sixsixsix/" );
851             zipArchiver.addResources( files );
852 
853             zipArchiver.createArchive();
854 
855             ZipFile zf = new ZipFile( step1file );
856             fileModeAssert( 040007, zf.getEntry( "sixsixsix/a/" ).getUnixMode() );
857             fileModeAssert( 0100077, zf.getEntry( "sixsixsix/b/FileInB.txt" ).getUnixMode() );
858             fileModeAssert( 0100707, zf.getEntry( "Test2.txt" ).getUnixMode() );
859             zf.close();
860         }
861 
862         File Step2file = new File( "target/output/forced-file-mode-from-zip.zip" );
863         {
864             final ZipArchiver za2 = getZipArchiver( Step2file );
865             za2.setFileMode( 0666 );
866             za2.setDirectoryMode( 0676 );
867 
868             PlexusIoZipFileResourceCollection zipSrc = new PlexusIoZipFileResourceCollection();
869             zipSrc.setFile( step1file );
870             zipSrc.setPrefix( "zz/" );
871             za2.addResources( zipSrc );
872             za2.createArchive();
873             ZipFile zf = new ZipFile( Step2file );
874             fileModeAssert( 040676, zf.getEntry( "zz/sixsixsix/a/" ).getUnixMode() );
875             fileModeAssert( 0100666, zf.getEntry( "zz/Test2.txt" ).getUnixMode() );
876             zf.close();
877         }
878 
879         File step3file = new File( "target/output/forced-file-mode-from-zip2.zip" );
880         {
881             final ZipArchiver za2 = getZipArchiver( step3file );
882             za2.setFileMode( 0666 );
883             za2.setDirectoryMode( 0676 );
884 
885             PlexusArchiverZipFileResourceCollection zipSrc = new PlexusArchiverZipFileResourceCollection();
886             zipSrc.setFile( step1file );
887             zipSrc.setPrefix( "zz/" );
888             za2.addResources( zipSrc );
889             za2.createArchive();
890             ZipFile zf = new ZipFile( Step2file );
891             fileModeAssert( 040676, zf.getEntry( "zz/sixsixsix/a/" ).getUnixMode() );
892             fileModeAssert( 0100666, zf.getEntry( "zz/Test2.txt" ).getUnixMode() );
893             zf.close();
894         }
895     }
896 
897 }