/* Copyright (C) 2008-2016 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.InteropServices; using System.Security; namespace Alphaleonis.Win32.Filesystem { public static partial class File { #region GetAttributes /// Gets the of the file on the path. /// The path to the file. /// The of the file on the path. [SecurityCritical] public static FileAttributes GetAttributes(string path) { return GetAttributesExCore(null, path, PathFormat.RelativePath, true); } /// [AlphaFS] Gets the of the file on the path. /// The path to the file. /// Indicates the format of the path parameter(s). /// The of the file on the path. [SecurityCritical] public static FileAttributes GetAttributes(string path, PathFormat pathFormat) { return GetAttributesExCore(null, path, pathFormat, true); } /// [AlphaFS] Gets the of the file on the path. /// The transaction. /// The path to the file. /// The of the file on the path. [SecurityCritical] public static FileAttributes GetAttributesTransacted(KernelTransaction transaction, string path) { return GetAttributesExCore(transaction, path, PathFormat.RelativePath, true); } /// [AlphaFS] Gets the of the file on the path. /// The transaction. /// The path to the file. /// Indicates the format of the path parameter(s). /// The of the file on the path. [SecurityCritical] public static FileAttributes GetAttributesTransacted(KernelTransaction transaction, string path, PathFormat pathFormat) { return GetAttributesExCore(transaction, path, pathFormat, true); } #endregion #region Internal Methods /// Gets the or of the specified file or directory. /// The or of the specified file or directory. /// /// /// Generic type parameter. /// The transaction. /// The path to the file or directory. /// Indicates the format of the path parameter(s). /// [SuppressMessage("Microsoft.Interoperability", "CA1404:CallGetLastErrorImmediatelyAfterPInvoke", Justification = "Marshal.GetLastWin32Error() is manipulated.")] [SecurityCritical] internal static T GetAttributesExCore(KernelTransaction transaction, string path, PathFormat pathFormat, bool returnErrorOnNotFound) { if (pathFormat == PathFormat.RelativePath) Path.CheckSupportedPathFormat(path, true, true); string pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.CheckInvalidPathChars); var data = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA(); int dataInitialised = FillAttributeInfoCore(transaction, pathLp, ref data, false, returnErrorOnNotFound); if (dataInitialised != Win32Errors.ERROR_SUCCESS) NativeError.ThrowException(dataInitialised, pathLp); return (T) (typeof (T) == typeof (FileAttributes) ? (object) data.dwFileAttributes : data); } /// /// Calls NativeMethods.GetFileAttributesEx to retrieve WIN32_FILE_ATTRIBUTE_DATA. /// Note that classes should use -1 as the uninitialized state for dataInitialized when relying on this method. /// /// No path (null, empty string) checking or normalization is performed. /// . /// . /// [in,out]. /// . /// . /// 0 on success, otherwise a Win32 error code. [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] [SecurityCritical] internal static int FillAttributeInfoCore(KernelTransaction transaction, string pathLp, ref NativeMethods.WIN32_FILE_ATTRIBUTE_DATA win32AttrData, bool tryagain, bool returnErrorOnNotFound) { int dataInitialised = (int)Win32Errors.ERROR_SUCCESS; #region Try Again // Someone has a handle to the file open, or other error. if (tryagain) { NativeMethods.WIN32_FIND_DATA findData; using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors)) { bool error = false; SafeFindFileHandle handle = transaction == null || !NativeMethods.IsAtLeastWindowsVista // FindFirstFileEx() / FindFirstFileTransacted() // In the ANSI version of this function, the name is limited to MAX_PATH characters. // To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. // 2013-01-13: MSDN confirms LongPath usage. // A trailing backslash is not allowed. ? NativeMethods.FindFirstFileEx(Path.RemoveTrailingDirectorySeparator(pathLp, false), NativeMethods.FindexInfoLevels, out findData, NativeMethods.FINDEX_SEARCH_OPS.SearchNameMatch, IntPtr.Zero, NativeMethods.LargeCache) : NativeMethods.FindFirstFileTransacted(Path.RemoveTrailingDirectorySeparator(pathLp, false), NativeMethods.FindexInfoLevels, out findData, NativeMethods.FINDEX_SEARCH_OPS.SearchNameMatch, IntPtr.Zero, NativeMethods.LargeCache, transaction.SafeHandle); try { if (handle.IsInvalid) { error = true; dataInitialised = Marshal.GetLastWin32Error(); if (dataInitialised == Win32Errors.ERROR_FILE_NOT_FOUND || dataInitialised == Win32Errors.ERROR_PATH_NOT_FOUND || dataInitialised == Win32Errors.ERROR_NOT_READY) // Floppy device not ready. { if (!returnErrorOnNotFound) { // Return default value for backward compatibility dataInitialised = (int)Win32Errors.ERROR_SUCCESS; win32AttrData.dwFileAttributes = (FileAttributes)(-1); } } return dataInitialised; } } finally { try { if (handle != null) handle.Close(); } catch { // If we're already returning an error, don't throw another one. if (!error) NativeError.ThrowException(dataInitialised, pathLp); } } } // Copy the attribute information. win32AttrData = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA(findData); } #endregion // Try Again else { using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors)) { if (!(transaction == null || !NativeMethods.IsAtLeastWindowsVista // GetFileAttributesEx() / GetFileAttributesTransacted() // In the ANSI version of this function, the name is limited to MAX_PATH characters. // To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. // 2013-01-13: MSDN confirms LongPath usage. ? NativeMethods.GetFileAttributesEx(pathLp, NativeMethods.GetFileExInfoLevels.GetFileExInfoStandard, out win32AttrData) : NativeMethods.GetFileAttributesTransacted(pathLp, NativeMethods.GetFileExInfoLevels.GetFileExInfoStandard, out win32AttrData, transaction.SafeHandle))) { dataInitialised = Marshal.GetLastWin32Error(); if (dataInitialised != Win32Errors.ERROR_FILE_NOT_FOUND && dataInitialised != Win32Errors.ERROR_PATH_NOT_FOUND && dataInitialised != Win32Errors.ERROR_NOT_READY) // Floppy device not ready. { // In case someone latched onto the file. Take the perf hit only for failure. return FillAttributeInfoCore(transaction, pathLp, ref win32AttrData, true, returnErrorOnNotFound); } if (!returnErrorOnNotFound) { // Return default value for backward compbatibility. dataInitialised = (int)Win32Errors.ERROR_SUCCESS; win32AttrData.dwFileAttributes = (FileAttributes)(-1); } } } } return dataInitialised; } #endregion // Internal Methods } }