1 /* 2 * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.nio.fs; 27 28 import java.nio.file.attribute.*; 29 import java.util.concurrent.TimeUnit; 30 import jdk.internal.misc.Unsafe; 31 import sun.security.action.GetPropertyAction; 32 33 import static sun.nio.fs.WindowsNativeDispatcher.*; 34 import static sun.nio.fs.WindowsConstants.*; 35 36 /** 37 * Windows implementation of DosFileAttributes/BasicFileAttributes 38 */ 39 40 class WindowsFileAttributes 41 implements DosFileAttributes 42 { 43 private static final Unsafe unsafe = Unsafe.getUnsafe(); 44 45 /* 46 * typedef struct _BY_HANDLE_FILE_INFORMATION { 47 * DWORD dwFileAttributes; 48 * FILETIME ftCreationTime; 49 * FILETIME ftLastAccessTime; 50 * FILETIME ftLastWriteTime; 51 * DWORD dwVolumeSerialNumber; 52 * DWORD nFileSizeHigh; 53 * DWORD nFileSizeLow; 54 * DWORD nNumberOfLinks; 55 * DWORD nFileIndexHigh; 56 * DWORD nFileIndexLow; 57 * } BY_HANDLE_FILE_INFORMATION; 58 */ 59 private static final short SIZEOF_FILE_INFORMATION = 52; 60 private static final short OFFSETOF_FILE_INFORMATION_ATTRIBUTES = 0; 61 private static final short OFFSETOF_FILE_INFORMATION_CREATETIME = 4; 62 private static final short OFFSETOF_FILE_INFORMATION_LASTACCESSTIME = 12; 63 private static final short OFFSETOF_FILE_INFORMATION_LASTWRITETIME = 20; 64 private static final short OFFSETOF_FILE_INFORMATION_VOLSERIALNUM = 28; 65 private static final short OFFSETOF_FILE_INFORMATION_SIZEHIGH = 32; 66 private static final short OFFSETOF_FILE_INFORMATION_SIZELOW = 36; 67 private static final short OFFSETOF_FILE_INFORMATION_INDEXHIGH = 44; 68 private static final short OFFSETOF_FILE_INFORMATION_INDEXLOW = 48; 69 70 /* 71 * typedef struct _WIN32_FILE_ATTRIBUTE_DATA { 72 * DWORD dwFileAttributes; 73 * FILETIME ftCreationTime; 74 * FILETIME ftLastAccessTime; 75 * FILETIME ftLastWriteTime; 76 * DWORD nFileSizeHigh; 77 * DWORD nFileSizeLow; 78 * } WIN32_FILE_ATTRIBUTE_DATA; 79 */ 80 private static final short SIZEOF_FILE_ATTRIBUTE_DATA = 36; 81 private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES = 0; 82 private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME = 4; 83 private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME = 12; 84 private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME = 20; 85 private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH = 28; 86 private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW = 32; 87 88 /** 89 * typedef struct _WIN32_FIND_DATA { 90 * DWORD dwFileAttributes; 91 * FILETIME ftCreationTime; 92 * FILETIME ftLastAccessTime; 93 * FILETIME ftLastWriteTime; 94 * DWORD nFileSizeHigh; 95 * DWORD nFileSizeLow; 96 * DWORD dwReserved0; 97 * DWORD dwReserved1; 98 * TCHAR cFileName[MAX_PATH]; 99 * TCHAR cAlternateFileName[14]; 100 * } WIN32_FIND_DATA; 101 */ 102 private static final short SIZEOF_FIND_DATA = 592; 103 private static final short OFFSETOF_FIND_DATA_ATTRIBUTES = 0; 104 private static final short OFFSETOF_FIND_DATA_CREATETIME = 4; 105 private static final short OFFSETOF_FIND_DATA_LASTACCESSTIME = 12; 106 private static final short OFFSETOF_FIND_DATA_LASTWRITETIME = 20; 107 private static final short OFFSETOF_FIND_DATA_SIZEHIGH = 28; 108 private static final short OFFSETOF_FIND_DATA_SIZELOW = 32; 109 private static final short OFFSETOF_FIND_DATA_RESERVED0 = 36; 110 111 // used to adjust values between Windows and java epoch 112 private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L; 113 114 // indicates if accurate metadata is required (interesting on NTFS only) 115 private static final boolean ensureAccurateMetadata; 116 static { 117 String propValue = GetPropertyAction.privilegedGetProperty( 118 "sun.nio.fs.ensureAccurateMetadata", "false"); 119 ensureAccurateMetadata = propValue.isEmpty() ? true : Boolean.parseBoolean(propValue); 120 } 121 122 // attributes 123 private final int fileAttrs; 124 private final long creationTime; 125 private final long lastAccessTime; 126 private final long lastWriteTime; 127 private final long size; 128 private final int reparseTag; 129 130 // additional attributes when using GetFileInformationByHandle 131 private final int volSerialNumber; 132 private final int fileIndexHigh; 133 private final int fileIndexLow; 134 135 /** 136 * Convert 64-bit value representing the number of 100-nanosecond intervals 137 * since January 1, 1601 to a FileTime. 138 */ 139 static FileTime toFileTime(long time) { 140 // 100ns -> us 141 time /= 10L; 142 // adjust to java epoch 143 time += WINDOWS_EPOCH_IN_MICROSECONDS; 144 return FileTime.from(time, TimeUnit.MICROSECONDS); 145 } 146 147 /** 148 * Convert FileTime to 64-bit value representing the number of 100-nanosecond 149 * intervals since January 1, 1601. 150 */ 151 static long toWindowsTime(FileTime time) { 152 long value = time.to(TimeUnit.MICROSECONDS); 153 // adjust to Windows epoch+= 11644473600000000L; 154 value -= WINDOWS_EPOCH_IN_MICROSECONDS; 155 // us -> 100ns 156 value *= 10L; 157 return value; 158 } 159 160 /** 161 * Initialize a new instance of this class 162 */ 163 private WindowsFileAttributes(int fileAttrs, 164 long creationTime, 165 long lastAccessTime, 166 long lastWriteTime, 167 long size, 168 int reparseTag, 169 int volSerialNumber, 170 int fileIndexHigh, 171 int fileIndexLow) 172 { 173 this.fileAttrs = fileAttrs; 174 this.creationTime = creationTime; 175 this.lastAccessTime = lastAccessTime; 176 this.lastWriteTime = lastWriteTime; 177 this.size = size; 178 this.reparseTag = reparseTag; 179 this.volSerialNumber = volSerialNumber; 180 this.fileIndexHigh = fileIndexHigh; 181 this.fileIndexLow = fileIndexLow; 182 } 183 184 /** 185 * Create a WindowsFileAttributes from a BY_HANDLE_FILE_INFORMATION structure 186 */ 187 private static WindowsFileAttributes fromFileInformation(long address, int reparseTag) { 188 int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES); 189 long creationTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_CREATETIME); 190 long lastAccessTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTACCESSTIME); 191 long lastWriteTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTWRITETIME); 192 long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZEHIGH)) << 32) 193 + (unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZELOW) & 0xFFFFFFFFL); 194 int volSerialNumber = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_VOLSERIALNUM); 195 int fileIndexHigh = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXHIGH); 196 int fileIndexLow = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXLOW); 197 return new WindowsFileAttributes(fileAttrs, 198 creationTime, 199 lastAccessTime, 200 lastWriteTime, 201 size, 202 reparseTag, 203 volSerialNumber, 204 fileIndexHigh, 205 fileIndexLow); 206 } 207 208 /** 209 * Create a WindowsFileAttributes from a WIN32_FILE_ATTRIBUTE_DATA structure 210 */ 211 private static WindowsFileAttributes fromFileAttributeData(long address, int reparseTag) { 212 int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES); 213 long creationTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME); 214 long lastAccessTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME); 215 long lastWriteTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME); 216 long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH)) << 32) 217 + (unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW) & 0xFFFFFFFFL); 218 return new WindowsFileAttributes(fileAttrs, 219 creationTime, 220 lastAccessTime, 221 lastWriteTime, 222 size, 223 reparseTag, 224 0, // volSerialNumber 225 0, // fileIndexHigh 226 0); // fileIndexLow 227 } 228 229 230 /** 231 * Allocates a native buffer for a WIN32_FIND_DATA structure 232 */ 233 static NativeBuffer getBufferForFindData() { 234 return NativeBuffers.getNativeBuffer(SIZEOF_FIND_DATA); 235 } 236 237 /** 238 * Create a WindowsFileAttributes from a WIN32_FIND_DATA structure 239 */ 240 static WindowsFileAttributes fromFindData(long address) { 241 int fileAttrs = unsafe.getInt(address + OFFSETOF_FIND_DATA_ATTRIBUTES); 242 long creationTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_CREATETIME); 243 long lastAccessTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTACCESSTIME); 244 long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME); 245 long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32) 246 + (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL); 247 int reparseTag = isReparsePoint(fileAttrs) ? 248 unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0; 249 return new WindowsFileAttributes(fileAttrs, 250 creationTime, 251 lastAccessTime, 252 lastWriteTime, 253 size, 254 reparseTag, 255 0, // volSerialNumber 256 0, // fileIndexHigh 257 0); // fileIndexLow 258 } 259 260 /** 261 * Reads the attributes of an open file 262 */ 263 static WindowsFileAttributes readAttributes(long handle) 264 throws WindowsException 265 { 266 NativeBuffer buffer = NativeBuffers 267 .getNativeBuffer(SIZEOF_FILE_INFORMATION); 268 try { 269 long address = buffer.address(); 270 GetFileInformationByHandle(handle, address); 271 272 // if file is a reparse point then read the tag 273 int reparseTag = 0; 274 int fileAttrs = unsafe 275 .getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES); 276 if (isReparsePoint(fileAttrs)) { 277 int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; 278 NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size); 279 try { 280 DeviceIoControlGetReparsePoint(handle, reparseBuffer.address(), size); 281 reparseTag = (int)unsafe.getLong(reparseBuffer.address()); 282 } finally { 283 reparseBuffer.release(); 284 } 285 } 286 287 return fromFileInformation(address, reparseTag); 288 } finally { 289 buffer.release(); 290 } 291 } 292 293 /** 294 * Returns attributes of given file. 295 */ 296 static WindowsFileAttributes get(WindowsPath path, boolean followLinks) 297 throws WindowsException 298 { 299 if (!ensureAccurateMetadata) { 300 WindowsException firstException = null; 301 302 // GetFileAttributesEx is the fastest way to read the attributes 303 NativeBuffer buffer = 304 NativeBuffers.getNativeBuffer(SIZEOF_FILE_ATTRIBUTE_DATA); 305 try { 306 long address = buffer.address(); 307 GetFileAttributesEx(path.getPathForWin32Calls(), address); 308 // if reparse point then file may be a sym link; otherwise 309 // just return the attributes 310 int fileAttrs = unsafe 311 .getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES); 312 if (!isReparsePoint(fileAttrs)) 313 return fromFileAttributeData(address, 0); 314 } catch (WindowsException x) { 315 if (x.lastError() != ERROR_SHARING_VIOLATION) 316 throw x; 317 firstException = x; 318 } finally { 319 buffer.release(); 320 } 321 322 // For sharing violations, fallback to FindFirstFile if the file 323 // is not a root directory. 324 if (firstException != null) { 325 String search = path.getPathForWin32Calls(); 326 char last = search.charAt(search.length() -1); 327 if (last == ':' || last == '\\') 328 throw firstException; 329 buffer = getBufferForFindData(); 330 try { 331 long handle = FindFirstFile(search, buffer.address()); 332 FindClose(handle); 333 WindowsFileAttributes attrs = fromFindData(buffer.address()); 334 // FindFirstFile does not follow sym links. Even if 335 // followLinks is false, there isn't sufficient information 336 // in the WIN32_FIND_DATA structure to know if the reparse 337 // point is a sym link. 338 if (attrs.isReparsePoint()) 339 throw firstException; 340 return attrs; 341 } catch (WindowsException ignore) { 342 throw firstException; 343 } finally { 344 buffer.release(); 345 } 346 } 347 } 348 349 // file is reparse point so need to open file to get attributes 350 long handle = path.openForReadAttributeAccess(followLinks); 351 try { 352 return readAttributes(handle); 353 } finally { 354 CloseHandle(handle); 355 } 356 } 357 358 /** 359 * Returns true if the attributes are of the same file - both files must 360 * be open. 361 */ 362 static boolean isSameFile(WindowsFileAttributes attrs1, 363 WindowsFileAttributes attrs2) 364 { 365 // volume serial number and file index must be the same 366 return (attrs1.volSerialNumber == attrs2.volSerialNumber) && 367 (attrs1.fileIndexHigh == attrs2.fileIndexHigh) && 368 (attrs1.fileIndexLow == attrs2.fileIndexLow); 369 } 370 371 /** 372 * Returns true if the attributes are of a file with a reparse point. 373 */ 374 static boolean isReparsePoint(int attributes) { 375 return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; 376 } 377 378 // package-private 379 int attributes() { 380 return fileAttrs; 381 } 382 383 int volSerialNumber() { 384 return volSerialNumber; 385 } 386 387 int fileIndexHigh() { 388 return fileIndexHigh; 389 } 390 391 int fileIndexLow() { 392 return fileIndexLow; 393 } 394 395 @Override 396 public long size() { 397 return size; 398 } 399 400 @Override 401 public FileTime lastModifiedTime() { 402 return toFileTime(lastWriteTime); 403 } 404 405 @Override 406 public FileTime lastAccessTime() { 407 return toFileTime(lastAccessTime); 408 } 409 410 @Override 411 public FileTime creationTime() { 412 return toFileTime(creationTime); 413 } 414 415 @Override 416 public Object fileKey() { 417 return null; 418 } 419 420 // package private 421 boolean isReparsePoint() { 422 return isReparsePoint(fileAttrs); 423 } 424 425 boolean isDirectoryLink() { 426 return isSymbolicLink() && ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0); 427 } 428 429 @Override 430 public boolean isSymbolicLink() { 431 return reparseTag == IO_REPARSE_TAG_SYMLINK; 432 } 433 434 @Override 435 public boolean isDirectory() { 436 // ignore FILE_ATTRIBUTE_DIRECTORY attribute if file is a sym link 437 if (isSymbolicLink()) 438 return false; 439 return ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0); 440 } 441 442 @Override 443 public boolean isOther() { 444 if (isSymbolicLink()) 445 return false; 446 // return true if device or reparse point 447 return ((fileAttrs & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)) != 0); 448 } 449 450 @Override 451 public boolean isRegularFile() { 452 return !isSymbolicLink() && !isDirectory() && !isOther(); 453 } 454 455 @Override 456 public boolean isReadOnly() { 457 return (fileAttrs & FILE_ATTRIBUTE_READONLY) != 0; 458 } 459 460 @Override 461 public boolean isHidden() { 462 return (fileAttrs & FILE_ATTRIBUTE_HIDDEN) != 0; 463 } 464 465 @Override 466 public boolean isArchive() { 467 return (fileAttrs & FILE_ATTRIBUTE_ARCHIVE) != 0; 468 } 469 470 @Override 471 public boolean isSystem() { 472 return (fileAttrs & FILE_ATTRIBUTE_SYSTEM) != 0; 473 } 474 }