提交 7ac88d81 编写于 作者: A alanb

6808647: (file) Paths.get("C:").newDirectoryStream() iterates over Path...

6808647: (file) Paths.get("C:").newDirectoryStream() iterates over Path elements with additional slash [win]
6808648: (file) Files.walkFileTree should obtain file attributes during iteration [win]
Reviewed-by: sherman
上级 ca0148c2
......@@ -252,6 +252,7 @@ FILES_src = \
sun/nio/fs/AbstractUserDefinedFileAttributeView.java \
sun/nio/fs/AbstractWatchKey.java \
sun/nio/fs/AbstractWatchService.java \
sun/nio/fs/BasicFileAttributesHolder.java \
sun/nio/fs/Cancellable.java \
sun/nio/fs/DefaultFileSystemProvider.java \
sun/nio/fs/DefaultFileTypeDetector.java \
......
......@@ -28,6 +28,7 @@ package java.nio.file;
import java.nio.file.attribute.*;
import java.io.IOException;
import java.util.*;
import sun.nio.fs.BasicFileAttributesHolder;
/**
* Simple file tree walker that works in a similar manner to nftw(3C).
......@@ -65,6 +66,10 @@ class FileTreeWalker {
* Walk file tree starting at the given file
*/
void walk(Path start, int maxDepth) {
// don't use attributes of starting file as they may be stale
if (start instanceof BasicFileAttributesHolder) {
((BasicFileAttributesHolder)start).invalidate();
}
FileVisitResult result = walk(start,
maxDepth,
new ArrayList<AncestorDirectory>());
......@@ -75,11 +80,9 @@ class FileTreeWalker {
/**
* @param file
* The directory to visit
* @param path
* list of directories that is relative path from starting file
* the directory to visit
* @param depth
* Depth remaining
* depth remaining
* @param ancestors
* use when cycle detection is enabled
*/
......@@ -91,28 +94,36 @@ class FileTreeWalker {
if (depth-- < 0)
return FileVisitResult.CONTINUE;
// if attributes are cached then use them if possible
BasicFileAttributes attrs = null;
if (file instanceof BasicFileAttributesHolder) {
BasicFileAttributes cached = ((BasicFileAttributesHolder)file).get();
if (!followLinks || !cached.isSymbolicLink())
attrs = cached;
}
IOException exc = null;
// attempt to get attributes of file. If fails and we are following
// links then a link target might not exist so get attributes of link
try {
if (attrs == null) {
try {
attrs = Attributes.readBasicFileAttributes(file, linkOptions);
} catch (IOException x1) {
if (followLinks) {
try {
attrs = Attributes
.readBasicFileAttributes(file, LinkOption.NOFOLLOW_LINKS);
} catch (IOException x2) {
exc = x2;
try {
attrs = Attributes.readBasicFileAttributes(file, linkOptions);
} catch (IOException x1) {
if (followLinks) {
try {
attrs = Attributes
.readBasicFileAttributes(file, LinkOption.NOFOLLOW_LINKS);
} catch (IOException x2) {
exc = x2;
}
} else {
exc = x1;
}
} else {
exc = x1;
}
} catch (SecurityException x) {
return FileVisitResult.CONTINUE;
}
} catch (SecurityException x) {
return FileVisitResult.CONTINUE;
}
// unable to get attributes of file
......
/*
* Copyright 2008-2009 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 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.
*/
package sun.nio.fs;
import java.nio.file.attribute.BasicFileAttributes;
/**
* Implemented by objects that may hold or cache the attributes of a file.
*/
public interface BasicFileAttributesHolder {
/**
* Returns cached attributes (may be null). If file is a symbolic link then
* the attributes are the link attributes and not the final target of the
* file.
*/
BasicFileAttributes get();
/**
* Invalidates cached attributes
*/
void invalidate();
}
......@@ -26,6 +26,7 @@
package sun.nio.fs;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Iterator;
import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
......@@ -49,6 +50,9 @@ class WindowsDirectoryStream
// first entry in the directory
private final String firstName;
// buffer for WIN32_FIND_DATA structure that receives information about file
private final NativeBuffer findDataBuffer;
private final Object closeLock = new Object();
// need closeLock to access these
......@@ -75,6 +79,7 @@ class WindowsDirectoryStream
FirstFile first = FindFirstFile(search);
this.handle = first.handle();
this.firstName = first.name();
this.findDataBuffer = WindowsFileAttributes.getBufferForFindData();
} catch (WindowsException x) {
if (x.lastError() == ERROR_DIRECTORY) {
throw new NotDirectoryException(dir.getPathForExceptionMessage());
......@@ -95,6 +100,7 @@ class WindowsDirectoryStream
return;
isOpen = false;
}
findDataBuffer.release();
try {
FindClose(handle);
} catch (WindowsException x) {
......@@ -133,11 +139,19 @@ class WindowsDirectoryStream
}
// applies filter and also ignores "." and ".."
private Path acceptEntry(String s) {
private Path acceptEntry(String s, BasicFileAttributes attrs) {
if (s.equals(".") || s.equals(".."))
return null;
if (dir.needsSlashWhenResolving()) {
StringBuilder sb = new StringBuilder(dir.toString());
sb.append('\\');
sb.append(s);
s = sb.toString();
} else {
s = dir + s;
}
Path entry = WindowsPath
.createFromNormalizedPath(dir.getFileSystem(), dir + "\\" + s);
.createFromNormalizedPath(dir.getFileSystem(), s, attrs);
if (filter.accept(entry)) {
return entry;
} else {
......@@ -149,21 +163,27 @@ class WindowsDirectoryStream
private Path readNextEntry() {
// handle first element returned by search
if (first != null) {
nextEntry = acceptEntry(first);
nextEntry = acceptEntry(first, null);
first = null;
if (nextEntry != null)
return nextEntry;
}
String name = null;
for (;;) {
String name = null;
WindowsFileAttributes attrs;
// synchronize on closeLock to prevent close while reading
synchronized (closeLock) {
if (!isOpen)
throwAsConcurrentModificationException(new
IllegalStateException("Directory stream is closed"));
try {
name = FindNextFile(handle);
name = FindNextFile(handle, findDataBuffer.address());
if (name == null) {
// NO_MORE_FILES
return null;
}
} catch (WindowsException x) {
try {
x.rethrowAsIOException(dir);
......@@ -171,13 +191,16 @@ class WindowsDirectoryStream
throwAsConcurrentModificationException(ioe);
}
}
}
// EOF
if (name == null)
return null;
// grab the attributes from the WIN32_FIND_DATA structure
// (needs to be done while holding closeLock because close
// will release the buffer)
attrs = WindowsFileAttributes
.fromFindData(findDataBuffer.address());
}
Path entry = acceptEntry(name);
// return entry if accepted by filter
Path entry = acceptEntry(name, attrs);
if (entry != null)
return entry;
}
......
......@@ -87,6 +87,29 @@ class WindowsFileAttributes
private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH = 28;
private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW = 32;
/**
* typedef struct _WIN32_FIND_DATA {
* DWORD dwFileAttributes;
* FILETIME ftCreationTime;
* FILETIME ftLastAccessTime;
* FILETIME ftLastWriteTime;
* DWORD nFileSizeHigh;
* DWORD nFileSizeLow;
* DWORD dwReserved0;
* DWORD dwReserved1;
* TCHAR cFileName[MAX_PATH];
* TCHAR cAlternateFileName[14];
* } WIN32_FIND_DATA;
*/
private static final short SIZEOF_FIND_DATA = 592;
private static final short OFFSETOF_FIND_DATA_ATTRIBUTES = 0;
private static final short OFFSETOF_FIND_DATA_CREATETIME = 4;
private static final short OFFSETOF_FIND_DATA_LASTACCESSTIME = 12;
private static final short OFFSETOF_FIND_DATA_LASTWRITETIME = 20;
private static final short OFFSETOF_FIND_DATA_SIZEHIGH = 28;
private static final short OFFSETOF_FIND_DATA_SIZELOW = 32;
private static final short OFFSETOF_FIND_DATA_RESERVED0 = 36;
// indicates if accurate metadata is required (interesting on NTFS only)
private static final boolean ensureAccurateMetadata;
static {
......@@ -210,6 +233,41 @@ class WindowsFileAttributes
0); // fileIndexLow
}
/**
* Allocates a native buffer for a WIN32_FIND_DATA structure
*/
static NativeBuffer getBufferForFindData() {
return NativeBuffers.getNativeBuffer(SIZEOF_FIND_DATA);
}
/**
* Create a WindowsFileAttributes from a WIN32_FIND_DATA structure
*/
static WindowsFileAttributes fromFindData(long address) {
int fileAttrs = unsafe.getInt(address + OFFSETOF_FIND_DATA_ATTRIBUTES);
long creationTime =
toJavaTime(unsafe.getLong(address + OFFSETOF_FIND_DATA_CREATETIME));
long lastAccessTime =
toJavaTime(unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTACCESSTIME));
long lastWriteTime =
toJavaTime(unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME));
long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32)
+ (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL);
int reparseTag = ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) ?
+ unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0;
return new WindowsFileAttributes(fileAttrs,
creationTime,
lastAccessTime,
lastWriteTime,
size,
reparseTag,
1, // linkCount
0, // volSerialNumber
0, // fileIndexHigh
0); // fileIndexLow
}
/**
* Reads the attributes of an open file
*/
......
......@@ -236,11 +236,9 @@ class WindowsFileSystem
@Override
public Path getPath(String path) {
WindowsPathParser.Result result = WindowsPathParser.parse(path);
return new WindowsPath(this, result.type(), result.root(), result.path());
return WindowsPath.parse(this, path);
}
@Override
public UserPrincipalLookupService getUserPrincipalLookupService() {
return theLookupService;
......
......@@ -211,9 +211,10 @@ class WindowsNativeDispatcher {
* LPWIN32_FIND_DATA lpFindFileData
* )
*
* @return lpFindFileData->cFileName
* @return lpFindFileData->cFileName or null
*/
static native String FindNextFile(long handle) throws WindowsException;
static native String FindNextFile(long handle, long address)
throws WindowsException;
/**
* HANDLE FindFirstStreamW(
......
......@@ -83,10 +83,10 @@ class WindowsPath extends AbstractPath {
/**
* Initializes a new instance of this class.
*/
WindowsPath(WindowsFileSystem fs,
WindowsPathType type,
String root,
String path)
private WindowsPath(WindowsFileSystem fs,
WindowsPathType type,
String root,
String path)
{
this.fs = fs;
this.type = type;
......@@ -95,7 +95,7 @@ class WindowsPath extends AbstractPath {
}
/**
* Creates a WindowsPath by parsing the given path.
* Creates a Path by parsing the given path.
*/
static WindowsPath parse(WindowsFileSystem fs, String path) {
WindowsPathParser.Result result = WindowsPathParser.parse(path);
......@@ -103,18 +103,71 @@ class WindowsPath extends AbstractPath {
}
/**
* Creates a WindowsPath from a given path that is known to be normalized.
* Creates a Path from a given path that is known to be normalized.
*/
static WindowsPath createFromNormalizedPath(WindowsFileSystem fs, String path) {
static WindowsPath createFromNormalizedPath(WindowsFileSystem fs,
String path,
BasicFileAttributes attrs)
{
try {
WindowsPathParser.Result result =
WindowsPathParser.parseNormalizedPath(path);
return new WindowsPath(fs, result.type(), result.root(), result.path());
if (attrs == null) {
return new WindowsPath(fs,
result.type(),
result.root(),
result.path());
} else {
return new WindowsPathWithAttributes(fs,
result.type(),
result.root(),
result.path(),
attrs);
}
} catch (InvalidPathException x) {
throw new AssertionError(x.getMessage());
}
}
/**
* Creates a WindowsPath from a given path that is known to be normalized.
*/
static WindowsPath createFromNormalizedPath(WindowsFileSystem fs,
String path)
{
return createFromNormalizedPath(fs, path, null);
}
/**
* Special implementation with attached/cached attributes (used to quicken
* file tree traveral)
*/
private static class WindowsPathWithAttributes
extends WindowsPath implements BasicFileAttributesHolder
{
final WeakReference<BasicFileAttributes> ref;
WindowsPathWithAttributes(WindowsFileSystem fs,
WindowsPathType type,
String root,
String path,
BasicFileAttributes attrs)
{
super(fs, type, root, path);
ref = new WeakReference<BasicFileAttributes>(attrs);
}
@Override
public BasicFileAttributes get() {
return ref.get();
}
@Override
public void invalidate() {
ref.clear();
}
}
// use this message when throwing exceptions
String getPathForExceptionMessage() {
return path;
......@@ -290,6 +343,12 @@ class WindowsPath extends AbstractPath {
return type == WindowsPathType.UNC;
}
boolean needsSlashWhenResolving() {
if (path.endsWith("\\"))
return false;
return path.length() > root.length();
}
@Override
public boolean isAbsolute() {
return type == WindowsPathType.ABSOLUTE || type == WindowsPathType.UNC;
......
......@@ -392,16 +392,16 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile1(JNIEnv* env, jclass this,
JNIEXPORT jstring JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_FindNextFile(JNIEnv* env, jclass this,
jlong handle)
jlong handle, jlong dataAddress)
{
WIN32_FIND_DATAW data;
HANDLE h = (HANDLE)jlong_to_ptr(handle);
WIN32_FIND_DATAW* data = (WIN32_FIND_DATAW*)jlong_to_ptr(dataAddress);
if (FindNextFileW(h, &data) != 0) {
return (*env)->NewString(env, data.cFileName, wcslen(data.cFileName));
if (FindNextFileW(h, data) != 0) {
return (*env)->NewString(env, data->cFileName, wcslen(data->cFileName));
} else {
if (GetLastError() != ERROR_NO_MORE_FILES)
throwWindowsException(env, GetLastError());
if (GetLastError() != ERROR_NO_MORE_FILES)
throwWindowsException(env, GetLastError());
return NULL;
}
}
......
/*
* Copyright 2008-2009 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.
*/
/* @test
* @bug 6808647
* @summary Checks that a DirectoryStream's iterator returns the expected
* path when opening a directory by specifying only the drive letter.
* @library ..
*/
import java.nio.file.*;
import java.io.File;
import java.io.IOException;
public class DriveLetter {
public static void main(String[] args) throws IOException {
String os = System.getProperty("os.name");
if (!os.startsWith("Windows")) {
System.out.println("This is Windows specific test");
return;
}
String here = System.getProperty("user.dir");
if (here.length() < 2 || here.charAt(1) != ':')
throw new RuntimeException("Unable to determine drive letter");
// create temporary file in current directory
File tempFile = File.createTempFile("foo", "tmp", new File(here));
try {
// we should expect C:foo.tmp to be returned by iterator
String drive = here.substring(0, 2);
Path expected = Paths.get(drive).resolve(tempFile.getName());
boolean found = false;
DirectoryStream<Path> stream = Paths.get(drive).newDirectoryStream();
try {
for (Path file : stream) {
if (file.equals(expected)) {
found = true;
break;
}
}
} finally {
stream.close();
}
if (!found)
throw new RuntimeException("Temporary file not found???");
} finally {
tempFile.delete();
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册