private SafeFindFileHandle FindFirstFile(string pathLp, out NativeMethods.WIN32_FIND_DATA win32FindData)
        {
            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), FindExInfoLevel, out win32FindData, _limitSearchToDirs, IntPtr.Zero, LargeCache)
            : NativeMethods.FindFirstFileTransacted(Path.RemoveTrailingDirectorySeparator(pathLp, false), FindExInfoLevel, out win32FindData, _limitSearchToDirs, IntPtr.Zero, LargeCache, Transaction.SafeHandle);

            int lastError = Marshal.GetLastWin32Error();


            if (handle != null && handle.IsInvalid)
            {
                handle.Close();

                if (!ContinueOnException)
                {
                    switch ((uint)lastError)
                    {
                    case Win32Errors.ERROR_FILE_NOT_FOUND:
                    case Win32Errors.ERROR_PATH_NOT_FOUND:
                        // MSDN: .NET 3.5+: DirectoryNotFoundException: Path is invalid, such as referring to an unmapped drive.
                        // Directory.Delete()

                        NativeError.ThrowException(IsDirectory ? (int)Win32Errors.ERROR_PATH_NOT_FOUND : Win32Errors.ERROR_FILE_NOT_FOUND, pathLp);
                        break;

                    case Win32Errors.ERROR_DIRECTORY:
                        // MSDN: .NET 3.5+: IOException: path is a file name.
                        // Directory.EnumerateDirectories()
                        // Directory.EnumerateFiles()
                        // Directory.EnumerateFileSystemEntries()
                        // Directory.GetDirectories()
                        // Directory.GetFiles()
                        // Directory.GetFileSystemEntries()

                        NativeError.ThrowException(lastError, pathLp);
                        break;

                    case Win32Errors.ERROR_ACCESS_DENIED:
                        // MSDN: .NET 3.5+: UnauthorizedAccessException: The caller does not have the required permission.
                        NativeError.ThrowException(lastError, pathLp);
                        break;
                    }

                    // MSDN: .NET 3.5+: IOException
                    NativeError.ThrowException(lastError, pathLp);
                }
            }

            return(handle);
        }
Example #2
0
        public FileSystemEntryInfo Get()
        {
            NativeMethods.Win32FindData win32FindData;

            // ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups.
            using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
                using (SafeFindFileHandle handle = FindFirstFile(InputPath, out win32FindData))
                {
                    return(handle.IsInvalid ? null : new FileSystemEntryInfo(win32FindData)
                    {
                        FullPath = InputPath
                    });
                }
        }
        public T Get <T>()
        {
            NativeMethods.WIN32_FIND_DATA win32FindData;

            // ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups.
            using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
                using (SafeFindFileHandle handle = FindFirstFile(InputPath, out win32FindData))
                {
                    if (handle != null && !handle.IsInvalid)
                    {
                        return(NewFileSystemEntryType <T>(win32FindData, InputPath, (win32FindData.dwFileAttributes & FileAttributes.Directory) != 0));
                    }
                }

            return((T)(object)null);
        }
Example #4
0
        /// <summary>[AlphaFS] Enumerates the streams of type :$DATA from the specified file or directory.</summary>
        /// <param name="transaction">The transaction.</param>
        /// <param name="path">The path to the file or directory to enumerate streams of.</param>
        /// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
        /// <returns>The streams of type :$DATA in the specified file or directory.</returns>
        internal static IEnumerable <AlternateDataStreamInfo> EnumerateAlternateDataStreamsCore(KernelTransaction transaction, string path, PathFormat pathFormat)
        {
            using (var buffer = new SafeGlobalMemoryBufferHandle(Marshal.SizeOf(typeof(NativeMethods.WIN32_FIND_STREAM_DATA))))
            {
                string pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat,
                                                               GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.CheckInvalidPathChars |
                                                               GetFullPathOptions.CheckAdditional);

                using (SafeFindFileHandle handle = transaction == null
               ? NativeMethods.FindFirstStreamW(pathLp, NativeMethods.STREAM_INFO_LEVELS.FindStreamInfoStandard, buffer, 0)
               : NativeMethods.FindFirstStreamTransactedW(pathLp, NativeMethods.STREAM_INFO_LEVELS.FindStreamInfoStandard, buffer, 0, transaction.SafeHandle))
                {
                    int errorCode = Marshal.GetLastWin32Error();

                    if (handle.IsInvalid)
                    {
                        if (errorCode == Win32Errors.ERROR_HANDLE_EOF)
                        {
                            yield break;
                        }

                        NativeError.ThrowException(errorCode);
                    }

                    while (true)
                    {
                        yield return(new AlternateDataStreamInfo(pathLp, buffer.PtrToStructure <NativeMethods.WIN32_FIND_STREAM_DATA>(0)));

                        if (!NativeMethods.FindNextStreamW(handle, buffer))
                        {
                            int lastError = Marshal.GetLastWin32Error();
                            if (lastError == Win32Errors.ERROR_HANDLE_EOF)
                            {
                                break;
                            }

                            NativeError.ThrowException(lastError, pathLp);
                        }
                    }
                }
            }
        }
