Merge
This commit is contained in:
commit
5cd1a06f1a
@ -78,7 +78,6 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
// configurable by env map
|
// configurable by env map
|
||||||
private final String defaultDir; // default dir for the file system
|
private final String defaultDir; // default dir for the file system
|
||||||
private final String nameEncoding; // default encoding for name/comment
|
private final String nameEncoding; // default encoding for name/comment
|
||||||
private final boolean buildDirTree; // build a dir tree for directoryStream ops
|
|
||||||
private final boolean useTempFile; // use a temp file for newOS, default
|
private final boolean useTempFile; // use a temp file for newOS, default
|
||||||
// is to use BAOS for better performance
|
// is to use BAOS for better performance
|
||||||
private final boolean createNew; // create a new zip if not exists
|
private final boolean createNew; // create a new zip if not exists
|
||||||
@ -94,7 +93,6 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
this.createNew = "true".equals(env.get("create"));
|
this.createNew = "true".equals(env.get("create"));
|
||||||
this.nameEncoding = env.containsKey("encoding") ?
|
this.nameEncoding = env.containsKey("encoding") ?
|
||||||
(String)env.get("encoding") : "UTF-8";
|
(String)env.get("encoding") : "UTF-8";
|
||||||
this.buildDirTree = TRUE.equals(env.get("buildDirTreea"));
|
|
||||||
this.useTempFile = TRUE.equals(env.get("useTempFile"));
|
this.useTempFile = TRUE.equals(env.get("useTempFile"));
|
||||||
this.defaultDir = env.containsKey("default.dir") ?
|
this.defaultDir = env.containsKey("default.dir") ?
|
||||||
(String)env.get("default.dir") : "/";
|
(String)env.get("default.dir") : "/";
|
||||||
@ -290,28 +288,16 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
try {
|
try {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
e = getEntry0(path);
|
e = getEntry0(path);
|
||||||
} finally {
|
|
||||||
endRead();
|
|
||||||
}
|
|
||||||
if (e == null) {
|
if (e == null) {
|
||||||
if (path.length == 0) {
|
IndexNode inode = getInode(path);
|
||||||
e = new Entry(new byte[0]); // root
|
|
||||||
} else if (buildDirTree) {
|
|
||||||
IndexNode inode = getDirs().get(IndexNode.keyOf(path));
|
|
||||||
if (inode == null)
|
if (inode == null)
|
||||||
return null;
|
return null;
|
||||||
e = new Entry(inode.name);
|
e = new Entry(inode.name); // pseudo directory
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
e.method = METHOD_STORED; // STORED for dir
|
e.method = METHOD_STORED; // STORED for dir
|
||||||
BasicFileAttributes bfas = Attributes.readBasicFileAttributes(zfpath);
|
e.mtime = e.atime = e.ctime = -1;// -1 for all times
|
||||||
if (bfas.lastModifiedTime() != null)
|
}
|
||||||
e.mtime = bfas.lastModifiedTime().toMillis();
|
} finally {
|
||||||
if (bfas.lastAccessTime() != null)
|
endRead();
|
||||||
e.atime = bfas.lastAccessTime().toMillis();
|
|
||||||
if (bfas.creationTime() != null)
|
|
||||||
e.ctime = bfas.creationTime().toMillis();
|
|
||||||
}
|
}
|
||||||
return new ZipFileAttributes(e);
|
return new ZipFileAttributes(e);
|
||||||
}
|
}
|
||||||
@ -346,7 +332,7 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
beginRead();
|
beginRead();
|
||||||
try {
|
try {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
return getEntry0(path) != null;
|
return getInode(path) != null;
|
||||||
} finally {
|
} finally {
|
||||||
endRead();
|
endRead();
|
||||||
}
|
}
|
||||||
@ -355,13 +341,10 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
boolean isDirectory(byte[] path)
|
boolean isDirectory(byte[] path)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
if (buildDirTree)
|
|
||||||
return getDirs().containsKey(IndexNode.keyOf(path));
|
|
||||||
|
|
||||||
beginRead();
|
beginRead();
|
||||||
try {
|
try {
|
||||||
Entry e = getEntry0(path);
|
IndexNode n = getInode(path);
|
||||||
return (e != null && e.isDir()) || path.length == 0;
|
return n != null && n.isDir();
|
||||||
} finally {
|
} finally {
|
||||||
endRead();
|
endRead();
|
||||||
}
|
}
|
||||||
@ -383,8 +366,7 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
beginWrite(); // iteration of inodes needs exclusive lock
|
beginWrite(); // iteration of inodes needs exclusive lock
|
||||||
try {
|
try {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
if (buildDirTree) {
|
IndexNode inode = getInode(path);
|
||||||
IndexNode inode = getDirs().get(IndexNode.keyOf(path));
|
|
||||||
if (inode == null)
|
if (inode == null)
|
||||||
throw new NotDirectoryException(getString(path));
|
throw new NotDirectoryException(getString(path));
|
||||||
List<Path> list = new ArrayList<>();
|
List<Path> list = new ArrayList<>();
|
||||||
@ -396,28 +378,6 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
child = child.sibling;
|
child = child.sibling;
|
||||||
}
|
}
|
||||||
return list.iterator();
|
return list.iterator();
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDirectory(path))
|
|
||||||
throw new NotDirectoryException(getString(path));
|
|
||||||
List<Path> list = new ArrayList<>();
|
|
||||||
path = toDirectoryPath(path);
|
|
||||||
for (IndexNode key : inodes.keySet()) {
|
|
||||||
if (!isParentOf(path, key.name)) // is "path" the parent of "name"
|
|
||||||
continue;
|
|
||||||
int off = path.length;
|
|
||||||
while (off < key.name.length) {
|
|
||||||
if (key.name[off] == '/')
|
|
||||||
break;
|
|
||||||
off++;
|
|
||||||
}
|
|
||||||
if (off < (key.name.length - 1))
|
|
||||||
continue;
|
|
||||||
ZipPath zp = toZipPath(key.name);
|
|
||||||
if (filter == null || filter.accept(zp))
|
|
||||||
list.add(zp);
|
|
||||||
}
|
|
||||||
return list.iterator();
|
|
||||||
} finally {
|
} finally {
|
||||||
endWrite();
|
endWrite();
|
||||||
}
|
}
|
||||||
@ -433,7 +393,6 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
ensureOpen();
|
ensureOpen();
|
||||||
if (dir.length == 0 || exists(dir)) // root dir, or exiting dir
|
if (dir.length == 0 || exists(dir)) // root dir, or exiting dir
|
||||||
throw new FileAlreadyExistsException(getString(dir));
|
throw new FileAlreadyExistsException(getString(dir));
|
||||||
|
|
||||||
checkParents(dir);
|
checkParents(dir);
|
||||||
Entry e = new Entry(dir, Entry.NEW);
|
Entry e = new Entry(dir, Entry.NEW);
|
||||||
e.method = METHOD_STORED; // STORED for dir
|
e.method = METHOD_STORED; // STORED for dir
|
||||||
@ -476,7 +435,7 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
checkParents(dst);
|
checkParents(dst);
|
||||||
}
|
}
|
||||||
Entry u = new Entry(eSrc, Entry.COPY); // copy eSrc entry
|
Entry u = new Entry(eSrc, Entry.COPY); // copy eSrc entry
|
||||||
u.name = dst; // change name
|
u.name(dst); // change name
|
||||||
if (eSrc.type == Entry.NEW || eSrc.type == Entry.FILECH)
|
if (eSrc.type == Entry.NEW || eSrc.type == Entry.FILECH)
|
||||||
{
|
{
|
||||||
u.type = eSrc.type; // make it the same type
|
u.type = eSrc.type; // make it the same type
|
||||||
@ -869,43 +828,27 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
private void checkParents(byte[] path) throws IOException {
|
private void checkParents(byte[] path) throws IOException {
|
||||||
beginRead();
|
beginRead();
|
||||||
try {
|
try {
|
||||||
while ((path = getParent(path)) != null) {
|
while ((path = getParent(path)) != null && path.length != 0) {
|
||||||
if (!inodes.containsKey(IndexNode.keyOf(path)))
|
if (!inodes.containsKey(IndexNode.keyOf(path))) {
|
||||||
throw new NoSuchFileException(getString(path));
|
throw new NoSuchFileException(getString(path));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
endRead();
|
endRead();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static byte[] ROOTPATH = new byte[0];
|
||||||
private static byte[] getParent(byte[] path) {
|
private static byte[] getParent(byte[] path) {
|
||||||
int off = path.length - 1;
|
int off = path.length - 1;
|
||||||
if (off > 0 && path[off] == '/') // isDirectory
|
if (off > 0 && path[off] == '/') // isDirectory
|
||||||
off--;
|
off--;
|
||||||
while (off > 0 && path[off] != '/') { off--; }
|
while (off > 0 && path[off] != '/') { off--; }
|
||||||
if (off == 0)
|
if (off <= 0)
|
||||||
return null; // top entry
|
return ROOTPATH;
|
||||||
return Arrays.copyOf(path, off + 1);
|
return Arrays.copyOf(path, off + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If "starter" is the parent directory of "path"
|
|
||||||
private static boolean isParentOf(byte[] p, byte[] c) {
|
|
||||||
final int plen = p.length;
|
|
||||||
if (plen == 0) // root dir
|
|
||||||
return true;
|
|
||||||
if (plen >= c.length)
|
|
||||||
return false;
|
|
||||||
int n = 0;
|
|
||||||
while (n < plen) {
|
|
||||||
if (p[n] != c[n])
|
|
||||||
return false;
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
if (p[n - 1] != '/' && (c[n] != '/' || n == c.length - 1))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final void beginWrite() {
|
private final void beginWrite() {
|
||||||
rwlock.writeLock().lock();
|
rwlock.writeLock().lock();
|
||||||
}
|
}
|
||||||
@ -1058,6 +1001,7 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
if (end.endpos == 0) {
|
if (end.endpos == 0) {
|
||||||
inodes = new LinkedHashMap<>(10);
|
inodes = new LinkedHashMap<>(10);
|
||||||
locpos = 0;
|
locpos = 0;
|
||||||
|
buildNodeTree();
|
||||||
return null; // only END header present
|
return null; // only END header present
|
||||||
}
|
}
|
||||||
if (end.cenlen > end.endpos)
|
if (end.cenlen > end.endpos)
|
||||||
@ -1101,6 +1045,7 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
if (pos + ENDHDR != cen.length) {
|
if (pos + ENDHDR != cen.length) {
|
||||||
zerror("invalid CEN header (bad header size)");
|
zerror("invalid CEN header (bad header size)");
|
||||||
}
|
}
|
||||||
|
buildNodeTree();
|
||||||
return cen;
|
return cen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1125,12 +1070,15 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
|
|
||||||
private boolean hasUpdate = false;
|
private boolean hasUpdate = false;
|
||||||
|
|
||||||
|
// shared key. consumer guarantees the "writeLock" before use it.
|
||||||
|
private final IndexNode LOOKUPKEY = IndexNode.keyOf(null);
|
||||||
|
|
||||||
private void updateDelete(Entry e) {
|
private void updateDelete(Entry e) {
|
||||||
beginWrite();
|
beginWrite();
|
||||||
try {
|
try {
|
||||||
inodes.remove(IndexNode.keyOf(e.name)); //inodes.remove(e.name);
|
removeFromTree(e);
|
||||||
|
inodes.remove(e);
|
||||||
hasUpdate = true;
|
hasUpdate = true;
|
||||||
dirs = null;
|
|
||||||
} finally {
|
} finally {
|
||||||
endWrite();
|
endWrite();
|
||||||
}
|
}
|
||||||
@ -1139,9 +1087,16 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
private void update(Entry e) {
|
private void update(Entry e) {
|
||||||
beginWrite();
|
beginWrite();
|
||||||
try {
|
try {
|
||||||
inodes.put(IndexNode.keyOf(e.name), e); //inodes.put(e, e);
|
IndexNode old = inodes.put(e, e);
|
||||||
|
if (old != null) {
|
||||||
|
removeFromTree(old);
|
||||||
|
}
|
||||||
|
if (e.type == Entry.NEW || e.type == Entry.FILECH) {
|
||||||
|
IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(e.name)));
|
||||||
|
e.sibling = parent.child;
|
||||||
|
parent.child = e;
|
||||||
|
}
|
||||||
hasUpdate = true;
|
hasUpdate = true;
|
||||||
dirs = null;
|
|
||||||
} finally {
|
} finally {
|
||||||
endWrite();
|
endWrite();
|
||||||
}
|
}
|
||||||
@ -1229,7 +1184,7 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
// ext) without enflating/deflating from the old zip
|
// ext) without enflating/deflating from the old zip
|
||||||
// file LOC entry.
|
// file LOC entry.
|
||||||
written += copyLOCEntry(e, true, os, written, buf);
|
written += copyLOCEntry(e, true, os, written, buf);
|
||||||
} else { // NEW or FILECH
|
} else { // NEW, FILECH or CEN
|
||||||
e.locoff = written;
|
e.locoff = written;
|
||||||
written += e.writeLOC(os); // write loc header
|
written += e.writeLOC(os); // write loc header
|
||||||
if (e.bytes != null) { // in-memory, deflated
|
if (e.bytes != null) { // in-memory, deflated
|
||||||
@ -1266,6 +1221,9 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
x.printStackTrace(); // skip any in-accurate entry
|
x.printStackTrace(); // skip any in-accurate entry
|
||||||
}
|
}
|
||||||
} else { // unchanged inode
|
} else { // unchanged inode
|
||||||
|
if (inode.pos == -1) {
|
||||||
|
continue; // pseudo directory node
|
||||||
|
}
|
||||||
e = Entry.readCEN(this, inode.pos);
|
e = Entry.readCEN(this, inode.pos);
|
||||||
try {
|
try {
|
||||||
written += copyLOCEntry(e, false, os, written, buf);
|
written += copyLOCEntry(e, false, os, written, buf);
|
||||||
@ -1318,34 +1276,28 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
//System.out.printf("->sync(%s) done!%n", toString());
|
//System.out.printf("->sync(%s) done!%n", toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Entry getEntry0(byte[] path) throws IOException {
|
private IndexNode getInode(byte[] path) {
|
||||||
if (path == null)
|
if (path == null)
|
||||||
throw new NullPointerException("path");
|
throw new NullPointerException("path");
|
||||||
if (path.length == 0)
|
|
||||||
return null;
|
|
||||||
IndexNode inode = null;
|
|
||||||
IndexNode key = IndexNode.keyOf(path);
|
IndexNode key = IndexNode.keyOf(path);
|
||||||
if ((inode = inodes.get(key)) == null) {
|
IndexNode inode = inodes.get(key);
|
||||||
if (path[path.length -1] == '/') // already has a slash
|
if (inode == null &&
|
||||||
return null;
|
(path.length == 0 || path[path.length -1] != '/')) {
|
||||||
|
// if does not ends with a slash
|
||||||
path = Arrays.copyOf(path, path.length + 1);
|
path = Arrays.copyOf(path, path.length + 1);
|
||||||
path[path.length - 1] = '/';
|
path[path.length - 1] = '/';
|
||||||
if ((inode = inodes.get(key.as(path))) == null)
|
inode = inodes.get(key.as(path));
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
if (inode instanceof Entry)
|
return inode;
|
||||||
return (Entry)inode;
|
|
||||||
return Entry.readCEN(this, inode.pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if the "name" a parent directory of any entry (dir empty)
|
private Entry getEntry0(byte[] path) throws IOException {
|
||||||
boolean isAncestor(byte[] name) {
|
IndexNode inode = getInode(path);
|
||||||
for (Map.Entry<IndexNode, IndexNode> entry : inodes.entrySet()) {
|
if (inode instanceof Entry)
|
||||||
byte[] ename = entry.getKey().name;
|
return (Entry)inode;
|
||||||
if (isParentOf(name, ename))
|
if (inode == null || inode.pos == -1)
|
||||||
return true;
|
return null;
|
||||||
}
|
return Entry.readCEN(this, inode.pos);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteFile(byte[] path, boolean failIfNotExists)
|
public void deleteFile(byte[] path, boolean failIfNotExists)
|
||||||
@ -1359,7 +1311,7 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
if (failIfNotExists)
|
if (failIfNotExists)
|
||||||
throw new NoSuchFileException(getString(path));
|
throw new NoSuchFileException(getString(path));
|
||||||
} else {
|
} else {
|
||||||
if (e.isDir() && isAncestor(path))
|
if (e.isDir() && e.child != null)
|
||||||
throw new DirectoryNotEmptyException(getString(path));
|
throw new DirectoryNotEmptyException(getString(path));
|
||||||
updateDelete(e);
|
updateDelete(e);
|
||||||
}
|
}
|
||||||
@ -1539,7 +1491,6 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
public int available() {
|
public int available() {
|
||||||
return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem;
|
return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long size() {
|
public long size() {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
@ -1762,7 +1713,7 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
int pos = -1; // postion in cen table, -1 menas the
|
int pos = -1; // postion in cen table, -1 menas the
|
||||||
// entry does not exists in zip file
|
// entry does not exists in zip file
|
||||||
IndexNode(byte[] name, int pos) {
|
IndexNode(byte[] name, int pos) {
|
||||||
as(name);
|
name(name);
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1770,15 +1721,25 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
return new IndexNode(name, -1);
|
return new IndexNode(name, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
final IndexNode as(byte[] name) { // reuse the node, mostly
|
final void name(byte[] name) {
|
||||||
this.name = name; // as a lookup "key"
|
this.name = name;
|
||||||
this.hashcode = Arrays.hashCode(name);
|
this.hashcode = Arrays.hashCode(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
final IndexNode as(byte[] name) { // reuse the node, mostly
|
||||||
|
name(name); // as a lookup "key"
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isDir() {
|
||||||
|
return name != null &&
|
||||||
|
(name.length == 0 || name[name.length - 1] == '/');
|
||||||
|
}
|
||||||
|
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (!(other instanceof IndexNode))
|
if (!(other instanceof IndexNode)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return Arrays.equals(name, ((IndexNode)other).name);
|
return Arrays.equals(name, ((IndexNode)other).name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1798,6 +1759,7 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
static final int FILECH = 3; // fch update in "file"
|
static final int FILECH = 3; // fch update in "file"
|
||||||
static final int COPY = 4; // copy of a CEN entry
|
static final int COPY = 4; // copy of a CEN entry
|
||||||
|
|
||||||
|
|
||||||
byte[] bytes; // updated content bytes
|
byte[] bytes; // updated content bytes
|
||||||
Path file; // use tmp file to store bytes;
|
Path file; // use tmp file to store bytes;
|
||||||
int type = CEN; // default is the entry read from cen
|
int type = CEN; // default is the entry read from cen
|
||||||
@ -1825,7 +1787,7 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
Entry() {}
|
Entry() {}
|
||||||
|
|
||||||
Entry(byte[] name) {
|
Entry(byte[] name) {
|
||||||
this.name = name;
|
name(name);
|
||||||
this.mtime = System.currentTimeMillis();
|
this.mtime = System.currentTimeMillis();
|
||||||
this.crc = 0;
|
this.crc = 0;
|
||||||
this.size = 0;
|
this.size = 0;
|
||||||
@ -1839,8 +1801,8 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Entry (Entry e, int type) {
|
Entry (Entry e, int type) {
|
||||||
|
name(e.name);
|
||||||
this.version = e.version;
|
this.version = e.version;
|
||||||
this.name = e.name;
|
|
||||||
this.ctime = e.ctime;
|
this.ctime = e.ctime;
|
||||||
this.atime = e.atime;
|
this.atime = e.atime;
|
||||||
this.mtime = e.mtime;
|
this.mtime = e.mtime;
|
||||||
@ -1855,7 +1817,6 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
this.attrsEx = e.attrsEx;
|
this.attrsEx = e.attrsEx;
|
||||||
this.locoff = e.locoff;
|
this.locoff = e.locoff;
|
||||||
this.comment = e.comment;
|
this.comment = e.comment;
|
||||||
|
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1865,12 +1826,6 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
this.method = METHOD_STORED;
|
this.method = METHOD_STORED;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isDir() {
|
|
||||||
return name != null &&
|
|
||||||
(name.length == 0 ||
|
|
||||||
name[name.length - 1] == '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
int version() throws ZipException {
|
int version() throws ZipException {
|
||||||
if (method == METHOD_DEFLATED)
|
if (method == METHOD_DEFLATED)
|
||||||
return 20;
|
return 20;
|
||||||
@ -1909,7 +1864,7 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
locoff = CENOFF(cen, pos);
|
locoff = CENOFF(cen, pos);
|
||||||
|
|
||||||
pos += CENHDR;
|
pos += CENHDR;
|
||||||
name = Arrays.copyOfRange(cen, pos, pos + nlen);
|
name(Arrays.copyOfRange(cen, pos, pos + nlen));
|
||||||
|
|
||||||
pos += nlen;
|
pos += nlen;
|
||||||
if (elen > 0) {
|
if (elen > 0) {
|
||||||
@ -2132,7 +2087,8 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
}
|
}
|
||||||
writeShort(os, flag); // general purpose bit flag
|
writeShort(os, flag); // general purpose bit flag
|
||||||
writeShort(os, method); // compression method
|
writeShort(os, method); // compression method
|
||||||
writeInt(os, mtime); // last modification time
|
// last modification time
|
||||||
|
writeInt(os, (int)javaToDosTime(mtime));
|
||||||
writeInt(os, crc); // crc-32
|
writeInt(os, crc); // crc-32
|
||||||
if (elen64 != 0) {
|
if (elen64 != 0) {
|
||||||
writeInt(os, ZIP64_MINVAL);
|
writeInt(os, ZIP64_MINVAL);
|
||||||
@ -2318,50 +2274,56 @@ public class ZipFileSystem extends FileSystem {
|
|||||||
// structure.
|
// structure.
|
||||||
// A possible solution is to build the node tree ourself as
|
// A possible solution is to build the node tree ourself as
|
||||||
// implemented below.
|
// implemented below.
|
||||||
private HashMap<IndexNode, IndexNode> dirs;
|
|
||||||
private IndexNode root;
|
private IndexNode root;
|
||||||
private IndexNode addToDir(IndexNode child) {
|
|
||||||
IndexNode cinode = dirs.get(child);
|
|
||||||
if (cinode != null)
|
|
||||||
return cinode;
|
|
||||||
|
|
||||||
byte[] cname = child.name;
|
private void addToTree(IndexNode inode, HashSet<IndexNode> dirs) {
|
||||||
byte[] pname = getParent(cname);
|
if (dirs.contains(inode)) {
|
||||||
IndexNode pinode;
|
return;
|
||||||
|
|
||||||
if (pname != null)
|
|
||||||
pinode = addToDir(IndexNode.keyOf(pname));
|
|
||||||
else
|
|
||||||
pinode = root;
|
|
||||||
cinode = inodes.get(child);
|
|
||||||
if (cname[cname.length -1] != '/') { // not a dir
|
|
||||||
cinode.sibling = pinode.child;
|
|
||||||
pinode.child = cinode;
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
//cinode = dirs.get(child);
|
IndexNode parent;
|
||||||
if (cinode == null) // pseudo directry entry
|
byte[] name = inode.name;
|
||||||
cinode = new IndexNode(cname, -1);
|
byte[] pname = getParent(name);
|
||||||
cinode.sibling = pinode.child;
|
if (inodes.containsKey(LOOKUPKEY.as(pname))) {
|
||||||
pinode.child = cinode;
|
parent = inodes.get(LOOKUPKEY);
|
||||||
|
} else { // pseudo directory entry
|
||||||
dirs.put(child, cinode);
|
parent = new IndexNode(pname, -1);
|
||||||
return cinode;
|
inodes.put(parent, parent);
|
||||||
|
}
|
||||||
|
addToTree(parent, dirs);
|
||||||
|
inode.sibling = parent.child;
|
||||||
|
parent.child = inode;
|
||||||
|
if (name[name.length -1] == '/')
|
||||||
|
dirs.add(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMap<IndexNode, IndexNode> getDirs()
|
private void removeFromTree(IndexNode inode) {
|
||||||
throws IOException
|
IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(inode.name)));
|
||||||
{
|
IndexNode child = parent.child;
|
||||||
|
if (child == inode) {
|
||||||
|
parent.child = child.sibling;
|
||||||
|
} else {
|
||||||
|
IndexNode last = child;
|
||||||
|
while ((child = child.sibling) != null) {
|
||||||
|
if (child == inode) {
|
||||||
|
last.sibling = child.sibling;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
last = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildNodeTree() throws IOException {
|
||||||
beginWrite();
|
beginWrite();
|
||||||
try {
|
try {
|
||||||
if (dirs != null)
|
HashSet<IndexNode> dirs = new HashSet<>();
|
||||||
return dirs;
|
IndexNode root = new IndexNode(ROOTPATH, -1);
|
||||||
dirs = new HashMap<>();
|
inodes.put(root, root);
|
||||||
root = new IndexNode(new byte[0], -1);
|
dirs.add(root);
|
||||||
dirs.put(root, root);
|
for (IndexNode node : inodes.keySet().toArray(new IndexNode[0])) {
|
||||||
for (IndexNode node : inodes.keySet())
|
addToTree(node, dirs);
|
||||||
addToDir(node);
|
}
|
||||||
return dirs;
|
|
||||||
} finally {
|
} finally {
|
||||||
endWrite();
|
endWrite();
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ public class ZipPath extends Path {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ZipPath toRealPath(boolean resolveLinks) throws IOException {
|
public ZipPath toRealPath(boolean resolveLinks) throws IOException {
|
||||||
ZipPath realPath = new ZipPath(zfs, getResolvedPath());
|
ZipPath realPath = new ZipPath(zfs, getResolvedPath()).toAbsolutePath();
|
||||||
realPath.checkAccess();
|
realPath.checkAccess();
|
||||||
return realPath;
|
return realPath;
|
||||||
}
|
}
|
||||||
@ -472,8 +472,11 @@ public class ZipPath extends Path {
|
|||||||
int n = offsets[i];
|
int n = offsets[i];
|
||||||
int len = (i == offsets.length - 1)?
|
int len = (i == offsets.length - 1)?
|
||||||
(path.length - n):(offsets[i + 1] - n - 1);
|
(path.length - n):(offsets[i + 1] - n - 1);
|
||||||
if (len == 1 && path[n] == (byte)'.')
|
if (len == 1 && path[n] == (byte)'.') {
|
||||||
|
if (m == 0 && path[0] == '/') // absolute path
|
||||||
|
to[m++] = '/';
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (len == 2 && path[n] == '.' && path[n + 1] == '.') {
|
if (len == 2 && path[n] == '.' && path[n + 1] == '.') {
|
||||||
if (lastMOff >= 0) {
|
if (lastMOff >= 0) {
|
||||||
m = lastM[lastMOff--]; // retreat
|
m = lastM[lastMOff--]; // retreat
|
||||||
@ -726,6 +729,8 @@ public class ZipPath extends Path {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSameFile(Path other) throws IOException {
|
public boolean isSameFile(Path other) throws IOException {
|
||||||
|
if (this.equals(other))
|
||||||
|
return true;
|
||||||
if (other == null ||
|
if (other == null ||
|
||||||
this.getFileSystem() != other.getFileSystem())
|
this.getFileSystem() != other.getFileSystem())
|
||||||
return false;
|
return false;
|
||||||
|
@ -193,6 +193,17 @@ public class PathOps {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PathOps isSameFile(String target) {
|
||||||
|
try {
|
||||||
|
out.println("check two paths are same");
|
||||||
|
checkPath();
|
||||||
|
check(path.isSameFile(test(target).path()), true);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
PathOps invalid() {
|
PathOps invalid() {
|
||||||
if (!(exc instanceof InvalidPathException)) {
|
if (!(exc instanceof InvalidPathException)) {
|
||||||
out.println("InvalidPathException not thrown as expected");
|
out.println("InvalidPathException not thrown as expected");
|
||||||
@ -344,7 +355,12 @@ public class PathOps {
|
|||||||
.normalize("foo");
|
.normalize("foo");
|
||||||
test("/foo/bar/gus/../..")
|
test("/foo/bar/gus/../..")
|
||||||
.normalize("/foo");
|
.normalize("/foo");
|
||||||
|
test("/./.")
|
||||||
|
.normalize("/");
|
||||||
|
test("/.")
|
||||||
|
.normalize("/");
|
||||||
|
test("/./abc")
|
||||||
|
.normalize("/abc");
|
||||||
// invalid
|
// invalid
|
||||||
test("foo\u0000bar")
|
test("foo\u0000bar")
|
||||||
.invalid();
|
.invalid();
|
||||||
@ -365,6 +381,10 @@ public class PathOps {
|
|||||||
.root("/")
|
.root("/")
|
||||||
.parent("/foo")
|
.parent("/foo")
|
||||||
.name("bar");
|
.name("bar");
|
||||||
|
|
||||||
|
// isSameFile
|
||||||
|
test("/fileDoesNotExist")
|
||||||
|
.isSameFile("/fileDoesNotExist");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void npes() {
|
static void npes() {
|
||||||
|
@ -28,6 +28,7 @@ import java.nio.file.*;
|
|||||||
import java.nio.file.attribute.*;
|
import java.nio.file.attribute.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.zip.*;
|
||||||
|
|
||||||
import static java.nio.file.StandardOpenOption.*;
|
import static java.nio.file.StandardOpenOption.*;
|
||||||
import static java.nio.file.StandardCopyOption.*;
|
import static java.nio.file.StandardCopyOption.*;
|
||||||
@ -42,7 +43,8 @@ public class ZipFSTester {
|
|||||||
FileSystem fs = null;
|
FileSystem fs = null;
|
||||||
try {
|
try {
|
||||||
fs = newZipFileSystem(Paths.get(args[0]), new HashMap<String, Object>());
|
fs = newZipFileSystem(Paths.get(args[0]), new HashMap<String, Object>());
|
||||||
test(fs);
|
test0(fs);
|
||||||
|
test1(fs);
|
||||||
test2(fs); // more tests
|
test2(fs); // more tests
|
||||||
} finally {
|
} finally {
|
||||||
if (fs != null)
|
if (fs != null)
|
||||||
@ -50,11 +52,31 @@ public class ZipFSTester {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test(FileSystem fs)
|
static void test0(FileSystem fs)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
List<String> list = new LinkedList<>();
|
||||||
|
try (ZipFile zf = new ZipFile(fs.toString())) {
|
||||||
|
Enumeration<? extends ZipEntry> zes = zf.entries();
|
||||||
|
while (zes.hasMoreElements()) {
|
||||||
|
list.add(zes.nextElement().getName());
|
||||||
|
}
|
||||||
|
for (String pname : list) {
|
||||||
|
Path path = fs.getPath(pname);
|
||||||
|
if (!path.exists())
|
||||||
|
throw new RuntimeException("path existence check failed!");
|
||||||
|
while ((path = path.getParent()) != null) {
|
||||||
|
if (!path.exists())
|
||||||
|
throw new RuntimeException("parent existence check failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test1(FileSystem fs)
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
Random rdm = new Random();
|
Random rdm = new Random();
|
||||||
|
|
||||||
// clone a fs and test on it
|
// clone a fs and test on it
|
||||||
Path tmpfsPath = getTempPath();
|
Path tmpfsPath = getTempPath();
|
||||||
Map<String, Object> env = new HashMap<String, Object>();
|
Map<String, Object> env = new HashMap<String, Object>();
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
# questions.
|
# questions.
|
||||||
#
|
#
|
||||||
# @test
|
# @test
|
||||||
# @bug 6990846
|
# @bug 6990846 7009092 7009085
|
||||||
# @summary Test ZipFileSystem demo
|
# @summary Test ZipFileSystem demo
|
||||||
# @build Basic PathOps ZipFSTester
|
# @build Basic PathOps ZipFSTester
|
||||||
# @run shell basic.sh
|
# @run shell basic.sh
|
||||||
|
Loading…
x
Reference in New Issue
Block a user