6990846: Demo: NIO.2 filesystem provider for zip/jar archives

The first drop of the zip filesystem provider, as a separate demo

Reviewed-by: alanb
This commit is contained in:
Xueming Shen 2010-10-08 21:33:28 -07:00
parent 98a4c7fec4
commit 2d526410d4
22 changed files with 6954 additions and 1 deletions

View File

@ -31,7 +31,7 @@ BUILDDIR = ..
PRODUCT = demos
include $(BUILDDIR)/common/Defs.gmk
SUBDIRS = jni
SUBDIRS = jni nio
SUBDIRS_desktop = applets jfc
SUBDIRS_management = management
SUBDIRS_misc = scripting

View File

@ -0,0 +1,39 @@
#
# Copyright (c) 1997, 2007, 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
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
#
# Makefile for building the jfc demos
#
BUILDDIR = ../..
PRODUCT = demos
include $(BUILDDIR)/common/Defs.gmk
SUBDIRS = zipfs
include $(BUILDDIR)/common/Subdirs.gmk
all build clean clobber::
$(SUBDIRS-loop)

View File

@ -0,0 +1,44 @@
#
# Copyright (c) 1997, 2002, 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
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
#
# Makefile to build the ZipFileSystem demo.
#
BUILDDIR = ../../..
PRODUCT = demo/zipfs
DEMONAME = zipfs
include $(BUILDDIR)/common/Defs.gmk
DEMO_ROOT = $(SHARE_SRC)/demo/nio/$(DEMONAME)
DEMO_TOPFILES = ./README.txt
DEMO_SRCDIR = $(DEMO_ROOT)
DEMO_DESTDIR = $(DEMODIR)/nio/$(DEMONAME)
#
# Demo jar building rules.
#
include $(BUILDDIR)/common/Demo.gmk

View File

@ -0,0 +1,664 @@
/*
* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.net.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import static java.nio.file.StandardOpenOption.*;
import static java.nio.file.StandardCopyOption.*;
/*
* ZipFileSystem usage demo
*
* java [-cp .../zipfs.jar:./] Demo action ZipfileName [...]
*
* To deploy the provider, either copy the zipfs.jar into JDK/JRE
* extensions directory or add
* <JDK_HOME>/demo/nio/ZipFileSystem/zipfs.jar
* into your class path as showed above.
*
* @author Xueming Shen
*/
public class Demo {
static enum Action {
rename, // <java Demo rename zipfile src dst>
// rename entry src to dst inside zipfile
movein, // <java Demo movein zipfile src dst>
// move an external src file into zipfile
// as entry dst
moveout, // <java Demo moveout zipfile src dst>
// move a zipfile entry src out to dst
copy, // <java Demo copy zipfile src dst>
// copy entry src to dst inside zipfile
copyin, // <java Demo copyin zipfile src dst>
// copy an external src file into zipfile
// as entry dst
copyout, // <java Demo copyout zipfile src dst>
// copy zipfile entry src" out to file dst
zzmove, // <java Demo zzmove zfsrc zfdst path>
// move entry path/dir from zfsrc to zfdst
zzcopy, // <java Demo zzcopy zfsrc zfdst path>
// copy path from zipfile zfsrc to zipfile
// zfdst
attrs, // <java Demo attrs zipfile path>
// printout the attributes of entry path
attrsspace, // <java Demo attrsspace zipfile path>
// printout the storespace attrs of entry path
setmtime, // <java Demo setmtime zipfile "MM/dd/yy-HH:mm:ss" path...>
// set the lastModifiedTime of entry path
lsdir, // <java Demo lsdir zipfile dir>
// list dir's direct child files/dirs
mkdir, // <java Demo mkdir zipfile dir>
mkdirs, // <java Demo mkdirs zipfile dir>
rmdirs, // <java Demo rmdirs zipfile dir>
list, // <java Demo list zipfile [dir]>
// recursively list all entries of dir
// via DirectoryStream
tlist, // <java Demo tlist zipfile [dir]>
// list with buildDirTree=true
vlist, // <java Demo vlist zipfile [dir]>
// recursively verbose list all entries of
// dir via DirectoryStream
walk, // <java Demo walk zipfile [dir]>
// recursively walk all entries of dir
// via Files.walkFileTree
twalk, // <java Demo twalk zipfile [dir]>
// walk with buildDirTree=true
extract, // <java Demo extract zipfile file [...]>
update, // <java Demo extract zipfile file [...]>
delete, // <java Demo delete zipfile file [...]>
add, // <java Demo add zipfile file [...]>
create, // <java Demo create zipfile file [...]>
// create a new zipfile if it doesn't exit
// and then add the file(s) into it.
attrs2, // <java Demo attrs2 zipfile file [...]>
// test different ways to print attrs
}
public static void main(String[] args) throws Throwable {
Action action = Action.valueOf(args[0]);;
Map<String, Object> env = env = new HashMap<String, Object>();
if (action == Action.create)
env.put("createNew", true);
if (action == Action.tlist || action == Action.twalk)
env.put("buildDirTree", true);
FileSystem fs = FileSystems.newFileSystem(
URI.create("zip" + Paths.get(args[1]).toUri().toString().substring(4)),
env,
null);
try {
FileSystem fs2;
Path path, src, dst;
boolean isRename = false;
switch (action) {
case rename:
src = fs.getPath(args[2]);
dst = fs.getPath(args[3]);
src.moveTo(dst);
break;
case moveout:
src = fs.getPath(args[2]);
dst = Paths.get(args[3]);
src.moveTo(dst);
break;
case movein:
src = Paths.get(args[2]);
dst = fs.getPath(args[3]);
src.moveTo(dst);
break;
case copy:
src = fs.getPath(args[2]);
dst = fs.getPath(args[3]);
src.copyTo(dst);
break;
case copyout:
src = fs.getPath(args[2]);
dst = Paths.get(args[3]);
src.copyTo(dst);
break;
case copyin:
src = Paths.get(args[2]);
dst = fs.getPath(args[3]);
src.copyTo(dst);
break;
case zzmove:
fs2 = FileSystems.newFileSystem(
URI.create("zip" + Paths.get(args[2]).toUri().toString().substring(4)),
env,
null);
//sf1.getPath(args[3]).moveTo(fs2.getPath(args[3]));
z2zmove(fs, fs2, args[3]);
fs2.close();
break;
case zzcopy:
fs2 = FileSystems.newFileSystem(
URI.create("zip" + Paths.get(args[2]).toUri().toString().substring(4)),
env,
null);
//sf1.getPath(args[3]).copyTo(fs2.getPath(args[3]));
z2zcopy(fs, fs2, args[3]);
fs2.close();
break;
case attrs:
for (int i = 2; i < args.length; i++) {
path = fs.getPath(args[i]);
System.out.println(
Attributes.readBasicFileAttributes(path).toString());
}
break;
case setmtime:
DateFormat df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss");
Date newDatetime = df.parse(args[2]);
for (int i = 3; i < args.length; i++) {
path = fs.getPath(args[i]);
path.setAttribute("lastModifiedTime",
FileTime.fromMillis(newDatetime.getTime()));
System.out.println(
Attributes.readBasicFileAttributes(path).toString());
}
break;
case attrsspace:
path = fs.getPath("/");
FileStore fstore = path.getFileStore();
//System.out.println(fstore.getFileStoreAttributeView(FileStoreSpaceAttributeView.class)
// .readAttributes());
// or
System.out.printf("filestore[%s]%n", fstore.name());
System.out.printf(" totalSpace: %d%n",
(Long)fstore.getAttribute("space:totalSpace"));
System.out.printf(" usableSpace: %d%n",
(Long)fstore.getAttribute("space:usableSpace"));
System.out.printf(" unallocSpace: %d%n",
(Long)fstore.getAttribute("space:unallocatedSpace"));
break;
case list:
case tlist:
if (args.length < 3)
list(fs.getPath("/"), false);
else
list(fs.getPath(args[2]), false);
break;
case vlist:
if (args.length < 3)
list(fs.getPath("/"), true);
else
list(fs.getPath(args[2]), true);
break;
case twalk:
case walk:
walk(fs.getPath((args.length > 2)? args[2] : "/"));
break;
case extract:
if (args.length == 2) {
extract(fs, "/");
} else {
for (int i = 2; i < args.length; i++) {
extract(fs, args[i]);
}
}
break;
case delete:
for (int i = 2; i < args.length; i++)
fs.getPath(args[i]).delete();
break;
case create:
case add:
case update:
for (int i = 2; i < args.length; i++) {
update(fs, args[i]);
}
break;
case lsdir:
path = fs.getPath(args[2]);
final String fStr = (args.length > 3)?args[3]:"";
DirectoryStream<Path> ds = path.newDirectoryStream(
new DirectoryStream.Filter<Path>() {
public boolean accept(Path path) {
return path.toString().contains(fStr);
}
});
for (Path p : ds)
System.out.println(p);
break;
case mkdir:
fs.getPath(args[2]).createDirectory();
break;
case mkdirs:
mkdirs(fs.getPath(args[2]));
break;
case attrs2:
for (int i = 2; i < args.length; i++) {
path = fs.getPath(args[i]);
System.out.println("-------(1)---------");
System.out.println(
Attributes.readBasicFileAttributes(path).toString());
System.out.println("-------(2)---------");
Map<String, ?> map = path.readAttributes("zip:*");
for (Map.Entry<String, ?> e : map.entrySet()) {
System.out.printf(" %s : %s%n", e.getKey(), e.getValue());
}
System.out.println("-------(3)---------");
map = path.readAttributes("size,lastModifiedTime,isDirectory");
for (Map.Entry<String, ?> e : map.entrySet()) {
System.out.printf(" %s : %s%n", e.getKey(), e.getValue());
}
}
break;
}
} catch (Exception x) {
x.printStackTrace();
} finally {
if (fs != null)
fs.close();
}
}
private static byte[] getBytes(String name) {
return name.getBytes();
}
private static String getString(byte[] name) {
return new String(name);
}
private static void walk(Path path) throws IOException
{
Files.walkFileTree(
path,
new SimpleFileVisitor<Path>() {
private int indent = 0;
private void indent() {
int n = 0;
while (n++ < indent)
System.out.printf(" ");
}
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs)
{
indent();
System.out.printf("%s%n", file.getName().toString());
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs)
{
indent();
System.out.printf("[%s]%n", dir.toString());
indent += 2;
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir,
IOException ioe)
{
indent -= 2;
return FileVisitResult.CONTINUE;
}
});
}
private static void update(FileSystem fs, String path) throws Throwable{
Path src = FileSystems.getDefault().getPath(path);
if (Boolean.TRUE.equals(src.getAttribute("isDirectory"))) {
DirectoryStream<Path> ds = src.newDirectoryStream();
for (Path child : ds)
update(fs, child.toString());
ds.close();
} else {
Path dst = fs.getPath(path);
Path parent = dst.getParent();
if (parent != null && parent.notExists())
mkdirs(parent);
src.copyTo(dst, REPLACE_EXISTING);
}
}
private static void extract(FileSystem fs, String path) throws Throwable{
Path src = fs.getPath(path);
if (Boolean.TRUE.equals(src.getAttribute("isDirectory"))) {
DirectoryStream<Path> ds = src.newDirectoryStream();
for (Path child : ds)
extract(fs, child.toString());
ds.close();
} else {
if (path.startsWith("/"))
path = path.substring(1);
Path dst = FileSystems.getDefault().getPath(path);
Path parent = dst.getParent();
if (parent.notExists())
mkdirs(parent);
src.copyTo(dst, REPLACE_EXISTING);
}
}
// use DirectoryStream
private static void z2zcopy(FileSystem src, FileSystem dst, String path)
throws IOException
{
Path srcPath = src.getPath(path);
Path dstPath = dst.getPath(path);
if (Boolean.TRUE.equals(srcPath.getAttribute("isDirectory"))) {
if (!dstPath.exists()) {
try {
mkdirs(dstPath);
} catch (FileAlreadyExistsException x) {}
}
DirectoryStream<Path> ds = srcPath.newDirectoryStream();
for (Path child : ds) {
z2zcopy(src, dst,
path + (path.endsWith("/")?"":"/") + child.getName());
}
ds.close();
} else {
//System.out.println("copying..." + path);
srcPath.copyTo(dstPath);
}
}
// use TreeWalk to move
private static void z2zmove(FileSystem src, FileSystem dst, String path)
throws IOException
{
final Path srcPath = src.getPath(path).toAbsolutePath();
final Path dstPath = dst.getPath(path).toAbsolutePath();
Files.walkFileTree(srcPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs)
{
Path dst = srcPath.relativize(file);
dst = dstPath.resolve(dst);
try {
Path parent = dstPath.getParent();
if (parent != null && parent.notExists())
mkdirs(parent);
file.moveTo(dst);
} catch (IOException x) {
x.printStackTrace();
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs)
{
Path dst = srcPath.relativize(dir);
dst = dstPath.resolve(dst);
try {
if (dst.notExists())
mkdirs(dst);
} catch (IOException x) {
x.printStackTrace();
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir,
IOException ioe)
throws IOException
{
try {
dir.delete();
} catch (IOException x) {
//x.printStackTrace();
}
return FileVisitResult.CONTINUE;
}
});
}
private static void mkdirs(Path path) throws IOException {
path = path.toAbsolutePath();
Path parent = path.getParent();
if (parent != null) {
if (parent.notExists())
mkdirs(parent);
}
path.createDirectory();
}
private static void rmdirs(Path path) throws IOException {
while (path != null && path.getNameCount() != 0) {
path.delete();
path = path.getParent();
}
}
private static void list(Path path, boolean verbose ) throws IOException {
if (verbose)
System.out.println(Attributes.readBasicFileAttributes(path).toString());
else
System.out.printf(" %s%n", path.toString());
if (path.notExists())
return;
if (Attributes.readBasicFileAttributes(path).isDirectory()) {
DirectoryStream<Path> ds = path.newDirectoryStream();
for (Path child : ds)
list(child, verbose);
ds.close();
}
}
// check the content of two paths are equal
private static void checkEqual(Path src, Path dst) throws IOException
{
//System.out.printf("checking <%s> vs <%s>...%n",
// src.toString(), dst.toString());
//streams
InputStream isSrc = src.newInputStream();
InputStream isDst = dst.newInputStream();
byte[] bufSrc = new byte[8192];
byte[] bufDst = new byte[8192];
try {
int nSrc = 0;
while ((nSrc = isSrc.read(bufSrc)) != -1) {
int nDst = 0;
while (nDst < nSrc) {
int n = isDst.read(bufDst, nDst, nSrc - nDst);
if (n == -1) {
System.out.printf("checking <%s> vs <%s>...%n",
src.toString(), dst.toString());
throw new RuntimeException("CHECK FAILED!");
}
nDst += n;
}
while (--nSrc >= 0) {
if (bufSrc[nSrc] != bufDst[nSrc]) {
System.out.printf("checking <%s> vs <%s>...%n",
src.toString(), dst.toString());
throw new RuntimeException("CHECK FAILED!");
}
nSrc--;
}
}
} finally {
isSrc.close();
isDst.close();
}
// channels
SeekableByteChannel chSrc = src.newByteChannel();
SeekableByteChannel chDst = dst.newByteChannel();
if (chSrc.size() != chDst.size()) {
System.out.printf("src[%s].size=%d, dst[%s].size=%d%n",
chSrc.toString(), chSrc.size(),
chDst.toString(), chDst.size());
throw new RuntimeException("CHECK FAILED!");
}
ByteBuffer bbSrc = ByteBuffer.allocate(8192);
ByteBuffer bbDst = ByteBuffer.allocate(8192);
try {
int nSrc = 0;
while ((nSrc = chSrc.read(bbSrc)) != -1) {
int nDst = chDst.read(bbDst);
if (nSrc != nDst) {
System.out.printf("checking <%s> vs <%s>...%n",
src.toString(), dst.toString());
throw new RuntimeException("CHECK FAILED!");
}
while (--nSrc >= 0) {
if (bbSrc.get(nSrc) != bbDst.get(nSrc)) {
System.out.printf("checking <%s> vs <%s>...%n",
src.toString(), dst.toString());
throw new RuntimeException("CHECK FAILED!");
}
nSrc--;
}
bbSrc.flip();
bbDst.flip();
}
} catch (IOException x) {
x.printStackTrace();
} finally {
chSrc.close();
chDst.close();
}
}
private static void fchCopy(Path src, Path dst) throws IOException
{
Set<OpenOption> read = new HashSet<>();
read.add(READ);
Set<OpenOption> openwrite = new HashSet<>();
openwrite.add(CREATE_NEW);
openwrite.add(WRITE);
FileChannel srcFc = src.getFileSystem()
.provider()
.newFileChannel(src, read);
FileChannel dstFc = dst.getFileSystem()
.provider()
.newFileChannel(dst, openwrite);
try {
ByteBuffer bb = ByteBuffer.allocate(8192);
while (srcFc.read(bb) >= 0) {
bb.flip();
dstFc.write(bb);
bb.clear();
}
} finally {
srcFc.close();
dstFc.close();
}
}
private static void chCopy(Path src, Path dst) throws IOException
{
Set<OpenOption> read = new HashSet<>();
read.add(READ);
Set<OpenOption> openwrite = new HashSet<>();
openwrite.add(CREATE_NEW);
openwrite.add(WRITE);
SeekableByteChannel srcCh = src.newByteChannel(read);
SeekableByteChannel dstCh = dst.newByteChannel(openwrite);
try {
ByteBuffer bb = ByteBuffer.allocate(8192);
while (srcCh.read(bb) >= 0) {
bb.flip();
dstCh.write(bb);
bb.clear();
}
} finally {
srcCh.close();
dstCh.close();
}
}
private static void streamCopy(Path src, Path dst) throws IOException
{
InputStream isSrc = src.newInputStream();
OutputStream osDst = dst.newOutputStream();
byte[] buf = new byte[8192];
try {
int n = 0;
while ((n = isSrc.read(buf)) != -1) {
osDst.write(buf, 0, n);
}
} finally {
isSrc.close();
osDst.close();
}
}
}

