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.length() == 0) ? 120 true : Boolean.valueOf(propValue); 121 } 122 123 // attributes 124 private final int fileAttrs; 125 private final long creationTime; 126 private final long lastAccessTime; 127 private final long lastWriteTime; 128 private final long size; 129 private final int reparseTag; 130 131 // additional attributes when using GetFileInformationByHandle 132 private final int volSerialNumber; 133 private final int fileIndexHigh; 134 private final int fileIndexLow; 135 136 /** 137 * Convert 64-bit value representing the number of 100-nanosecond intervals 138 * since January 1, 1601 to a FileTime. 139 */ 140 static FileTime toFileTime(long time) { 141 // 100ns -> us 142 time /= 10L; 143 // adjust to java epoch 144 time += WINDOWS_EPOCH_IN_MICROSECONDS; 145 return FileTime.from(time, TimeUnit.MICROSECONDS); 146 } 147 148 /** 149 * Convert FileTime to 64-bit value representing the number of 100-nanosecond 150 * intervals since January 1, 1601. 151 */ 152 static long toWindowsTime(FileTime time) { 153 long value = time.to(TimeUnit.MICROSECONDS); 154 // adjust to Windows epoch+= 11644473600000000L; 155 value -= WINDOWS_EPOCH_IN_MICROSECONDS; 156 // us -> 100ns 157 value *= 10L; 158 return value; 159 } 160 161 /** 162 * Initialize a new instance of this class 163 */ 164 private WindowsFileAttributes(int fileAttrs, 165 long creationTime, 166 long lastAccessTime, 167 long lastWriteTime, 168 long size, 169 int reparseTag, 170 int volSerialNumber, 171 int fileIndexHigh, 172 int fileIndexLow) 173 { 174 this.fileAttrs = fileAttrs; 175 this.creationTime = creationTime; 176 this.lastAccessTime = lastAccessTime; 177 this.lastWriteTime = lastWriteTime; 178 this.size = size; 179 this.reparseTag = reparseTag; 180 this.volSerialNumber = volSerialNumber; 181 this.fileIndexHigh = fileIndexHigh; 182 this.fileIndexLow = fileIndexLow; 183 } 184 185 /** 186 * Create a WindowsFileAttributes from a BY_HANDLE_FILE_INFORMATION structure 187 */ 188 private static WindowsFileAttributes fromFileInformation(long address, int reparseTag) { 189 int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES); 190 long creationTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_CREATETIME); 191 long lastAccessTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTACCESSTIME); 192 long lastWriteTime = unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTWRITETIME); 193 long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZEHIGH)) << 32) 194 + (unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZELOW) & 0xFFFFFFFFL); 195 int volSerialNumber = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_VOLSERIALNUM); 196 int fileIndexHigh = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXHIGH); 197 int fileIndexLow = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXLOW); 198 return new WindowsFileAttributes(fileAttrs, 199 creationTime, 200 lastAccessTime, 201 lastWriteTime, 202 size, 203 reparseTag, 204 volSerialNumber, 205 fileIndexHigh, 206 fileIndexLow); 207 } 208 209 /** 210 * Create a WindowsFileAttributes from a WIN32_FILE_ATTRIBUTE_DATA structure 211 */ 212 private static WindowsFileAttributes fromFileAttributeData(long address, int reparseTag) { 213 int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES); 214 long creationTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME); 215 long lastAccessTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME); 216 long lastWriteTime = unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME); 217 long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH)) << 32) 218 + (unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW) & 0xFFFFFFFFL); 219 return new WindowsFileAttributes(fileAttrs, 220 creationTime, 221 lastAccessTime, 222 lastWriteTime, 223 size, 224 reparseTag, 225 0, // volSerialNumber 226 0, // fileIndexHigh 227 0); // fileIndexLow 228 } 229 230 231 /** 232 * Allocates a native buffer for a WIN32_FIND_DATA structure 233 */ 234 static NativeBuffer getBufferForFindData() { 235 return NativeBuffers.getNativeBuffer(SIZEOF_FIND_DATA); 236 } 237 238 /** 239 * Create a WindowsFileAttributes from a WIN32_FIND_DATA structure 240 */ 241 static WindowsFileAttributes fromFindData(long address) { 242 int fileAttrs = unsafe.getInt(address + OFFSETOF_FIND_DATA_ATTRIBUTES); 243 long creationTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_CREATETIME); 244 long lastAccessTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTACCESSTIME); 245 long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME); 246 long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32) 247 + (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL); 248 int reparseTag = isReparsePoint(fileAttrs) ? 249 unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0; 250 return new WindowsFileAttributes(fileAttrs, 251 creationTime, 252 lastAccessTime, 253 lastWriteTime, 254 size, 255 reparseTag, 256 0, // volSerialNumber 257 0, // fileIndexHigh 258 0); // fileIndexLow 259 } 260 261 /** 262 * Reads the attributes of an open file 263 */ 264 static WindowsFileAttributes readAttributes(long handle) 265 throws WindowsException 266 { 267 NativeBuffer buffer = NativeBuffers 268 .getNativeBuffer(SIZEOF_FILE_INFORMATION); 269 try { 270 long address = buffer.address(); 271 GetFileInformationByHandle(handle, address); 272 273 // if file is a reparse point then read the tag 274 int reparseTag = 0; 275 int fileAttrs = unsafe 276 .getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES); 277 if (isReparsePoint(fileAttrs)) { 278 int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; 279 NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size); 280 try { 281 DeviceIoControlGetReparsePoint(handle, reparseBuffer.address(), size); 282 reparseTag = (int)unsafe.getLong(reparseBuffer.address()); 283 } finally { 284 reparseBuffer.release(); 285 } 286 } 287 288 return fromFileInformation(address, reparseTag); 289 } finally { 290 buffer.release(); 291 } 292 } 293 294 /** 295 * Returns attributes of given file. 296 */ 297 static WindowsFileAttributes get(WindowsPath path, boolean followLinks) 298 throws WindowsException 299 { 300 if (!ensureAccurateMetadata) { 301 WindowsException firstException = null; 302 303 // GetFileAttributesEx is the fastest way to read the attributes 304 NativeBuffer buffer = 305 NativeBuffers.getNativeBuffer(SIZEOF_FILE_ATTRIBUTE_DATA); 306 try { 307 long address = buffer.address(); 308 GetFileAttributesEx(path.getPathForWin32Calls(), address); 309 // if reparse point then file may be a sym link; otherwise 310 // just return the attributes 311 int fileAttrs = unsafe 312 .getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES); 313 if (!isReparsePoint(fileAttrs)) 314 return fromFileAttributeData(address, 0); 315 } catch (WindowsException x) { 316 if (x.lastError() != ERROR_SHARING_VIOLATION) 317 throw x; 318 firstException = x; 319 } finally { 320 buffer.release(); 321 } 322 323 // For sharing violations, fallback to FindFirstFile if the file 324 // is not a root directory. 325 if (firstException != null) { 326 String search = path.getPathForWin32Calls(); 327 char last = search.charAt(search.length() -1); 328 if (last == ':' || last == '\\') 329 throw firstException; 330 buffer = getBufferForFindData(); 331 try { 332 long handle = FindFirstFile(search, buffer.address()); 333 FindClose(handle); 334 WindowsFileAttributes attrs = fromFindData(buffer.address()); 335 // FindFirstFile does not follow sym links. Even if 336 // followLinks is false, there isn't sufficient information 337 // in the WIN32_FIND_DATA structure to know if the reparse 338 // point is a sym link. 339 if (attrs.isReparsePoint()) 340 throw firstException; 341 return attrs; 342 } catch (WindowsException ignore) { 343 throw firstException; 344 } finally { 345 buffer.release(); 346 } 347 } 348 } 349 350 // file is reparse point so need to open file to get attributes 351 long handle = path.openForReadAttributeAccess(followLinks); 352 try { 353 return readAttributes(handle); 354 } finally { 355 CloseHandle(handle); 356 } 357 } 358 359 /** 360 * Returns true if the attributes are of the same file - both files must 361 * be open. 362 */ 363 static boolean isSameFile(WindowsFileAttributes attrs1, 364 WindowsFileAttributes attrs2) 365 { 366 // volume serial number and file index must be the same 367 return (attrs1.volSerialNumber == attrs2.volSerialNumber) && 368 (attrs1.fileIndexHigh == attrs2.fileIndexHigh) && 369 (attrs1.fileIndexLow == attrs2.fileIndexLow); 370 } 371 372 /** 373 * Returns true if the attributes are of a file with a reparse point. 374 */ 375 static boolean isReparsePoint(int attributes) { 376 return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; 377 } 378 379 // package-private 380 int attributes() { 381 return fileAttrs; 382 } 383 384 int volSerialNumber() { 385 return volSerialNumber; 386 } 387 388 int fileIndexHigh() { 389 return fileIndexHigh; 390 } 391 392 int fileIndexLow() { 393 return fileIndexLow; 394 } 395 396 @Override 397 public long size() { 398 return size; 399 } 400 401 @Override 402 public FileTime lastModifiedTime() { 403 return toFileTime(lastWriteTime); 404 } 405 406 @Override 407 public FileTime lastAccessTime() { 408 return toFileTime(lastAccessTime); 409 } 410 411 @Override 412 public FileTime creationTime() { 413 return toFileTime(creationTime); 414 } 415 416 @Override 417 public Object fileKey() { 418 return null; 419 } 420 421 // package private 422 boolean isReparsePoint() { 423 return isReparsePoint(fileAttrs); 424 } 425 426 boolean isDirectoryLink() { 427 return isSymbolicLink() && ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0); 428 } 429 430 @Override 431 public boolean isSymbolicLink() { 432 return reparseTag == IO_REPARSE_TAG_SYMLINK; 433 } 434 435 @Override 436 public boolean isDirectory() { 437 // ignore FILE_ATTRIBUTE_DIRECTORY attribute if file is a sym link 438 if (isSymbolicLink()) 439 return false; 440 return ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0); 441 } 442 443 @Override 444 public boolean isOther() { 445 if (isSymbolicLink()) 446 return false; 447 // return true if device or reparse point 448 return ((fileAttrs & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)) != 0); 449 } 450 451 @Override 452 public boolean isRegularFile() { 453 return !isSymbolicLink() && !isDirectory() && !isOther(); 454 } 455 456 @Override 457 public boolean isReadOnly() { 458 return (fileAttrs & FILE_ATTRIBUTE_READONLY) != 0; 459 } 460 461 @Override 462 public boolean isHidden() { 463 return (fileAttrs & FILE_ATTRIBUTE_HIDDEN) != 0; 464 } 465 466 @Override 467 public boolean isArchive() { 468 return (fileAttrs & FILE_ATTRIBUTE_ARCHIVE) != 0; 469 } 470 471 @Override 472 public boolean isSystem() { 473 return (fileAttrs & FILE_ATTRIBUTE_SYSTEM) != 0; 474 } 475 }