|
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 } |