View File

@ -0,0 +1,3 @@
com.sun.nio.zipfs.ZipFileSystemProvider
com.sun.nio.zipfs.JarFileSystemProvider

View File

@ -0,0 +1,29 @@
ZipFileSystem is a file system provider that treats the contents of a zip or
JAR file as a java.nio.file.FileSystem.
To deploy the provider you must copy zipfs.jar into your extensions
directory or else add <JDK_HOME>/demo/nio/ZipFileSystem/zipfs.jar
to your class path.
The factory methods defined by the java.nio.file.FileSystems class can be
used to create a FileSystem, eg:
// use file type detection
Map<String,?> env = Collections.emptyMap();
Path jarfile = Path.get("foo.jar");
FileSystem fs = FileSystems.newFileSystem(jarfile, env);
-or
// locate file system by URI
Map<String,?> env = Collections.emptyMap();
URI uri = URI.create("zip:///mydir/foo.jar");
FileSystem fs = FileSystems.newFileSystem(uri, env);
Once a FileSystem is created then classes in the java.nio.file package
can be used to access files in the zip/JAR file, eg:
Path mf = fs.getPath("/META-INF/MANIFEST.MF");
InputStream in = mf.newInputStream();

View File

@ -0,0 +1,71 @@
/*
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.nio.zipfs;
import java.nio.file.*;
import java.nio.file.spi.*;
import java.nio.file.attribute.*;
import java.nio.file.spi.FileSystemProvider;
import java.net.URI;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class JarFileSystemProvider extends ZipFileSystemProvider
{
@Override
public String getScheme() {
return "jar";
}
@Override
protected Path uriToPath(URI uri) {
String scheme = uri.getScheme();
if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) {
throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'");
}
try {
String uristr = uri.toString();
int end = uristr.indexOf("!/");
uristr = uristr.substring(4, (end == -1) ? uristr.length() : end);
uri = new URI(uristr);
return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null))
.toAbsolutePath();
} catch (URISyntaxException e) {
throw new AssertionError(e); //never thrown
}
}
}

View File

@ -0,0 +1,160 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.nio.zipfs;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.util.Arrays;
/**
* Utility class for zipfile name and comment decoding and encoding
*
* @author Xueming Shen
*/
final class ZipCoder {
String toString(byte[] ba, int length) {
CharsetDecoder cd = decoder().reset();
int len = (int)(length * cd.maxCharsPerByte());
char[] ca = new char[len];
if (len == 0)
return new String(ca);
ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);
CharBuffer cb = CharBuffer.wrap(ca);
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
cr = cd.flush(cb);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
return new String(ca, 0, cb.position());
}
String toString(byte[] ba) {
return toString(ba, ba.length);
}
byte[] getBytes(String s) {
CharsetEncoder ce = encoder().reset();
char[] ca = s.toCharArray();
int len = (int)(ca.length * ce.maxBytesPerChar());
byte[] ba = new byte[len];
if (len == 0)
return ba;
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca);
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
cr = ce.flush(bb);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
if (bb.position() == ba.length) // defensive copy?
return ba;
else
return Arrays.copyOf(ba, bb.position());
}
// assume invoked only if "this" is not utf8
byte[] getBytesUTF8(String s) {
if (isutf8)
return getBytes(s);
if (utf8 == null)
utf8 = new ZipCoder(Charset.forName("UTF-8"));
return utf8.getBytes(s);
}
String toStringUTF8(byte[] ba, int len) {
if (isutf8)
return toString(ba, len);
if (utf8 == null)
utf8 = new ZipCoder(Charset.forName("UTF-8"));
return utf8.toString(ba, len);
}
boolean isUTF8() {
return isutf8;
}
private Charset cs;
private boolean isutf8;
private ZipCoder utf8;
private ZipCoder(Charset cs) {
this.cs = cs;
this.isutf8 = cs.name().equals("UTF-8");
}
static ZipCoder get(Charset charset) {
return new ZipCoder(charset);
}
static ZipCoder get(String csn) {
try {
return new ZipCoder(Charset.forName(csn));
} catch (Throwable t) {
t.printStackTrace();
}
return new ZipCoder(Charset.defaultCharset());
}
private final ThreadLocal<CharsetDecoder> decTL = new ThreadLocal<>();
private final ThreadLocal<CharsetEncoder> encTL = new ThreadLocal<>();
private CharsetDecoder decoder() {
CharsetDecoder dec = decTL.get();
if (dec == null) {
dec = cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
decTL.set(dec);
}
return dec;
}
private CharsetEncoder encoder() {
CharsetEncoder enc = encTL.get();
if (enc == null) {
enc = cs.newEncoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
encTL.set(enc);
}
return enc;
}
}

View File

