test/jdk/jdk/nio/zipfs/TestPosix.java
changeset 57665 bf325b739c8a
equal deleted inserted replaced
57664:1d2ea8db7083 57665:bf325b739c8a
       
     1 /*
       
     2  * Copyright (c) 2019, SAP SE. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 import java.io.File;
       
    25 import java.io.FileOutputStream;
       
    26 import java.io.IOException;
       
    27 import java.io.InputStream;
       
    28 import java.nio.file.*;
       
    29 import java.nio.file.attribute.BasicFileAttributes;
       
    30 import java.nio.file.attribute.GroupPrincipal;
       
    31 import java.nio.file.attribute.PosixFileAttributeView;
       
    32 import java.nio.file.attribute.PosixFileAttributes;
       
    33 import java.nio.file.attribute.PosixFilePermission;
       
    34 import java.nio.file.attribute.PosixFilePermissions;
       
    35 import java.nio.file.attribute.UserPrincipal;
       
    36 import java.security.AccessController;
       
    37 import java.security.PrivilegedAction;
       
    38 import java.security.PrivilegedActionException;
       
    39 import java.security.PrivilegedExceptionAction;
       
    40 import java.util.Collections;
       
    41 import java.util.Enumeration;
       
    42 import java.util.HashMap;
       
    43 import java.util.Map;
       
    44 import java.util.Set;
       
    45 import java.util.concurrent.atomic.AtomicInteger;
       
    46 import java.util.jar.JarEntry;
       
    47 import java.util.jar.JarFile;
       
    48 import java.util.spi.ToolProvider;
       
    49 import java.util.zip.ZipEntry;
       
    50 import java.util.zip.ZipFile;
       
    51 
       
    52 import org.testng.annotations.Test;
       
    53 
       
    54 import static java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE;
       
    55 import static java.nio.file.attribute.PosixFilePermission.GROUP_READ;
       
    56 import static java.nio.file.attribute.PosixFilePermission.GROUP_WRITE;
       
    57 import static java.nio.file.attribute.PosixFilePermission.OTHERS_EXECUTE;
       
    58 import static java.nio.file.attribute.PosixFilePermission.OTHERS_READ;
       
    59 import static java.nio.file.attribute.PosixFilePermission.OTHERS_WRITE;
       
    60 import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE;
       
    61 import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
       
    62 import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
       
    63 import static org.testng.Assert.assertEquals;
       
    64 import static org.testng.Assert.assertNotNull;
       
    65 import static org.testng.Assert.assertNull;
       
    66 import static org.testng.Assert.assertTrue;
       
    67 import static org.testng.Assert.fail;
       
    68 
       
    69 /**
       
    70  * @test
       
    71  * @bug 8213031
       
    72  * @modules jdk.zipfs
       
    73  *          jdk.jartool
       
    74  * @run testng TestPosix
       
    75  * @run testng/othervm/java.security.policy=test.policy.posix TestPosix
       
    76  * @summary Test POSIX zip file operations.
       
    77  */
       
    78 public class TestPosix {
       
    79     private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
       
    80         .orElseThrow(()->new RuntimeException("jar tool not found"));
       
    81 
       
    82     // files and directories
       
    83     private static final Path ZIP_FILE = Paths.get("testPosix.zip");
       
    84     private static final Path JAR_FILE = Paths.get("testPosix.jar");
       
    85     private static final Path ZIP_FILE_COPY = Paths.get("testPosixCopy.zip");
       
    86     private static final Path UNZIP_DIR = Paths.get("unzip/");
       
    87 
       
    88     // permission sets
       
    89     private static final Set<PosixFilePermission> ALLPERMS =
       
    90         PosixFilePermissions.fromString("rwxrwxrwx");
       
    91     private static final Set<PosixFilePermission> EMPTYPERMS =
       
    92         Collections.<PosixFilePermission>emptySet();
       
    93     private static final Set<PosixFilePermission> UR = Set.of(OWNER_READ);
       
    94     private static final Set<PosixFilePermission> UW = Set.of(OWNER_WRITE);
       
    95     private static final Set<PosixFilePermission> UE = Set.of(OWNER_EXECUTE);
       
    96     private static final Set<PosixFilePermission> GR = Set.of(GROUP_READ);
       
    97     private static final Set<PosixFilePermission> GW = Set.of(GROUP_WRITE);
       
    98     private static final Set<PosixFilePermission> GE = Set.of(GROUP_EXECUTE);
       
    99     private static final Set<PosixFilePermission> OR = Set.of(OTHERS_READ);
       
   100     private static final Set<PosixFilePermission> OW = Set.of(OTHERS_WRITE);
       
   101     private static final Set<PosixFilePermission> OE = Set.of(OTHERS_EXECUTE);
       
   102 
       
   103     // principals
       
   104     private static final UserPrincipal DUMMY_USER = ()->"defusr";
       
   105     private static final GroupPrincipal DUMMY_GROUP = ()->"defgrp";
       
   106 
       
   107     // FS open options
       
   108     private static final Map<String, Object> ENV_DEFAULT = Collections.<String, Object>emptyMap();
       
   109     private static final Map<String, Object> ENV_POSIX = Map.of("enablePosixFileAttributes", true);
       
   110 
       
   111     // misc
       
   112     private static final CopyOption[] COPY_ATTRIBUTES = {StandardCopyOption.COPY_ATTRIBUTES};
       
   113     private static final Map<String, ZipFileEntryInfo> ENTRIES = new HashMap<>();
       
   114 
       
   115     private int entriesCreated;
       
   116 
       
   117     static enum checkExpects {
       
   118         contentOnly,
       
   119         noPermDataInZip,
       
   120         permsInZip,
       
   121         permsPosix
       
   122     }
       
   123 
       
   124     static class ZipFileEntryInfo {
       
   125         // permissions to set initially
       
   126         private final Set<PosixFilePermission> intialPerms;
       
   127         // permissions to set in a later call
       
   128         private final Set<PosixFilePermission> laterPerms;
       
   129         // permissions that should be effective in the zip file
       
   130         private final Set<PosixFilePermission> permsInZip;
       
   131         // permissions that should be returned by zipfs w/Posix support
       
   132         private final Set<PosixFilePermission> permsPosix;
       
   133         // entry is a directory
       
   134         private final boolean isDir;
       
   135         // need additional read flag in copy test
       
   136         private final boolean setReadFlag;
       
   137 
       
   138         private ZipFileEntryInfo(Set<PosixFilePermission> initialPerms, Set<PosixFilePermission> laterPerms,
       
   139             Set<PosixFilePermission> permsInZip, Set<PosixFilePermission> permsZipPosix, boolean isDir, boolean setReadFlag)
       
   140         {
       
   141             this.intialPerms = initialPerms;
       
   142             this.laterPerms = laterPerms;
       
   143             this.permsInZip = permsInZip;
       
   144             this.permsPosix = permsZipPosix;
       
   145             this.isDir = isDir;
       
   146             this.setReadFlag = setReadFlag;
       
   147         }
       
   148     }
       
   149 
       
   150     static class CopyVisitor extends SimpleFileVisitor<Path> {
       
   151         private Path from, to;
       
   152         private boolean copyPerms;
       
   153 
       
   154         CopyVisitor(Path from, Path to) {
       
   155             this.from = from;
       
   156             this.to = to;
       
   157         }
       
   158 
       
   159         CopyVisitor(Path from, Path to, boolean copyPerms) {
       
   160             this.from = from;
       
   161             this.to = to;
       
   162             this.copyPerms = copyPerms;
       
   163         }
       
   164 
       
   165         @Override
       
   166         public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
       
   167             FileVisitResult rc = super.preVisitDirectory(dir, attrs);
       
   168             Path target = to.resolve(from.relativize(dir).toString());
       
   169             if (!Files.exists(target)) {
       
   170                 Files.copy(dir, target, COPY_ATTRIBUTES);
       
   171                 if (copyPerms) {
       
   172                     Files.setPosixFilePermissions(target, Files.getPosixFilePermissions(dir));
       
   173                 }
       
   174             }
       
   175             return rc;
       
   176         }
       
   177 
       
   178         @Override
       
   179         public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
       
   180             FileVisitResult rc = super.visitFile(file, attrs);
       
   181             Path target = to.resolve(from.relativize(file).toString());
       
   182             Files.copy(file, target, COPY_ATTRIBUTES);
       
   183             if (copyPerms) {
       
   184                 Files.setPosixFilePermissions(target, Files.getPosixFilePermissions(file));
       
   185             }
       
   186             return rc;
       
   187         }
       
   188     }
       
   189 
       
   190     static class DeleteVisitor extends SimpleFileVisitor<Path> {
       
   191         @Override
       
   192         public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
       
   193             FileVisitResult rc = super.postVisitDirectory(dir, exc);
       
   194             Files.delete(dir);
       
   195             return rc;
       
   196         }
       
   197 
       
   198         @Override
       
   199         public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
       
   200             FileVisitResult rc = super.visitFile(file, attrs);
       
   201             Files.delete(file);
       
   202             return rc;
       
   203         }
       
   204     }
       
   205 
       
   206     @FunctionalInterface
       
   207     static interface Executor {
       
   208         void doIt() throws IOException;
       
   209     }
       
   210 
       
   211     static {
       
   212         ENTRIES.put("dir",        new ZipFileEntryInfo(ALLPERMS,   null, ALLPERMS,   ALLPERMS,   true,  false));
       
   213         ENTRIES.put("uread",      new ZipFileEntryInfo(UR,         null, UR,         UR,         false, false));
       
   214         ENTRIES.put("uwrite",     new ZipFileEntryInfo(UW,         null, UW,         UW,         false, true));
       
   215         ENTRIES.put("uexec",      new ZipFileEntryInfo(UE,         null, UE,         UE,         false, true));
       
   216         ENTRIES.put("gread",      new ZipFileEntryInfo(GR,         null, GR,         GR,         false, true));
       
   217         ENTRIES.put("gwrite",     new ZipFileEntryInfo(GW,         null, GW,         GW,         false, true));
       
   218         ENTRIES.put("gexec",      new ZipFileEntryInfo(GE,         null, GE,         GE,         false, true));
       
   219         ENTRIES.put("oread",      new ZipFileEntryInfo(OR,         null, OR,         OR,         false, true));
       
   220         ENTRIES.put("owrite",     new ZipFileEntryInfo(OW,         null, OW,         OW,         false, true));
       
   221         ENTRIES.put("oexec",      new ZipFileEntryInfo(OE,         null, OE,         OE,         false, true));
       
   222         ENTRIES.put("emptyperms", new ZipFileEntryInfo(EMPTYPERMS, null, EMPTYPERMS, EMPTYPERMS, false, true));
       
   223         ENTRIES.put("noperms",    new ZipFileEntryInfo(null,       null, null,       ALLPERMS,   false, false));
       
   224         ENTRIES.put("permslater", new ZipFileEntryInfo(null,       UR,   UR,         UR,         false, false));
       
   225     }
       
   226 
       
   227     private static String expectedDefaultOwner(Path zf) {
       
   228         try {
       
   229             try {
       
   230                 PrivilegedExceptionAction<String> pa = ()->Files.getOwner(zf).getName();
       
   231                 return AccessController.doPrivileged(pa);
       
   232             } catch (UnsupportedOperationException e) {
       
   233                 // if we can't get the owner of the file, we fall back to system property user.name
       
   234                 PrivilegedAction<String> pa = ()->System.getProperty("user.name");
       
   235                 return AccessController.doPrivileged(pa);
       
   236             }
       
   237         } catch (PrivilegedActionException | SecurityException e) {
       
   238             System.out.println("Caught " + e.getClass().getName() + "(" + e.getMessage() +
       
   239                 ") when running a privileged operation to get the default owner.");
       
   240             return null;
       
   241         }
       
   242     }
       
   243 
       
   244     private static String expectedDefaultGroup(Path zf, String defaultOwner) {
       
   245         try {
       
   246             try {
       
   247                 PosixFileAttributeView zfpv = Files.getFileAttributeView(zf, PosixFileAttributeView.class);
       
   248                 if (zfpv == null) {
       
   249                     return defaultOwner;
       
   250                 }
       
   251                 PrivilegedExceptionAction<String> pa = ()->zfpv.readAttributes().group().getName();
       
   252                 return AccessController.doPrivileged(pa);
       
   253             } catch (UnsupportedOperationException e) {
       
   254                 return defaultOwner;
       
   255             }
       
   256         } catch (PrivilegedActionException | SecurityException e) {
       
   257             System.out.println("Caught an exception when running a privileged operation to get the default group.");
       
   258             e.printStackTrace();
       
   259             return null;
       
   260         }
       
   261     }
       
   262 
       
   263     private void putEntry(FileSystem fs, String name, ZipFileEntryInfo entry) throws IOException {
       
   264         if (entry.isDir) {
       
   265             if (entry.intialPerms == null) {
       
   266                 Files.createDirectory(fs.getPath(name));
       
   267             } else {
       
   268                 Files.createDirectory(fs.getPath(name), PosixFilePermissions.asFileAttribute(entry.intialPerms));
       
   269             }
       
   270 
       
   271         } else {
       
   272             if (entry.intialPerms == null) {
       
   273                 Files.createFile(fs.getPath(name));
       
   274             } else {
       
   275                 Files.createFile(fs.getPath(name), PosixFilePermissions.asFileAttribute(entry.intialPerms));
       
   276             }
       
   277         }
       
   278         if (entry.laterPerms != null) {
       
   279             Files.setAttribute(fs.getPath(name), "zip:permissions", entry.laterPerms);
       
   280         }
       
   281         entriesCreated++;
       
   282     }
       
   283 
       
   284     private FileSystem createTestZipFile(Path zpath, Map<String, Object> env) throws IOException {
       
   285         if (Files.exists(zpath)) {
       
   286             System.out.println("Deleting old " + zpath + "...");
       
   287             Files.delete(zpath);
       
   288         }
       
   289         System.out.println("Creating " + zpath + "...");
       
   290         entriesCreated = 0;
       
   291         var opts = new HashMap<String, Object>();
       
   292         opts.putAll(env);
       
   293         opts.put("create", true);
       
   294         FileSystem fs = FileSystems.newFileSystem(zpath, opts);
       
   295         for (String name : ENTRIES.keySet()) {
       
   296             putEntry(fs, name, ENTRIES.get(name));
       
   297         }
       
   298         return fs;
       
   299     }
       
   300 
       
   301     private FileSystem createEmptyZipFile(Path zpath, Map<String, Object> env) throws IOException {
       
   302         if (Files.exists(zpath)) {
       
   303             System.out.println("Deleting old " + zpath + "...");
       
   304             Files.delete(zpath);
       
   305         }
       
   306         System.out.println("Creating " + zpath + "...");
       
   307         var opts = new HashMap<String, Object>();
       
   308         opts.putAll(env);
       
   309         opts.put("create", true);
       
   310         return FileSystems.newFileSystem(zpath, opts);
       
   311     }
       
   312 
       
   313     private void delTree(Path p) throws IOException {
       
   314         if (Files.exists(p)) {
       
   315             Files.walkFileTree(p, new DeleteVisitor());
       
   316         }
       
   317     }
       
   318 
       
   319     private void addOwnerRead(Path root) throws IOException {
       
   320         for (String name : ENTRIES.keySet()) {
       
   321             ZipFileEntryInfo ei = ENTRIES.get(name);
       
   322             if (!ei.setReadFlag) {
       
   323                 continue;
       
   324             }
       
   325             Path setReadOn = root.resolve(name);
       
   326             Set<PosixFilePermission> perms = Files.getPosixFilePermissions(setReadOn);
       
   327             perms.add(OWNER_READ);
       
   328             Files.setPosixFilePermissions(setReadOn, perms);
       
   329         }
       
   330     }
       
   331 
       
   332     private void removeOwnerRead(Path root) throws IOException {
       
   333         for (String name : ENTRIES.keySet()) {
       
   334             ZipFileEntryInfo ei = ENTRIES.get(name);
       
   335             if (!ei.setReadFlag) {
       
   336                 continue;
       
   337             }
       
   338             Path removeReadFrom = root.resolve(name);
       
   339             Set<PosixFilePermission> perms = Files.getPosixFilePermissions(removeReadFrom);
       
   340             perms.remove(OWNER_READ);
       
   341             Files.setPosixFilePermissions(removeReadFrom, perms);
       
   342         }
       
   343     }
       
   344 
       
   345     @SuppressWarnings("unchecked")
       
   346     private void checkEntry(Path file, checkExpects expected) {
       
   347         System.out.println("Checking " + file + "...");
       
   348         String name = file.getFileName().toString();
       
   349         ZipFileEntryInfo ei = ENTRIES.get(name);
       
   350         assertNotNull(ei, "Found unknown entry " + name + ".");
       
   351         BasicFileAttributes attrs = null;
       
   352         if (expected == checkExpects.permsPosix) {
       
   353             try {
       
   354                 attrs = Files.readAttributes(file, PosixFileAttributes.class);
       
   355             } catch (IOException e) {
       
   356                 e.printStackTrace();
       
   357                 fail("Caught IOException reading file attributes (posix) for " + name + ": " + e.getMessage());
       
   358             }
       
   359         } else {
       
   360             try {
       
   361                 attrs = Files.readAttributes(file, BasicFileAttributes.class);
       
   362             } catch (IOException e) {
       
   363                 e.printStackTrace();
       
   364                 fail("Caught IOException reading file attributes (basic) " + name + ": " + e.getMessage());
       
   365             }
       
   366         }
       
   367         assertEquals(Files.isDirectory(file), ei.isDir, "Unexpected directory attribute for:" + System.lineSeparator() + attrs);
       
   368 
       
   369         if (expected == checkExpects.contentOnly) {
       
   370             return;
       
   371         }
       
   372 
       
   373         Set<PosixFilePermission> permissions;
       
   374         if (expected == checkExpects.permsPosix) {
       
   375             try {
       
   376                 permissions = Files.getPosixFilePermissions(file);
       
   377             } catch (IOException e) {
       
   378                 e.printStackTrace();
       
   379                 fail("Caught IOException getting permission attribute for:" + System.lineSeparator() + attrs);
       
   380                 return;
       
   381             }
       
   382             comparePermissions(ei.permsPosix, permissions);
       
   383         } else if (expected == checkExpects.permsInZip || expected == checkExpects.noPermDataInZip) {
       
   384             try {
       
   385                 permissions = (Set<PosixFilePermission>)Files.getAttribute(file, "zip:permissions");
       
   386             } catch (IOException e) {
       
   387                 e.printStackTrace();
       
   388                 fail("Caught IOException getting permission attribute for:" + System.lineSeparator() + attrs);
       
   389                 return;
       
   390             }
       
   391             comparePermissions(expected == checkExpects.noPermDataInZip ? null : ei.permsInZip, permissions);
       
   392         }
       
   393     }
       
   394 
       
   395     private void doCheckEntries(Path path, checkExpects expected) throws IOException {
       
   396         AtomicInteger entries = new AtomicInteger();
       
   397 
       
   398         try (DirectoryStream<Path> paths = Files.newDirectoryStream(path)) {
       
   399             paths.forEach(file -> {
       
   400                 entries.getAndIncrement();
       
   401                 checkEntry(file, expected);
       
   402             });
       
   403         }
       
   404         System.out.println("Number of entries: " + entries.get() + ".");
       
   405         assertEquals(entries.get(), entriesCreated, "File contained wrong number of entries.");
       
   406     }
       
   407 
       
   408     private void checkEntries(FileSystem fs, checkExpects expected) throws IOException {
       
   409         System.out.println("Checking permissions on file system " + fs + "...");
       
   410         doCheckEntries(fs.getPath("/"), expected);
       
   411     }
       
   412 
       
   413     private void checkEntries(Path path, checkExpects expected) throws IOException {
       
   414         System.out.println("Checking permissions on path " + path + "...");
       
   415         doCheckEntries(path, expected);
       
   416     }
       
   417 
       
   418     private boolean throwsUOE(Executor e) throws IOException {
       
   419         try {
       
   420             e.doIt();
       
   421             return false;
       
   422         } catch (UnsupportedOperationException exc) {
       
   423             return true;
       
   424         }
       
   425     }
       
   426 
       
   427     private void comparePermissions(Set<PosixFilePermission> expected, Set<PosixFilePermission> actual) {
       
   428         if (expected == null) {
       
   429             assertNull(actual, "Permissions are not null");
       
   430         } else {
       
   431             assertNotNull(actual, "Permissions are null.");
       
   432             assertEquals(actual.size(), expected.size(), "Unexpected number of permissions (" +
       
   433                 actual.size() + " received vs " + expected.size() + " expected).");
       
   434             for (PosixFilePermission p : expected) {
       
   435                 assertTrue(actual.contains(p), "Posix permission " + p + " missing.");
       
   436             }
       
   437         }
       
   438     }
       
   439 
       
   440     /**
       
   441      * This tests whether the entries in a zip file created w/o
       
   442      * Posix support are correct.
       
   443      *
       
   444      * @throws IOException
       
   445      */
       
   446     @Test
       
   447     public void testDefault() throws IOException {
       
   448         // create zip file using zipfs with default options
       
   449         createTestZipFile(ZIP_FILE, ENV_DEFAULT).close();
       
   450         // check entries on zipfs with default options
       
   451         try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE, ENV_DEFAULT)) {
       
   452             checkEntries(zip, checkExpects.permsInZip);
       
   453         }
       
   454         // check entries on zipfs with posix options
       
   455         try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE, ENV_POSIX)) {
       
   456             checkEntries(zip, checkExpects.permsPosix);
       
   457         }
       
   458     }
       
   459 
       
   460     /**
       
   461      * This tests whether the entries in a zip file created w/
       
   462      * Posix support are correct.
       
   463      *
       
   464      * @throws IOException
       
   465      */
       
   466     @Test
       
   467     public void testPosix() throws IOException {
       
   468         // create zip file using zipfs with posix option
       
   469         createTestZipFile(ZIP_FILE, ENV_POSIX).close();
       
   470         // check entries on zipfs with default options
       
   471         try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE, ENV_DEFAULT)) {
       
   472             checkEntries(zip, checkExpects.permsInZip);
       
   473         }
       
   474         // check entries on zipfs with posix options
       
   475         try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE, ENV_POSIX)) {
       
   476             checkEntries(zip, checkExpects.permsPosix);
       
   477         }
       
   478     }
       
   479 
       
   480     /**
       
   481      * This tests whether the entries in a zip file copied from another
       
   482      * are correct.
       
   483      *
       
   484      * @throws IOException
       
   485      */
       
   486     @Test
       
   487     public void testCopy() throws IOException {
       
   488         // copy zip to zip with default options
       
   489         try (FileSystem zipIn = createTestZipFile(ZIP_FILE, ENV_DEFAULT);
       
   490              FileSystem zipOut = createEmptyZipFile(ZIP_FILE_COPY, ENV_DEFAULT)) {
       
   491             Path from = zipIn.getPath("/");
       
   492             Files.walkFileTree(from, new CopyVisitor(from, zipOut.getPath("/")));
       
   493         }
       
   494         // check entries on copied zipfs with default options
       
   495         try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE_COPY, ENV_DEFAULT)) {
       
   496             checkEntries(zip, checkExpects.permsInZip);
       
   497         }
       
   498         // check entries on copied zipfs with posix options
       
   499         try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE_COPY, ENV_POSIX)) {
       
   500             checkEntries(zip, checkExpects.permsPosix);
       
   501         }
       
   502     }
       
   503 
       
   504     /**
       
   505      * This tests whether the entries of a zip file look correct after extraction
       
   506      * and re-packing. When not using zipfs with Posix support, we expect the
       
   507      * effective permissions in the resulting zip file to be empty.
       
   508      *
       
   509      * @throws IOException
       
   510      */
       
   511     @Test
       
   512     public void testUnzipDefault() throws IOException {
       
   513         delTree(UNZIP_DIR);
       
   514         Files.createDirectory(UNZIP_DIR);
       
   515 
       
   516         try (FileSystem srcZip = createTestZipFile(ZIP_FILE, ENV_DEFAULT)) {
       
   517             Path from = srcZip.getPath("/");
       
   518             Files.walkFileTree(from, new CopyVisitor(from, UNZIP_DIR));
       
   519         }
       
   520 
       
   521         // we just check that the entries got extracted to file system
       
   522         checkEntries(UNZIP_DIR, checkExpects.contentOnly);
       
   523 
       
   524         // the target zip file is opened with Posix support
       
   525         // but we expect no permission data to be copied using the default copy method
       
   526         try (FileSystem tgtZip = createEmptyZipFile(ZIP_FILE_COPY, ENV_POSIX)) {
       
   527             Files.walkFileTree(UNZIP_DIR, new CopyVisitor(UNZIP_DIR, tgtZip.getPath("/")));
       
   528         }
       
   529 
       
   530         // check entries on copied zipfs - no permission data should exist
       
   531         try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE_COPY, ENV_DEFAULT)) {
       
   532             checkEntries(zip, checkExpects.noPermDataInZip);
       
   533         }
       
   534     }
       
   535 
       
   536     /**
       
   537      * This tests whether the entries of a zip file look correct after extraction
       
   538      * and re-packing. If the default file system supports Posix, we test whether we
       
   539      * correctly carry the Posix permissions. Otherwise there's not much to test in
       
   540      * this method.
       
   541      *
       
   542      * @throws IOException
       
   543      */
       
   544     @Test
       
   545     public void testUnzipPosix() throws IOException {
       
   546         delTree(UNZIP_DIR);
       
   547         Files.createDirectory(UNZIP_DIR);
       
   548 
       
   549         try {
       
   550             Files.getPosixFilePermissions(UNZIP_DIR);
       
   551         } catch (Exception e) {
       
   552             // if we run into any exception here, be it because of the fact that the file system
       
   553             // is not Posix or if we have insufficient security permissions, we can't do this test.
       
   554             System.out.println("This can't be tested here because of " + e);
       
   555             return;
       
   556         }
       
   557 
       
   558         try (FileSystem srcZip = createTestZipFile(ZIP_FILE, ENV_POSIX)) {
       
   559             Path from = srcZip.getPath("/");
       
   560             // copy permissions as well
       
   561             Files.walkFileTree(from, new CopyVisitor(from, UNZIP_DIR, true));
       
   562         }
       
   563 
       
   564         // permissions should have been propagated to file system
       
   565         checkEntries(UNZIP_DIR, checkExpects.permsPosix);
       
   566 
       
   567         try (FileSystem tgtZip = createEmptyZipFile(ZIP_FILE_COPY, ENV_POSIX)) {
       
   568             // Make some files owner readable to be able to copy them into the zipfs
       
   569             addOwnerRead(UNZIP_DIR);
       
   570 
       
   571             // copy permissions as well
       
   572             Files.walkFileTree(UNZIP_DIR, new CopyVisitor(UNZIP_DIR, tgtZip.getPath("/"), true));
       
   573 
       
   574             // Fix back all the files in the target zip file which have been made readable before
       
   575             removeOwnerRead(tgtZip.getPath("/"));
       
   576         }
       
   577 
       
   578         // check entries on copied zipfs - permission data should have been propagated
       
   579         try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE_COPY, ENV_POSIX)) {
       
   580             checkEntries(zip, checkExpects.permsPosix);
       
   581         }
       
   582     }
       
   583 
       
   584     /**
       
   585      * Tests POSIX default behavior.
       
   586      *
       
   587      * @throws IOException
       
   588      */
       
   589     @Test
       
   590     public void testPosixDefaults() throws IOException {
       
   591         // test with posix = false, expect UnsupportedOperationException
       
   592         try (FileSystem zipIn = createTestZipFile(ZIP_FILE, ENV_DEFAULT)) {
       
   593             var entry = zipIn.getPath("/dir");
       
   594             assertTrue(throwsUOE(()->Files.getPosixFilePermissions(entry)));
       
   595             assertTrue(throwsUOE(()->Files.setPosixFilePermissions(entry, UW)));
       
   596             assertTrue(throwsUOE(()->Files.getOwner(entry)));
       
   597             assertTrue(throwsUOE(()->Files.setOwner(entry, DUMMY_USER)));
       
   598             assertTrue(throwsUOE(()->Files.getFileAttributeView(entry, PosixFileAttributeView.class)));
       
   599         }
       
   600 
       
   601         // test with posix = true -> default values
       
   602         try (FileSystem zipIn = FileSystems.newFileSystem(ZIP_FILE, ENV_POSIX)) {
       
   603             String defaultOwner = expectedDefaultOwner(ZIP_FILE);
       
   604             String defaultGroup = expectedDefaultGroup(ZIP_FILE, defaultOwner);
       
   605             var entry = zipIn.getPath("/noperms");
       
   606             comparePermissions(ALLPERMS, Files.getPosixFilePermissions(entry));
       
   607             var owner = Files.getOwner(entry);
       
   608             assertNotNull(owner, "owner should not be null");
       
   609             if (defaultOwner != null) {
       
   610                 assertEquals(owner.getName(), defaultOwner);
       
   611             }
       
   612             Files.setOwner(entry, DUMMY_USER);
       
   613             assertEquals(Files.getOwner(entry), DUMMY_USER);
       
   614             var view = Files.getFileAttributeView(entry, PosixFileAttributeView.class);
       
   615             var group = view.readAttributes().group();
       
   616             assertNotNull(group, "group must not be null");
       
   617             if (defaultGroup != null) {
       
   618                 assertEquals(group.getName(), defaultGroup);
       
   619             }
       
   620             view.setGroup(DUMMY_GROUP);
       
   621             assertEquals(view.readAttributes().group(), DUMMY_GROUP);
       
   622             entry = zipIn.getPath("/uexec");
       
   623             Files.setPosixFilePermissions(entry, GR); // will be persisted
       
   624             comparePermissions(GR, Files.getPosixFilePermissions(entry));
       
   625         }
       
   626 
       
   627         // test with posix = true + custom defaults of type String
       
   628         try (FileSystem zipIn = FileSystems.newFileSystem(ZIP_FILE, Map.of("enablePosixFileAttributes", true,
       
   629             "defaultOwner", "auser", "defaultGroup", "agroup", "defaultPermissions", "r--------")))
       
   630         {
       
   631             var entry = zipIn.getPath("/noperms");
       
   632             comparePermissions(UR, Files.getPosixFilePermissions(entry));
       
   633             assertEquals(Files.getOwner(entry).getName(), "auser");
       
   634             var view = Files.getFileAttributeView(entry, PosixFileAttributeView.class);
       
   635             assertEquals(view.readAttributes().group().getName(), "agroup");
       
   636             // check if the change to permissions of /uexec was persisted
       
   637             comparePermissions(GR, Files.getPosixFilePermissions(zipIn.getPath("/uexec")));
       
   638         }
       
   639 
       
   640         // test with posix = true + custom defaults as Objects
       
   641         try (FileSystem zipIn = FileSystems.newFileSystem(ZIP_FILE, Map.of("enablePosixFileAttributes", true,
       
   642             "defaultOwner", DUMMY_USER, "defaultGroup", DUMMY_GROUP, "defaultPermissions", UR)))
       
   643         {
       
   644             var entry = zipIn.getPath("/noperms");
       
   645             comparePermissions(UR, Files.getPosixFilePermissions(entry));
       
   646             assertEquals(Files.getOwner(entry), DUMMY_USER);
       
   647             var view = Files.getFileAttributeView(entry, PosixFileAttributeView.class);
       
   648             assertEquals(view.readAttributes().group(), DUMMY_GROUP);
       
   649         }
       
   650     }
       
   651 
       
   652     /**
       
   653      * Sanity check to test whether the zip file can be unzipped with the java.util.zip API.
       
   654      *
       
   655      * @throws IOException
       
   656      */
       
   657     @Test
       
   658     public void testUnzipWithJavaUtilZip() throws IOException {
       
   659         createTestZipFile(ZIP_FILE, ENV_DEFAULT).close();
       
   660         delTree(UNZIP_DIR);
       
   661         Files.createDirectory(UNZIP_DIR);
       
   662         File targetDir = UNZIP_DIR.toFile();
       
   663         try (ZipFile zf = new ZipFile(ZIP_FILE.toFile())) {
       
   664             Enumeration<? extends ZipEntry> zenum = zf.entries();
       
   665             while (zenum.hasMoreElements()) {
       
   666                 ZipEntry ze = zenum.nextElement();
       
   667                 File target = new File(targetDir + File.separator + ze.getName());
       
   668                 if (ze.isDirectory()) {
       
   669                     target.mkdir();
       
   670                     continue;
       
   671                 }
       
   672                 try (InputStream is = zf.getInputStream(ze);
       
   673                      FileOutputStream fos = new FileOutputStream(target))
       
   674                 {
       
   675                     while (is.available() > 0) {
       
   676                         fos.write(is.read());
       
   677                     }
       
   678                 }
       
   679             }
       
   680         }
       
   681     }
       
   682 
       
   683     /**
       
   684      * Sanity check to test whether a jar file created with zipfs can be
       
   685      * extracted with the java.util.jar API.
       
   686      *
       
   687      * @throws IOException
       
   688      */
       
   689     @Test
       
   690     public void testJarFile() throws IOException {
       
   691         // create jar file using zipfs with default options
       
   692         createTestZipFile(JAR_FILE, ENV_DEFAULT).close();
       
   693 
       
   694         // extract it using java.util.jar.JarFile
       
   695         delTree(UNZIP_DIR);
       
   696         Files.createDirectory(UNZIP_DIR);
       
   697         File targetDir = UNZIP_DIR.toFile();
       
   698         try (JarFile jf = new JarFile(ZIP_FILE.toFile())) {
       
   699             Enumeration<? extends JarEntry> zenum = jf.entries();
       
   700             while (zenum.hasMoreElements()) {
       
   701                 JarEntry ze = zenum.nextElement();
       
   702                 File target = new File(targetDir + File.separator + ze.getName());
       
   703                 if (ze.isDirectory()) {
       
   704                     target.mkdir();
       
   705                     continue;
       
   706                 }
       
   707                 try (InputStream is = jf.getInputStream(ze);
       
   708                      FileOutputStream fos = new FileOutputStream(target))
       
   709                 {
       
   710                     while (is.available() > 0) {
       
   711                         fos.write(is.read());
       
   712                     }
       
   713                 }
       
   714             }
       
   715         }
       
   716 
       
   717         // extract it using the jar tool
       
   718         delTree(UNZIP_DIR);
       
   719         System.out.println("jar xvf " + JAR_FILE);
       
   720 
       
   721         // the run method catches IOExceptions, we need to expose them
       
   722         int rc = JAR_TOOL.run(System.out, System.err, "xvf", JAR_FILE.toString());
       
   723         assertEquals(rc, 0, "Return code of jar call is " + rc + " but expected 0");
       
   724     }
       
   725 }