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