@ -0,0 +1,261 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.nio.zipfs;
import java.nio.ByteBuffer;
/**
*
* @author Xueming Shen
*/
class ZipConstants {
/*
* Compression methods
*/
static final int METHOD_STORED = 0;
static final int METHOD_DEFLATED = 8;
static final int METHOD_DEFLATED64 = 9;
static final int METHOD_BZIP2 = 12;
static final int METHOD_LZMA = 14;
static final int METHOD_LZ77 = 19;
/*
* General purpose big flag
*/
static final int FLAG_ENCRYPTED = 0x01;
static final int FLAG_DATADESCR = 0x08; // crc, size and csize in dd
static final int FLAG_EFS = 0x800; // If this bit is set the filename and
// comment fields for this file must be
// encoded using UTF-8.
/*
* Header signatures
*/
static long LOCSIG = 0x04034b50L; // "PK\003\004"
static long EXTSIG = 0x08074b50L; // "PK\007\008"
static long CENSIG = 0x02014b50L; // "PK\001\002"
static long ENDSIG = 0x06054b50L; // "PK\005\006"
/*
* Header sizes in bytes (including signatures)
*/
static final int LOCHDR = 30; // LOC header size
static final int EXTHDR = 16; // EXT header size
static final int CENHDR = 46; // CEN header size
static final int ENDHDR = 22; // END header size
/*
* Local file (LOC) header field offsets
*/
static final int LOCVER = 4; // version needed to extract
static final int LOCFLG = 6; // general purpose bit flag
static final int LOCHOW = 8; // compression method
static final int LOCTIM = 10; // modification time
static final int LOCCRC = 14; // uncompressed file crc-32 value
static final int LOCSIZ = 18; // compressed size
static final int LOCLEN = 22; // uncompressed size
static final int LOCNAM = 26; // filename length
static final int LOCEXT = 28; // extra field length
/*
* Extra local (EXT) header field offsets
*/
static final int EXTCRC = 4; // uncompressed file crc-32 value
static final int EXTSIZ = 8; // compressed size
static final int EXTLEN = 12; // uncompressed size
/*
* Central directory (CEN) header field offsets
*/
static final int CENVEM = 4; // version made by
static final int CENVER = 6; // version needed to extract
static final int CENFLG = 8; // encrypt, decrypt flags
static final int CENHOW = 10; // compression method
static final int CENTIM = 12; // modification time
static final int CENCRC = 16; // uncompressed file crc-32 value
static final int CENSIZ = 20; // compressed size
static final int CENLEN = 24; // uncompressed size
static final int CENNAM = 28; // filename length
static final int CENEXT = 30; // extra field length
static final int CENCOM = 32; // comment length
static final int CENDSK = 34; // disk number start
static final int CENATT = 36; // internal file attributes
static final int CENATX = 38; // external file attributes
static final int CENOFF = 42; // LOC header offset
/*
* End of central directory (END) header field offsets
*/
static final int ENDSUB = 8; // number of entries on this disk
static final int ENDTOT = 10; // total number of entries
static final int ENDSIZ = 12; // central directory size in bytes
static final int ENDOFF = 16; // offset of first CEN header
static final int ENDCOM = 20; // zip file comment length
/*
* ZIP64 constants
*/
static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006"
static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007"
static final int ZIP64_ENDHDR = 56; // ZIP64 end header size
static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size
static final int ZIP64_EXTHDR = 24; // EXT header size
static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID
static final int ZIP64_MINVAL32 = 0xFFFF;
static final long ZIP64_MINVAL = 0xFFFFFFFFL;
/*
* Zip64 End of central directory (END) header field offsets
*/
static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir
static final int ZIP64_ENDVEM = 12; // version made by
static final int ZIP64_ENDVER = 14; // version needed to extract
static final int ZIP64_ENDNMD = 16; // number of this disk
static final int ZIP64_ENDDSK = 20; // disk number of start
static final int ZIP64_ENDTOD = 24; // total number of entries on this disk
static final int ZIP64_ENDTOT = 32; // total number of entries
static final int ZIP64_ENDSIZ = 40; // central directory size in bytes
static final int ZIP64_ENDOFF = 48; // offset of first CEN header
static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector
/*
* Zip64 End of central directory locator field offsets
*/
static final int ZIP64_LOCDSK = 4; // disk number start
static final int ZIP64_LOCOFF = 8; // offset of zip64 end
static final int ZIP64_LOCTOT = 16; // total number of disks
/*
* Zip64 Extra local (EXT) header field offsets
*/
static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value
static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte
static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte
/*
* Extra field header ID
*/
static final int EXTID_ZIP64 = 0x0001; // ZIP64
static final int EXTID_NTFS = 0x000a; // NTFS
static final int EXTID_UNIX = 0x000d; // UNIX
/*
* fields access methods
*/
///////////////////////////////////////////////////////
static final int CH(byte[] b, int n) {
return b[n] & 0xff;
}
static final int SH(byte[] b, int n) {
return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8);
}
static final long LG(byte[] b, int n) {
return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL;
}
static final long LL(byte[] b, int n) {
return (LG(b, n)) | (LG(b, n + 4) << 32);
}
static final long GETSIG(byte[] b) {
return LG(b, 0);
}
// local file (LOC) header fields
static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature
static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract
static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags
static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method
static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time
static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data
static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size
static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size
static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length
static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length
// extra local (EXT) header fields
static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data
static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size
static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size
// end of central directory header (END) fields
static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk
static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries
static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size
static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset
static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment
static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);}
// zip64 end of central directory recoder fields
static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk
static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries
static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size
static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset
static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset
//////////////////////////////////////////
static final int CH(ByteBuffer b, int pos) {
return b.get(pos) & 0xff;
}
static final int SH(ByteBuffer b, int pos) {
return b.getShort(pos) & 0xffff;
}
static final long LG(ByteBuffer b, int pos) {
return b.getInt(pos) & 0xffffffffL;
}
// central directory header (END) fields
static final long CENSIG(ByteBuffer b, int pos) { return LG(b, pos + 0); }
static final int CENVEM(ByteBuffer b, int pos) { return SH(b, pos + 4); }
static final int CENVER(ByteBuffer b, int pos) { return SH(b, pos + 6); }
static final int CENFLG(ByteBuffer b, int pos) { return SH(b, pos + 8); }
static final int CENHOW(ByteBuffer b, int pos) { return SH(b, pos + 10);}
static final long CENTIM(ByteBuffer b, int pos) { return LG(b, pos + 12);}
static final long CENCRC(ByteBuffer b, int pos) { return LG(b, pos + 16);}
static final long CENSIZ(ByteBuffer b, int pos) { return LG(b, pos + 20);}
static final long CENLEN(ByteBuffer b, int pos) { return LG(b, pos + 24);}
static final int CENNAM(ByteBuffer b, int pos) { return SH(b, pos + 28);}
static final int CENEXT(ByteBuffer b, int pos) { return SH(b, pos + 30);}
static final int CENCOM(ByteBuffer b, int pos) { return SH(b, pos + 32);}
static final int CENDSK(ByteBuffer b, int pos) { return SH(b, pos + 34);}
static final int CENATT(ByteBuffer b, int pos) { return SH(b, pos + 36);}
static final long CENATX(ByteBuffer b, int pos) { return LG(b, pos + 38);}
static final long CENOFF(ByteBuffer b, int pos) { return LG(b, pos + 42);}
/* The END header is followed by a variable length comment of size < 64k. */
static final long END_MAXLEN = 0xFFFF + ENDHDR;
static final int READBLOCKSZ = 128;
}

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.nio.zipfs;
import java.nio.file.DirectoryStream;
import java.nio.file.ClosedDirectoryStreamException;
import java.nio.file.NotDirectoryException;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.io.IOException;
import static com.sun.nio.zipfs.ZipUtils.*;
/**
*
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
*/
public class ZipDirectoryStream implements DirectoryStream<Path> {
private final ZipFileSystem zipfs;
private final byte[] path;
private final DirectoryStream.Filter<? super Path> filter;
private volatile boolean isClosed;
private volatile Iterator<Path> itr;
ZipDirectoryStream(ZipPath zipPath,
DirectoryStream.Filter<? super java.nio.file.Path> filter)
throws IOException
{
this.zipfs = zipPath.getFileSystem();
this.path = zipPath.getResolvedPath();
this.filter = filter;
// sanity check
if (!zipfs.isDirectory(path))
throw new NotDirectoryException(zipPath.toString());
}
@Override
public synchronized Iterator<Path> iterator() {
if (isClosed)
throw new ClosedDirectoryStreamException();
if (itr != null)
throw new IllegalStateException("Iterator has already been returned");
try {
itr = zipfs.iteratorOf(path, filter);
} catch (IOException e) {
throw new IllegalStateException(e);
}
return new Iterator<Path>() {
private Path next;
@Override
public boolean hasNext() {
if (isClosed)
return false;
return itr.hasNext();
}
@Override
public synchronized Path next() {
if (isClosed)
throw new NoSuchElementException();
return itr.next();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public synchronized void close() throws IOException {
isClosed = true;
}
}

View File

@ -0,0 +1,185 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.nio.zipfs;
import java.nio.file.ReadOnlyFileSystemException;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.FileAttributeView;
import java.nio.file.attribute.FileTime;
import java.io.IOException;
import java.util.LinkedHashMap;
/*
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
*/
public class ZipFileAttributeView implements BasicFileAttributeView
{
private static enum AttrID {
size,
creationTime,
lastAccessTime,
lastModifiedTime,
isDirectory,
isRegularFile,
isSymbolicLink,
isOther,
fileKey,
compressedSize,
crc,
method
};
private final ZipPath path;
private final boolean isZipView;
private ZipFileAttributeView(ZipPath path, boolean isZipView) {
this.path = path;
this.isZipView = isZipView;
}
static <V extends FileAttributeView> V get(ZipPath path, Class<V> type) {
if (type == null)
throw new NullPointerException();
if (type == BasicFileAttributeView.class)
return (V)new ZipFileAttributeView(path, false);
if (type == ZipFileAttributeView.class)
return (V)new ZipFileAttributeView(path, true);
return null;
}
static ZipFileAttributeView get(ZipPath path, String type) {
if (type == null)
throw new NullPointerException();
if (type.equals("basic"))
return new ZipFileAttributeView(path, false);
if (type.equals("zip"))
return new ZipFileAttributeView(path, true);
return null;
}
@Override
public String name() {
return isZipView ? "zip" : "basic";
}
public ZipFileAttributes readAttributes() throws IOException
{
return path.getAttributes();
}
@Override
public void setTimes(FileTime lastModifiedTime,
FileTime lastAccessTime,
FileTime createTime)
throws IOException
{
path.setTimes(lastModifiedTime, lastAccessTime, createTime);
}
void setAttribute(String attribute, Object value)
throws IOException
{
try {
if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime)
setTimes ((FileTime)value, null, null);
return;
} catch (IllegalArgumentException x) {}
throw new UnsupportedOperationException("'" + attribute +
"' is unknown or read-only attribute");
}
public Object getAttribute(String attribute, boolean domap)
throws IOException
{
ZipFileAttributes zfas = readAttributes();
if (!domap) {
try {
return attribute(AttrID.valueOf(attribute), zfas);
} catch (IllegalArgumentException x) {}
return null;
}
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
if ("*".equals(attribute)) {
for (AttrID id : AttrID.values()) {
try {
map.put(id.name(), attribute(id, zfas));
} catch (IllegalArgumentException x) {}
}
} else {
String[] as = attribute.split(",");
for (String a : as) {
try {
map.put(a, attribute(AttrID.valueOf(a), zfas));
} catch (IllegalArgumentException x) {}
}
}
return map;
}
Object attribute(AttrID id, ZipFileAttributes zfas) {
switch (id) {
case size:
return zfas.size();
case creationTime:
return zfas.creationTime();
case lastAccessTime:
return zfas.lastAccessTime();
case lastModifiedTime:
return zfas.lastModifiedTime();
case isDirectory:
return zfas.isDirectory();
case isRegularFile:
return zfas.isRegularFile();
case isSymbolicLink:
return zfas.isSymbolicLink();
case isOther:
return zfas.isOther();
case fileKey:
return zfas.fileKey();
case compressedSize:
if (isZipView)
return zfas.compressedSize();
break;
case crc:
if (isZipView)
return zfas.crc();
break;
case method:
if (isZipView)
return zfas.method();
break;
}
return null;
}
}

View File

@ -0,0 +1,156 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.nio.zipfs;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.Arrays;
import java.util.Formatter;
import static com.sun.nio.zipfs.ZipUtils.*;
/**
*
* @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal
*/
public class ZipFileAttributes implements BasicFileAttributes
{
private final ZipFileSystem.Entry e;
ZipFileAttributes(ZipFileSystem.Entry e) {
this.e = e;
}
///////// basic attributes ///////////
@Override
public FileTime creationTime() {
if (e.ctime != -1)
return FileTime.fromMillis(dosToJavaTime(e.ctime));
return null;
}
@Override
public boolean isDirectory() {
return e.isDir();
}
@Override
public boolean isOther() {
return false;
}
@Override
public boolean isRegularFile() {
return !e.isDir();
}
@Override
public FileTime lastAccessTime() {
if (e.atime != -1)
return FileTime.fromMillis(dosToJavaTime(e.atime));
return null;
}
@Override
public FileTime lastModifiedTime() {
return FileTime.fromMillis(dosToJavaTime(e.mtime));
}
@Override
public long size() {
return e.size;
}
@Override
public boolean isSymbolicLink() {
return false;
}
@Override
public Object fileKey() {
return null;
}
///////// zip entry attributes ///////////
public byte[] name() {
return Arrays.copyOf(e.name, e.name.length);
}
public long compressedSize() {
return e.csize;
}
public long crc() {
return e.crc;
}
public int method() {
return e.method;
}
public byte[] extra() {
if (e.extra != null)
return Arrays.copyOf(e.extra, e.extra.length);
return null;
}
public byte[] comment() {
if (e.comment != null)
return Arrays.copyOf(e.comment, e.comment.length);
return null;
}
public String toString() {
StringBuilder sb = new StringBuilder();
Formatter fm = new Formatter(sb);
fm.format("[/%s]%n", new String(e.name)); // TBD encoding
fm.format(" creationTime : %s%n", creationTime());
if (lastAccessTime() != null)
fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis());
else
fm.format(" lastAccessTime : null%n");
fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis());
fm.format(" isRegularFile : %b%n", isRegularFile());
fm.format(" isDirectory : %b%n", isDirectory());
fm.format(" isSymbolicLink : %b%n", isSymbolicLink());
fm.format(" isOther : %b%n", isOther());
fm.format(" fileKey : %s%n", fileKey());
fm.format(" size : %d%n", size());
fm.format(" compressedSize : %d%n", compressedSize());
fm.format(" crc : %x%n", crc());
fm.format(" method : %d%n", method());
fm.close();
return sb.toString();
}
}

View File