Example #5
0
 static internal extern bool FindNextFileW([In] SafeFindFileHandle hFindFile, [In, Out] WIN32_FIND_DATA lpFindFileData);
Example #6
0
        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;

                // ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups.
                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 != null && 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);
        }
Example #7
0
        public IEnumerable <FileSystemEntryInfo> Enumerate()
        {
            // MSDN: Queue
            // Represents a first-in, first-out collection of objects.
            // The capacity of a Queue is the number of elements the Queue can hold.
            // As elements are added to a Queue, the capacity is automatically increased as required through reallocation. The capacity can be decreased by calling TrimToSize.
            // The growth factor is the number by which the current capacity is multiplied when a greater capacity is required. The growth factor is determined when the Queue is constructed.
            // The capacity of the Queue will always increase by a minimum value, regardless of the growth factor; a growth factor of 1.0 will not prevent the Queue from increasing in size.
            // If the size of the collection can be estimated, specifying the initial capacity eliminates the need to perform a number of resizing operations while adding elements to the Queue.
            // This constructor is an O(n) operation, where n is capacity.

            Queue <string> dirs = new Queue <string>(1000);

            // Removes the object at the beginning of your Queue.
            // The algorithmic complexity of this is O(1). It doesn't loop over elements.
            dirs.Enqueue(InputPath);

            // ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups.
            using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
                while (dirs.Count > 0)
                {
                    string path   = Path.AddDirectorySeparator(dirs.Dequeue(), false);
                    string pathLp = path + Path.WildcardStarMatchAll;
                    NativeMethods.Win32FindData win32FindData;

                    using (SafeFindFileHandle handle = FindFirstFile(pathLp, out win32FindData))
                    {
                        if (handle.IsInvalid && ContinueOnException)
                        {
                            continue;
                        }

                        do
                        {
                            string fileName = win32FindData.FileName;
                            switch (fileName)
                            {
                            // Skip entries.
                            case ".":
                            case "..":
                                break;

                            default:
                                string fullPathLp = path + fileName;
                                bool   fseiIsDir  = (win32FindData.FileAttributes & FileAttributes.Directory) == FileAttributes.Directory;

                                // Or not: Skip on reparse points here to cleanly separate regular directories from links.
                                if (SkipReparsePoints &&
                                    (win32FindData.FileAttributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
                                {
                                    continue;
                                }

                                // If object is a directory, add it to the queue for later traversal.
                                if (fseiIsDir && _searchAllDirs)
                                {
                                    dirs.Enqueue(fullPathLp);
                                }


                                if (!(_nameFilter == null || (_nameFilter != null && _nameFilter.IsMatch(fileName))))
                                {
                                    break;
                                }

                                // Make sure the requested file system object type is returned.
                                // null = Return files and directories.
                                // true = Return only directories.
                                // false = Return only files.
                                switch (FileSystemObjectType)
                                {
                                case null:
                                    yield return(new FileSystemEntryInfo(win32FindData)
                                    {
                                        FullPath = fullPathLp
                                    });

                                    break;

                                case true:
                                    if (fseiIsDir)
                                    {
                                        yield return new FileSystemEntryInfo(win32FindData)
                                               {
                                                   FullPath = fullPathLp
                                               }
                                    }
                                    ;
                                    break;

                                case false:
                                    if (!fseiIsDir)
                                    {
                                        yield return new FileSystemEntryInfo(win32FindData)
                                               {
                                                   FullPath = fullPathLp
                                               }
                                    }
                                    ;
                                    break;
                                }
                                break;
                            }
                        } while (NativeMethods.FindNextFile(handle, out win32FindData));


                        uint lastError = (uint)Marshal.GetLastWin32Error();
                        switch (lastError)
                        {
                        case Win32Errors.ERROR_NO_MORE_FILES:
                            lastError = Win32Errors.NO_ERROR;
                            break;

                        case Win32Errors.ERROR_FILE_NOT_FOUND:
                        case Win32Errors.ERROR_PATH_NOT_FOUND:
                            if (lastError == Win32Errors.ERROR_FILE_NOT_FOUND && IsFolder)
                            {
                                lastError = Win32Errors.ERROR_PATH_NOT_FOUND;
                            }
                            break;
                        }

                        if (!ContinueOnException && lastError != Win32Errors.NO_ERROR)
                        {
                            NativeError.ThrowException(lastError, InputPath);
                        }
                    }
                }
        }
 internal static extern bool FindNextStreamW(SafeFindFileHandle handle,
    SafeGlobalMemoryBufferHandle lpFindStreamData);
 internal static extern bool FindNextFileName(SafeFindFileHandle hFindStream,
    [MarshalAs(UnmanagedType.U4)] out uint stringLength, StringBuilder linkName);
 internal static extern bool FindNextFile(SafeFindFileHandle hFindFile, out Win32FindData lpFindFileData);
        /// <summary>[AlphaFS] Creates an enumeration of all the hard links to the specified <paramref name="path"/>.</summary>
        /// <exception cref="PlatformNotSupportedException">Thrown when a Platform Not Supported error condition occurs.</exception>
        /// <param name="transaction">The transaction.</param>
        /// <param name="path">The name of the file.</param>
        /// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
        /// <returns>An enumerable collection of <see cref="string"/> of all the hard links to the specified <paramref name="path"/></returns>
        internal static IEnumerable <string> EnumerateHardlinksInternal(KernelTransaction transaction, string path, PathFormat pathFormat)
        {
            if (!NativeMethods.IsAtLeastWindowsVista)
            {
                throw new PlatformNotSupportedException(Resources.RequiresWindowsVistaOrHigher);
            }

            string pathLp = Path.GetExtendedLengthPathInternal(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck);

            // Default buffer length, will be extended if needed, although this should not happen.
            uint          length  = NativeMethods.MaxPathUnicode;
            StringBuilder builder = new StringBuilder((int)length);


getFindFirstFileName:

            using (SafeFindFileHandle handle = transaction == null

                                               // FindFirstFileName() / FindFirstFileNameTransacted()
                                               // 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 does not confirm LongPath usage but a Unicode version of this function exists.

            ? NativeMethods.FindFirstFileName(pathLp, 0, out length, builder)
            : NativeMethods.FindFirstFileNameTransacted(pathLp, 0, out length, builder, transaction.SafeHandle))
            {
                if (handle.IsInvalid)
                {
                    int lastError = Marshal.GetLastWin32Error();
                    switch ((uint)lastError)
                    {
                    case Win32Errors.ERROR_MORE_DATA:
                        builder = new StringBuilder((int)length);
                        handle.Close();
                        goto getFindFirstFileName;

                    default:
                        // If the function fails, the return value is INVALID_HANDLE_VALUE.
                        NativeError.ThrowException(lastError, pathLp);
                        break;
                    }
                }

                yield return(builder.ToString());


                //length = NativeMethods.MaxPathUnicode;
                //builder = new StringBuilder((int)length);

                do
                {
                    while (!NativeMethods.FindNextFileName(handle, out length, builder))
                    {
                        int lastError = Marshal.GetLastWin32Error();
                        switch ((uint)lastError)
                        {
                        // We've reached the end of the enumeration.
                        case Win32Errors.ERROR_HANDLE_EOF:
                            yield break;

                        case Win32Errors.ERROR_MORE_DATA:
                            builder = new StringBuilder((int)length);
                            continue;

                        default:
                            //If the function fails, the return value is zero (0).
                            NativeError.ThrowException(lastError);
                            break;
                        }
                    }

                    yield return(builder.ToString());
                } while (true);
            }
        }
Example #12
0
 static internal extern bool FindNextFileW([In] SafeFindFileHandle hFindFile, [In, Out] FileSystemEntryInfo lpFindFileData);
        public IEnumerable <T> Enumerate <T>()
        {
            // MSDN: Queue
            // Represents a first-in, first-out collection of objects.
            // The capacity of a Queue is the number of elements the Queue can hold.
            // As elements are added to a Queue, the capacity is automatically increased as required through reallocation. The capacity can be decreased by calling TrimToSize.
            // The growth factor is the number by which the current capacity is multiplied when a greater capacity is required. The growth factor is determined when the Queue is constructed.
            // The capacity of the Queue will always increase by a minimum value, regardless of the growth factor; a growth factor of 1.0 will not prevent the Queue from increasing in size.
            // If the size of the collection can be estimated, specifying the initial capacity eliminates the need to perform a number of resizing operations while adding elements to the Queue.
            // This constructor is an O(n) operation, where n is capacity.

            var dirs = new Queue <string>(1000);

            // Removes the object at the beginning of your Queue.
            // The algorithmic complexity of this is O(1). It doesn't loop over elements.
            dirs.Enqueue(InputPath);

            // ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups.
            using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors))
                while (dirs.Count > 0)
                {
                    string path   = Path.AddTrailingDirectorySeparator(dirs.Dequeue(), false);
                    string pathLp = path + Path.WildcardStarMatchAll;
                    NativeMethods.WIN32_FIND_DATA win32FindData;

                    using (SafeFindFileHandle handle = FindFirstFile(pathLp, out win32FindData))
                    {
                        if (handle != null && handle.IsInvalid && ContinueOnException)
                        {
                            handle.Close();
                            continue;
                        }

                        do
                        {
                            string fileName = win32FindData.cFileName;

                            // Skip entries "." and ".."
                            if (fileName.Equals(Path.CurrentDirectoryPrefix, StringComparison.OrdinalIgnoreCase) ||
                                fileName.Equals(Path.ParentDirectoryPrefix, StringComparison.OrdinalIgnoreCase))
                            {
                                continue;
                            }

                            // Skip reparse points here to cleanly separate regular directories from links.
                            if (SkipReparsePoints && (win32FindData.dwFileAttributes & FileAttributes.ReparsePoint) != 0)
                            {
                                continue;
                            }


                            string fseiFullPathLp = path + fileName;
                            bool   fseiIsFolder   = (win32FindData.dwFileAttributes & FileAttributes.Directory) != 0;

                            // If object is a directory, add it to the queue for later traversal.
                            if (fseiIsFolder && Recursive)
                            {
                                dirs.Enqueue(fseiFullPathLp);
                            }


                            // Determine yield.
                            if (!(_nameFilter == null || (_nameFilter != null && _nameFilter.IsMatch(fileName))))
                            {
                                continue;
                            }

                            var res = NewFileSystemEntryType <T>(win32FindData, fseiFullPathLp, fseiIsFolder);
                            if (res == null)
                            {
                                continue;
                            }

                            yield return(res);
                        } while (NativeMethods.FindNextFile(handle, out win32FindData));


                        var lastError = (uint)Marshal.GetLastWin32Error();

                        if (!ContinueOnException)
                        {
                            switch (lastError)
                            {
                            case Win32Errors.ERROR_NO_MORE_FILES:
                                lastError = Win32Errors.NO_ERROR;
                                break;

                            case Win32Errors.ERROR_FILE_NOT_FOUND:
                            case Win32Errors.ERROR_PATH_NOT_FOUND:
                                if (lastError == Win32Errors.ERROR_FILE_NOT_FOUND && IsDirectory)
                                {
                                    lastError = Win32Errors.ERROR_PATH_NOT_FOUND;
                                }
                                break;
                            }

                            if (lastError != Win32Errors.NO_ERROR)
                            {
                                NativeError.ThrowException(lastError, pathLp);
                            }
                        }
                    }
                }
        }