893N/A/*
2362N/A * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
893N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
893N/A *
893N/A * This code is free software; you can redistribute it and/or modify it
893N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
893N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
893N/A *
893N/A * This code is distributed in the hope that it will be useful, but WITHOUT
893N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
893N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
893N/A * version 2 for more details (a copy is included in the LICENSE file that
893N/A * accompanied this code).
893N/A *
893N/A * You should have received a copy of the GNU General Public License version
893N/A * 2 along with this work; if not, write to the Free Software Foundation,
893N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
893N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
893N/A */
893N/A
893N/Apackage sun.nio.fs;
893N/A
893N/Aimport java.nio.file.attribute.*;
893N/Aimport java.util.concurrent.TimeUnit;
893N/Aimport java.security.AccessController;
893N/Aimport sun.misc.Unsafe;
893N/Aimport sun.security.action.GetPropertyAction;
893N/A
893N/Aimport static sun.nio.fs.WindowsNativeDispatcher.*;
893N/Aimport static sun.nio.fs.WindowsConstants.*;
893N/A
893N/A/**
893N/A * Windows implementation of DosFileAttributes/BasicFileAttributes
893N/A */
893N/A
893N/Aclass WindowsFileAttributes
893N/A implements DosFileAttributes
893N/A{
893N/A private static final Unsafe unsafe = Unsafe.getUnsafe();
893N/A
893N/A /*
893N/A * typedef struct _BY_HANDLE_FILE_INFORMATION {
893N/A * DWORD dwFileAttributes;
893N/A * FILETIME ftCreationTime;
893N/A * FILETIME ftLastAccessTime;
893N/A * FILETIME ftLastWriteTime;
893N/A * DWORD dwVolumeSerialNumber;
893N/A * DWORD nFileSizeHigh;
893N/A * DWORD nFileSizeLow;
893N/A * DWORD nNumberOfLinks;
893N/A * DWORD nFileIndexHigh;
893N/A * DWORD nFileIndexLow;
893N/A * } BY_HANDLE_FILE_INFORMATION;
893N/A */
893N/A private static final short SIZEOF_FILE_INFORMATION = 52;
893N/A private static final short OFFSETOF_FILE_INFORMATION_ATTRIBUTES = 0;
893N/A private static final short OFFSETOF_FILE_INFORMATION_CREATETIME = 4;
893N/A private static final short OFFSETOF_FILE_INFORMATION_LASTACCESSTIME = 12;
893N/A private static final short OFFSETOF_FILE_INFORMATION_LASTWRITETIME = 20;
893N/A private static final short OFFSETOF_FILE_INFORMATION_VOLSERIALNUM = 28;
893N/A private static final short OFFSETOF_FILE_INFORMATION_SIZEHIGH = 32;
893N/A private static final short OFFSETOF_FILE_INFORMATION_SIZELOW = 36;
893N/A private static final short OFFSETOF_FILE_INFORMATION_INDEXHIGH = 44;
893N/A private static final short OFFSETOF_FILE_INFORMATION_INDEXLOW = 48;
893N/A
893N/A /*
893N/A * typedef struct _WIN32_FILE_ATTRIBUTE_DATA {
893N/A * DWORD dwFileAttributes;
893N/A * FILETIME ftCreationTime;
893N/A * FILETIME ftLastAccessTime;
893N/A * FILETIME ftLastWriteTime;
893N/A * DWORD nFileSizeHigh;
893N/A * DWORD nFileSizeLow;
893N/A * } WIN32_FILE_ATTRIBUTE_DATA;
893N/A */
893N/A private static final short SIZEOF_FILE_ATTRIBUTE_DATA = 36;
893N/A private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES = 0;
893N/A private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME = 4;
893N/A private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME = 12;
893N/A private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME = 20;
893N/A private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH = 28;
893N/A private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW = 32;
893N/A
907N/A /**
907N/A * typedef struct _WIN32_FIND_DATA {
907N/A * DWORD dwFileAttributes;
907N/A * FILETIME ftCreationTime;
907N/A * FILETIME ftLastAccessTime;
907N/A * FILETIME ftLastWriteTime;
907N/A * DWORD nFileSizeHigh;
907N/A * DWORD nFileSizeLow;
907N/A * DWORD dwReserved0;
907N/A * DWORD dwReserved1;
907N/A * TCHAR cFileName[MAX_PATH];
907N/A * TCHAR cAlternateFileName[14];
907N/A * } WIN32_FIND_DATA;
907N/A */
907N/A private static final short SIZEOF_FIND_DATA = 592;
907N/A private static final short OFFSETOF_FIND_DATA_ATTRIBUTES = 0;
907N/A private static final short OFFSETOF_FIND_DATA_CREATETIME = 4;
907N/A private static final short OFFSETOF_FIND_DATA_LASTACCESSTIME = 12;
907N/A private static final short OFFSETOF_FIND_DATA_LASTWRITETIME = 20;
907N/A private static final short OFFSETOF_FIND_DATA_SIZEHIGH = 28;
907N/A private static final short OFFSETOF_FIND_DATA_SIZELOW = 32;
907N/A private static final short OFFSETOF_FIND_DATA_RESERVED0 = 36;
907N/A
1319N/A // used to adjust values between Windows and java epoch
1319N/A private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
1319N/A
893N/A // indicates if accurate metadata is required (interesting on NTFS only)
893N/A private static final boolean ensureAccurateMetadata;
893N/A static {
893N/A String propValue = AccessController.doPrivileged(
893N/A new GetPropertyAction("sun.nio.fs.ensureAccurateMetadata", "false"));
893N/A ensureAccurateMetadata = (propValue.length() == 0) ?
893N/A true : Boolean.valueOf(propValue);
893N/A }
893N/A
893N/A // attributes
893N/A private final int fileAttrs;
893N/A private final long creationTime;
893N/A private final long lastAccessTime;
893N/A private final long lastWriteTime;
893N/A private final long size;
893N/A private final int reparseTag;
893N/A
893N/A // additional attributes when using GetFileInformationByHandle
893N/A private final int volSerialNumber;
893N/A private final int fileIndexHigh;
893N/A private final int fileIndexLow;
893N/A
893N/A /**
893N/A * Convert 64-bit value representing the number of 100-nanosecond intervals
1319N/A * since January 1, 1601 to a FileTime.
893N/A */
1319N/A static FileTime toFileTime(long time) {
1319N/A // 100ns -> us
1319N/A time /= 10L;
1319N/A // adjust to java epoch
1319N/A time += WINDOWS_EPOCH_IN_MICROSECONDS;
1319N/A return FileTime.from(time, TimeUnit.MICROSECONDS);
893N/A }
893N/A
893N/A /**
1319N/A * Convert FileTime to 64-bit value representing the number of 100-nanosecond
893N/A * intervals since January 1, 1601.
893N/A */
1319N/A static long toWindowsTime(FileTime time) {
1319N/A long value = time.to(TimeUnit.MICROSECONDS);
1319N/A // adjust to Windows epoch+= 11644473600000000L;
1319N/A value -= WINDOWS_EPOCH_IN_MICROSECONDS;
1319N/A // us -> 100ns
1319N/A value *= 10L;
1319N/A return value;
893N/A }
893N/A
893N/A /**
893N/A * Initialize a new instance of this class
893N/A */
893N/A private WindowsFileAttributes(int fileAttrs,
893N/A long creationTime,
893N/A long lastAccessTime,
893N/A long lastWriteTime,
893N/A long size,
893N/A int reparseTag,
893N/A int volSerialNumber,
893N/A int fileIndexHigh,
893N/A int fileIndexLow)
893N/A {
893N/A this.fileAttrs = fileAttrs;
893N/A this.creationTime = creationTime;
893N/A this.lastAccessTime = lastAccessTime;
893N/A this.lastWriteTime = lastWriteTime;
893N/A this.size = size;
893N/A this.reparseTag = reparseTag;
893N/A this.volSerialNumber = volSerialNumber;
893N/A this.fileIndexHigh = fileIndexHigh;
893N/A this.fileIndexLow = fileIndexLow;
893N/A }
893N/A
893N/A /**
893N/A * Create a WindowsFileAttributes from a BY_HANDLE_FILE_INFORMATION structure
893N/A */
893N/A private static WindowsFileAttributes fromFileInformation(long address, int reparseTag) {
893N/A int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES);
1319N/A long creationTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_CREATETIME);
1319N/A long lastAccessTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTACCESSTIME);
1319N/A long lastWriteTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTWRITETIME);
893N/A long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZEHIGH)) << 32)
893N/A + (unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZELOW) & 0xFFFFFFFFL);
893N/A int volSerialNumber = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_VOLSERIALNUM);
893N/A int fileIndexHigh = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXHIGH);
893N/A int fileIndexLow = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXLOW);
893N/A return new WindowsFileAttributes(fileAttrs,
893N/A creationTime,
893N/A lastAccessTime,
893N/A lastWriteTime,
893N/A size,
893N/A reparseTag,
893N/A volSerialNumber,
893N/A fileIndexHigh,
893N/A fileIndexLow);
893N/A }
893N/A
893N/A /**
893N/A * Create a WindowsFileAttributes from a WIN32_FILE_ATTRIBUTE_DATA structure
893N/A */
893N/A private static WindowsFileAttributes fromFileAttributeData(long address, int reparseTag) {
893N/A int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES);
1319N/A long creationTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME);
1319N/A long lastAccessTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME);
1319N/A long lastWriteTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME);
893N/A long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH)) << 32)
893N/A + (unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW) & 0xFFFFFFFFL);
893N/A return new WindowsFileAttributes(fileAttrs,
893N/A creationTime,
893N/A lastAccessTime,
893N/A lastWriteTime,
893N/A size,
893N/A reparseTag,
893N/A 0, // volSerialNumber
893N/A 0, // fileIndexHigh
893N/A 0); // fileIndexLow
893N/A }
893N/A
907N/A
907N/A /**
907N/A * Allocates a native buffer for a WIN32_FIND_DATA structure
907N/A */
907N/A static NativeBuffer getBufferForFindData() {
907N/A return NativeBuffers.getNativeBuffer(SIZEOF_FIND_DATA);
907N/A }
907N/A
907N/A /**
907N/A * Create a WindowsFileAttributes from a WIN32_FIND_DATA structure
907N/A */
907N/A static WindowsFileAttributes fromFindData(long address) {
907N/A int fileAttrs = unsafe.getInt(address + OFFSETOF_FIND_DATA_ATTRIBUTES);
1319N/A long creationTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_CREATETIME);
1319N/A long lastAccessTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTACCESSTIME);
1319N/A long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME);
907N/A long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32)
907N/A + (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL);
1576N/A int reparseTag = isReparsePoint(fileAttrs) ?
1576N/A unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0;
907N/A return new WindowsFileAttributes(fileAttrs,
907N/A creationTime,
907N/A lastAccessTime,
907N/A lastWriteTime,
907N/A size,
907N/A reparseTag,
907N/A 0, // volSerialNumber
907N/A 0, // fileIndexHigh
907N/A 0); // fileIndexLow
907N/A }
907N/A
893N/A /**
893N/A * Reads the attributes of an open file
893N/A */
893N/A static WindowsFileAttributes readAttributes(long handle)
893N/A throws WindowsException
893N/A {
893N/A NativeBuffer buffer = NativeBuffers
893N/A .getNativeBuffer(SIZEOF_FILE_INFORMATION);
893N/A try {
893N/A long address = buffer.address();
893N/A GetFileInformationByHandle(handle, address);
893N/A
893N/A // if file is a reparse point then read the tag
893N/A int reparseTag = 0;
893N/A int fileAttrs = unsafe
893N/A .getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES);
1576N/A if (isReparsePoint(fileAttrs)) {
893N/A int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
893N/A NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size);
893N/A try {
893N/A DeviceIoControlGetReparsePoint(handle, reparseBuffer.address(), size);
893N/A reparseTag = (int)unsafe.getLong(reparseBuffer.address());
893N/A } finally {
893N/A reparseBuffer.release();
893N/A }
893N/A }
893N/A
893N/A return fromFileInformation(address, reparseTag);
893N/A } finally {
893N/A buffer.release();
893N/A }
893N/A }
893N/A
893N/A /**
893N/A * Returns attributes of given file.
893N/A */
893N/A static WindowsFileAttributes get(WindowsPath path, boolean followLinks)
893N/A throws WindowsException
893N/A {
893N/A if (!ensureAccurateMetadata) {
1476N/A WindowsException firstException = null;
1476N/A
1476N/A // GetFileAttributesEx is the fastest way to read the attributes
893N/A NativeBuffer buffer =
893N/A NativeBuffers.getNativeBuffer(SIZEOF_FILE_ATTRIBUTE_DATA);
893N/A try {
893N/A long address = buffer.address();
893N/A GetFileAttributesEx(path.getPathForWin32Calls(), address);
893N/A // if reparse point then file may be a sym link; otherwise
893N/A // just return the attributes
893N/A int fileAttrs = unsafe
893N/A .getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES);
1576N/A if (!isReparsePoint(fileAttrs))
893N/A return fromFileAttributeData(address, 0);
1476N/A } catch (WindowsException x) {
1476N/A if (x.lastError() != ERROR_SHARING_VIOLATION)
1476N/A throw x;
1476N/A firstException = x;
893N/A } finally {
893N/A buffer.release();
893N/A }
1476N/A
1476N/A // For sharing violations, fallback to FindFirstFile if the file
1476N/A // is not a root directory.
1476N/A if (firstException != null) {
1476N/A String search = path.getPathForWin32Calls();
1476N/A char last = search.charAt(search.length() -1);
1476N/A if (last == ':' || last == '\\')
1476N/A throw firstException;
1476N/A buffer = getBufferForFindData();
1476N/A try {
1476N/A long handle = FindFirstFile(search, buffer.address());
1476N/A FindClose(handle);
1476N/A WindowsFileAttributes attrs = fromFindData(buffer.address());
1476N/A // FindFirstFile does not follow sym links. Even if
1476N/A // followLinks is false, there isn't sufficient information
1476N/A // in the WIN32_FIND_DATA structure to know if the reparse
1476N/A // point is a sym link.
1476N/A if (attrs.isReparsePoint())
1476N/A throw firstException;
1476N/A return attrs;
1476N/A } catch (WindowsException ignore) {
1476N/A throw firstException;
1476N/A } finally {
1476N/A buffer.release();
1476N/A }
1476N/A }
893N/A }
893N/A
893N/A // file is reparse point so need to open file to get attributes
893N/A long handle = path.openForReadAttributeAccess(followLinks);
893N/A try {
893N/A return readAttributes(handle);
893N/A } finally {
893N/A CloseHandle(handle);
893N/A }
893N/A }
893N/A
893N/A /**
1576N/A * Returns true if the attributes are of the same file - both files must
893N/A * be open.
893N/A */
893N/A static boolean isSameFile(WindowsFileAttributes attrs1,
893N/A WindowsFileAttributes attrs2)
893N/A {
893N/A // volume serial number and file index must be the same
893N/A return (attrs1.volSerialNumber == attrs2.volSerialNumber) &&
893N/A (attrs1.fileIndexHigh == attrs2.fileIndexHigh) &&
893N/A (attrs1.fileIndexLow == attrs2.fileIndexLow);
893N/A }
893N/A
1576N/A /**
1576N/A * Returns true if the attributes are of a file with a reparse point.
1576N/A */
1576N/A static boolean isReparsePoint(int attributes) {
1576N/A return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
1576N/A }
1576N/A
893N/A // package-private
893N/A int attributes() {
893N/A return fileAttrs;
893N/A }
893N/A
893N/A int volSerialNumber() {
893N/A if (volSerialNumber == 0)
893N/A throw new AssertionError("Should not get here");
893N/A return volSerialNumber;
893N/A }
893N/A
893N/A int fileIndexHigh() {
893N/A if (volSerialNumber == 0)
893N/A throw new AssertionError("Should not get here");
893N/A return fileIndexHigh;
893N/A }
893N/A
893N/A int fileIndexLow() {
893N/A if (volSerialNumber == 0)
893N/A throw new AssertionError("Should not get here");
893N/A return fileIndexLow;
893N/A }
893N/A
893N/A @Override
893N/A public long size() {
893N/A return size;
893N/A }
893N/A
893N/A @Override
1319N/A public FileTime lastModifiedTime() {
1319N/A return toFileTime(lastWriteTime);
893N/A }
893N/A
893N/A @Override
1319N/A public FileTime lastAccessTime() {
1319N/A return toFileTime(lastAccessTime);
893N/A }
893N/A
893N/A @Override
1319N/A public FileTime creationTime() {
1319N/A return toFileTime(creationTime);
893N/A }
893N/A
893N/A @Override
893N/A public Object fileKey() {
893N/A return null;
893N/A }
893N/A
893N/A // package private
893N/A boolean isReparsePoint() {
1576N/A return isReparsePoint(fileAttrs);
893N/A }
893N/A
893N/A boolean isDirectoryLink() {
893N/A return isSymbolicLink() && ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0);
893N/A }
893N/A
893N/A @Override
893N/A public boolean isSymbolicLink() {
893N/A return reparseTag == IO_REPARSE_TAG_SYMLINK;
893N/A }
893N/A
893N/A @Override
893N/A public boolean isDirectory() {
893N/A // ignore FILE_ATTRIBUTE_DIRECTORY attribute if file is a sym link
893N/A if (isSymbolicLink())
893N/A return false;
893N/A return ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0);
893N/A }
893N/A
893N/A @Override
893N/A public boolean isOther() {
893N/A if (isSymbolicLink())
893N/A return false;
893N/A // return true if device or reparse point
893N/A return ((fileAttrs & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)) != 0);
893N/A }
893N/A
893N/A @Override
893N/A public boolean isRegularFile() {
893N/A return !isSymbolicLink() && !isDirectory() && !isOther();
893N/A }
893N/A
893N/A @Override
893N/A public boolean isReadOnly() {
893N/A return (fileAttrs & FILE_ATTRIBUTE_READONLY) != 0;
893N/A }
893N/A
893N/A @Override
893N/A public boolean isHidden() {
893N/A return (fileAttrs & FILE_ATTRIBUTE_HIDDEN) != 0;
893N/A }
893N/A
893N/A @Override
893N/A public boolean isArchive() {
893N/A return (fileAttrs & FILE_ATTRIBUTE_ARCHIVE) != 0;
893N/A }
893N/A
893N/A @Override
893N/A public boolean isSystem() {
893N/A return (fileAttrs & FILE_ATTRIBUTE_SYSTEM) != 0;
893N/A }
893N/A}