From 37c2784f8e4185797e5f49d2fcce1991450bc408 Mon Sep 17 00:00:00 2001 From: alanb Date: Mon, 18 Jan 2010 15:21:34 +0000 Subject: [PATCH] 6917021: (file) copyTo/moveTo can overrwrite existing file when target associated with custom provider Reviewed-by: chegar --- .../classes/sun/nio/fs/AbstractPath.java | 24 +- test/java/nio/file/Path/CopyAndMove.java | 256 ++++---- .../nio/file/Path/PassThroughFileSystem.java | 554 ++++++++++++++++++ test/java/nio/file/TestUtil.java | 11 +- 4 files changed, 718 insertions(+), 127 deletions(-) create mode 100644 test/java/nio/file/Path/PassThroughFileSystem.java diff --git a/src/share/classes/sun/nio/fs/AbstractPath.java b/src/share/classes/sun/nio/fs/AbstractPath.java index 71204bd0a..e81e3eb1f 100644 --- a/src/share/classes/sun/nio/fs/AbstractPath.java +++ b/src/share/classes/sun/nio/fs/AbstractPath.java @@ -256,8 +256,8 @@ abstract class AbstractPath extends Path { } if (option == null) throw new NullPointerException(); - throw new IllegalArgumentException("'" + option + - "' is not a valid copy option"); + throw new UnsupportedOperationException("'" + option + + "' is not a recognized copy option"); } return result; } @@ -279,9 +279,21 @@ abstract class AbstractPath extends Path { if (attrs.isSymbolicLink()) throw new IOException("Copying of symbolic links not supported"); - // delete target file - if (opts.replaceExisting) - target.deleteIfExists(); + // check if target exists + boolean exists; + if (opts.replaceExisting) { + try { + target.deleteIfExists(); + exists = false; + } catch (DirectoryNotEmptyException x) { + // let exception translate to FileAlreadyExistsException (6895012) + exists = true; + } + } else { + exists = target.exists(); + } + if (exists) + throw new FileAlreadyExistsException(target.toString()); // create directory or file if (attrs.isDirectory()) { @@ -318,7 +330,7 @@ abstract class AbstractPath extends Path { ReadableByteChannel rbc = newByteChannel(); try { // open target file for writing - SeekableByteChannel sbc = target.newByteChannel(CREATE, WRITE); + SeekableByteChannel sbc = target.newByteChannel(CREATE_NEW, WRITE); // simple copy loop try { diff --git a/test/java/nio/file/Path/CopyAndMove.java b/test/java/nio/file/Path/CopyAndMove.java index 18abbe0de..9d24e6db3 100644 --- a/test/java/nio/file/Path/CopyAndMove.java +++ b/test/java/nio/file/Path/CopyAndMove.java @@ -22,10 +22,10 @@ */ /* @test - * @bug 4313887 6838333 + * @bug 4313887 6838333 6917021 * @summary Unit test for java.nio.file.Path copyTo/moveTo methods * @library .. - * @build CopyAndMove + * @build CopyAndMove PassThroughFileSystem * @run main/othervm CopyAndMove */ @@ -40,22 +40,31 @@ import java.util.*; public class CopyAndMove { static final Random rand = new Random(); static boolean heads() { return rand.nextBoolean(); } - static boolean supportsLinks; public static void main(String[] args) throws Exception { Path dir1 = TestUtil.createTemporaryDirectory(); try { - supportsLinks = TestUtil.supportsLinks(dir1); - - // Exercise copyTo - doCopyTests(dir1); + // Same directory + doCopyTests(dir1, dir1, TestUtil.supportsLinks(dir1)); + doMoveTests(dir1, dir1, TestUtil.supportsLinks(dir1)); + + // Different directories. Use test.dir if possible as it might be + // a different volume/file system and so improve test coverage. + String testDir = System.getProperty("test.dir", "."); + Path dir2 = TestUtil.createTemporaryDirectory(testDir); + try { + boolean testSymbolicLinks = + TestUtil.supportsLinks(dir1) && TestUtil.supportsLinks(dir2); + doCopyTests(dir1, dir2, testSymbolicLinks); + doMoveTests(dir1, dir2, testSymbolicLinks); + } finally { + TestUtil.removeAll(dir2); + } - // Exercise moveTo - // if test.dir differs to temporary file system then can test - // moving between devices - String testDir = System.getProperty("test.dir"); - Path dir2 = (testDir != null) ? Paths.get(testDir) : dir1; - doMoveTests(dir1, dir2); + // Target is location associated with custom provider + Path dir3 = PassThroughFileSystem.create().getPath(dir1.toString()); + doCopyTests(dir1, dir3, false); + doMoveTests(dir1, dir3, false); } finally { TestUtil.removeAll(dir1); @@ -186,30 +195,37 @@ public class CopyAndMove { checkBasicAttributes(basicAttributes, Attributes.readBasicFileAttributes(target, NOFOLLOW_LINKS)); - // verify POSIX attributes - if (posixAttributes != null && !basicAttributes.isSymbolicLink()) { - checkPosixAttributes(posixAttributes, - Attributes.readPosixFileAttributes(target, NOFOLLOW_LINKS)); - } + // verify other attributes when same provider + if (source.getFileSystem().provider() == target.getFileSystem().provider()) { - // verify DOS attributes - if (dosAttributes != null && !basicAttributes.isSymbolicLink()) { - checkDosAttributes(dosAttributes, - Attributes.readDosFileAttributes(target, NOFOLLOW_LINKS)); - } + // verify POSIX attributes + if (posixAttributes != null && !basicAttributes.isSymbolicLink()) { + checkPosixAttributes(posixAttributes, + Attributes.readPosixFileAttributes(target, NOFOLLOW_LINKS)); + } - // verify named attributes - if (namedAttributes != null && - target.getFileStore().supportsFileAttributeView("xattr")) - { - checkUserDefinedFileAttributes(namedAttributes, readUserDefinedFileAttributes(target)); + // verify DOS attributes + if (dosAttributes != null && !basicAttributes.isSymbolicLink()) { + checkDosAttributes(dosAttributes, + Attributes.readDosFileAttributes(target, NOFOLLOW_LINKS)); + } + + // verify named attributes + if (namedAttributes != null && + target.getFileStore().supportsFileAttributeView("xattr")) + { + checkUserDefinedFileAttributes(namedAttributes, + readUserDefinedFileAttributes(target)); + } } } /** * Tests all possible ways to invoke moveTo */ - static void doMoveTests(Path dir1, Path dir2) throws IOException { + static void doMoveTests(Path dir1, Path dir2, boolean supportsLinks) + throws IOException + { Path source, target, entry; boolean sameDevice = dir1.getFileStore().equals(dir2.getFileStore()); @@ -220,7 +236,7 @@ public class CopyAndMove { * Test: move regular file, target does not exist */ source = createSourceFile(dir1); - target = getTargetFile(dir1); + target = getTargetFile(dir2); moveAndVerify(source, target); target.delete(); @@ -228,7 +244,7 @@ public class CopyAndMove { * Test: move regular file, target exists */ source = createSourceFile(dir1); - target = getTargetFile(dir1).createFile(); + target = getTargetFile(dir2).createFile(); try { moveAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); @@ -248,7 +264,7 @@ public class CopyAndMove { * Test: move regular file, target does not exist */ source = createSourceFile(dir1); - target = getTargetFile(dir1); + target = getTargetFile(dir2); moveAndVerify(source, target, REPLACE_EXISTING); target.delete(); @@ -256,7 +272,7 @@ public class CopyAndMove { * Test: move regular file, target exists */ source = createSourceFile(dir1); - target = getTargetFile(dir1).createFile(); + target = getTargetFile(dir2).createFile(); moveAndVerify(source, target, REPLACE_EXISTING); target.delete(); @@ -264,7 +280,7 @@ public class CopyAndMove { * Test: move regular file, target exists and is empty directory */ source = createSourceFile(dir1); - target = getTargetFile(dir1).createDirectory(); + target = getTargetFile(dir2).createDirectory(); moveAndVerify(source, target, REPLACE_EXISTING); target.delete(); @@ -272,7 +288,7 @@ public class CopyAndMove { * Test: move regular file, target exists and is non-empty directory */ source = createSourceFile(dir1); - target = getTargetFile(dir1).createDirectory(); + target = getTargetFile(dir2).createDirectory(); entry = target.resolve("foo").createFile(); try { moveAndVerify(source, target); @@ -311,7 +327,7 @@ public class CopyAndMove { * Test: move empty directory, target does not exist */ source = createSourceDirectory(dir1); - target = getTargetFile(dir1); + target = getTargetFile(dir2); moveAndVerify(source, target); target.delete(); @@ -319,7 +335,7 @@ public class CopyAndMove { * Test: move empty directory, target exists */ source = createSourceDirectory(dir1); - target = getTargetFile(dir1).createFile(); + target = getTargetFile(dir2).createFile(); try { moveAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); @@ -339,7 +355,7 @@ public class CopyAndMove { * Test: move empty directory, target does not exist */ source = createSourceDirectory(dir1); - target = getTargetFile(dir1); + target = getTargetFile(dir2); moveAndVerify(source, target, REPLACE_EXISTING); target.delete(); @@ -347,7 +363,7 @@ public class CopyAndMove { * Test: move empty directory, target exists */ source = createSourceDirectory(dir1); - target = getTargetFile(dir1).createFile(); + target = getTargetFile(dir2).createFile(); moveAndVerify(source, target, REPLACE_EXISTING); target.delete(); @@ -355,7 +371,7 @@ public class CopyAndMove { * Test: move empty, target exists and is empty directory */ source = createSourceDirectory(dir1); - target = getTargetFile(dir1).createDirectory(); + target = getTargetFile(dir2).createDirectory(); moveAndVerify(source, target, REPLACE_EXISTING); target.delete(); @@ -363,7 +379,7 @@ public class CopyAndMove { * Test: move empty directory, target exists and is non-empty directory */ source = createSourceDirectory(dir1); - target = getTargetFile(dir1).createDirectory(); + target = getTargetFile(dir2).createDirectory(); entry = target.resolve("foo").createFile(); try { moveAndVerify(source, target, REPLACE_EXISTING); @@ -418,7 +434,7 @@ public class CopyAndMove { if (supportsLinks) { Path tmp = createSourceFile(dir1); source = dir1.resolve("link").createSymbolicLink(tmp); - target = getTargetFile(dir1); + target = getTargetFile(dir2); moveAndVerify(source, target); target.delete(); tmp.delete(); @@ -429,7 +445,7 @@ public class CopyAndMove { */ if (supportsLinks) { source = dir1.resolve("link").createSymbolicLink(dir2); - target = getTargetFile(dir1); + target = getTargetFile(dir2); moveAndVerify(source, target); target.delete(); } @@ -440,7 +456,7 @@ public class CopyAndMove { if (supportsLinks) { Path tmp = Paths.get("doesnotexist"); source = dir1.resolve("link").createSymbolicLink(tmp); - target = getTargetFile(dir1); + target = getTargetFile(dir2); moveAndVerify(source, target); target.delete(); } @@ -450,7 +466,7 @@ public class CopyAndMove { */ if (supportsLinks) { source = dir1.resolve("link").createSymbolicLink(dir2); - target = getTargetFile(dir1).createFile(); + target = getTargetFile(dir2).createFile(); try { moveAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); @@ -465,7 +481,7 @@ public class CopyAndMove { */ if (supportsLinks) { source = dir1.resolve("link").createSymbolicLink(dir2); - target = getTargetFile(dir1).createFile(); + target = getTargetFile(dir2).createFile(); moveAndVerify(source, target, REPLACE_EXISTING); target.delete(); } @@ -475,7 +491,7 @@ public class CopyAndMove { */ if (supportsLinks) { source = dir1.resolve("link").createSymbolicLink(dir2); - target = getTargetFile(dir1).createDirectory(); + target = getTargetFile(dir2).createDirectory(); moveAndVerify(source, target, REPLACE_EXISTING); target.delete(); } @@ -485,7 +501,7 @@ public class CopyAndMove { */ if (supportsLinks) { source = dir1.resolve("link").createSymbolicLink(dir2); - target = getTargetFile(dir1).createDirectory(); + target = getTargetFile(dir2).createDirectory(); entry = target.resolve("foo").createFile(); try { moveAndVerify(source, target); @@ -502,7 +518,7 @@ public class CopyAndMove { */ if (supportsLinks) { source = dir1.resolve("link").createSymbolicLink(dir1); - target = getTargetFile(dir1).createFile(); + target = getTargetFile(dir2).createFile(); moveAndVerify(source, target, REPLACE_EXISTING); target.delete(); } @@ -513,7 +529,7 @@ public class CopyAndMove { * Test nulls */ source = createSourceFile(dir1); - target = getTargetFile(dir1); + target = getTargetFile(dir2); try { source.moveTo(null); throw new RuntimeException("NullPointerException expected"); @@ -533,7 +549,7 @@ public class CopyAndMove { * Test UOE */ source = createSourceFile(dir1); - target = getTargetFile(dir1); + target = getTargetFile(dir2); try { source.moveTo(target, new CopyOption() { }); } catch (UnsupportedOperationException x) { } @@ -577,28 +593,32 @@ public class CopyAndMove { checkBasicAttributes(basicAttributes, Attributes.readBasicFileAttributes(source, linkOptions)); - // check POSIX attributes are copied - String os = System.getProperty("os.name"); - if (os.equals("SunOS") || os.equals("Linux")) { - checkPosixAttributes( - Attributes.readPosixFileAttributes(source, linkOptions), - Attributes.readPosixFileAttributes(target, linkOptions)); - } + // verify other attributes when same provider + if (source.getFileSystem().provider() == target.getFileSystem().provider()) { - // check DOS attributes are copied - if (os.startsWith("Windows")) { - checkDosAttributes( - Attributes.readDosFileAttributes(source, linkOptions), - Attributes.readDosFileAttributes(target, linkOptions)); - } + // check POSIX attributes are copied + String os = System.getProperty("os.name"); + if (os.equals("SunOS") || os.equals("Linux")) { + checkPosixAttributes( + Attributes.readPosixFileAttributes(source, linkOptions), + Attributes.readPosixFileAttributes(target, linkOptions)); + } - // check named attributes are copied - if (followLinks && - source.getFileStore().supportsFileAttributeView("xattr") && - target.getFileStore().supportsFileAttributeView("xattr")) - { - checkUserDefinedFileAttributes(readUserDefinedFileAttributes(source), - readUserDefinedFileAttributes(target)); + // check DOS attributes are copied + if (os.startsWith("Windows")) { + checkDosAttributes( + Attributes.readDosFileAttributes(source, linkOptions), + Attributes.readDosFileAttributes(target, linkOptions)); + } + + // check named attributes are copied + if (followLinks && + source.getFileStore().supportsFileAttributeView("xattr") && + target.getFileStore().supportsFileAttributeView("xattr")) + { + checkUserDefinedFileAttributes(readUserDefinedFileAttributes(source), + readUserDefinedFileAttributes(target)); + } } } } @@ -606,7 +626,9 @@ public class CopyAndMove { /** * Tests all possible ways to invoke copyTo */ - static void doCopyTests(Path dir) throws IOException { + static void doCopyTests(Path dir1, Path dir2, boolean supportsLinks) + throws IOException + { Path source, target, link, entry; // -- regular file -- @@ -614,8 +636,8 @@ public class CopyAndMove { /** * Test: move regular file, target does not exist */ - source = createSourceFile(dir); - target = getTargetFile(dir); + source = createSourceFile(dir1); + target = getTargetFile(dir2); copyAndVerify(source, target); source.delete(); target.delete(); @@ -623,8 +645,8 @@ public class CopyAndMove { /** * Test: copy regular file, target exists */ - source = createSourceFile(dir); - target = getTargetFile(dir).createFile(); + source = createSourceFile(dir1); + target = getTargetFile(dir2).createFile(); try { copyAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); @@ -643,8 +665,8 @@ public class CopyAndMove { /** * Test: copy regular file, target does not exist */ - source = createSourceFile(dir); - target = getTargetFile(dir); + source = createSourceFile(dir1); + target = getTargetFile(dir2); copyAndVerify(source, target, REPLACE_EXISTING); source.delete(); target.delete(); @@ -652,8 +674,8 @@ public class CopyAndMove { /** * Test: copy regular file, target exists */ - source = createSourceFile(dir); - target = getTargetFile(dir).createFile(); + source = createSourceFile(dir1); + target = getTargetFile(dir2).createFile(); copyAndVerify(source, target, REPLACE_EXISTING); source.delete(); target.delete(); @@ -661,8 +683,8 @@ public class CopyAndMove { /** * Test: copy regular file, target exists and is empty directory */ - source = createSourceFile(dir); - target = getTargetFile(dir).createDirectory(); + source = createSourceFile(dir1); + target = getTargetFile(dir2).createDirectory(); copyAndVerify(source, target, REPLACE_EXISTING); source.delete(); target.delete(); @@ -670,8 +692,8 @@ public class CopyAndMove { /** * Test: copy regular file, target exists and is non-empty directory */ - source = createSourceFile(dir); - target = getTargetFile(dir).createDirectory(); + source = createSourceFile(dir1); + target = getTargetFile(dir2).createDirectory(); entry = target.resolve("foo").createFile(); try { copyAndVerify(source, target); @@ -685,8 +707,8 @@ public class CopyAndMove { /** * Test: copy regular file + attributes */ - source = createSourceFile(dir); - target = getTargetFile(dir); + source = createSourceFile(dir1); + target = getTargetFile(dir2); copyAndVerify(source, target, COPY_ATTRIBUTES); source.delete(); target.delete(); @@ -697,8 +719,8 @@ public class CopyAndMove { /* * Test: copy directory, target does not exist */ - source = createSourceDirectory(dir); - target = getTargetFile(dir); + source = createSourceDirectory(dir1); + target = getTargetFile(dir2); copyAndVerify(source, target); source.delete(); target.delete(); @@ -706,8 +728,8 @@ public class CopyAndMove { /** * Test: copy directory, target exists */ - source = createSourceDirectory(dir); - target = getTargetFile(dir).createFile(); + source = createSourceDirectory(dir1); + target = getTargetFile(dir2).createFile(); try { copyAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); @@ -726,8 +748,8 @@ public class CopyAndMove { /** * Test: copy directory, target does not exist */ - source = createSourceDirectory(dir); - target = getTargetFile(dir); + source = createSourceDirectory(dir1); + target = getTargetFile(dir2); copyAndVerify(source, target, REPLACE_EXISTING); source.delete(); target.delete(); @@ -735,8 +757,8 @@ public class CopyAndMove { /** * Test: copy directory, target exists */ - source = createSourceDirectory(dir); - target = getTargetFile(dir).createFile(); + source = createSourceDirectory(dir1); + target = getTargetFile(dir2).createFile(); copyAndVerify(source, target, REPLACE_EXISTING); source.delete(); target.delete(); @@ -744,8 +766,8 @@ public class CopyAndMove { /** * Test: copy directory, target exists and is empty directory */ - source = createSourceDirectory(dir); - target = getTargetFile(dir).createDirectory(); + source = createSourceDirectory(dir1); + target = getTargetFile(dir2).createDirectory(); copyAndVerify(source, target, REPLACE_EXISTING); source.delete(); target.delete(); @@ -753,8 +775,8 @@ public class CopyAndMove { /** * Test: copy directory, target exists and is non-empty directory */ - source = createSourceDirectory(dir); - target = getTargetFile(dir).createDirectory(); + source = createSourceDirectory(dir1); + target = getTargetFile(dir2).createDirectory(); entry = target.resolve("foo").createFile(); try { copyAndVerify(source, target, REPLACE_EXISTING); @@ -768,8 +790,8 @@ public class CopyAndMove { /* * Test: copy directory + attributes */ - source = createSourceDirectory(dir); - target = getTargetFile(dir); + source = createSourceDirectory(dir1); + target = getTargetFile(dir2); copyAndVerify(source, target, COPY_ATTRIBUTES); source.delete(); target.delete(); @@ -780,9 +802,9 @@ public class CopyAndMove { * Test: Follow link */ if (supportsLinks) { - source = createSourceFile(dir); - link = dir.resolve("link").createSymbolicLink(source); - target = getTargetFile(dir); + source = createSourceFile(dir1); + link = dir1.resolve("link").createSymbolicLink(source); + target = getTargetFile(dir2); copyAndVerify(link, target); link.delete(); source.delete(); @@ -792,9 +814,9 @@ public class CopyAndMove { * Test: Copy link (to file) */ if (supportsLinks) { - source = createSourceFile(dir); - link = dir.resolve("link").createSymbolicLink(source); - target = getTargetFile(dir); + source = createSourceFile(dir1); + link = dir1.resolve("link").createSymbolicLink(source); + target = getTargetFile(dir2); copyAndVerify(link, target, NOFOLLOW_LINKS); link.delete(); source.delete(); @@ -804,9 +826,9 @@ public class CopyAndMove { * Test: Copy link (to directory) */ if (supportsLinks) { - source = dir.resolve("mydir").createDirectory(); - link = dir.resolve("link").createSymbolicLink(source); - target = getTargetFile(dir); + source = dir1.resolve("mydir").createDirectory(); + link = dir1.resolve("link").createSymbolicLink(source); + target = getTargetFile(dir2); copyAndVerify(link, target, NOFOLLOW_LINKS); link.delete(); source.delete(); @@ -817,8 +839,8 @@ public class CopyAndMove { */ if (supportsLinks) { assertTrue(source.notExists()); - link = dir.resolve("link").createSymbolicLink(source); - target = getTargetFile(dir); + link = dir1.resolve("link").createSymbolicLink(source); + target = getTargetFile(dir2); copyAndVerify(link, target, NOFOLLOW_LINKS); link.delete(); } @@ -830,8 +852,8 @@ public class CopyAndMove { System.getProperty("os.name").startsWith("Windows")) { Path unc = Paths.get("\\\\rialto\\share\\file"); - link = dir.resolve("link").createSymbolicLink(unc); - target = getTargetFile(dir); + link = dir1.resolve("link").createSymbolicLink(unc); + target = getTargetFile(dir2); copyAndVerify(link, target, NOFOLLOW_LINKS); link.delete(); } @@ -841,8 +863,8 @@ public class CopyAndMove { /** * Test nulls */ - source = createSourceFile(dir); - target = getTargetFile(dir); + source = createSourceFile(dir1); + target = getTargetFile(dir2); try { source.copyTo(null); throw new RuntimeException("NullPointerException expected"); @@ -861,8 +883,8 @@ public class CopyAndMove { /** * Test UOE */ - source = createSourceFile(dir); - target = getTargetFile(dir); + source = createSourceFile(dir1); + target = getTargetFile(dir2); try { source.copyTo(target, new CopyOption() { }); } catch (UnsupportedOperationException x) { } diff --git a/test/java/nio/file/Path/PassThroughFileSystem.java b/test/java/nio/file/Path/PassThroughFileSystem.java new file mode 100644 index 000000000..41870ccc0 --- /dev/null +++ b/test/java/nio/file/Path/PassThroughFileSystem.java @@ -0,0 +1,554 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.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.nio.channels.SeekableByteChannel; +import java.net.URI; +import java.util.*; +import java.io.*; + +/** + * A "pass through" file system implementation that passes through, or delegates, + * everything to the default file system. + */ + +class PassThroughFileSystem extends FileSystem { + private final FileSystemProvider provider; + private final FileSystem delegate; + + PassThroughFileSystem(FileSystemProvider provider, FileSystem delegate) { + this.provider = provider; + this.delegate = delegate; + } + + /** + * Creates a new "pass through" file system. Useful for test environments + * where the provider might not be deployed. + */ + static FileSystem create() throws IOException { + FileSystemProvider provider = new PassThroughProvider(); + Map env = Collections.emptyMap(); + URI uri = URI.create("pass:///"); + return provider.newFileSystem(uri, env); + } + + @Override + public FileSystemProvider provider() { + return provider; + } + + @Override + public void close() throws IOException { + delegate.close(); + } + + @Override + public boolean isOpen() { + return delegate.isOpen(); + } + + @Override + public boolean isReadOnly() { + return delegate.isReadOnly(); + } + + @Override + public String getSeparator() { + return delegate.getSeparator(); + } + + @Override + public Iterable getRootDirectories() { + final Iterable roots = delegate.getRootDirectories(); + return new Iterable() { + @Override + public Iterator iterator() { + final Iterator itr = roots.iterator(); + return new Iterator() { + @Override + public boolean hasNext() { + return itr.hasNext(); + } + @Override + public Path next() { + return new PassThroughPath(delegate, itr.next()); + } + @Override + public void remove() { + itr.remove(); + } + }; + } + }; + } + + @Override + public Iterable getFileStores() { + // assume that unwrapped objects aren't exposed + return delegate.getFileStores(); + } + + @Override + public Set supportedFileAttributeViews() { + // assume that unwrapped objects aren't exposed + return delegate.supportedFileAttributeViews(); + } + + @Override + public Path getPath(String path) { + return new PassThroughPath(this, delegate.getPath(path)); + } + + @Override + public PathMatcher getPathMatcher(String syntaxAndPattern) { + final PathMatcher matcher = delegate.getPathMatcher(syntaxAndPattern); + return new PathMatcher() { + @Override + public boolean matches(Path path) { + return matcher.matches(PassThroughPath.unwrap(path)); + } + }; + } + + @Override + public UserPrincipalLookupService getUserPrincipalLookupService() { + // assume that unwrapped objects aren't exposed + return delegate.getUserPrincipalLookupService(); + } + + @Override + public WatchService newWatchService() throws IOException { + // to keep it simple + throw new UnsupportedOperationException(); + } + + static class PassThroughProvider extends FileSystemProvider { + private static final String SCHEME = "pass"; + private static volatile PassThroughFileSystem delegate; + + public PassThroughProvider() { } + + @Override + public String getScheme() { + return SCHEME; + } + + private void checkScheme(URI uri) { + if (!uri.getScheme().equalsIgnoreCase(SCHEME)) + throw new IllegalArgumentException(); + } + + private void checkUri(URI uri) { + checkScheme(uri); + if (!uri.getSchemeSpecificPart().equals("///")) + throw new IllegalArgumentException(); + } + + @Override + public FileSystem newFileSystem(URI uri, Map env) + throws IOException + { + checkUri(uri); + synchronized (PassThroughProvider.class) { + if (delegate != null) + throw new FileSystemAlreadyExistsException(); + PassThroughFileSystem result = + new PassThroughFileSystem(this, FileSystems.getDefault()); + delegate = result; + return result; + } + } + + @Override + public FileSystem getFileSystem(URI uri) { + checkUri(uri); + FileSystem result = delegate; + if (result == null) + throw new FileSystemNotFoundException(); + return result; + } + + @Override + public Path getPath(URI uri) { + checkScheme(uri); + if (delegate == null) + throw new FileSystemNotFoundException(); + uri = URI.create(delegate.provider().getScheme() + ":" + + uri.getSchemeSpecificPart()); + return new PassThroughPath(delegate, delegate.provider().getPath(uri)); + } + } + + static class PassThroughPath extends Path { + private final FileSystem fs; + private final Path delegate; + + PassThroughPath(FileSystem fs, Path delegate) { + this.fs = fs; + this.delegate = delegate; + } + + private Path wrap(Path path) { + return (path != null) ? new PassThroughPath(fs, path) : null; + } + + static Path unwrap(Path wrapper) { + if (!(wrapper instanceof PassThroughPath)) + throw new ProviderMismatchException(); + return ((PassThroughPath)wrapper).delegate; + } + + @Override + public FileSystem getFileSystem() { + return fs; + } + + @Override + public boolean isAbsolute() { + return delegate.isAbsolute(); + } + + @Override + public Path getRoot() { + return wrap(delegate.getRoot()); + } + + + @Override + public Path getName() { + return wrap(delegate.getName()); + } + + @Override + public Path getParent() { + return wrap(delegate.getParent()); + } + + @Override + public int getNameCount() { + return delegate.getNameCount(); + } + + @Override + public Path getName(int index) { + return wrap(delegate.getName(index)); + } + + @Override + public Path subpath(int beginIndex, int endIndex) { + return wrap(delegate.subpath(beginIndex, endIndex)); + } + + @Override + public boolean startsWith(Path other) { + return delegate.startsWith(unwrap(other)); + } + + @Override + public boolean endsWith(Path other) { + return delegate.endsWith(unwrap(other)); + } + + @Override + public Path normalize() { + return wrap(delegate.normalize()); + } + + @Override + public Path resolve(Path other) { + return wrap(delegate.resolve(unwrap(other))); + } + + @Override + public Path resolve(String other) { + return wrap(delegate.resolve(other)); + } + + @Override + public Path relativize(Path other) { + return wrap(delegate.relativize(unwrap(other))); + } + + @Override + public void setAttribute(String attribute, Object value, LinkOption... options) + throws IOException + { + delegate.setAttribute(attribute, value, options); + } + + @Override + public Object getAttribute(String attribute, LinkOption... options) + throws IOException + { + // assume that unwrapped objects aren't exposed + return delegate.getAttribute(attribute, options); + } + + @Override + public Map readAttributes(String attributes, LinkOption... options) + throws IOException + { + // assume that unwrapped objects aren't exposed + return delegate.readAttributes(attributes, options); + } + + @Override + public V getFileAttributeView(Class type, + LinkOption... options) + { + return delegate.getFileAttributeView(type, options); + } + + @Override + public void delete() throws IOException { + delegate.delete(); + } + + @Override + public void deleteIfExists() throws IOException { + delegate.deleteIfExists(); + } + + @Override + public Path createSymbolicLink(Path target, FileAttribute... attrs) + throws IOException + { + delegate.createSymbolicLink(unwrap(target), attrs); + return this; + } + + @Override + public Path createLink(Path existing) throws IOException { + delegate.createLink(unwrap(existing)); + return this; + } + + @Override + public Path readSymbolicLink() throws IOException { + return wrap(delegate.readSymbolicLink()); + } + + @Override + public URI toUri() { + String ssp = delegate.toUri().getSchemeSpecificPart(); + return URI.create(fs.provider().getScheme() + ":" + ssp); + } + + @Override + public Path toAbsolutePath() { + return wrap(delegate.toAbsolutePath()); + } + + @Override + public Path toRealPath(boolean resolveLinks) throws IOException { + return wrap(delegate.toRealPath(resolveLinks)); + } + + @Override + public Path copyTo(Path target, CopyOption... options) throws IOException { + return wrap(delegate.copyTo(unwrap(target), options)); + } + + @Override + public Path moveTo(Path target, CopyOption... options) throws IOException { + return wrap(delegate.copyTo(unwrap(target), options)); + } + + private DirectoryStream wrap(final DirectoryStream stream) { + return new DirectoryStream() { + @Override + public Iterator iterator() { + final Iterator itr = stream.iterator(); + return new Iterator() { + @Override + public boolean hasNext() { + return itr.hasNext(); + } + @Override + public Path next() { + return wrap(itr.next()); + } + @Override + public void remove() { + itr.remove(); + } + }; + } + @Override + public void close() throws IOException { + stream.close(); + } + }; + } + + @Override + public DirectoryStream newDirectoryStream() throws IOException { + return wrap(delegate.newDirectoryStream()); + } + + @Override + public DirectoryStream newDirectoryStream(String glob) + throws IOException + { + return wrap(delegate.newDirectoryStream(glob)); + } + + @Override + public DirectoryStream newDirectoryStream(DirectoryStream.Filter filter) + throws IOException + { + return wrap(delegate.newDirectoryStream(filter)); + } + + @Override + public Path createFile(FileAttribute... attrs) throws IOException { + delegate.createFile(attrs); + return this; + } + + @Override + public Path createDirectory(FileAttribute... attrs) + throws IOException + { + delegate.createDirectory(attrs); + return this; + } + + @Override + public SeekableByteChannel newByteChannel(Set options, + FileAttribute... attrs) + throws IOException + { + return delegate.newByteChannel(options, attrs); + } + + @Override + public SeekableByteChannel newByteChannel(OpenOption... options) + throws IOException + { + return delegate.newByteChannel(options); + } + + @Override + public InputStream newInputStream(OpenOption... options) throws IOException { + return delegate.newInputStream(); + } + + @Override + public OutputStream newOutputStream(OpenOption... options) + throws IOException + { + return delegate.newOutputStream(options); + } + + @Override + public boolean isHidden() throws IOException { + return delegate.isHidden(); + } + + @Override + public void checkAccess(AccessMode... modes) throws IOException { + delegate.checkAccess(modes); + } + + @Override + public boolean exists() { + return delegate.exists(); + } + + @Override + public boolean notExists() { + return delegate.notExists(); + } + + @Override + public FileStore getFileStore() throws IOException { + return delegate.getFileStore(); + } + + @Override + public WatchKey register(WatchService watcher, + WatchEvent.Kind[] events, + WatchEvent.Modifier... modifiers) + { + throw new UnsupportedOperationException(); + } + + @Override + public WatchKey register(WatchService watcher, + WatchEvent.Kind... events) + { + throw new UnsupportedOperationException(); + } + + + @Override + public Iterator iterator() { + final Iterator itr = delegate.iterator(); + return new Iterator() { + @Override + public boolean hasNext() { + return itr.hasNext(); + } + @Override + public Path next() { + return wrap(itr.next()); + } + @Override + public void remove() { + itr.remove(); + } + }; + } + + @Override + public int compareTo(Path other) { + return delegate.compareTo(unwrap(other)); + } + + @Override + public boolean isSameFile(Path other) throws IOException { + return delegate.isSameFile(unwrap(other)); + } + + + @Override + public boolean equals(Object other) { + if (!(other instanceof PassThroughPath)) + return false; + return delegate.equals(unwrap((PassThroughPath)other)); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public String toString() { + return delegate.toString(); + } + } +} diff --git a/test/java/nio/file/TestUtil.java b/test/java/nio/file/TestUtil.java index 2436a4599..972dc250d 100644 --- a/test/java/nio/file/TestUtil.java +++ b/test/java/nio/file/TestUtil.java @@ -30,17 +30,20 @@ public class TestUtil { private TestUtil() { } - public static Path createTemporaryDirectory() throws IOException { - Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir")); + static Path createTemporaryDirectory(String where) throws IOException { + Path top = FileSystems.getDefault().getPath(where); Random r = new Random(); - Path dir; do { - dir = tmpdir.resolve("name" + r.nextInt()); + dir = top.resolve("name" + r.nextInt()); } while (dir.exists()); return dir.createDirectory(); } + static Path createTemporaryDirectory() throws IOException { + return createTemporaryDirectory(System.getProperty("java.io.tmpdir")); + } + static void removeAll(Path dir) { Files.walkFileTree(dir, new FileVisitor() { @Override -- GitLab