@ -0,0 +1,157 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.nio.zipfs;
import java.io.IOException;
import java.nio.file.FileStore;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.attribute.FileAttributeView;
import java.nio.file.attribute.FileStoreAttributeView;
import java.nio.file.attribute.FileStoreSpaceAttributeView;
import java.nio.file.attribute.FileStoreSpaceAttributes;
import java.nio.file.attribute.Attributes;
import java.nio.file.attribute.BasicFileAttributeView;
import java.util.Formatter;
/*
*
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
*/
public class ZipFileStore extends FileStore {
private final ZipFileSystem zfs;
ZipFileStore(ZipPath zpath) {
this.zfs = (ZipFileSystem)zpath.getFileSystem();
}
@Override
public String name() {
return zfs.toString() + "/";
}
@Override
public String type() {
return "zipfs";
}
@Override
public boolean isReadOnly() {
return zfs.isReadOnly();
}
@Override
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
return (type == BasicFileAttributeView.class ||
type == ZipFileAttributeView.class);
}
@Override
public boolean supportsFileAttributeView(String name) {
return name.equals("basic") || name.equals("zip");
}
@Override
@SuppressWarnings("unchecked")
public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) {
if (type == null)
throw new NullPointerException();
if (type == FileStoreSpaceAttributeView.class)
return (V) new ZipFileStoreAttributeView(this);
return null;
}
@Override
public Object getAttribute(String attribute) throws IOException {
if (attribute.equals("space:totalSpace"))
return new ZipFileStoreAttributeView(this).readAttributes().totalSpace();
if (attribute.equals("space:usableSpace"))
return new ZipFileStoreAttributeView(this).readAttributes().usableSpace();
if (attribute.equals("space:unallocatedSpace"))
return new ZipFileStoreAttributeView(this).readAttributes().unallocatedSpace();
throw new UnsupportedOperationException("does not support the given attribute");
}
private static class ZipFileStoreAttributeView implements FileStoreSpaceAttributeView {
private final ZipFileStore fileStore;
public ZipFileStoreAttributeView(ZipFileStore fileStore) {
this.fileStore = fileStore;
}
@Override
public String name() {
return "space";
}
@Override
public FileStoreSpaceAttributes readAttributes() throws IOException {
final String file = fileStore.name();
Path path = FileSystems.getDefault().getPath(file);
final long size = Attributes.readBasicFileAttributes(path).size();
final FileStore fstore = path.getFileStore();
final FileStoreSpaceAttributes fstoreAttrs =
Attributes.readFileStoreSpaceAttributes(fstore);
return new FileStoreSpaceAttributes() {
public long totalSpace() {
return size;
}
public long usableSpace() {
if (!fstore.isReadOnly())
return fstoreAttrs.usableSpace();
return 0;
}
public long unallocatedSpace() {
if (!fstore.isReadOnly())
return fstoreAttrs.unallocatedSpace();
return 0;
}
public String toString() {
StringBuilder sb = new StringBuilder();
Formatter fm = new Formatter(sb);
fm.format("FileStoreSpaceAttributes[%s]%n", file);
fm.format(" totalSpace: %d%n", totalSpace());
fm.format(" usableSpace: %d%n", usableSpace());
fm.format(" unallocSpace: %d%n", unallocatedSpace());
fm.close();
return sb.toString();
}
};
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.nio.zipfs;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.FileRef;
import java.nio.file.FileSystem;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystemAlreadyExistsException;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.ProviderMismatchException;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.spi.FileSystemProvider;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
*
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
*/
public class ZipFileSystemProvider extends FileSystemProvider {
private final Map<Path, ZipFileSystem> filesystems = new HashMap<>();
public ZipFileSystemProvider() {}
@Override
public String getScheme() {
return "zip";
}
protected Path uriToPath(URI uri) {
String scheme = uri.getScheme();
if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) {
throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'");
}
try {
return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null))
.toAbsolutePath();
} catch (URISyntaxException e) {
throw new AssertionError(e); //never thrown
}
}
@Override
public FileSystem newFileSystem(URI uri, Map<String, ?> env)
throws IOException
{
return newFileSystem(uriToPath(uri), env);
}
@Override
public FileSystem newFileSystem(FileRef file, Map<String, ?> env)
throws IOException
{
if (!(file instanceof Path))
throw new UnsupportedOperationException();
Path path = (Path)file;
if (!path.toUri().getScheme().equalsIgnoreCase("file")) {
throw new UnsupportedOperationException();
}
return newFileSystem(path, env);
}
private FileSystem newFileSystem(Path path, Map<String, ?> env)
throws IOException
{
synchronized(filesystems) {
if (filesystems.containsKey(path))
throw new FileSystemAlreadyExistsException();
ZipFileSystem zipfs = new ZipFileSystem(this, path, env);
filesystems.put(path, zipfs);
return zipfs;
}
}
@Override
public Path getPath(URI uri) {
FileSystem fs = getFileSystem(uri);
String fragment = uri.getFragment();
if (fragment == null) {
throw new IllegalArgumentException("URI: "
+ uri
+ " does not contain path fragment ex. zip:///c:/foo.zip#/BAR");
}
return fs.getPath(fragment);
}
@Override
public FileChannel newFileChannel(Path path,
Set<? extends OpenOption> options,
FileAttribute<?>... attrs)
throws IOException
{
if (path == null)
throw new NullPointerException("path is null");
if (path instanceof ZipPath)
return ((ZipPath)path).newFileChannel(options, attrs);
throw new ProviderMismatchException();
}
@Override
public FileSystem getFileSystem(URI uri) {
synchronized (filesystems) {
ZipFileSystem zipfs = filesystems.get(uriToPath(uri));
if (zipfs == null)
throw new FileSystemNotFoundException();
return zipfs;
}
}
void removeFileSystem(Path zfpath) {
synchronized (filesystems) {
filesystems.remove(zfpath);
}
}
}

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.nio.zipfs;
import java.io.PrintStream;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import com.sun.nio.zipfs.ZipFileSystem.Entry;
import static com.sun.nio.zipfs.ZipConstants.*;
import static com.sun.nio.zipfs.ZipUtils.*;
/**
* Print the loc and cen tables of the ZIP file
*
* @author Xueming Shen
*/
public class ZipInfo {
public static void main(String[] args) throws Throwable {
if (args.length < 2) {
print("Usage: java ZipInfo [cen|loc] zfname");
} else {
Map<String, ?> env = Collections.emptyMap();
ZipFileSystem zfs = (ZipFileSystem)(new ZipFileSystemProvider()
.newFileSystem(Paths.get(args[1]), env));
long pos = 0;
if ("loc".equals(args[0])) {
print("[Local File Header]%n");
byte[] buf = new byte[1024];
for (int i = 0; i < zfs.getEntryNames().length; i++) {
Entry loc = Entry.readLOC(zfs, pos, buf);
print("--------loc[%x]--------%n", pos);
printLOC(loc);
pos = loc.endPos;
}
} if ("cen".equals(args[0])) {
int i = 0;
Iterator<ZipFileSystem.IndexNode> itr = zfs.inodes.values().iterator();
print("[Central Directory Header]%n");
while (itr.hasNext()) {
Entry cen = Entry.readCEN(zfs.cen, itr.next().pos);
print("--------cen[%d]--------%n", i);
printCEN(cen);
i++;
}
}
zfs.close();
}
}
static void print(String fmt, Object... objs) {
System.out.printf(fmt, objs);
}
static void printLOC(Entry loc) {
print(" [%x, %x]%n", loc.startPos, loc.endPos);
print(" Signature : %8x%n", LOCSIG);
print(" Version : %4x [%d.%d]%n",
loc.version, loc. version/10, loc. version%10);
print(" Flag : %4x%n", loc.flag);
print(" Method : %4x%n", loc. method);
print(" LastMTime : %8x [%tc]%n",
loc.mtime, dosToJavaTime(loc.mtime));
print(" CRC : %8x%n", loc.crc);
print(" CSize : %8x%n", loc.csize);
print(" Size : %8x%n", loc.size);
print(" NameLength : %4x [%s]%n",
loc.nlen, new String(loc.name));
print(" ExtraLength : %4x%n", loc.elen);
if (loc.hasZip64)
print(" *ZIP64*%n");
}
static void printCEN(Entry cen) {
print(" Signature : %08x%n", CENSIG);
print(" VerMadeby : %4x [%d.%d]%n",
cen.versionMade, cen.versionMade/10, cen.versionMade%10);
print(" VerExtract : %4x [%d.%d]%n",
cen.version, cen.version/10, cen.version%10);
print(" Flag : %4x%n", cen.flag);
print(" Method : %4x%n", cen.method);
print(" LastMTime : %8x [%tc]%n",
cen.mtime, dosToJavaTime(cen.mtime));
print(" CRC : %8x%n", cen.crc);
print(" CSize : %8x%n", cen.csize);
print(" Size : %8x%n", cen.size);
print(" NameLen : %4x [%s]%n",
cen.nlen, new String(cen.name));
print(" ExtraLen : %4x%n", cen.elen);
print(" CommentLen : %4x%n", cen.clen);
print(" DiskStart : %4x%n", cen.disk);
print(" Attrs : %4x%n", cen.attrs);
print(" AttrsEx : %8x%n", cen.attrsEx);
print(" LocOff : %8x%n", cen.locoff);
if (cen.hasZip64)
print(" *ZIP64*%n");
}
}

View File

