mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-20 10:27:52 +00:00
6907737: (file) FileVisitor and Files.walkFileTree issues
Reviewed-by: sherman
This commit is contained in:
parent
ee93235260
commit
b44a1bd105
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
package java.nio.file;
|
||||
|
||||
/**
|
||||
* Checked exception thrown when a file system loop, or cycle, is encountered.
|
||||
*
|
||||
* @since 1.7
|
||||
* @see Files#walkFileTree
|
||||
*/
|
||||
|
||||
public class FileSystemLoopException
|
||||
extends FileSystemException
|
||||
{
|
||||
private static final long serialVersionUID = 4843039591949217617L;
|
||||
|
||||
/**
|
||||
* Constructs an instance of this class.
|
||||
*
|
||||
* @param file
|
||||
* a string identifying the file causing the cycle or {@code null} if
|
||||
* not known
|
||||
*/
|
||||
public FileSystemLoopException(String file) {
|
||||
super(file);
|
||||
}
|
||||
}
|
||||
@ -38,7 +38,6 @@ import sun.nio.fs.BasicFileAttributesHolder;
|
||||
|
||||
class FileTreeWalker {
|
||||
private final boolean followLinks;
|
||||
private final boolean detectCycles;
|
||||
private final LinkOption[] linkOptions;
|
||||
private final FileVisitor<? super Path> visitor;
|
||||
private final int maxDepth;
|
||||
@ -48,17 +47,15 @@ class FileTreeWalker {
|
||||
int maxDepth)
|
||||
{
|
||||
boolean fl = false;
|
||||
boolean dc = false;
|
||||
for (FileVisitOption option: options) {
|
||||
// will throw NPE if options contains null
|
||||
switch (option) {
|
||||
case FOLLOW_LINKS : fl = true; break;
|
||||
case DETECT_CYCLES : dc = true; break;
|
||||
case FOLLOW_LINKS : fl = true; break;
|
||||
default:
|
||||
throw new AssertionError("Should not get here");
|
||||
}
|
||||
}
|
||||
this.followLinks = fl;
|
||||
this.detectCycles = fl | dc;
|
||||
this.linkOptions = (fl) ? new LinkOption[0] :
|
||||
new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
|
||||
this.visitor = visitor;
|
||||
@ -68,13 +65,11 @@ class FileTreeWalker {
|
||||
/**
|
||||
* Walk file tree starting at the given file
|
||||
*/
|
||||
void walk(Path start) {
|
||||
void walk(Path start) throws IOException {
|
||||
FileVisitResult result = walk(start,
|
||||
0,
|
||||
new ArrayList<AncestorDirectory>());
|
||||
if (result == null) {
|
||||
throw new NullPointerException("Visitor returned 'null'");
|
||||
}
|
||||
Objects.nonNull(result, "FileVisitor returned null");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,11 +83,8 @@ class FileTreeWalker {
|
||||
private FileVisitResult walk(Path file,
|
||||
int depth,
|
||||
List<AncestorDirectory> ancestors)
|
||||
throws IOException
|
||||
{
|
||||
// depth check
|
||||
if (depth > maxDepth)
|
||||
return FileVisitResult.CONTINUE;
|
||||
|
||||
// if attributes are cached then use them if possible
|
||||
BasicFileAttributes attrs = null;
|
||||
if ((depth > 0) &&
|
||||
@ -137,13 +129,13 @@ class FileTreeWalker {
|
||||
return visitor.visitFileFailed(file, exc);
|
||||
}
|
||||
|
||||
// file is not a directory so invoke visitFile method
|
||||
if (!attrs.isDirectory()) {
|
||||
// at maximum depth or file is not a directory
|
||||
if (depth >= maxDepth || !attrs.isDirectory()) {
|
||||
return visitor.visitFile(file, attrs);
|
||||
}
|
||||
|
||||
// check for cycles
|
||||
if (detectCycles) {
|
||||
// check for cycles when following links
|
||||
if (followLinks) {
|
||||
Object key = attrs.fileKey();
|
||||
|
||||
// if this directory and ancestor has a file key then we compare
|
||||
@ -153,19 +145,23 @@ class FileTreeWalker {
|
||||
if (key != null && ancestorKey != null) {
|
||||
if (key.equals(ancestorKey)) {
|
||||
// cycle detected
|
||||
return visitor.visitFile(file, attrs);
|
||||
return visitor.visitFileFailed(file,
|
||||
new FileSystemLoopException(file.toString()));
|
||||
}
|
||||
} else {
|
||||
boolean isSameFile = false;
|
||||
try {
|
||||
if (file.isSameFile(ancestor.file())) {
|
||||
// cycle detected
|
||||
return visitor.visitFile(file, attrs);
|
||||
}
|
||||
isSameFile = file.isSameFile(ancestor.file());
|
||||
} catch (IOException x) {
|
||||
// ignore
|
||||
} catch (SecurityException x) {
|
||||
// ignore
|
||||
}
|
||||
if (isSameFile) {
|
||||
// cycle detected
|
||||
return visitor.visitFileFailed(file,
|
||||
new FileSystemLoopException(file.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +177,7 @@ class FileTreeWalker {
|
||||
try {
|
||||
stream = file.newDirectoryStream();
|
||||
} catch (IOException x) {
|
||||
return visitor.preVisitDirectoryFailed(file, x);
|
||||
return visitor.visitFileFailed(file, x);
|
||||
} catch (SecurityException x) {
|
||||
// ignore, as per spec
|
||||
return FileVisitResult.CONTINUE;
|
||||
@ -192,20 +188,14 @@ class FileTreeWalker {
|
||||
|
||||
// invoke preVisitDirectory and then visit each entry
|
||||
try {
|
||||
result = visitor.preVisitDirectory(file);
|
||||
result = visitor.preVisitDirectory(file, attrs);
|
||||
if (result != FileVisitResult.CONTINUE) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// if an I/O occurs during iteration then a CME is thrown. We
|
||||
// need to distinguish this from a CME thrown by the visitor.
|
||||
boolean inAction = false;
|
||||
|
||||
try {
|
||||
for (Path entry: stream) {
|
||||
inAction = true;
|
||||
result = walk(entry, depth+1, ancestors);
|
||||
inAction = false;
|
||||
|
||||
// returning null will cause NPE to be thrown
|
||||
if (result == null || result == FileVisitResult.TERMINATE)
|
||||
@ -215,17 +205,9 @@ class FileTreeWalker {
|
||||
if (result == FileVisitResult.SKIP_SIBLINGS)
|
||||
break;
|
||||
}
|
||||
} catch (ConcurrentModificationException x) {
|
||||
// if CME thrown because the iteration failed then remember
|
||||
// the IOException so that it is notified to postVisitDirectory
|
||||
if (!inAction) {
|
||||
// iteration failed
|
||||
Throwable t = x.getCause();
|
||||
if (t instanceof IOException)
|
||||
ioe = (IOException)t;
|
||||
}
|
||||
if (ioe == null)
|
||||
throw x;
|
||||
} catch (DirectoryIteratorException e) {
|
||||
// IOException will be notified to postVisitDirectory
|
||||
ioe = e.getCause();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
@ -238,7 +220,7 @@ class FileTreeWalker {
|
||||
|
||||
} finally {
|
||||
// remove key from trail if doing cycle detection
|
||||
if (detectCycles) {
|
||||
if (followLinks) {
|
||||
ancestors.remove(ancestors.size()-1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,9 +37,5 @@ public enum FileVisitOption {
|
||||
/**
|
||||
* Follow symbolic links.
|
||||
*/
|
||||
FOLLOW_LINKS,
|
||||
/**
|
||||
* Detect cycles in the file tree.
|
||||
*/
|
||||
DETECT_CYCLES;
|
||||
FOLLOW_LINKS;
|
||||
}
|
||||
|
||||
@ -40,33 +40,28 @@ import java.io.IOException;
|
||||
* Path start = ...
|
||||
* Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
|
||||
* @Override
|
||||
* public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
* try {
|
||||
* file.delete();
|
||||
* } catch (IOException exc) {
|
||||
* // failed to delete, do error handling here
|
||||
* }
|
||||
* public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
|
||||
* throws IOException
|
||||
* {
|
||||
* file.delete();
|
||||
* return FileVisitResult.CONTINUE;
|
||||
* }
|
||||
* @Override
|
||||
* public FileVisitResult postVisitDirectory(Path dir, IOException e) {
|
||||
* if (e == null) {
|
||||
* try {
|
||||
* dir.delete();
|
||||
* } catch (IOException exc) {
|
||||
* // failed to delete, do error handling here
|
||||
* }
|
||||
* } else {
|
||||
* public FileVisitResult postVisitDirectory(Path dir, IOException e)
|
||||
* throws IOException
|
||||
* {
|
||||
* if (e != null) {
|
||||
* // directory iteration failed
|
||||
* throw e;
|
||||
* }
|
||||
* dir.delete();
|
||||
* return FileVisitResult.CONTINUE;
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* <p> Furthermore, suppose we want to copy a file tree rooted at a source
|
||||
* directory to a target location. In that case, symbolic links should be
|
||||
* followed and the target directory should be created before the entries in
|
||||
* the directory are copied.
|
||||
* <p> Furthermore, suppose we want to copy a file tree to a target location.
|
||||
* In that case, symbolic links should be followed and the target directory
|
||||
* should be created before the entries in the directory are copied.
|
||||
* <pre>
|
||||
* final Path source = ...
|
||||
* final Path target = ...
|
||||
@ -74,25 +69,21 @@ import java.io.IOException;
|
||||
* Files.walkFileTree(source, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
|
||||
* new SimpleFileVisitor<Path>() {
|
||||
* @Override
|
||||
* public FileVisitResult preVisitDirectory(Path dir) {
|
||||
* public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
|
||||
* throws IOException
|
||||
* {
|
||||
* try {
|
||||
* dir.copyTo(target.resolve(source.relativize(dir)));
|
||||
* } catch (FileAlreadyExistsException e) {
|
||||
* // ignore
|
||||
* } catch (IOException e) {
|
||||
* // copy failed, do error handling here
|
||||
* // skip rest of directory and descendants
|
||||
* return SKIP_SUBTREE;
|
||||
* }
|
||||
* return CONTINUE;
|
||||
* }
|
||||
* @Override
|
||||
* public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
* try {
|
||||
* file.copyTo(target.resolve(source.relativize(file)));
|
||||
* } catch (IOException e) {
|
||||
* // copy failed, do error handling here
|
||||
* }
|
||||
* public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
|
||||
* throws IOException
|
||||
* {
|
||||
* file.copyTo(target.resolve(source.relativize(file)));
|
||||
* return CONTINUE;
|
||||
* }
|
||||
* });
|
||||
@ -114,22 +105,16 @@ public interface FileVisitor<T> {
|
||||
*
|
||||
* @param dir
|
||||
* a reference to the directory
|
||||
* @param attrs
|
||||
* the directory's basic attributes
|
||||
*
|
||||
* @return the visit result
|
||||
*/
|
||||
FileVisitResult preVisitDirectory(T dir);
|
||||
|
||||
/**
|
||||
* Invoked for a directory that could not be opened.
|
||||
*
|
||||
* @param dir
|
||||
* a reference to the directory
|
||||
* @param exc
|
||||
* the I/O exception thrown from the attempt to open the directory
|
||||
*
|
||||
* @return the visit result
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
FileVisitResult preVisitDirectoryFailed(T dir, IOException exc);
|
||||
FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Invoked for a file in a directory.
|
||||
@ -140,21 +125,30 @@ public interface FileVisitor<T> {
|
||||
* the file's basic attributes
|
||||
*
|
||||
* @return the visit result
|
||||
*
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
FileVisitResult visitFile(T file, BasicFileAttributes attrs);
|
||||
FileVisitResult visitFile(T file, BasicFileAttributes attrs)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Invoked for a file when its basic file attributes could not be read.
|
||||
* Invoked for a file that could not be visited. This method is invoked
|
||||
* if the file's attributes could not be read, the file is a directory
|
||||
* that could not be opened, and other reasons.
|
||||
*
|
||||
* @param file
|
||||
* a reference to the file
|
||||
* @param exc
|
||||
* the I/O exception thrown from the attempt to read the file
|
||||
* attributes
|
||||
* the I/O exception that prevented the file from being visited
|
||||
*
|
||||
* @return the visit result
|
||||
*
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
FileVisitResult visitFileFailed(T file, IOException exc);
|
||||
FileVisitResult visitFileFailed(T file, IOException exc)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Invoked for a directory after entries in the directory, and all of their
|
||||
@ -171,6 +165,10 @@ public interface FileVisitor<T> {
|
||||
* of the directory to complete prematurely
|
||||
*
|
||||
* @return the visit result
|
||||
*
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
FileVisitResult postVisitDirectory(T dir, IOException exc);
|
||||
FileVisitResult postVisitDirectory(T dir, IOException exc)
|
||||
throws IOException;
|
||||
}
|
||||
|
||||
@ -135,9 +135,9 @@ public final class Files {
|
||||
* FileVisitor} invoked for each file encountered. File tree traversal
|
||||
* completes when all accessible files in the tree have been visited, or a
|
||||
* visit method returns a result of {@link FileVisitResult#TERMINATE
|
||||
* TERMINATE}. Where a visit method terminates due an uncaught error or
|
||||
* runtime exception then the traversal is terminated and the error or
|
||||
* exception is propagated to the caller of this method.
|
||||
* TERMINATE}. Where a visit method terminates due an {@code IOException},
|
||||
* an uncaught error, or runtime exception, then the traversal is terminated
|
||||
* and the error or exception is propagated to the caller of this method.
|
||||
*
|
||||
* <p> For each file encountered this method attempts to gets its {@link
|
||||
* java.nio.file.attribute.BasicFileAttributes}. If the file is not a
|
||||
@ -146,12 +146,10 @@ public final class Files {
|
||||
* due to an I/O exception, then the {@link FileVisitor#visitFileFailed
|
||||
* visitFileFailed} method is invoked with the I/O exception.
|
||||
*
|
||||
* <p> Where the file is a directory, this method attempts to open it by
|
||||
* invoking its {@link Path#newDirectoryStream newDirectoryStream} method.
|
||||
* Where the directory could not be opened, due to an {@code IOException},
|
||||
* then the {@link FileVisitor#preVisitDirectoryFailed preVisitDirectoryFailed}
|
||||
* method is invoked with the I/O exception, after which, the file tree walk
|
||||
* continues, by default, at the next <em>sibling</em> of the directory.
|
||||
* <p> Where the file is a directory, and the directory could not be opened,
|
||||
* then the {@code visitFileFailed} method is invoked with the I/O exception,
|
||||
* after which, the file tree walk continues, by default, at the next
|
||||
* <em>sibling</em> of the directory.
|
||||
*
|
||||
* <p> Where the directory is opened successfully, then the entries in the
|
||||
* directory, and their <em>descendants</em> are visited. When all entries
|
||||
@ -171,26 +169,25 @@ public final class Files {
|
||||
* method is invoked as specified above).
|
||||
*
|
||||
* <p> If the {@code options} parameter contains the {@link
|
||||
* FileVisitOption#DETECT_CYCLES DETECT_CYCLES} or {@link
|
||||
* FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} options then this method keeps
|
||||
* FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then this method keeps
|
||||
* track of directories visited so that cycles can be detected. A cycle
|
||||
* arises when there is an entry in a directory that is an ancestor of the
|
||||
* directory. Cycle detection is done by recording the {@link
|
||||
* java.nio.file.attribute.BasicFileAttributes#fileKey file-key} of directories,
|
||||
* or if file keys are not available, by invoking the {@link Path#isSameFile
|
||||
* isSameFile} method to test if a directory is the same file as an
|
||||
* ancestor. When a cycle is detected the {@link FileVisitor#visitFile
|
||||
* visitFile} is invoked with the attributes of the directory. The {@link
|
||||
* java.nio.file.attribute.BasicFileAttributes#isDirectory isDirectory}
|
||||
* method may be used to test if the file is a directory and that a cycle is
|
||||
* detected. The {@code preVisitDirectory} and {@code postVisitDirectory}
|
||||
* methods are not invoked.
|
||||
* ancestor. When a cycle is detected it is treated as an I/O error, and the
|
||||
* {@link FileVisitor#visitFileFailed visitFileFailed} method is invoked with
|
||||
* an instance of {@link FileSystemLoopException}.
|
||||
*
|
||||
* <p> The {@code maxDepth} parameter is the maximum number of levels of
|
||||
* directories to visit. A value of {@code 0} means that only the starting
|
||||
* file is visited, unless denied by the security manager. A value of
|
||||
* {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all
|
||||
* levels should be visited.
|
||||
* levels should be visited. The {@code visitFile} method is invoked for all
|
||||
* files, including directories, encountered at {@code maxDepth}, unless the
|
||||
* basic file attributes cannot be read, in which case the {@code
|
||||
* visitFileFailed} method is invoked.
|
||||
*
|
||||
* <p> If a visitor returns a result of {@code null} then {@code
|
||||
* NullPointerException} is thrown.
|
||||
@ -215,11 +212,14 @@ public final class Files {
|
||||
* In the case of the default provider, the {@link
|
||||
* SecurityManager#checkRead(String) checkRead} method is invoked
|
||||
* to check read access to the directory.
|
||||
* @throws IOException
|
||||
* If an I/O error is thrown by a visitor method
|
||||
*/
|
||||
public static void walkFileTree(Path start,
|
||||
Set<FileVisitOption> options,
|
||||
int maxDepth,
|
||||
FileVisitor<? super Path> visitor)
|
||||
throws IOException
|
||||
{
|
||||
if (maxDepth < 0)
|
||||
throw new IllegalArgumentException("'maxDepth' is negative");
|
||||
@ -245,8 +245,12 @@ public final class Files {
|
||||
* In the case of the default provider, the {@link
|
||||
* SecurityManager#checkRead(String) checkRead} method is invoked
|
||||
* to check read access to the directory.
|
||||
* @throws IOException
|
||||
* If an I/O error is thrown by a visitor method
|
||||
*/
|
||||
public static void walkFileTree(Path start, FileVisitor<? super Path> visitor) {
|
||||
public static void walkFileTree(Path start, FileVisitor<? super Path> visitor)
|
||||
throws IOException
|
||||
{
|
||||
walkFileTree(start,
|
||||
EnumSet.noneOf(FileVisitOption.class),
|
||||
Integer.MAX_VALUE,
|
||||
|
||||
@ -27,7 +27,7 @@ package java.nio.file;
|
||||
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.io.IOException;
|
||||
import java.io.IOError;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A simple visitor of files with default behavior to visit all files and to
|
||||
@ -47,14 +47,6 @@ public class SimpleFileVisitor<T> implements FileVisitor<T> {
|
||||
protected SimpleFileVisitor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws NullPointerException if obj is null.
|
||||
*/
|
||||
private static void checkNotNull(Object obj) {
|
||||
if (obj == null)
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked for a directory before entries in the directory are visited.
|
||||
*
|
||||
@ -62,28 +54,14 @@ public class SimpleFileVisitor<T> implements FileVisitor<T> {
|
||||
* CONTINUE}.
|
||||
*/
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(T dir) {
|
||||
checkNotNull(dir);
|
||||
public FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
|
||||
throws IOException
|
||||
{
|
||||
Objects.nonNull(dir);
|
||||
Objects.nonNull(attrs);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked for a directory that could not be opened.
|
||||
*
|
||||
* <p> Unless overridden, this method throws {@link IOError} with the I/O
|
||||
* exception as cause.
|
||||
*
|
||||
* @throws IOError
|
||||
* with the I/O exception thrown when the attempt to open the
|
||||
* directory failed
|
||||
*/
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectoryFailed(T dir, IOException exc) {
|
||||
checkNotNull(dir);
|
||||
checkNotNull(exc);
|
||||
throw new IOError(exc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked for a file in a directory.
|
||||
*
|
||||
@ -91,27 +69,26 @@ public class SimpleFileVisitor<T> implements FileVisitor<T> {
|
||||
* CONTINUE}.
|
||||
*/
|
||||
@Override
|
||||
public FileVisitResult visitFile(T file, BasicFileAttributes attrs) {
|
||||
checkNotNull(file);
|
||||
checkNotNull(attrs);
|
||||
public FileVisitResult visitFile(T file, BasicFileAttributes attrs)
|
||||
throws IOException
|
||||
{
|
||||
Objects.nonNull(file);
|
||||
Objects.nonNull(attrs);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked for a file when its basic file attributes could not be read.
|
||||
* Invoked for a file that could not be visited.
|
||||
*
|
||||
* <p> Unless overridden, this method throws {@link IOError} with the I/O
|
||||
* exception as cause.
|
||||
*
|
||||
* @throws IOError
|
||||
* with the I/O exception thrown when the attempt to read the file
|
||||
* attributes failed
|
||||
* <p> Unless overridden, this method re-throws the I/O exception that prevented
|
||||
* the file from being visited.
|
||||
*/
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(T file, IOException exc) {
|
||||
checkNotNull(file);
|
||||
checkNotNull(exc);
|
||||
throw new IOError(exc);
|
||||
public FileVisitResult visitFileFailed(T file, IOException exc)
|
||||
throws IOException
|
||||
{
|
||||
Objects.nonNull(file);
|
||||
throw exc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,18 +97,16 @@ public class SimpleFileVisitor<T> implements FileVisitor<T> {
|
||||
*
|
||||
* <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE
|
||||
* CONTINUE} if the directory iteration completes without an I/O exception;
|
||||
* otherwise this method throws {@link IOError} with the I/O exception as
|
||||
* cause.
|
||||
*
|
||||
* @throws IOError
|
||||
* with the I/O exception thrown when iteration of the directory
|
||||
* completed prematurely due to an I/O error
|
||||
* otherwise this method re-throws the I/O exception that caused the iteration
|
||||
* of the directory to terminate prematurely.
|
||||
*/
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(T dir, IOException exc) {
|
||||
checkNotNull(dir);
|
||||
public FileVisitResult postVisitDirectory(T dir, IOException exc)
|
||||
throws IOException
|
||||
{
|
||||
Objects.nonNull(dir);
|
||||
if (exc != null)
|
||||
throw new IOError(exc);
|
||||
throw exc;
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,17 +285,11 @@ public class Chmod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(FileRef dir) {
|
||||
public FileVisitResult preVisitDirectory(FileRef dir, BasicFileAttributes attrs) {
|
||||
chmod(dir, changer);
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectoryFailed(FileRef dir, IOException exc) {
|
||||
System.err.println("WARNING: " + exc);
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(FileRef file, BasicFileAttributes attrs) {
|
||||
chmod(file, changer);
|
||||
|
||||
@ -85,7 +85,7 @@ public class Copy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir) {
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
|
||||
// before visiting entries in a directory we copy the directory
|
||||
// (okay if directory already exists).
|
||||
CopyOption[] options = (preserve) ?
|
||||
@ -103,20 +103,10 @@ public class Copy {
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) {
|
||||
System.err.format("Unable to copy: %s: %s%n", dir, exc);
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
if (attrs.isDirectory()) {
|
||||
System.err.println("cycle detected: " + file);
|
||||
} else {
|
||||
copyFile(file, target.resolve(source.relativize(file)),
|
||||
prompt, preserve);
|
||||
}
|
||||
copyFile(file, target.resolve(source.relativize(file)),
|
||||
prompt, preserve);
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
@ -137,7 +127,11 @@ public class Copy {
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(Path file, IOException exc) {
|
||||
System.err.format("Unable to copy: %s: %s%n", file, exc);
|
||||
if (exc instanceof FileSystemLoopException) {
|
||||
System.err.println("cycle detected: " + file);
|
||||
} else {
|
||||
System.err.format("Unable to copy: %s: %s%n", file, exc);
|
||||
}
|
||||
return CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,12 +78,10 @@ public class WatchDir {
|
||||
// register directory and sub-directories
|
||||
Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir) {
|
||||
try {
|
||||
register(dir);
|
||||
} catch (IOException x) {
|
||||
throw new IOError(x);
|
||||
}
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
|
||||
throws IOException
|
||||
{
|
||||
register(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
|
||||
67
jdk/test/java/nio/file/Files/MaxDepth.java
Normal file
67
jdk/test/java/nio/file/Files/MaxDepth.java
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Unit test for Files.walkFileTree to test maxDepth parameter
|
||||
*/
|
||||
|
||||
public class MaxDepth {
|
||||
public static void main(String[] args) throws Exception {
|
||||
final Path top = Paths.get(args[0]);
|
||||
|
||||
for (int i=0; i<5; i++) {
|
||||
Set<FileVisitOption> opts = Collections.emptySet();
|
||||
final int maxDepth = i;
|
||||
Files.walkFileTree(top, opts, maxDepth, new SimpleFileVisitor<Path>() {
|
||||
// compute depth based on relative path to top directory
|
||||
private int depth(Path file) {
|
||||
Path rp = file.relativize(top);
|
||||
return (rp == null) ? 0 : rp.getNameCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
|
||||
int d = depth(dir);
|
||||
if (d == maxDepth)
|
||||
throw new RuntimeException("Should not open directories at maxDepth");
|
||||
if (d > maxDepth)
|
||||
throw new RuntimeException("Too deep");
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
int d = depth(file);
|
||||
if (d > maxDepth)
|
||||
throw new RuntimeException("Too deep");
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -30,6 +30,7 @@
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.Attributes;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
@ -117,25 +118,25 @@ public class Misc {
|
||||
|
||||
SimpleFileVisitor<Path> visitor = new SimpleFileVisitor<Path>() { };
|
||||
boolean ranTheGauntlet = false;
|
||||
try { visitor.preVisitDirectory(null);
|
||||
BasicFileAttributes attrs = Attributes.readBasicFileAttributes(Paths.get("."));
|
||||
|
||||
try { visitor.preVisitDirectory(null, attrs);
|
||||
} catch (NullPointerException x0) {
|
||||
try { visitor.preVisitDirectoryFailed(null, new IOException());
|
||||
try { visitor.preVisitDirectory(dir, null);
|
||||
} catch (NullPointerException x1) {
|
||||
try { visitor.preVisitDirectoryFailed(dir, null);
|
||||
try { visitor.visitFile(null, attrs);
|
||||
} catch (NullPointerException x2) {
|
||||
try { visitor.visitFile(null, Attributes.readBasicFileAttributes(Paths.get(".")));
|
||||
} catch (NullPointerException x3) {
|
||||
try { visitor.visitFile(dir, null);
|
||||
} catch (NullPointerException x4) {
|
||||
} catch (NullPointerException x3) {
|
||||
try { visitor.visitFileFailed(null, new IOException());
|
||||
} catch (NullPointerException x5) {
|
||||
} catch (NullPointerException x4) {
|
||||
try { visitor.visitFileFailed(dir, null);
|
||||
} catch (NullPointerException x6) {
|
||||
} catch (NullPointerException x5) {
|
||||
try { visitor.postVisitDirectory(null, new IOException());
|
||||
} catch (NullPointerException x7) {
|
||||
} catch (NullPointerException x6) {
|
||||
// if we get here then all visit* methods threw NPE as expected
|
||||
ranTheGauntlet = true;
|
||||
}}}}}}}}
|
||||
}}}}}}}
|
||||
if (!ranTheGauntlet)
|
||||
throw new RuntimeException("A visit method did not throw NPE");
|
||||
}
|
||||
|
||||
@ -56,29 +56,34 @@ public class PrintFileTree {
|
||||
|
||||
final boolean reportCycles = printCycles;
|
||||
Files.walkFileTree(dir, options, Integer.MAX_VALUE, new FileVisitor<FileRef>() {
|
||||
public FileVisitResult preVisitDirectory(FileRef dir) {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(FileRef dir, BasicFileAttributes attrs) {
|
||||
System.out.println(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
public FileVisitResult preVisitDirectoryFailed(FileRef dir, IOException exc) {
|
||||
exc.printStackTrace();
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@Override
|
||||
public FileVisitResult visitFile(FileRef file, BasicFileAttributes attrs) {
|
||||
if (!attrs.isDirectory() || reportCycles)
|
||||
System.out.println(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
public FileVisitResult postVisitDirectory(FileRef dir, IOException exc) {
|
||||
if (exc != null) {
|
||||
exc.printStackTrace();
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(FileRef dir, IOException exc)
|
||||
throws IOException
|
||||
{
|
||||
if (exc != null)
|
||||
throw exc;
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
public FileVisitResult visitFileFailed(FileRef file, IOException exc) {
|
||||
exc.printStackTrace();
|
||||
return FileVisitResult.TERMINATE;
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(FileRef file, IOException exc)
|
||||
throws IOException
|
||||
{
|
||||
if (reportCycles && (exc instanceof FileSystemLoopException)) {
|
||||
System.out.println(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
throw exc;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -54,32 +54,28 @@ public class SkipSiblings {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Path dir = Paths.get(args[0]);
|
||||
|
||||
Files.walkFileTree(dir, new FileVisitor<Path>() {
|
||||
public FileVisitResult preVisitDirectory(Path dir) {
|
||||
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
|
||||
check(dir);
|
||||
if (skip(dir))
|
||||
return FileVisitResult.SKIP_SIBLINGS;
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) {
|
||||
throw new RuntimeException(exc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
check(file);
|
||||
if (skip(file))
|
||||
return FileVisitResult.SKIP_SIBLINGS;
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException x) {
|
||||
if (x != null)
|
||||
throw new RuntimeException(x);
|
||||
check(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
public FileVisitResult visitFileFailed(Path file, IOException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,22 +49,19 @@ public class TerminateWalk {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Path dir = Paths.get(args[0]);
|
||||
|
||||
Files.walkFileTree(dir, new FileVisitor<Path>() {
|
||||
public FileVisitResult preVisitDirectory(Path dir) {
|
||||
return maybeTerminate();
|
||||
}
|
||||
public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) {
|
||||
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
|
||||
return maybeTerminate();
|
||||
}
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
return maybeTerminate();
|
||||
}
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException x) {
|
||||
return maybeTerminate();
|
||||
}
|
||||
public FileVisitResult visitFileFailed(Path file, IOException x) {
|
||||
return maybeTerminate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +116,7 @@ public class WalkWithSecurity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir) {
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
|
||||
System.out.println(dir);
|
||||
count++;
|
||||
return FileVisitResult.CONTINUE;
|
||||
|
||||
@ -22,9 +22,9 @@
|
||||
#
|
||||
|
||||
# @test
|
||||
# @bug 4313887
|
||||
# @bug 4313887 6907737
|
||||
# @summary Unit test for walkFileTree method
|
||||
# @build CreateFileTree PrintFileTree SkipSiblings TerminateWalk
|
||||
# @build CreateFileTree PrintFileTree SkipSiblings TerminateWalk MaxDepth
|
||||
# @run shell walk_file_tree.sh
|
||||
|
||||
# if TESTJAVA isn't set then we assume an interactive run.
|
||||
@ -84,6 +84,10 @@ if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
|
||||
$JAVA TerminateWalk "$ROOT"
|
||||
if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
|
||||
|
||||
# test maxDepth
|
||||
$JAVA MaxDepth "$ROOT"
|
||||
if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
|
||||
|
||||
# clean-up
|
||||
rm -r "$ROOT"
|
||||
|
||||
|
||||
@ -44,15 +44,10 @@ public class TestUtil {
|
||||
return createTemporaryDirectory(System.getProperty("java.io.tmpdir"));
|
||||
}
|
||||
|
||||
static void removeAll(Path dir) {
|
||||
static void removeAll(Path dir) throws IOException {
|
||||
Files.walkFileTree(dir, new FileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) {
|
||||
System.err.format("Error occured accessing directory %s\n", dir, exc);
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@Override
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user