8197398: (zipfs) Files.walkFileTree walk indefinitelly while processing JAR file with "/" as a directory inside
Reviewed-by: alanb
This commit is contained in:
parent
315e71f87e
commit
de35357cf5
@ -317,7 +317,7 @@ class ZipFileSystem extends FileSystem {
|
||||
if (inode == null)
|
||||
return null;
|
||||
e = new Entry(inode.name, inode.isdir); // pseudo directory
|
||||
e.method = METHOD_STORED; // STORED for dir
|
||||
e.method = METHOD_STORED; // STORED for dir
|
||||
e.mtime = e.atime = e.ctime = zfsDefaultTimeStamp;
|
||||
}
|
||||
} finally {
|
||||
@ -1087,9 +1087,8 @@ class ZipFileSystem extends FileSystem {
|
||||
if (pos + CENHDR + nlen > limit) {
|
||||
zerror("invalid CEN header (bad header size)");
|
||||
}
|
||||
IndexNode inode = new IndexNode(cen, pos + CENHDR, nlen, pos);
|
||||
IndexNode inode = new IndexNode(cen, nlen, pos);
|
||||
inodes.put(inode, inode);
|
||||
|
||||
// skip ext and comment
|
||||
pos += (CENHDR + nlen + elen + clen);
|
||||
}
|
||||
@ -1173,9 +1172,15 @@ class ZipFileSystem extends FileSystem {
|
||||
size = 16;
|
||||
}
|
||||
// read loc, use the original loc.elen/nlen
|
||||
if (readFullyAt(buf, 0, LOCHDR , locoff) != LOCHDR)
|
||||
//
|
||||
// an extra byte after loc is read, which should be the first byte of the
|
||||
// 'name' field of the loc. if this byte is '/', which means the original
|
||||
// entry has an absolute path in original zip/jar file, the e.writeLOC()
|
||||
// is used to output the loc, in which the leading "/" will be removed
|
||||
if (readFullyAt(buf, 0, LOCHDR + 1 , locoff) != LOCHDR + 1)
|
||||
throw new ZipException("loc: reading failed");
|
||||
if (updateHeader) {
|
||||
|
||||
if (updateHeader || LOCNAM(buf) > 0 && buf[LOCHDR] == '/') {
|
||||
locoff += LOCHDR + LOCNAM(buf) + LOCEXT(buf); // skip header
|
||||
size += e.csize;
|
||||
written = e.writeLOC(os) + size;
|
||||
@ -1275,6 +1280,10 @@ class ZipFileSystem extends FileSystem {
|
||||
if (inode.pos == -1) {
|
||||
continue; // pseudo directory node
|
||||
}
|
||||
if (inode.name.length == 1 && inode.name[0] == '/') {
|
||||
continue; // no root '/' directory even it
|
||||
// exits in original zip/jar file.
|
||||
}
|
||||
e = Entry.readCEN(this, inode);
|
||||
try {
|
||||
written += copyLOCEntry(e, false, os, written, buf);
|
||||
@ -1796,15 +1805,20 @@ class ZipFileSystem extends FileSystem {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
// constructor for cenInit()
|
||||
IndexNode(byte[] cen, int noff, int nlen, int pos) {
|
||||
// constructor for cenInit() (1) remove tailing '/' (2) pad leading '/'
|
||||
IndexNode(byte[] cen, int nlen, int pos) {
|
||||
int noff = pos + CENHDR;
|
||||
if (cen[noff + nlen - 1] == '/') {
|
||||
isdir = true;
|
||||
nlen--;
|
||||
}
|
||||
name = new byte[nlen + 1];
|
||||
System.arraycopy(cen, pos + CENHDR, name, 1, nlen);
|
||||
name[0] = '/';
|
||||
if (nlen > 0 && cen[noff] == '/') {
|
||||
name = Arrays.copyOfRange(cen, noff, noff + nlen);
|
||||
} else {
|
||||
name = new byte[nlen + 1];
|
||||
System.arraycopy(cen, noff, name, 1, nlen);
|
||||
name[0] = '/';
|
||||
}
|
||||
name(name);
|
||||
this.pos = pos;
|
||||
}
|
||||
@ -2505,7 +2519,12 @@ class ZipFileSystem extends FileSystem {
|
||||
private void buildNodeTree() throws IOException {
|
||||
beginWrite();
|
||||
try {
|
||||
IndexNode root = new IndexNode(ROOTPATH, true);
|
||||
IndexNode root = inodes.get(LOOKUPKEY.as(ROOTPATH));
|
||||
if (root == null) {
|
||||
root = new IndexNode(ROOTPATH, true);
|
||||
} else {
|
||||
inodes.remove(root);
|
||||
}
|
||||
IndexNode[] nodes = inodes.keySet().toArray(new IndexNode[0]);
|
||||
inodes.put(root, root);
|
||||
ParentLookup lookup = new ParentLookup();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 7156873 8040059 8028480 8034773 8153248 8061777
|
||||
* @bug 7156873 8040059 8028480 8034773 8153248 8061777 8197398
|
||||
* @summary ZipFileSystem regression tests
|
||||
*
|
||||
* @modules jdk.zipfs
|
||||
@ -31,22 +31,155 @@
|
||||
*/
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.spi.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class ZFSTests {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
test8197398();
|
||||
test7156873();
|
||||
test8061777();
|
||||
tests();
|
||||
}
|
||||
|
||||
static void test8197398() throws Throwable {
|
||||
|
||||
// root entry "/"
|
||||
Path path = Paths.get("rootdir.zip");
|
||||
URI uri = URI.create("jar:" + path.toUri());
|
||||
|
||||
Set<String> dirs = new HashSet<>();
|
||||
Set<String> files = new HashSet<>();
|
||||
try (OutputStream os = Files.newOutputStream(path);
|
||||
ZipOutputStream zos = new ZipOutputStream(os)) {
|
||||
zos.putNextEntry(new ZipEntry("/")); dirs.add("/");
|
||||
zos.putNextEntry(new ZipEntry("foo")); files.add("/foo");
|
||||
zos.write("/foo".getBytes());
|
||||
zos.putNextEntry(new ZipEntry("bar")); files.add("/bar");
|
||||
zos.write("/bar".getBytes());
|
||||
}
|
||||
AtomicInteger cnt = new AtomicInteger();
|
||||
int max = 3;
|
||||
try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
|
||||
Files.walkFileTree(fs.getRootDirectories().iterator().next(),
|
||||
new SimpleFileVisitor<Path>() {
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
|
||||
throws IOException {
|
||||
if (cnt.incrementAndGet() > max)
|
||||
throw new RuntimeException("visited too many files/dirs");
|
||||
files.remove(file.toString());
|
||||
if (!Arrays.equals(Files.readAllBytes(file), file.toString().getBytes()))
|
||||
throw new RuntimeException("visited files has wrong content: " + file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
|
||||
throws IOException {
|
||||
if (cnt.incrementAndGet() > max)
|
||||
throw new RuntimeException("visited too many files/dirs");
|
||||
dirs.remove(dir.toString());
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
if (cnt.get() != max || dirs.size() != 0 || files.size() != 0)
|
||||
throw new RuntimeException("walk files/dirs failed");
|
||||
|
||||
} finally {
|
||||
Files.deleteIfExists(path);
|
||||
}
|
||||
|
||||
// absolute file/dir, no need to test cnt again..
|
||||
dirs.clear();
|
||||
files.clear();
|
||||
try (OutputStream os = Files.newOutputStream(path);
|
||||
ZipOutputStream zos = new ZipOutputStream(os)) {
|
||||
zos.putNextEntry(new ZipEntry("/")); dirs.add("/");
|
||||
zos.putNextEntry(new ZipEntry("/fooo/")); dirs.add("/fooo");
|
||||
zos.putNextEntry(new ZipEntry("/foo")); files.add("/foo");
|
||||
zos.write("/foo".getBytes());
|
||||
zos.putNextEntry(new ZipEntry("/bar")); files.add("/bar");
|
||||
zos.write("/bar".getBytes());
|
||||
zos.putNextEntry(new ZipEntry("/fooo/bar")); files.add("/fooo/bar");
|
||||
zos.write("/fooo/bar".getBytes());
|
||||
}
|
||||
|
||||
try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
|
||||
Files.walkFileTree(fs.getRootDirectories().iterator().next(),
|
||||
new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
|
||||
throws IOException {
|
||||
files.remove(file.toString());
|
||||
if (!Arrays.equals(Files.readAllBytes(file), file.toString().getBytes()))
|
||||
throw new RuntimeException("visited files has wrong content: " + file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
|
||||
throws IOException {
|
||||
dirs.remove(dir.toString());
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
if (dirs.size() != 0 || files.size() != 0)
|
||||
throw new RuntimeException("walk files/dirs failed");
|
||||
|
||||
// for next test: updated any entry, the result zipfs file should have no
|
||||
// absolute path entry
|
||||
Files.write(fs.getPath("/foo"), "/foo".getBytes());
|
||||
}
|
||||
|
||||
// updated zfs should have the same dirs/files (path is not absolute though)
|
||||
dirs.add("/");
|
||||
dirs.add("/fooo");
|
||||
files.add("/foo");
|
||||
files.add("/bar");
|
||||
files.add("/fooo/bar");
|
||||
try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
|
||||
Files.walk(fs.getPath("/")).forEach( p -> {
|
||||
if (Files.isDirectory(p)) {
|
||||
dirs.remove(p.toString());
|
||||
} else {
|
||||
files.remove(p.toString());
|
||||
try {
|
||||
if (!Arrays.equals(Files.readAllBytes(p), p.toString().getBytes()))
|
||||
throw new RuntimeException("visited files has wrong content: " + p);
|
||||
} catch (IOException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (dirs.size() != 0 || files.size() != 0)
|
||||
throw new RuntimeException("walk files/dirs failed");
|
||||
|
||||
}
|
||||
// updated zip file should not have "/" and entry with absolute path
|
||||
String[] entries = new ZipFile(path.toFile()).stream()
|
||||
.map(ZipEntry::toString)
|
||||
.sorted()
|
||||
.toArray(String[]::new);
|
||||
if (!Arrays.equals(entries, new String[] {"bar", "foo", "fooo/", "fooo/bar" })) {
|
||||
System.out.println("unexpeded: " + Arrays.toString(entries));
|
||||
throw new RuntimeException("unexpected entreis in updated zipfs file");
|
||||
}
|
||||
Files.deleteIfExists(path);
|
||||
}
|
||||
|
||||
static void test7156873() throws Throwable {
|
||||
String DIRWITHSPACE = "testdir with spaces";
|
||||
Path dir = Paths.get(DIRWITHSPACE);
|
||||
@ -95,6 +228,7 @@ public class ZFSTests {
|
||||
Path path = Paths.get("file.zip");
|
||||
try {
|
||||
URI uri = URI.create("jar:" + path.toUri());
|
||||
|
||||
Map<String, Object> env = new HashMap<String, Object>();
|
||||
env.put("create", "true");
|
||||
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user