@ -0,0 +1,964 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.nio.zipfs;
import java.io.File;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.*;
import java.nio.file.DirectoryStream.Filter;
import java.nio.file.spi.FileSystemProvider;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.FileAttributeView;
import java.nio.file.attribute.FileTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.nio.file.StandardOpenOption.*;
import static java.nio.file.StandardCopyOption.*;
/**
*
* @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal
*/
public class ZipPath extends Path {
private final ZipFileSystem zfs;
private final byte[] path;
private volatile int[] offsets;
private int hashcode = 0; // cached hashcode (created lazily)
ZipPath(ZipFileSystem zfs, byte[] path) {
this(zfs, path, false);
}
ZipPath(ZipFileSystem zfs, byte[] path, boolean normalized)
{
this.zfs = zfs;
if (normalized)
this.path = path;
else
this.path = normalize(path);
}
@Override
public ZipPath getRoot() {
if (this.isAbsolute())
return new ZipPath(zfs, new byte[]{path[0]});
else
return null;
}
@Override
public Path getName() {
initOffsets();
int count = offsets.length;
if (count == 0)
return null; // no elements so no name
if (count == 1 && path[0] != '/')
return this;
int lastOffset = offsets[count-1];
int len = path.length - lastOffset;
byte[] result = new byte[len];
System.arraycopy(path, lastOffset, result, 0, len);
return new ZipPath(zfs, result);
}
@Override
public ZipPath getParent() {
initOffsets();
int count = offsets.length;
if (count == 0) // no elements so no parent
return null;
int len = offsets[count-1] - 1;
if (len <= 0) // parent is root only (may be null)
return getRoot();
byte[] result = new byte[len];
System.arraycopy(path, 0, result, 0, len);
return new ZipPath(zfs, result);
}
@Override
public int getNameCount() {
initOffsets();
return offsets.length;
}
@Override
public ZipPath getName(int index) {
initOffsets();
if (index < 0 || index >= offsets.length)
throw new IllegalArgumentException();
int begin = offsets[index];
int len;
if (index == (offsets.length-1))
len = path.length - begin;
else
len = offsets[index+1] - begin - 1;
// construct result
byte[] result = new byte[len];
System.arraycopy(path, begin, result, 0, len);
return new ZipPath(zfs, result);
}
@Override
public ZipPath subpath(int beginIndex, int endIndex) {
initOffsets();
if (beginIndex < 0 ||
beginIndex >= offsets.length ||
endIndex > offsets.length ||
beginIndex >= endIndex)
throw new IllegalArgumentException();
// starting offset and length
int begin = offsets[beginIndex];
int len;
if (endIndex == offsets.length)
len = path.length - begin;
else
len = offsets[endIndex] - begin - 1;
// construct result
byte[] result = new byte[len];
System.arraycopy(path, begin, result, 0, len);
return new ZipPath(zfs, result);
}
@Override
public ZipPath toRealPath(boolean resolveLinks) throws IOException {
ZipPath realPath = new ZipPath(zfs, getResolvedPath());
realPath.checkAccess();
return realPath;
}
@Override
public boolean isHidden() {
return false;
}
@Override
public ZipPath toAbsolutePath() {
if (isAbsolute()) {
return this;
} else {
//add / bofore the existing path
byte[] defaultdir = zfs.getDefaultDir().path;
int defaultlen = defaultdir.length;
boolean endsWith = (defaultdir[defaultlen - 1] == '/');
byte[] t = null;
if (endsWith)
t = new byte[defaultlen + path.length];
else
t = new byte[defaultlen + 1 + path.length];
System.arraycopy(defaultdir, 0, t, 0, defaultlen);
if (!endsWith)
t[defaultlen++] = '/';
System.arraycopy(path, 0, t, defaultlen, path.length);
return new ZipPath(zfs, t, true); // normalized
}
}
@Override
public URI toUri() {
String zfPath = zfs.toString();
if (File.separatorChar == '\\') // replace all separators by '/'
zfPath = "/" + zfPath.replace("\\", "/");
try {
return new URI("zip", "",
zfPath,
zfs.getString(toAbsolutePath().path));
} catch (Exception ex) {
throw new AssertionError(ex);
}
}
private boolean equalsNameAt(ZipPath other, int index) {
int mbegin = offsets[index];
int mlen = 0;
if (index == (offsets.length-1))
mlen = path.length - mbegin;
else
mlen = offsets[index + 1] - mbegin - 1;
int obegin = other.offsets[index];
int olen = 0;
if (index == (other.offsets.length - 1))
olen = other.path.length - obegin;
else
olen = other.offsets[index + 1] - obegin - 1;
if (mlen != olen)
return false;
int n = 0;
while(n < mlen) {
if (path[mbegin + n] != other.path[obegin + n])
return false;
n++;
}
return true;
}
@Override
public Path relativize(Path other) {
final ZipPath o = checkPath(other);
if (o.equals(this))
return null;
if (/* this.getFileSystem() != o.getFileSystem() || */
this.isAbsolute() != o.isAbsolute()) {
throw new IllegalArgumentException();
}
int mc = this.getNameCount();
int oc = o.getNameCount();
int n = Math.min(mc, oc);
int i = 0;
while (i < n) {
if (!equalsNameAt(o, i))
break;
i++;
}
int dotdots = mc - i;
int len = dotdots * 3 - 1;
if (i < oc)
len += (o.path.length - o.offsets[i] + 1);
byte[] result = new byte[len];
int pos = 0;
while (dotdots > 0) {
result[pos++] = (byte)'.';
result[pos++] = (byte)'.';
if (pos < len) // no tailing slash at the end
result[pos++] = (byte)'/';
dotdots--;
}
if (i < oc)
System.arraycopy(o.path, o.offsets[i],
result, pos,
o.path.length - o.offsets[i]);
return new ZipPath(getFileSystem(), result);
}
@Override
public ZipFileSystem getFileSystem() {
return zfs;
}
@Override
public boolean isAbsolute() {
return (this.path[0] == '/');
}
@Override
public ZipPath resolve(Path other) {
if (other == null)
return this;
final ZipPath o = checkPath(other);
if (o.isAbsolute())
return o;
byte[] resolved = null;
if (this.path[path.length - 1] == '/') {
resolved = new byte[path.length + o.path.length];
System.arraycopy(path, 0, resolved, 0, path.length);
System.arraycopy(o.path, 0, resolved, path.length, o.path.length);
} else {
resolved = new byte[path.length + 1 + o.path.length];
System.arraycopy(path, 0, resolved, 0, path.length);
resolved[path.length] = '/';
System.arraycopy(o.path, 0, resolved, path.length + 1, o.path.length);
}
return new ZipPath(zfs, resolved);
}
@Override
public ZipPath resolve(String other) {
return resolve(getFileSystem().getPath(other));
}
@Override
public boolean startsWith(Path other) {
final ZipPath o = checkPath(other);
if (o.isAbsolute() != this.isAbsolute())
return false;
final int oCount = o.getNameCount();
if (getNameCount() < oCount)
return false;
for (int i = 0; i < oCount; i++) {
if (!o.getName(i).equals(getName(i)))
return false;
}
return true;
}
@Override
public boolean endsWith(Path other) {
final ZipPath o = checkPath(other);
if (o.isAbsolute())
return this.isAbsolute() ? this.equals(o) : false;
int i = o.getNameCount();
int j = this.getNameCount();
if (j < i)
return false;
for (--i, --j; i >= 0; i--, j--) {
if (!o.getName(i).equals(this.getName(j)))
return false;
}
return true;
}
@Override
public Path normalize() {
byte[] resolved = getResolved();
if (resolved == path) // no change
return this;
if (resolved.length == 0)
return null;
return new ZipPath(zfs, resolved, true);
}
private ZipPath checkPath(Path path) {
if (path == null)
throw new NullPointerException();
if (!(path instanceof ZipPath))
throw new ProviderMismatchException();
return (ZipPath) path;
}
// create offset list if not already created
private void initOffsets() {
if (offsets == null) {
int count, index;
// count names
count = 0;
index = 0;
while (index < path.length) {
byte c = path[index++];
if (c != '/') {
count++;
while (index < path.length && path[index] != '/')
index++;
}
}
// populate offsets
int[] result = new int[count];
count = 0;
index = 0;
while (index < path.length) {
byte c = path[index];
if (c == '/') {
index++;
} else {
result[count++] = index++;
while (index < path.length && path[index] != '/')
index++;
}
}
synchronized (this) {
if (offsets == null)
offsets = result;
}
}
}
// resolved path for locating zip entry inside the zip file,
// the result path does not contain ./ and .. components
private volatile byte[] resolved = null;
byte[] getResolvedPath() {
byte[] r = resolved;
if (r == null) {
if (isAbsolute())
r = getResolved();
else
r = toAbsolutePath().getResolvedPath();
if (r[0] == '/')
r = Arrays.copyOfRange(r, 1, r.length);
resolved = r;
}
return resolved;
}
// removes redundant slashs, replace "\" to zip separator "/"
// and check for invalid characters
private byte[] normalize(byte[] path) {
if (path.length == 0)
return path;
byte prevC = 0;
for (int i = 0; i < path.length; i++) {
byte c = path[i];
if (c == '\\')
return normalize(path, i);
if (c == (byte)'/' && prevC == '/')
return normalize(path, i - 1);
if (c == '\u0000')
throw new InvalidPathException(zfs.getString(path),
"Path: nul character not allowed");
prevC = c;
}
return path;
}
private byte[] normalize(byte[] path, int off) {
byte[] to = new byte[path.length];
int n = 0;
while (n < off) {
to[n] = path[n];
n++;
}
int m = n;
byte prevC = 0;
while (n < path.length) {
byte c = path[n++];
if (c == (byte)'\\')
c = (byte)'/';
if (c == (byte)'/' && prevC == (byte)'/')
continue;
if (c == '\u0000')
throw new InvalidPathException(zfs.getString(path),
"Path: nul character not allowed");
to[m++] = c;
prevC = c;
}
if (m > 1 && to[m - 1] == '/')
m--;
return (m == to.length)? to : Arrays.copyOf(to, m);
}
// Remove DotSlash(./) and resolve DotDot (..) components
private byte[] getResolved() {
if (path.length == 0)
return path;
for (int i = 0; i < path.length; i++) {
byte c = path[i];
if (c == (byte)'.')
return resolve0();
}
return path;
}
// TBD: performance, avoid initOffsets
private byte[] resolve0() {
byte[] to = new byte[path.length];
int nc = getNameCount();
int[] lastM = new int[nc];
int lastMOff = -1;
int m = 0;
for (int i = 0; i < nc; i++) {
int n = offsets[i];
int len = (i == offsets.length - 1)?
(path.length - n):(offsets[i + 1] - n - 1);
if (len == 1 && path[n] == (byte)'.')
continue;
if (len == 2 && path[n] == '.' && path[n + 1] == '.') {
if (lastMOff >= 0) {
m = lastM[lastMOff--]; // retreat
continue;
}
if (path[0] == '/') { // "/../xyz" skip
if (m == 0)
to[m++] = '/';
} else { // "../xyz" -> "../xyz"
if (m != 0 && to[m-1] != '/')
to[m++] = '/';
while (len-- > 0)
to[m++] = path[n++];
}
continue;
}
if (m == 0 && path[0] == '/' || // absolute path
m != 0 && to[m-1] != '/') { // not the first name
to[m++] = '/';
}
lastM[++lastMOff] = m;
while (len-- > 0)
to[m++] = path[n++];
}
if (m > 1 && to[m - 1] == '/')
m--;
return (m == to.length)? to : Arrays.copyOf(to, m);
}
@Override
public String toString() {
return zfs.getString(path);
}
@Override
public int hashCode() {
int h = hashcode;
if (h == 0)
hashcode = h = Arrays.hashCode(path);
return h;
}
@Override
public boolean equals(Object obj) {
return obj != null &&
obj instanceof ZipPath &&
this.zfs == ((ZipPath)obj).zfs &&
compareTo((Path) obj) == 0;
}
@Override
public int compareTo(Path other) {
final ZipPath o = checkPath(other);
int len1 = this.path.length;
int len2 = o.path.length;
int n = Math.min(len1, len2);
byte v1[] = this.path;
byte v2[] = o.path;
int k = 0;
while (k < n) {
int c1 = v1[k] & 0xff;
int c2 = v2[k] & 0xff;
if (c1 != c2)
return c1 - c2;
k++;
}
return len1 - len2;
}
@Override
public Path createSymbolicLink(
Path target, FileAttribute<?>... attrs) throws IOException {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public Path createLink(
Path existing) throws IOException {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public Path readSymbolicLink() throws IOException {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public Path createDirectory(FileAttribute<?>... attrs)
throws IOException
{
zfs.createDirectory(getResolvedPath(), attrs);
return this;
}
public final Path createFile(FileAttribute<?>... attrs)
throws IOException
{
OutputStream os = newOutputStream(CREATE_NEW, WRITE);
try {
os.close();
} catch (IOException x) {}
return this;
}
@Override
public InputStream newInputStream(OpenOption... options)
throws IOException {
if (options.length > 0) {
for (OpenOption opt : options) {
if (opt != READ)
throw new UnsupportedOperationException("'" + opt + "' not allowed");
}
}
return zfs.newInputStream(getResolvedPath());
}
private static final DirectoryStream.Filter<Path> acceptAllFilter =
new DirectoryStream.Filter<Path>() {
@Override public boolean accept(Path entry) { return true; }
};
@Override
public final DirectoryStream<Path> newDirectoryStream() throws IOException {
return newDirectoryStream(acceptAllFilter);
}
@Override
public DirectoryStream<Path> newDirectoryStream(Filter<? super Path> filter)
throws IOException
{
return new ZipDirectoryStream(this, filter);
}
@Override
public final DirectoryStream<Path> newDirectoryStream(String glob)
throws IOException
{
// avoid creating a matcher if all entries are required.
if (glob.equals("*"))
return newDirectoryStream();
// create a matcher and return a filter that uses it.
final PathMatcher matcher = getFileSystem().getPathMatcher("glob:" + glob);
DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
@Override
public boolean accept(Path entry) {
return matcher.matches(entry.getName());
}
};
return newDirectoryStream(filter);
}
@Override
public final void delete() throws IOException {
zfs.deleteFile(getResolvedPath(), true);
}
@Override
public final void deleteIfExists() throws IOException {
zfs.deleteFile(getResolvedPath(), false);
}
ZipFileAttributes getAttributes() throws IOException
{
ZipFileAttributes zfas = zfs.getFileAttributes(getResolvedPath());
if (zfas == null)
throw new NoSuchFileException(toString());
return zfas;
}
@Override
@SuppressWarnings("unchecked")
public <V extends FileAttributeView> V getFileAttributeView(Class<V> type,
LinkOption... options)
{
return (V)ZipFileAttributeView.get(this, type);
}
@Override
public void setAttribute(String attribute,
Object value,
LinkOption... options)
throws IOException
{
String type = null;
String attr = null;
int colonPos = attribute.indexOf(':');
if (colonPos == -1) {
type = "basic";
attr = attribute;
} else {
type = attribute.substring(0, colonPos++);
attr = attribute.substring(colonPos);
}
ZipFileAttributeView view = ZipFileAttributeView.get(this, type);
if (view == null)
throw new UnsupportedOperationException("view <" + view + "> is not supported");
view.setAttribute(attr, value);
}
void setTimes(FileTime mtime, FileTime atime, FileTime ctime)
throws IOException
{
zfs.setTimes(getResolvedPath(), mtime, atime, ctime);
}
private Object getAttributesImpl(String attribute, boolean domap)
throws IOException
{
String view = null;
String attr = null;
int colonPos = attribute.indexOf(':');
if (colonPos == -1) {
view = "basic";
attr = attribute;
} else {
view = attribute.substring(0, colonPos++);
attr = attribute.substring(colonPos);
}
ZipFileAttributeView zfv = ZipFileAttributeView.get(this, view);
if (zfv == null) {
throw new UnsupportedOperationException("view not supported");
}
return zfv.getAttribute(attr, domap);
}
@Override
public Object getAttribute(String attribute, LinkOption... options)
throws IOException
{
return getAttributesImpl(attribute, false);
}
@Override
public Map<String,?> readAttributes(String attribute, LinkOption... options)
throws IOException
{
return (Map<String, ?>)getAttributesImpl(attribute, true);
}
@Override
public FileStore getFileStore() throws IOException {
// each ZipFileSystem only has one root (as requested for now)
if (exists())
return zfs.getFileStore(this);
throw new NoSuchFileException(zfs.getString(path));
}
@Override
public boolean isSameFile(Path other) throws IOException {
if (other == null ||
this.getFileSystem() != other.getFileSystem())
return false;
this.checkAccess();
other.checkAccess();
return Arrays.equals(this.getResolvedPath(),
((ZipPath)other).getResolvedPath());
}
public WatchKey register(
WatchService watcher,
WatchEvent.Kind<?>[] events,
WatchEvent.Modifier... modifiers) {
if (watcher == null || events == null || modifiers == null) {
throw new NullPointerException();
}
throw new UnsupportedOperationException();
}
@Override
public WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) {
return register(watcher, events, new WatchEvent.Modifier[0]);
}
@Override
public Iterator<Path> iterator() {
return new Iterator<Path>() {
private int i = 0;
@Override
public boolean hasNext() {
return (i < getNameCount());
}
@Override
public Path next() {
if (i < getNameCount()) {
Path result = getName(i);
i++;
return result;
} else {
throw new NoSuchElementException();
}
}
@Override
public void remove() {
throw new ReadOnlyFileSystemException();
}
};
}
@Override
public SeekableByteChannel newByteChannel(Set<? extends OpenOption> options,
FileAttribute<?>... attrs)
throws IOException
{
return zfs.newByteChannel(getResolvedPath(), options, attrs);
}
FileChannel newFileChannel(Set<? extends OpenOption> options,
FileAttribute<?>... attrs)
throws IOException
{
return zfs.newFileChannel(getResolvedPath(), options, attrs);
}
@Override
public SeekableByteChannel newByteChannel(OpenOption... options)
throws IOException {
Set<OpenOption> set = new HashSet<OpenOption>(options.length);
Collections.addAll(set, options);
return newByteChannel(set);
}
@Override
public void checkAccess(AccessMode... modes) throws IOException {
boolean w = false;
boolean x = false;
for (AccessMode mode : modes) {
switch (mode) {
case READ:
break;
case WRITE:
w = true;
break;
case EXECUTE:
x = true;
break;
default:
throw new UnsupportedOperationException();
}
}
ZipFileAttributes attrs = zfs.getFileAttributes(getResolvedPath());
if (attrs == null && (path.length != 1 || path[0] != '/'))
throw new NoSuchFileException(toString());
if (w) {
if (zfs.isReadOnly())
throw new AccessDeniedException(toString());
}
if (x)
throw new AccessDeniedException(toString());
}
@Override
public boolean exists() {
if (path.length == 1 && path[0] == '/')
return true;
try {
return zfs.exists(getResolvedPath());
} catch (IOException x) {}
return false;
}
@Override
public boolean notExists() {
return !exists();
}
@Override
public OutputStream newOutputStream(OpenOption... options)
throws IOException
{
if (options.length == 0)
return zfs.newOutputStream(getResolvedPath(),
CREATE_NEW, WRITE);
return zfs.newOutputStream(getResolvedPath(), options);
}
@Override
public Path moveTo(Path target, CopyOption... options)
throws IOException
{
if (this.zfs.provider() == target.getFileSystem().provider() &&
this.zfs.getZipFile().isSameFile(((ZipPath)target).zfs.getZipFile()))
{
zfs.copyFile(true,
getResolvedPath(),
((ZipPath)target).getResolvedPath(),
options);
} else {
copyToTarget(target, options);
delete();
}
return target;
}
@Override
public Path copyTo(Path target, CopyOption... options)
throws IOException
{
if (this.zfs.provider() == target.getFileSystem().provider() &&
this.zfs.getZipFile().isSameFile(((ZipPath)target).zfs.getZipFile()))
{
zfs.copyFile(false,
getResolvedPath(),
((ZipPath)target).getResolvedPath(),
options);
} else {
copyToTarget(target, options);
}
return target;
}
private void copyToTarget(Path target, CopyOption... options)
throws IOException
{
boolean replaceExisting = false;
boolean copyAttrs = false;
for (CopyOption opt : options) {
if (opt == REPLACE_EXISTING)
replaceExisting = true;
else if (opt == COPY_ATTRIBUTES)
copyAttrs = false;
}
// attributes of source file
ZipFileAttributes zfas = getAttributes();
// check if target exists
boolean exists;
if (replaceExisting) {
try {
target.deleteIfExists();
exists = false;
} catch (DirectoryNotEmptyException x) {
exists = true;
}
} else {
exists = target.exists();
}
if (exists)
throw new FileAlreadyExistsException(target.toString());
if (zfas.isDirectory()) {
// create directory or file
target.createDirectory();
} else {
InputStream is = zfs.newInputStream(getResolvedPath());
try {
OutputStream os = target.newOutputStream();
try {
byte[] buf = new byte[8192];
int n = 0;
while ((n = is.read(buf)) != -1) {
os.write(buf, 0, n);
}
} finally {
os.close();
}
} finally {
is.close();
}
}
if (copyAttrs) {
BasicFileAttributeView view =
target.getFileAttributeView(BasicFileAttributeView.class);
try {
view.setTimes(zfas.lastModifiedTime(), null, null);
} catch (IOException x) {
// rollback?
try {
target.delete();
} catch (IOException ignore) { }
throw x;
}
}
}
}

View File

@ -0,0 +1,289 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.nio.zipfs;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Date;
import java.util.regex.PatternSyntaxException;
/**
*
* @author Xueming Shen
*/
class ZipUtils {
/*
* Writes a 16-bit short to the output stream in little-endian byte order.
*/
public static void writeShort(OutputStream os, int v) throws IOException {
os.write((v >>> 0) & 0xff);
os.write((v >>> 8) & 0xff);
}
/*
* Writes a 32-bit int to the output stream in little-endian byte order.
*/
public static void writeInt(OutputStream os, long v) throws IOException {
os.write((int)((v >>> 0) & 0xff));
os.write((int)((v >>> 8) & 0xff));
os.write((int)((v >>> 16) & 0xff));
os.write((int)((v >>> 24) & 0xff));
}
/*
* Writes a 64-bit int to the output stream in little-endian byte order.
*/
public static void writeLong(OutputStream os, long v) throws IOException {
os.write((int)((v >>> 0) & 0xff));
os.write((int)((v >>> 8) & 0xff));
os.write((int)((v >>> 16) & 0xff));
os.write((int)((v >>> 24) & 0xff));
os.write((int)((v >>> 32) & 0xff));
os.write((int)((v >>> 40) & 0xff));
os.write((int)((v >>> 48) & 0xff));
os.write((int)((v >>> 56) & 0xff));
}
/*
* Writes an array of bytes to the output stream.
*/
public static void writeBytes(OutputStream os, byte[] b)
throws IOException
{
os.write(b, 0, b.length);
}
/*
* Writes an array of bytes to the output stream.
*/
public static void writeBytes(OutputStream os, byte[] b, int off, int len)
throws IOException
{
os.write(b, off, len);
}
/*
* Append a slash at the end, if it does not have one yet
*/
public static byte[] toDirectoryPath(byte[] dir) {
if (dir.length != 0 && dir[dir.length - 1] != '/') {
dir = Arrays.copyOf(dir, dir.length + 1);
dir[dir.length - 1] = '/';
}
return dir;
}
/*
* Converts DOS time to Java time (number of milliseconds since epoch).
*/
public static long dosToJavaTime(long dtime) {
Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
(int)(((dtime >> 21) & 0x0f) - 1),
(int)((dtime >> 16) & 0x1f),
(int)((dtime >> 11) & 0x1f),
(int)((dtime >> 5) & 0x3f),
(int)((dtime << 1) & 0x3e));
return d.getTime();
}
/*
* Converts Java time to DOS time.
*/
public static long javaToDosTime(long time) {
Date d = new Date(time);
int year = d.getYear() + 1900;
if (year < 1980) {
return (1 << 21) | (1 << 16);
}
return (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
d.getSeconds() >> 1;
}
private static final String regexMetaChars = ".^$+{[]|()";
private static final String globMetaChars = "\\*?[{";
private static boolean isRegexMeta(char c) {
return regexMetaChars.indexOf(c) != -1;
}
private static boolean isGlobMeta(char c) {
return globMetaChars.indexOf(c) != -1;
}
private static char EOL = 0; //TBD
private static char next(String glob, int i) {
if (i < glob.length()) {
return glob.charAt(i);
}
return EOL;
}
/*
* Creates a regex pattern from the given glob expression.
*
* @throws PatternSyntaxException
*/
public static String toRegexPattern(String globPattern) {
boolean inGroup = false;
StringBuilder regex = new StringBuilder("^");
int i = 0;
while (i < globPattern.length()) {
char c = globPattern.charAt(i++);
switch (c) {
case '\\':
// escape special characters
if (i == globPattern.length()) {
throw new PatternSyntaxException("No character to escape",
globPattern, i - 1);
}
char next = globPattern.charAt(i++);
if (isGlobMeta(next) || isRegexMeta(next)) {
regex.append('\\');
}
regex.append(next);
break;
case '/':
regex.append(c);
break;
case '[':
// don't match name separator in class
regex.append("[[^/]&&[");
if (next(globPattern, i) == '^') {
// escape the regex negation char if it appears
regex.append("\\^");
i++;
} else {
// negation
if (next(globPattern, i) == '!') {
regex.append('^');
i++;
}
// hyphen allowed at start
if (next(globPattern, i) == '-') {
regex.append('-');
i++;
}
}
boolean hasRangeStart = false;
char last = 0;
while (i < globPattern.length()) {
c = globPattern.charAt(i++);
if (c == ']') {
break;
}
if (c == '/') {
throw new PatternSyntaxException("Explicit 'name separator' in class",
globPattern, i - 1);
}
// TBD: how to specify ']' in a class?
if (c == '\\' || c == '[' ||
c == '&' && next(globPattern, i) == '&') {
// escape '\', '[' or "&&" for regex class
regex.append('\\');
}
regex.append(c);
if (c == '-') {
if (!hasRangeStart) {
throw new PatternSyntaxException("Invalid range",
globPattern, i - 1);
}
if ((c = next(globPattern, i++)) == EOL || c == ']') {
break;
}
if (c < last) {
throw new PatternSyntaxException("Invalid range",
globPattern, i - 3);
}
regex.append(c);
hasRangeStart = false;
} else {
hasRangeStart = true;
last = c;
}
}
if (c != ']') {
throw new PatternSyntaxException("Missing ']", globPattern, i - 1);
}
regex.append("]]");
break;
case '{':
if (inGroup) {
throw new PatternSyntaxException("Cannot nest groups",
globPattern, i - 1);
}
regex.append("(?:(?:");
inGroup = true;
break;
case '}':
if (inGroup) {
regex.append("))");
inGroup = false;
} else {
regex.append('}');
}
break;
case ',':
if (inGroup) {
regex.append(")|(?:");
} else {
regex.append(',');
}
break;
case '*':
if (next(globPattern, i) == '*') {
// crosses directory boundaries
regex.append(".*");
i++;
} else {
// within directory boundary
regex.append("[^/]*");
}
break;
case '?':
regex.append("[^/]");
break;
default:
if (isRegexMeta(c)) {
regex.append('\\');
}
regex.append(c);
}
}
if (inGroup) {
throw new PatternSyntaxException("Missing '}", globPattern, i - 1);
}
return regex.append('$').toString();
}
}

View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2009, 2010, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.nio.file.spi.FileSystemProvider;
import java.util.*;
import java.net.URI;
import java.io.IOException;
/**
* Basic test for zip provider
*/
public class Basic {
public static void main(String[] args) throws Exception {
Path zipfile = Paths.get(args[0]);
// Test: zip should should be returned in provider list
boolean found = false;
for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
if (provider.getScheme().equalsIgnoreCase("zip")) {
found = true;
break;
}
}
if (!found)
throw new RuntimeException("'zip' provider not installed");
// Test: FileSystems#newFileSystem(FileRef)
Map<String,?> env = new HashMap<String,Object>();
FileSystems.newFileSystem(zipfile, env, null).close();
// Test: FileSystems#newFileSystem(URI)
URI uri = URI.create("zip" + zipfile.toUri().toString().substring(4));
FileSystem fs = FileSystems.newFileSystem(uri, env, null);
// Test: exercise toUri method
String expected = uri.toString() + "#/foo";
String actual = fs.getPath("/foo").toUri().toString();
if (!actual.equals(expected)) {
throw new RuntimeException("toUri returned '" + actual +
"', expected '" + expected + "'");
}
// Test: exercise directory iterator and retrieval of basic attributes
Files.walkFileTree(fs.getPath("/"), new FileTreePrinter());
// Test: DirectoryStream
found = false;
DirectoryStream<Path> stream = fs.getPath("/").newDirectoryStream();
try {
for (Path entry: stream) {
found = entry.toString().equals("/META-INF/");
if (found) break;
}
} finally {
stream.close();
}
if (!found)
throw new RuntimeException("Expected file not found");
// Test: copy file from zip file to current (scratch) directory
Path source = fs.getPath("/META-INF/services/java.nio.file.spi.FileSystemProvider");
if (source.exists()) {
Path target = Paths.get(source.getName().toString());
source.copyTo(target, StandardCopyOption.REPLACE_EXISTING);
try {
long s1 = Attributes.readBasicFileAttributes(source).size();
long s2 = Attributes.readBasicFileAttributes(target).size();
if (s2 != s1)
throw new RuntimeException("target size != source size");
} finally {
target.delete();
}
}
// Test: FileStore
FileStore store = fs.getPath("/").getFileStore();
if (!store.supportsFileAttributeView("basic"))
throw new RuntimeException("BasicFileAttributeView should be supported");
// Test: ClosedFileSystemException
fs.close();
if (fs.isOpen())
throw new RuntimeException("FileSystem should be closed");
try {
fs.getPath("/missing").checkAccess(AccessMode.READ);
} catch (ClosedFileSystemException x) { }
}
// FileVisitor that pretty prints a file tree
static class FileTreePrinter extends SimpleFileVisitor<Path> {
private int indent = 0;
private void indent() {
StringBuilder sb = new StringBuilder(indent);
for (int i=0; i<indent; i++) sb.append(" ");
System.out.print(sb);
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs)
{
if (dir.getName() != null) {
indent();
System.out.println(dir.getName() + "/");
indent++;
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs)
{
indent();
System.out.print(file.getName());
if (attrs.isRegularFile())
System.out.format(" (%d)", attrs.size());
System.out.println();
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
throws IOException
{
if (exc != null)
super.postVisitDirectory(dir, exc);
if (dir.getName() != null)
indent--;
return FileVisitResult.CONTINUE;
}
}
}

View File

@ -0,0 +1,416 @@
/*
* Copyright (c) 2009, 2010, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.nio.file.*;
import java.net.*;
import java.util.*;
import java.io.IOException;
/**
* Tests path operations for zip provider.
*/
public class PathOps {
static final java.io.PrintStream out = System.out;
static FileSystem fs;
private String input;
private Path path;
private Exception exc;
private PathOps(String s) {
out.println();
input = s;
try {
path = fs.getPath(s);
out.format("%s -> %s", s, path);
} catch (Exception x) {
exc = x;
out.format("%s -> %s", s, x);
}
out.println();
}
Path path() {
return path;
}
void fail() {
throw new RuntimeException("PathOps failed");
}
void checkPath() {
if (path == null) {
throw new InternalError("path is null");
}
}
void check(Object result, String expected) {
out.format("\tExpected: %s\n", expected);
out.format("\tActual: %s\n", result);
if (result == null) {
if (expected == null) return;
} else {
// compare string representations
if (expected != null && result.toString().equals(expected.toString()))
return;
}
fail();
}
void check(Object result, boolean expected) {
check(result, Boolean.toString(expected));
}
PathOps root(String expected) {
out.println("check root");
checkPath();
check(path.getRoot(), expected);
return this;
}
PathOps parent(String expected) {
out.println("check parent");
checkPath();
check(path.getParent(), expected);
return this;
}
PathOps name(String expected) {
out.println("check name");
checkPath();
check(path.getName(), expected);
return this;
}
PathOps element(int index, String expected) {
out.format("check element %d\n", index);
checkPath();
check(path.getName(index), expected);
return this;
}
PathOps subpath(int startIndex, int endIndex, String expected) {
out.format("test subpath(%d,%d)\n", startIndex, endIndex);
checkPath();
check(path.subpath(startIndex, endIndex), expected);
return this;
}
PathOps starts(String prefix) {
out.format("test startsWith with %s\n", prefix);
checkPath();
Path s = fs.getPath(prefix);
check(path.startsWith(s), true);
return this;
}
PathOps notStarts(String prefix) {
out.format("test not startsWith with %s\n", prefix);
checkPath();
Path s = fs.getPath(prefix);
check(path.startsWith(s), false);
return this;
}
PathOps ends(String suffix) {
out.format("test endsWith %s\n", suffix);
checkPath();
Path s = fs.getPath(suffix);
check(path.endsWith(s), true);
return this;
}
PathOps notEnds(String suffix) {
out.format("test not endsWith %s\n", suffix);
checkPath();
Path s = fs.getPath(suffix);
check(path.endsWith(s), false);
return this;
}
PathOps absolute() {
out.println("check path is absolute");
checkPath();
check(path.isAbsolute(), true);
return this;
}
PathOps notAbsolute() {
out.println("check path is not absolute");
checkPath();
check(path.isAbsolute(), false);
return this;
}
PathOps resolve(String other, String expected) {
out.format("test resolve %s\n", other);
checkPath();
check(path.resolve(other), expected);
return this;
}
PathOps relativize(String other, String expected) {
out.format("test relativize %s\n", other);
checkPath();
Path that = fs.getPath(other);
check(path.relativize(that), expected);
return this;
}
PathOps normalize(String expected) {
out.println("check normalized path");
checkPath();
check(path.normalize(), expected);
return this;
}
PathOps string(String expected) {
out.println("check string representation");
checkPath();
check(path, expected);
return this;
}
PathOps invalid() {
if (!(exc instanceof InvalidPathException)) {
out.println("InvalidPathException not thrown as expected");
fail();
}
return this;
}
static PathOps test(String s) {
return new PathOps(s);
}
// -- PathOpss --
static void header(String s) {
out.println();
out.println();
out.println("-- " + s + " --");
}
static void doPathOpTests() {
header("Path operations");
// all components
test("/a/b/c")
.root("/")
.parent("/a/b")
.name("c");
// root component only
test("/")
.root("/")
.parent(null)
.name(null);
// no root component
test("a/b")
.root(null)
.parent("a")
.name("b");
// name component only
test("foo")
.root(null)
.parent(null)
.name("foo");
// startsWith
test("/")
.starts("/")
.notStarts("/foo");
test("/foo")
.starts("/")
.starts("/foo")
.notStarts("/f");
test("/foo/bar")
.starts("/")
.starts("/foo")
.starts("/foo/bar")
.notStarts("/f")
.notStarts("foo")
.notStarts("foo/bar");
test("foo")
.starts("foo")
.notStarts("f");
test("foo/bar")
.starts("foo")
.starts("foo/bar")
.notStarts("f")
.notStarts("/foo")
.notStarts("/foo/bar");
// endsWith
test("/")
.ends("/")
.notEnds("foo")
.notEnds("/foo");
test("/foo")
.ends("foo")
.ends("/foo")
.notEnds("/");
test("/foo/bar")
.ends("bar")
.ends("foo/bar")
.ends("/foo/bar")
.notEnds("/bar");
test("foo")
.ends("foo");
test("foo/bar")
.ends("bar")
.ends("foo/bar");
// elements
test("a/b/c")
.element(0,"a")
.element(1,"b")
.element(2,"c");
// isAbsolute
test("/")
.absolute();
test("/tmp")
.absolute();
test("tmp")
.notAbsolute();
// resolve
test("/tmp")
.resolve("foo", "/tmp/foo")
.resolve("/foo", "/foo");
test("tmp")
.resolve("foo", "tmp/foo")
.resolve("/foo", "/foo");
// relativize
test("/a/b/c")
.relativize("/a/b/c", null)
.relativize("/a/b/c/d/e", "d/e")
.relativize("/a/x", "../../x");
// normalize
test("/")
.normalize("/");
test("foo")
.normalize("foo");
test("/foo")
.normalize("/foo");
test(".")
.normalize(null);
test("..")
.normalize("..");
test("/..")
.normalize("/");
test("/../..")
.normalize("/");
test("foo/.")
.normalize("foo");
test("./foo")
.normalize("foo");
test("foo/..")
.normalize(null);
test("../foo")
.normalize("../foo");
test("../../foo")
.normalize("../../foo");
test("foo/bar/..")
.normalize("foo");
test("foo/bar/gus/../..")
.normalize("foo");
test("/foo/bar/gus/../..")
.normalize("/foo");
// invalid
test("foo\u0000bar")
.invalid();
test("\u0000foo")
.invalid();
test("bar\u0000")
.invalid();
test("//foo\u0000bar")
.invalid();
test("//\u0000foo")
.invalid();
test("//bar\u0000")
.invalid();
// normalization
test("//foo//bar")
.string("/foo/bar")
.root("/")
.parent("/foo")
.name("bar");
}
static void npes() {
header("NullPointerException");
Path path = fs.getPath("foo");
try {
path.resolve((String)null);
throw new RuntimeException("NullPointerException not thrown");
} catch (NullPointerException npe) {
}
try {
path.relativize(null);
throw new RuntimeException("NullPointerException not thrown");
} catch (NullPointerException npe) {
}
try {
path.compareTo(null);
throw new RuntimeException("NullPointerException not thrown");
} catch (NullPointerException npe) {
}
try {
path.startsWith(null);
throw new RuntimeException("NullPointerException not thrown");
} catch (NullPointerException npe) {
}
try {
path.endsWith(null);
throw new RuntimeException("NullPointerException not thrown");
} catch (NullPointerException npe) {
}
}
public static void main(String[] args) throws Throwable {
Path zipfile = Paths.get(args[0]);
Map<String,?> env = new HashMap<String,Object>();
fs = FileSystems.newFileSystem(zipfile, env, null);
npes();
doPathOpTests();
fs.close();
}
}

View File

@ -0,0 +1,633 @@
/*
* Copyright (c) 2010 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.net.*;
import java.util.*;
import static java.nio.file.StandardOpenOption.*;
import static java.nio.file.StandardCopyOption.*;
/*
* Tests various zipfs operations.
*/
public class ZipFSTester {
public static void main(String[] args) throws Throwable {
FileSystem fs = null;
try {
fs = newZipFileSystem(Paths.get(args[0]), new HashMap<String, Object>());
test(fs);
test2(fs); // more tests
} finally {
if (fs != null)
fs.close();
}
}
static void test(FileSystem fs)
throws Exception
{
Random rdm = new Random();
// clone a fs and test on it
Path tmpfsPath = getTempPath();
Map<String, Object> env = new HashMap<String, Object>();
env.put("createNew", true);
FileSystem fs0 = newZipFileSystem(tmpfsPath, env);
z2zcopy(fs, fs0, "/", 0);
fs0.close(); // sync to file
fs = newZipFileSystem(tmpfsPath, new HashMap<String, Object>());
try {
// prepare a src
Path src = getTempPath();
String tmpName = src.toString();
OutputStream os = src.newOutputStream();
byte[] bits = new byte[12345];
rdm.nextBytes(bits);
os.write(bits);
os.close();
// copyin
Path dst = getPathWithParents(fs, tmpName);
src.copyTo(dst);
checkEqual(src, dst);
// copy
Path dst2 = getPathWithParents(fs, "/xyz" + rdm.nextInt(100) +
"/efg" + rdm.nextInt(100) + "/foo.class");
dst.copyTo(dst2);
//dst.moveTo(dst2);
checkEqual(src, dst2);
// delete
dst.delete();
if (dst.exists())
throw new RuntimeException("Failed!");
// moveout
Path dst3 = Paths.get(tmpName + "_Tmp");
dst2.moveTo(dst3);
checkEqual(src, dst3);
// delete
if (dst2.exists())
throw new RuntimeException("Failed!");
dst3.delete();
if (dst3.exists())
throw new RuntimeException("Failed!");
// newInputStream on dir
Path parent = dst2.getParent();
try {
parent.newInputStream();
throw new RuntimeException("Failed");
} catch (FileSystemException e) {
e.printStackTrace(); // expected fse
}
// rmdirs
try {
rmdirs(parent);
} catch (IOException x) {
x.printStackTrace();
}
// newFileChannel() copy in, out and verify via fch
fchCopy(src, dst); // in
checkEqual(src, dst);
Path tmp = Paths.get(tmpName + "_Tmp");
fchCopy(dst, tmp); // out
checkEqual(src, tmp);
tmp.delete();
// test channels
channel(fs, dst);
dst.delete();
src.delete();
} finally {
if (fs != null)
fs.close();
if (tmpfsPath.exists())
tmpfsPath.delete();
}
}
static void test2(FileSystem fs) throws Exception {
Path fs1Path = getTempPath();
Path fs2Path = getTempPath();
Path fs3Path = getTempPath();
if (fs1Path.exists())
fs1Path.delete();
if (fs2Path.exists())
fs2Path.delete();
if (fs3Path.exists())
fs3Path.delete();
// create a new filesystem, copy everything from fs
Map<String, Object> env = new HashMap<String, Object>();
env.put("createNew", true);
FileSystem fs0 = newZipFileSystem(fs1Path, env);
final FileSystem fs2 = newZipFileSystem(fs2Path, env);
final FileSystem fs3 = newZipFileSystem(fs3Path, env);
System.out.println("copy src: fs -> fs0...");
z2zcopy(fs, fs0, "/", 0); // copy fs -> fs1
fs0.close(); // dump to file
System.out.println("open fs0 as fs1");
env = new HashMap<String, Object>();
final FileSystem fs1 = newZipFileSystem(fs1Path, env);
System.out.println("listing...");
final ArrayList<String> files = new ArrayList<>();
final ArrayList<String> dirs = new ArrayList<>();
list(fs1.getPath("/"), files, dirs);
Thread t0 = new Thread(new Runnable() {
public void run() {
List<String> list = new ArrayList<>(dirs);
Collections.shuffle(list);
for (String path : list) {
try {
z2zcopy(fs1, fs2, path, 0);
} catch (Exception x) {
x.printStackTrace();
}
}
}
});
Thread t1 = new Thread(new Runnable() {
public void run() {
List<String> list = new ArrayList<>(dirs);
Collections.shuffle(list);
for (String path : list) {
try {
z2zcopy(fs1, fs2, path, 1);
} catch (Exception x) {
x.printStackTrace();
}
}
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
List<String> list = new ArrayList<>(dirs);
Collections.shuffle(list);
for (String path : list) {
try {
z2zcopy(fs1, fs2, path, 2);
} catch (Exception x) {
x.printStackTrace();
}
}
}
});
Thread t3 = new Thread(new Runnable() {
public void run() {
List<String> list = new ArrayList<>(files);
Collections.shuffle(list);
while (!list.isEmpty()) {
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String path = itr.next();
try {
if (fs2.getPath(path).exists()) {
z2zmove(fs2, fs3, path);
itr.remove();
}
} catch (FileAlreadyExistsException x){
itr.remove();
} catch (Exception x) {
x.printStackTrace();
}
}
}
}
});
System.out.println("copying/removing...");
t0.start(); t1.start(); t2.start(); t3.start();
t0.join(); t1.join(); t2.join(); t3.join();
System.out.println("closing: fs1, fs2");
fs1.close();
fs2.close();
int failed = 0;
System.out.println("checkEqual: fs vs fs3");
for (String path : files) {
try {
checkEqual(fs.getPath(path), fs3.getPath(path));
} catch (IOException x) {
//x.printStackTrace();
failed++;
}
}
System.out.println("closing: fs3");
fs3.close();
System.out.println("opening: fs3 as fs4");
FileSystem fs4 = newZipFileSystem(fs3Path, env);
ArrayList<String> files2 = new ArrayList<>();
ArrayList<String> dirs2 = new ArrayList<>();
list(fs4.getPath("/"), files2, dirs2);
System.out.println("checkEqual: fs vs fs4");
for (String path : files2) {
checkEqual(fs.getPath(path), fs4.getPath(path));
}
System.out.println("walking: fs4");
walk(fs4.getPath("/"));
System.out.println("closing: fs4");
fs4.close();
System.out.printf("failed=%d%n", failed);
fs1Path.delete();
fs2Path.delete();
fs3Path.delete();
}
private static FileSystem newZipFileSystem(Path path, Map<String, ?> env)
throws IOException
{
return FileSystems.newFileSystem(
URI.create("zip" +
path.toUri().toString().substring(4)),
env,
null);
}
private static Path getTempPath() throws IOException
{
File tmp = File.createTempFile("testzipfs_", "zip");
tmp.delete(); // we need a clean path, no file
return tmp.toPath();
}
private static void list(Path path, List<String> files, List<String> dirs )
throws IOException
{
if (Attributes.readBasicFileAttributes(path).isDirectory()) {
DirectoryStream<Path> ds = path.newDirectoryStream();
for (Path child : ds)
list(child, files, dirs);
ds.close();
dirs.add(path.toString());
} else {
files.add(path.toString());
}
}
private static void z2zcopy(FileSystem src, FileSystem dst, String path,
int method)
throws IOException
{
Path srcPath = src.getPath(path);
Path dstPath = dst.getPath(path);
if (Boolean.TRUE.equals(srcPath.getAttribute("isDirectory"))) {
if (!dstPath.exists()) {
try {
mkdirs(dstPath);
} catch (FileAlreadyExistsException x) {}
}
DirectoryStream<Path> ds = srcPath.newDirectoryStream();
for (Path child : ds) {
z2zcopy(src, dst,
path + (path.endsWith("/")?"":"/") + child.getName(),
method);
}
ds.close();
} else {
try {
if (dstPath.exists())
return;
switch (method) {
case 0:
srcPath.copyTo(dstPath);
break;
case 1:
chCopy(srcPath, dstPath);
break;
case 2:
//fchCopy(srcPath, dstPath);
streamCopy(srcPath, dstPath);
break;
}
} catch (FileAlreadyExistsException x) {}
}
}
private static void z2zmove(FileSystem src, FileSystem dst, String path)
throws IOException
{
Path srcPath = src.getPath(path);
Path dstPath = dst.getPath(path);
if (Boolean.TRUE.equals(srcPath.getAttribute("isDirectory"))) {
if (!dstPath.exists())
mkdirs(dstPath);
DirectoryStream<Path> ds = srcPath.newDirectoryStream();
for (Path child : ds) {
z2zmove(src, dst,
path + (path.endsWith("/")?"":"/") + child.getName());
}
ds.close();
} else {
//System.out.println("moving..." + path);
Path parent = dstPath.getParent();
if (parent != null && parent.notExists())
mkdirs(parent);
srcPath.moveTo(dstPath);
}
}
private static void walk(Path path) throws IOException
{
Files.walkFileTree(
path,
new SimpleFileVisitor<Path>() {
private int indent = 0;
private void indent() {
int n = 0;
while (n++ < indent)
System.out.printf(" ");
}
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs)
{
indent();
System.out.printf("%s%n", file.getName().toString());
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs)
{
indent();
System.out.printf("[%s]%n", dir.toString());
indent += 2;
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir,
IOException ioe)
throws IOException
{
indent -= 2;
return FileVisitResult.CONTINUE;
}
});
}
private static void mkdirs(Path path) throws IOException {
path = path.toAbsolutePath();
Path parent = path.getParent();
if (parent != null) {
if (parent.notExists())
mkdirs(parent);
}
path.createDirectory();
}
private static void rmdirs(Path path) throws IOException {
while (path != null && path.getNameCount() != 0) {
path.delete();
path = path.getParent();
}
}
// check the content of two paths are equal
private static void checkEqual(Path src, Path dst) throws IOException
{
//System.out.printf("checking <%s> vs <%s>...%n",
// src.toString(), dst.toString());
//streams
InputStream isSrc = src.newInputStream();
InputStream isDst = dst.newInputStream();
byte[] bufSrc = new byte[8192];
byte[] bufDst = new byte[8192];
try {
int nSrc = 0;
while ((nSrc = isSrc.read(bufSrc)) != -1) {
int nDst = 0;
while (nDst < nSrc) {
int n = isDst.read(bufDst, nDst, nSrc - nDst);
if (n == -1) {
System.out.printf("checking <%s> vs <%s>...%n",
src.toString(), dst.toString());
throw new RuntimeException("CHECK FAILED!");
}
nDst += n;
}
while (--nSrc >= 0) {
if (bufSrc[nSrc] != bufDst[nSrc]) {
System.out.printf("checking <%s> vs <%s>...%n",
src.toString(), dst.toString());
throw new RuntimeException("CHECK FAILED!");
}
nSrc--;
}
}
} finally {
isSrc.close();
isDst.close();
}
// channels
SeekableByteChannel chSrc = src.newByteChannel();
SeekableByteChannel chDst = dst.newByteChannel();
if (chSrc.size() != chDst.size()) {
System.out.printf("src[%s].size=%d, dst[%s].size=%d%n",
chSrc.toString(), chSrc.size(),
chDst.toString(), chDst.size());
throw new RuntimeException("CHECK FAILED!");
}
ByteBuffer bbSrc = ByteBuffer.allocate(8192);
ByteBuffer bbDst = ByteBuffer.allocate(8192);
try {
int nSrc = 0;
while ((nSrc = chSrc.read(bbSrc)) != -1) {
int nDst = chDst.read(bbDst);
if (nSrc != nDst) {
System.out.printf("checking <%s> vs <%s>...%n",
src.toString(), dst.toString());
throw new RuntimeException("CHECK FAILED!");
}
while (--nSrc >= 0) {
if (bbSrc.get(nSrc) != bbDst.get(nSrc)) {
System.out.printf("checking <%s> vs <%s>...%n",
src.toString(), dst.toString());
throw new RuntimeException("CHECK FAILED!");
}
nSrc--;
}
bbSrc.flip();
bbDst.flip();
}
} catch (IOException x) {
x.printStackTrace();
} finally {
chSrc.close();
chDst.close();
}
}
private static void fchCopy(Path src, Path dst) throws IOException
{
Set<OpenOption> read = new HashSet<>();
read.add(READ);
Set<OpenOption> openwrite = new HashSet<>();
openwrite.add(CREATE_NEW);
openwrite.add(WRITE);
FileChannel srcFc = src.getFileSystem()
.provider()
.newFileChannel(src, read);
FileChannel dstFc = dst.getFileSystem()
.provider()
.newFileChannel(dst, openwrite);
try {
ByteBuffer bb = ByteBuffer.allocate(8192);
while (srcFc.read(bb) >= 0) {
bb.flip();
dstFc.write(bb);
bb.clear();
}
} finally {
srcFc.close();
dstFc.close();
}
}
private static void chCopy(Path src, Path dst) throws IOException
{
Set<OpenOption> read = new HashSet<>();
read.add(READ);
Set<OpenOption> openwrite = new HashSet<>();
openwrite.add(CREATE_NEW);
openwrite.add(WRITE);
SeekableByteChannel srcCh = src.newByteChannel(read);
SeekableByteChannel dstCh = dst.newByteChannel(openwrite);
try {
ByteBuffer bb = ByteBuffer.allocate(8192);
while (srcCh.read(bb) >= 0) {
bb.flip();
dstCh.write(bb);
bb.clear();
}
} finally {
srcCh.close();
dstCh.close();
}
}
private static void streamCopy(Path src, Path dst) throws IOException
{
InputStream isSrc = src.newInputStream();
OutputStream osDst = dst.newOutputStream();
byte[] buf = new byte[8192];
try {
int n = 0;
while ((n = isSrc.read(buf)) != -1) {
osDst.write(buf, 0, n);
}
} finally {
isSrc.close();
osDst.close();
}
}
static void channel(FileSystem fs, Path path)
throws Exception
{
System.out.println("test ByteChannel...");
SeekableByteChannel sbc = path.newByteChannel();
Set<OpenOption> read = new HashSet<>();
read.add(READ);
System.out.printf(" sbc[0]: pos=%d, size=%d%n", sbc.position(), sbc.size());
ByteBuffer bb = ByteBuffer.allocate((int)sbc.size());
int n = sbc.read(bb);
System.out.printf(" sbc[1]: read=%d, pos=%d, size=%d%n",
n, sbc.position(), sbc.size());
ByteBuffer bb2 = ByteBuffer.allocate((int)sbc.size());
int N = 120;
sbc.close();
// sbc.position(pos) is not supported in current version
// try the FileChannel
sbc = fs.provider().newFileChannel(path, read);
sbc.position(N);
System.out.printf(" sbc[2]: pos=%d, size=%d%n",
sbc.position(), sbc.size());
bb2.limit(100);
n = sbc.read(bb2);
System.out.printf(" sbc[3]: read=%d, pos=%d, size=%d%n",
n, sbc.position(), sbc.size());
System.out.printf(" sbc[4]: bb[%d]=%d, bb1[0]=%d%n",
N, bb.get(N) & 0xff, bb2.get(0) & 0xff);
sbc.close();
}
// create parents if does not exist
static Path getPathWithParents(FileSystem fs, String name)
throws Exception
{
Path path = fs.getPath(name);
Path parent = path.getParent();
if (parent != null && parent.notExists())
mkdirs(parent);
return path;
}
}

View File

@ -0,0 +1,73 @@
#
# Copyright (c) 2009, 2010, 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
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# @test
# @bug 6990846
# @summary Test ZipFileSystem demo
# @build Basic PathOps ZipFSTester
# @run shell basic.sh
if [ -z "${TESTJAVA}" ]; then
echo "Test must be run with jtreg"
exit 0
fi
ZIPFS="${TESTJAVA}/demo/nio/zipfs/zipfs.jar"
if [ ! -r "${ZIPFS}" ]; then
echo "${ZIPFS} not found"
exit 0
fi
OS=`uname -s`
case "$OS" in
Windows_* )
CLASSPATH="${TESTCLASSES};${ZIPFS}"
;;
* )
CLASSPATH="${TESTCLASSES}:${ZIPFS}"
;;
esac
export CLASSPATH
failures=0
go() {
echo ""
${TESTJAVA}/bin/java $1 $2 $3 2>&1
if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
}
# Run the tests
go Basic "${ZIPFS}"
go PathOps "${ZIPFS}"
go ZipFSTester "${ZIPFS}"
#
# Results
#
if [ $failures -gt 0 ];
then echo "$failures tests failed";
else echo "All tests passed";
fi
exit $failures