Path: blob/master/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java
41139 views
/*1* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.fs;2627import java.nio.file.attribute.*;28import java.util.concurrent.TimeUnit;29import jdk.internal.misc.Unsafe;30import sun.security.action.GetPropertyAction;3132import static sun.nio.fs.WindowsNativeDispatcher.*;33import static sun.nio.fs.WindowsConstants.*;3435/**36* Windows implementation of DosFileAttributes/BasicFileAttributes37*/3839class WindowsFileAttributes40implements DosFileAttributes41{42private static final Unsafe unsafe = Unsafe.getUnsafe();4344/*45* typedef struct _BY_HANDLE_FILE_INFORMATION {46* DWORD dwFileAttributes;47* FILETIME ftCreationTime;48* FILETIME ftLastAccessTime;49* FILETIME ftLastWriteTime;50* DWORD dwVolumeSerialNumber;51* DWORD nFileSizeHigh;52* DWORD nFileSizeLow;53* DWORD nNumberOfLinks;54* DWORD nFileIndexHigh;55* DWORD nFileIndexLow;56* } BY_HANDLE_FILE_INFORMATION;57*/58private static final short SIZEOF_FILE_INFORMATION = 52;59private static final short OFFSETOF_FILE_INFORMATION_ATTRIBUTES = 0;60private static final short OFFSETOF_FILE_INFORMATION_CREATETIME = 4;61private static final short OFFSETOF_FILE_INFORMATION_LASTACCESSTIME = 12;62private static final short OFFSETOF_FILE_INFORMATION_LASTWRITETIME = 20;63private static final short OFFSETOF_FILE_INFORMATION_VOLSERIALNUM = 28;64private static final short OFFSETOF_FILE_INFORMATION_SIZEHIGH = 32;65private static final short OFFSETOF_FILE_INFORMATION_SIZELOW = 36;66private static final short OFFSETOF_FILE_INFORMATION_INDEXHIGH = 44;67private static final short OFFSETOF_FILE_INFORMATION_INDEXLOW = 48;6869/*70* typedef struct _WIN32_FILE_ATTRIBUTE_DATA {71* DWORD dwFileAttributes;72* FILETIME ftCreationTime;73* FILETIME ftLastAccessTime;74* FILETIME ftLastWriteTime;75* DWORD nFileSizeHigh;76* DWORD nFileSizeLow;77* } WIN32_FILE_ATTRIBUTE_DATA;78*/79private static final short SIZEOF_FILE_ATTRIBUTE_DATA = 36;80private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES = 0;81private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME = 4;82private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME = 12;83private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME = 20;84private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH = 28;85private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW = 32;8687/**88* typedef struct _WIN32_FIND_DATA {89* DWORD dwFileAttributes;90* FILETIME ftCreationTime;91* FILETIME ftLastAccessTime;92* FILETIME ftLastWriteTime;93* DWORD nFileSizeHigh;94* DWORD nFileSizeLow;95* DWORD dwReserved0;96* DWORD dwReserved1;97* TCHAR cFileName[MAX_PATH];98* TCHAR cAlternateFileName[14];99* } WIN32_FIND_DATA;100*/101private static final short SIZEOF_FIND_DATA = 592;102private static final short OFFSETOF_FIND_DATA_ATTRIBUTES = 0;103private static final short OFFSETOF_FIND_DATA_CREATETIME = 4;104private static final short OFFSETOF_FIND_DATA_LASTACCESSTIME = 12;105private static final short OFFSETOF_FIND_DATA_LASTWRITETIME = 20;106private static final short OFFSETOF_FIND_DATA_SIZEHIGH = 28;107private static final short OFFSETOF_FIND_DATA_SIZELOW = 32;108private static final short OFFSETOF_FIND_DATA_RESERVED0 = 36;109110// used to adjust values between Windows and java epochs111private static final long WINDOWS_EPOCH_IN_MICROS = -11644473600000000L;112private static final long WINDOWS_EPOCH_IN_100NS = -116444736000000000L;113114// indicates if accurate metadata is required (interesting on NTFS only)115private static final boolean ensureAccurateMetadata;116static {117String propValue = GetPropertyAction.privilegedGetProperty(118"sun.nio.fs.ensureAccurateMetadata", "false");119ensureAccurateMetadata = propValue.isEmpty() ? true : Boolean.parseBoolean(propValue);120}121122// attributes123private final int fileAttrs;124private final long creationTime;125private final long lastAccessTime;126private final long lastWriteTime;127private final long size;128private final int reparseTag;129130// additional attributes when using GetFileInformationByHandle131private final int volSerialNumber;132private final int fileIndexHigh;133private final int fileIndexLow;134135/**136* Convert 64-bit value representing the number of 100-nanosecond intervals137* since January 1, 1601 to a FileTime.138*/139static FileTime toFileTime(long time) {140try {141long adjusted = Math.addExact(time, WINDOWS_EPOCH_IN_100NS);142long nanos = Math.multiplyExact(adjusted, 100L);143return FileTime.from(nanos, TimeUnit.NANOSECONDS);144} catch (ArithmeticException e) {145long micros = Math.addExact(time/10L, WINDOWS_EPOCH_IN_MICROS);146return FileTime.from(micros, TimeUnit.MICROSECONDS);147}148}149150/**151* Convert FileTime to 64-bit value representing the number of152* 100-nanosecond intervals since January 1, 1601.153*/154static long toWindowsTime(FileTime time) {155long adjusted = time.to(TimeUnit.NANOSECONDS)/100L;156return adjusted - WINDOWS_EPOCH_IN_100NS;157}158159/**160* Initialize a new instance of this class161*/162private WindowsFileAttributes(int fileAttrs,163long creationTime,164long lastAccessTime,165long lastWriteTime,166long size,167int reparseTag,168int volSerialNumber,169int fileIndexHigh,170int fileIndexLow)171{172this.fileAttrs = fileAttrs;173this.creationTime = creationTime;174this.lastAccessTime = lastAccessTime;175this.lastWriteTime = lastWriteTime;176this.size = size;177this.reparseTag = reparseTag;178this.volSerialNumber = volSerialNumber;179this.fileIndexHigh = fileIndexHigh;180this.fileIndexLow = fileIndexLow;181}182183/**184* Create a WindowsFileAttributes from a BY_HANDLE_FILE_INFORMATION structure185*/186private static WindowsFileAttributes fromFileInformation(long address, int reparseTag) {187int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES);188long creationTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_CREATETIME);189long lastAccessTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTACCESSTIME);190long lastWriteTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTWRITETIME);191long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZEHIGH)) << 32)192+ (unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZELOW) & 0xFFFFFFFFL);193int volSerialNumber = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_VOLSERIALNUM);194int fileIndexHigh = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXHIGH);195int fileIndexLow = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXLOW);196return new WindowsFileAttributes(fileAttrs,197creationTime,198lastAccessTime,199lastWriteTime,200size,201reparseTag,202volSerialNumber,203fileIndexHigh,204fileIndexLow);205}206207/**208* Create a WindowsFileAttributes from a WIN32_FILE_ATTRIBUTE_DATA structure209*/210private static WindowsFileAttributes fromFileAttributeData(long address, int reparseTag) {211int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES);212long creationTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME);213long lastAccessTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME);214long lastWriteTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME);215long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH)) << 32)216+ (unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW) & 0xFFFFFFFFL);217return new WindowsFileAttributes(fileAttrs,218creationTime,219lastAccessTime,220lastWriteTime,221size,222reparseTag,2230, // volSerialNumber2240, // fileIndexHigh2250); // fileIndexLow226}227228229/**230* Allocates a native buffer for a WIN32_FIND_DATA structure231*/232static NativeBuffer getBufferForFindData() {233return NativeBuffers.getNativeBuffer(SIZEOF_FIND_DATA);234}235236/**237* Create a WindowsFileAttributes from a WIN32_FIND_DATA structure238*/239static WindowsFileAttributes fromFindData(long address) {240int fileAttrs = unsafe.getInt(address + OFFSETOF_FIND_DATA_ATTRIBUTES);241long creationTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_CREATETIME);242long lastAccessTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTACCESSTIME);243long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME);244long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32)245+ (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL);246int reparseTag = isReparsePoint(fileAttrs) ?247unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0;248return new WindowsFileAttributes(fileAttrs,249creationTime,250lastAccessTime,251lastWriteTime,252size,253reparseTag,2540, // volSerialNumber2550, // fileIndexHigh2560); // fileIndexLow257}258259/**260* Reads the attributes of an open file261*/262static WindowsFileAttributes readAttributes(long handle)263throws WindowsException264{265NativeBuffer buffer = NativeBuffers266.getNativeBuffer(SIZEOF_FILE_INFORMATION);267try {268long address = buffer.address();269GetFileInformationByHandle(handle, address);270271// if file is a reparse point then read the tag272int reparseTag = 0;273int fileAttrs = unsafe274.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES);275if (isReparsePoint(fileAttrs)) {276int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;277NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size);278try {279DeviceIoControlGetReparsePoint(handle, reparseBuffer.address(), size);280reparseTag = (int)unsafe.getLong(reparseBuffer.address());281} finally {282reparseBuffer.release();283}284}285286return fromFileInformation(address, reparseTag);287} finally {288buffer.release();289}290}291292/**293* Returns attributes of given file.294*/295static WindowsFileAttributes get(WindowsPath path, boolean followLinks)296throws WindowsException297{298if (!ensureAccurateMetadata) {299WindowsException firstException = null;300301// GetFileAttributesEx is the fastest way to read the attributes302NativeBuffer buffer =303NativeBuffers.getNativeBuffer(SIZEOF_FILE_ATTRIBUTE_DATA);304try {305long address = buffer.address();306GetFileAttributesEx(path.getPathForWin32Calls(), address);307// if reparse point then file may be a sym link; otherwise308// just return the attributes309int fileAttrs = unsafe310.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES);311if (!isReparsePoint(fileAttrs))312return fromFileAttributeData(address, 0);313} catch (WindowsException x) {314if (x.lastError() != ERROR_SHARING_VIOLATION)315throw x;316firstException = x;317} finally {318buffer.release();319}320321// For sharing violations, fallback to FindFirstFile if the file322// is not a root directory.323if (firstException != null) {324String search = path.getPathForWin32Calls();325char last = search.charAt(search.length() -1);326if (last == ':' || last == '\\')327throw firstException;328buffer = getBufferForFindData();329try {330long handle = FindFirstFile(search, buffer.address());331FindClose(handle);332WindowsFileAttributes attrs = fromFindData(buffer.address());333// FindFirstFile does not follow sym links. Even if334// followLinks is false, there isn't sufficient information335// in the WIN32_FIND_DATA structure to know if the reparse336// point is a sym link.337if (attrs.isReparsePoint())338throw firstException;339return attrs;340} catch (WindowsException ignore) {341throw firstException;342} finally {343buffer.release();344}345}346}347348// file is reparse point so need to open file to get attributes349long handle = path.openForReadAttributeAccess(followLinks);350try {351return readAttributes(handle);352} finally {353CloseHandle(handle);354}355}356357/**358* Returns true if the attributes are of the same file - both files must359* be open.360*/361static boolean isSameFile(WindowsFileAttributes attrs1,362WindowsFileAttributes attrs2)363{364// volume serial number and file index must be the same365return (attrs1.volSerialNumber == attrs2.volSerialNumber) &&366(attrs1.fileIndexHigh == attrs2.fileIndexHigh) &&367(attrs1.fileIndexLow == attrs2.fileIndexLow);368}369370/**371* Returns true if the attributes are of a file with a reparse point.372*/373static boolean isReparsePoint(int attributes) {374return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;375}376377// package-private378int attributes() {379return fileAttrs;380}381382int volSerialNumber() {383return volSerialNumber;384}385386int fileIndexHigh() {387return fileIndexHigh;388}389390int fileIndexLow() {391return fileIndexLow;392}393394@Override395public long size() {396return size;397}398399@Override400public FileTime lastModifiedTime() {401return toFileTime(lastWriteTime);402}403404@Override405public FileTime lastAccessTime() {406return toFileTime(lastAccessTime);407}408409@Override410public FileTime creationTime() {411return toFileTime(creationTime);412}413414@Override415public Object fileKey() {416return null;417}418419// package private420boolean isReparsePoint() {421return isReparsePoint(fileAttrs);422}423424boolean isDirectoryLink() {425return isSymbolicLink() && ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0);426}427428@Override429public boolean isSymbolicLink() {430return reparseTag == IO_REPARSE_TAG_SYMLINK;431}432433boolean isUnixDomainSocket() {434return reparseTag == IO_REPARSE_TAG_AF_UNIX;435}436437@Override438public boolean isDirectory() {439// ignore FILE_ATTRIBUTE_DIRECTORY attribute if file is a sym link440if (isSymbolicLink())441return false;442return ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0);443}444445@Override446public boolean isOther() {447if (isSymbolicLink())448return false;449// return true if device or reparse point450return ((fileAttrs & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)) != 0);451}452453@Override454public boolean isRegularFile() {455return !isSymbolicLink() && !isDirectory() && !isOther();456}457458@Override459public boolean isReadOnly() {460return (fileAttrs & FILE_ATTRIBUTE_READONLY) != 0;461}462463@Override464public boolean isHidden() {465return (fileAttrs & FILE_ATTRIBUTE_HIDDEN) != 0;466}467468@Override469public boolean isArchive() {470return (fileAttrs & FILE_ATTRIBUTE_ARCHIVE) != 0;471}472473@Override474public boolean isSystem() {475return (fileAttrs & FILE_ATTRIBUTE_SYSTEM) != 0;476}477}478479480