예제 #1
0
        internal static void EncryptDecryptFileCore(bool isFolder, string path, bool encrypt, PathFormat pathFormat)
        {
            if (pathFormat != PathFormat.LongFullPath)
            {
                path = Path.GetExtendedLengthPathCore(null, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck);

                pathFormat = PathFormat.LongFullPath;
            }


            // MSDN: If lpFileName specifies a read-only file, the function fails and GetLastError returns ERROR_FILE_READ_ONLY.

            var attrs      = GetAttributesExCore <NativeMethods.WIN32_FILE_ATTRIBUTE_DATA>(null, path, pathFormat, true);
            var isReadOnly = (attrs.dwFileAttributes & FileAttributes.ReadOnly) != 0;

            if (isReadOnly)
            {
                SetAttributesCore(null, isFolder, path, attrs.dwFileAttributes &= ~FileAttributes.ReadOnly, pathFormat);
            }


            // EncryptFile() / DecryptFile()
            // 2013-01-13: MSDN does not confirm LongPath usage but a Unicode version of this function exists.

            var success   = encrypt ? NativeMethods.EncryptFile(path) : NativeMethods.DecryptFile(path, 0);
            var lastError = Marshal.GetLastWin32Error();


            if (isReadOnly)
            {
                var isHidden = (attrs.dwFileAttributes & FileAttributes.Hidden) != 0;

                // Get most current attributes.
                attrs = GetAttributesExCore <NativeMethods.WIN32_FILE_ATTRIBUTE_DATA>(null, path, pathFormat, true);

                attrs.dwFileAttributes |= FileAttributes.ReadOnly;

                if (isHidden)
                {
                    attrs.dwFileAttributes |= FileAttributes.Hidden;
                }


                SetAttributesCore(null, isFolder, path, attrs.dwFileAttributes, pathFormat);
            }


            if (!success)
            {
                switch ((uint)lastError)
                {
                case Win32Errors.ERROR_ACCESS_DENIED:
                    if (!string.Equals("NTFS", new DriveInfo(path).DriveFormat, StringComparison.OrdinalIgnoreCase))
                    {
                        throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "The drive does not support NTFS encryption: [{0}]", Path.GetPathRoot(path, false)));
                    }

                    break;


                case Win32Errors.ERROR_FILE_READ_ONLY:
                    if (IsDirectory(attrs.dwFileAttributes))
                    {
                        throw new DirectoryReadOnlyException(path);
                    }
                    else
                    {
                        throw new FileReadOnlyException(path);
                    }


                default:
                    if (lastError == Win32Errors.ERROR_FILE_NOT_FOUND && isFolder)
                    {
                        lastError = (int)Win32Errors.ERROR_PATH_NOT_FOUND;
                    }

                    NativeError.ThrowException(lastError, path);
                    break;
                }
            }
        }
예제 #2
0
        public FindFileSystemEntryInfo(KernelTransaction transaction, bool isFolder, string path, string searchPattern, DirectoryEnumerationOptions?options, DirectoryEnumerationFilters customFilters, PathFormat pathFormat, Type typeOfT)
        {
            if (null == options)
            {
                throw new ArgumentNullException("options");
            }


            Transaction = transaction;

            OriginalInputPath = path;

            InputPath = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck);

            IsRelativePath = !Path.IsPathRooted(OriginalInputPath, false);

            RelativeAbsolutePrefix = IsRelativePath ? InputPath.Replace(OriginalInputPath, string.Empty) : null;

            SearchPattern = searchPattern.TrimEnd(Path.TrimEndChars); // .NET behaviour.

            FileSystemObjectType = null;

            ContinueOnException = (options & DirectoryEnumerationOptions.ContinueOnException) != 0;

            AsLongPath = (options & DirectoryEnumerationOptions.AsLongPath) != 0;

            AsString         = typeOfT == typeof(string);
            AsFileSystemInfo = !AsString && (typeOfT == typeof(FileSystemInfo) || typeOfT.BaseType == typeof(FileSystemInfo));

            LargeCache = (options & DirectoryEnumerationOptions.LargeCache) != 0 ? NativeMethods.UseLargeCache : NativeMethods.FIND_FIRST_EX_FLAGS.NONE;

            // Only FileSystemEntryInfo makes use of (8.3) AlternateFileName.
            FindExInfoLevel = AsString || AsFileSystemInfo || (options & DirectoryEnumerationOptions.BasicSearch) != 0 ? NativeMethods.FindexInfoLevel : NativeMethods.FINDEX_INFO_LEVELS.Standard;


            if (null != customFilters)
            {
                InclusionFilter = customFilters.InclusionFilter;

                RecursionFilter = customFilters.RecursionFilter;

                ErrorHandler = customFilters.ErrorFilter;

#if !NET35
                CancellationToken = customFilters.CancellationToken;
#endif
            }

#if !NET35
            if (null == CancellationToken)
            {
                CancellationToken = new CancellationToken();
            }
#endif


            if (isFolder)
            {
                IsDirectory = true;

                Recursive = (options & DirectoryEnumerationOptions.Recursive) != 0 || null != RecursionFilter;

                SkipReparsePoints = (options & DirectoryEnumerationOptions.SkipReparsePoints) != 0;


                // Need folders or files to enumerate.
                if ((options & DirectoryEnumerationOptions.FilesAndFolders) == 0)
                {
                    options |= DirectoryEnumerationOptions.FilesAndFolders;
                }
            }

            else
            {
                options &= ~DirectoryEnumerationOptions.Folders; // Remove enumeration of folders.
                options |= DirectoryEnumerationOptions.Files;    // Add enumeration of files.
            }


            FileSystemObjectType = (options & DirectoryEnumerationOptions.FilesAndFolders) == DirectoryEnumerationOptions.FilesAndFolders

                                   // Folders and files (null).
            ? (bool?)null

                                   // Only folders (true) or only files (false).
            : (options & DirectoryEnumerationOptions.Folders) != 0;
        }
예제 #3
0
        /// <summary>[AlphaFS] Creates an enumeration of all the hard links to the specified <paramref name="path"/>.</summary>
        /// <returns>An enumerable collection of <see cref="string"/> of all the hard links to the specified <paramref name="path"/></returns>
        /// <exception cref="PlatformNotSupportedException">The operating system is older than Windows Vista.</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>
        internal static IEnumerable <string> EnumerateHardlinksCore(KernelTransaction transaction, string path, PathFormat pathFormat)
        {
            if (!NativeMethods.IsAtLeastWindowsVista)
            {
                throw new PlatformNotSupportedException(new Win32Exception((int)Win32Errors.ERROR_OLD_WIN_VERSION).Message);
            }

            var pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck);

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


getFindFirstFileName:

            using (var safeHandle = transaction == null

                                    // FindFirstFileNameW() / FindFirstFileNameTransactedW() / FindNextFileNameW()
                                    // 2013-01-13: MSDN does not confirm LongPath usage but a Unicode version of this function exists.
                                    // 2017-05-30: FindFirstFileNameW() MSDN confirms LongPath usage: Starting with Windows 10, version 1607

            ? NativeMethods.FindFirstFileNameW(pathLp, 0, out length, builder)
            : NativeMethods.FindFirstFileNameTransactedW(pathLp, 0, out length, builder, transaction.SafeHandle))
            {
                var lastError = Marshal.GetLastWin32Error();

                if (!NativeMethods.IsValidHandle(safeHandle, false))
                {
                    switch ((uint)lastError)
                    {
                    case Win32Errors.ERROR_MORE_DATA:
                        builder = new StringBuilder((int)length);
                        goto getFindFirstFileName;

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

                yield return(builder.ToString());


                do
                {
                    while (!NativeMethods.FindNextFileNameW(safeHandle, out length, builder))
                    {
                        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);
            }
        }
예제 #4
0
        internal static void DeleteDirectoryCore(FileSystemEntryInfo fileSystemEntryInfo, KernelTransaction transaction, string path, bool recursive, bool ignoreReadOnly, bool continueOnNotExist, PathFormat pathFormat)
        {
            #region Setup

            if (pathFormat == PathFormat.RelativePath)
            {
                Path.CheckSupportedPathFormat(path, true, true);
            }

            if (fileSystemEntryInfo == null)
            {
                // MSDN: .NET 3.5+: DirectoryNotFoundException:
                // Path does not exist or could not be found.
                // Path refers to a file instead of a directory.
                // The specified path is invalid (for example, it is on an unmapped drive).

                fileSystemEntryInfo = File.GetFileSystemEntryInfoCore(true, transaction, Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator), continueOnNotExist, pathFormat);
            }

            if (fileSystemEntryInfo == null)
            {
                return;
            }

            string pathLp = fileSystemEntryInfo.LongFullPath;

            #endregion // Setup

            // Do not follow mount points nor symbolic links, but do delete the reparse point itself.

            // If directory is reparse point, disable recursion.
            if (recursive && fileSystemEntryInfo.IsReparsePoint)
            {
                recursive = false;
            }


            // Check to see if this is a mount point, and unmount it.
            if (fileSystemEntryInfo.IsMountPoint)
            {
                int lastError = Volume.DeleteVolumeMountPointCore(pathLp, true);

                if (lastError != Win32Errors.ERROR_SUCCESS && lastError != Win32Errors.ERROR_PATH_NOT_FOUND)
                {
                    NativeError.ThrowException(lastError, pathLp);
                }

                // Now it is safe to delete the actual directory.
            }


            if (recursive)
            {
                // Enumerate all file system objects.
                foreach (var fsei in EnumerateFileSystemEntryInfosCore <FileSystemEntryInfo>(transaction, pathLp, Path.WildcardStarMatchAll, DirectoryEnumerationOptions.FilesAndFolders, PathFormat.LongFullPath))
                {
                    if (fsei.IsDirectory)
                    {
                        DeleteDirectoryCore(fsei, transaction, null, true, ignoreReadOnly, true, PathFormat.LongFullPath);
                    }
                    else
                    {
                        File.DeleteFileCore(transaction, fsei.LongFullPath, ignoreReadOnly, PathFormat.LongFullPath);
                    }
                }
            }

            #region Remove

startRemoveDirectory:

            if (!(transaction == null || !NativeMethods.IsAtLeastWindowsVista

                  // RemoveDirectory() / RemoveDirectoryTransacted()
                  // 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.
                  // 2014-09-09: MSDN confirms LongPath usage.

                  // RemoveDirectory on a symbolic link will remove the link itself.

            ? NativeMethods.RemoveDirectory(pathLp)
            : NativeMethods.RemoveDirectoryTransacted(pathLp, transaction.SafeHandle)))
            {
                int lastError = Marshal.GetLastWin32Error();
                switch ((uint)lastError)
                {
                case Win32Errors.ERROR_DIR_NOT_EMPTY:
                    // MSDN: .NET 3.5+: IOException: The directory specified by path is not an empty directory.
                    throw new DirectoryNotEmptyException(pathLp);


                case Win32Errors.ERROR_DIRECTORY:
                    // MSDN: .NET 3.5+: DirectoryNotFoundException: Path refers to a file instead of a directory.
                    if (File.ExistsCore(false, transaction, pathLp, PathFormat.LongFullPath))
                    {
                        throw new DirectoryNotFoundException(string.Format(CultureInfo.CurrentCulture, "({0}) {1}", Win32Errors.ERROR_INVALID_PARAMETER, string.Format(CultureInfo.CurrentCulture, Resources.Target_Directory_Is_A_File, pathLp)));
                    }
                    break;


                case Win32Errors.ERROR_PATH_NOT_FOUND:
                    if (continueOnNotExist)
                    {
                        return;
                    }
                    break;

                case Win32Errors.ERROR_SHARING_VIOLATION:
                    // MSDN: .NET 3.5+: IOException: The directory is being used by another process or there is an open handle on the directory.
                    NativeError.ThrowException(lastError, pathLp);
                    break;

                case Win32Errors.ERROR_ACCESS_DENIED:
                    var data            = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA();
                    int dataInitialised = File.FillAttributeInfoCore(transaction, pathLp, ref data, false, true);

                    if (data.dwFileAttributes != (FileAttributes)(-1))
                    {
                        if ((data.dwFileAttributes & FileAttributes.ReadOnly) != 0)
                        {
                            // MSDN: .NET 3.5+: IOException: The directory specified by path is read-only.

                            if (ignoreReadOnly)
                            {
                                // Reset directory attributes.
                                File.SetAttributesCore(true, transaction, pathLp, FileAttributes.Normal, true, PathFormat.LongFullPath);
                                goto startRemoveDirectory;
                            }

                            // MSDN: .NET 3.5+: IOException: The directory is read-only.
                            throw new DirectoryReadOnlyException(pathLp);
                        }
                    }

                    if (dataInitialised == Win32Errors.ERROR_SUCCESS)
                    {
                        // MSDN: .NET 3.5+: UnauthorizedAccessException: The caller does not have the required permission.
                        NativeError.ThrowException(lastError, pathLp);
                    }

                    break;
                }

                // MSDN: .NET 3.5+: IOException:
                // A file with the same name and location specified by path exists.
                // The directory specified by path is read-only, or recursive is false and path is not an empty directory.
                // The directory is the application's current working directory.
                // The directory contains a read-only file.
                // The directory is being used by another process.

                NativeError.ThrowException(lastError, pathLp);
            }

            #endregion // Remove
        }
예제 #5
0
        internal static IEnumerable <FileIdBothDirectoryInfo> EnumerateFileIdBothDirectoryInfoCore(KernelTransaction transaction, SafeFileHandle safeFileHandle, string path, FileShare shareMode, bool continueOnException, PathFormat pathFormat)
        {
            if (!NativeMethods.IsAtLeastWindowsVista)
            {
                throw new PlatformNotSupportedException(new Win32Exception((int)Win32Errors.ERROR_OLD_WIN_VERSION).Message);
            }


            var pathLp = path;

            var callerHandle = null != safeFileHandle;

            if (!callerHandle)
            {
                if (Utils.IsNullOrWhiteSpace(path))
                {
                    throw new ArgumentNullException("path");
                }

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

                safeFileHandle = File.CreateFileCore(transaction, pathLp, ExtendedFileAttributes.BackupSemantics, null, FileMode.Open, FileSystemRights.ReadData, shareMode, true, false, PathFormat.LongFullPath);
            }


            try
            {
                if (!NativeMethods.IsValidHandle(safeFileHandle, Marshal.GetLastWin32Error(), !continueOnException))
                {
                    yield break;
                }

                var fileNameOffset = (int)Marshal.OffsetOf(typeof(NativeMethods.FILE_ID_BOTH_DIR_INFO), "FileName");

                using (var safeBuffer = new SafeGlobalMemoryBufferHandle(NativeMethods.DefaultFileBufferSize))
                {
                    while (true)
                    {
                        var success = NativeMethods.GetFileInformationByHandleEx(safeFileHandle, NativeMethods.FILE_INFO_BY_HANDLE_CLASS.FILE_ID_BOTH_DIR_INFO, safeBuffer, (uint)safeBuffer.Capacity);

                        var lastError = Marshal.GetLastWin32Error();
                        if (!success)
                        {
                            switch ((uint)lastError)
                            {
                            case Win32Errors.ERROR_SUCCESS:
                            case Win32Errors.ERROR_NO_MORE_FILES:
                            case Win32Errors.ERROR_HANDLE_EOF:
                                yield break;

                            case Win32Errors.ERROR_MORE_DATA:
                                continue;

                            default:
                                NativeError.ThrowException(lastError, pathLp);

                                // Keep the compiler happy as we never get here.
                                yield break;
                            }
                        }


                        var offset = 0;
                        NativeMethods.FILE_ID_BOTH_DIR_INFO fibdi;

                        do
                        {
                            fibdi = safeBuffer.PtrToStructure <NativeMethods.FILE_ID_BOTH_DIR_INFO>(offset);

                            var fileName = safeBuffer.PtrToStringUni(offset + fileNameOffset, (int)(fibdi.FileNameLength / UnicodeEncoding.CharSize));

                            offset += fibdi.NextEntryOffset;


                            if (File.IsDirectory(fibdi.FileAttributes) &&
                                (fileName.Equals(Path.CurrentDirectoryPrefix, StringComparison.Ordinal) ||
                                 fileName.Equals(Path.ParentDirectoryPrefix, StringComparison.Ordinal)))
                            {
                                continue;
                            }


                            yield return(new FileIdBothDirectoryInfo(fibdi, fileName));


                            //offset += fibdi.NextEntryOffset;
                        } while (fibdi.NextEntryOffset != 0);
                    }
                }
            }
            finally
            {
                // Handle is ours, dispose.
                if (!callerHandle && null != safeFileHandle)
                {
                    safeFileHandle.Close();
                }
            }
        }
예제 #6
0
        private CopyMoveResult CopyToMoveToCore(string destinationPath, bool preserveDates, CopyOptions?copyOptions, MoveOptions?moveOptions, CopyMoveProgressRoutine progressHandler, object userProgressData, out string longFullPath, PathFormat pathFormat)
        {
            longFullPath = Path.GetExtendedLengthPathCore(Transaction, destinationPath, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck);

            return(Directory.CopyMoveCore(Transaction, LongFullName, longFullPath, preserveDates, copyOptions, moveOptions, progressHandler, userProgressData, null, PathFormat.LongFullPath));
        }
예제 #7
0
        internal static T GetAccessControlCore <T>(bool isFolder, string path, AccessControlSections includeSections, PathFormat pathFormat)
        {
            SecurityInformation securityInfo     = 0;
            PrivilegeEnabler    privilegeEnabler = null;

            if ((includeSections & AccessControlSections.Access) != 0)
            {
                securityInfo |= SecurityInformation.Dacl;
            }

            if ((includeSections & AccessControlSections.Group) != 0)
            {
                securityInfo |= SecurityInformation.Group;
            }

            if ((includeSections & AccessControlSections.Owner) != 0)
            {
                securityInfo |= SecurityInformation.Owner;
            }

            if ((includeSections & AccessControlSections.Audit) != 0)
            {
                // We need the SE_SECURITY_NAME privilege enabled to be able to get the
                // SACL descriptor. So we enable it here for the remainder of this function.
                privilegeEnabler = new PrivilegeEnabler(Privilege.Security);
                securityInfo    |= SecurityInformation.Sacl;
            }

            using (privilegeEnabler)
            {
                string pathLp = Path.GetExtendedLengthPathCore(null, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck);

                IntPtr pSidOwner, pSidGroup, pDacl, pSacl;
                SafeGlobalMemoryBufferHandle pSecurityDescriptor;
                ObjectSecurity objectSecurity;

                uint lastError = Security.NativeMethods.GetNamedSecurityInfo(pathLp, ObjectType.FileObject, securityInfo, out pSidOwner, out pSidGroup, out pDacl, out pSacl, out pSecurityDescriptor);

                try
                {
                    if (lastError == Win32Errors.ERROR_FILE_NOT_FOUND || lastError == Win32Errors.ERROR_PATH_NOT_FOUND)
                    {
                        lastError = (isFolder ? Win32Errors.ERROR_PATH_NOT_FOUND : Win32Errors.ERROR_FILE_NOT_FOUND);
                    }

                    // If the function fails, the return value is zero.
                    if (lastError != Win32Errors.ERROR_SUCCESS)
                    {
                        NativeError.ThrowException(lastError, pathLp);
                    }

                    if (!NativeMethods.IsValidHandle(pSecurityDescriptor, false))
                    {
                        throw new IOException(Resources.Returned_Invalid_Security_Descriptor);
                    }


                    uint length = Security.NativeMethods.GetSecurityDescriptorLength(pSecurityDescriptor);

                    // Seems not to work: Method .CopyTo: length > Capacity, so an Exception is thrown.
                    //byte[] managedBuffer = new byte[length];
                    //pSecurityDescriptor.CopyTo(managedBuffer, 0, (int) length);

                    byte[] managedBuffer = pSecurityDescriptor.ToByteArray(0, (int)length);

                    objectSecurity = (isFolder) ? (ObjectSecurity) new DirectorySecurity() : new FileSecurity();
                    objectSecurity.SetSecurityDescriptorBinaryForm(managedBuffer);
                }
                finally
                {
                    if (pSecurityDescriptor != null)
                    {
                        pSecurityDescriptor.Close();
                    }
                }

                return((T)(object)objectSecurity);
            }
        }
예제 #8
0
        internal static string GetHashCore(KernelTransaction transaction, string fileFullPath, HashType hashType, PathFormat pathFormat)
        {
            var options    = GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck;
            var fileNameLp = Path.GetExtendedLengthPathCore(transaction, fileFullPath, pathFormat, options);

            byte[] hash = null;


            using (var fs = OpenCore(transaction, fileNameLp, FileMode.Open, FileAccess.Read, FileShare.Read, ExtendedFileAttributes.Normal, null, null, PathFormat.LongFullPath))
            {
                switch (hashType)
                {
                case HashType.CRC32:
                    using (var hType = new Crc32())
                        hash = hType.ComputeHash(fs);
                    break;


                case HashType.CRC64ISO3309:
                    using (var hType = new Crc64())
                        hash = hType.ComputeHash(fs);
                    break;


                case HashType.MD5:
                    using (var hType = System.Security.Cryptography.MD5.Create())
                        hash = hType.ComputeHash(fs);
                    break;


                case HashType.RIPEMD160:
                    using (var hType = System.Security.Cryptography.RIPEMD160.Create())
                        hash = hType.ComputeHash(fs);
                    break;


                case HashType.SHA1:
                    using (var hType = System.Security.Cryptography.SHA1.Create())
                        hash = hType.ComputeHash(fs);
                    break;


                case HashType.SHA256:
                    using (var hType = System.Security.Cryptography.SHA256.Create())
                        hash = hType.ComputeHash(fs);
                    break;


                case HashType.SHA384:
                    using (var hType = System.Security.Cryptography.SHA384.Create())
                        hash = hType.ComputeHash(fs);
                    break;


                case HashType.SHA512:
                    using (var hType = System.Security.Cryptography.SHA512.Create())
                        hash = hType.ComputeHash(fs);
                    break;
                }
            }


            if (null != hash)
            {
                var sb = new StringBuilder(hash.Length);

                foreach (byte b in hash)
                {
                    sb.Append(b.ToString("X2", CultureInfo.InvariantCulture));
                }

                return(sb.ToString().ToUpperInvariant());
            }

            return(string.Empty);
        }
예제 #9
0
        internal static IEnumerable <FileIdBothDirectoryInfo> EnumerateFileIdBothDirectoryInfoCore(KernelTransaction transaction, SafeFileHandle safeHandle, string path, FileShare shareMode, bool continueOnException, PathFormat pathFormat)
        {
            if (!NativeMethods.IsAtLeastWindowsVista)
            {
                throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
            }

            bool callerHandle = safeHandle != null;

            if (!callerHandle)
            {
                if (Utils.IsNullOrWhiteSpace(path))
                {
                    throw new ArgumentNullException("path");
                }

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

                safeHandle = File.CreateFileCore(transaction, pathLp, ExtendedFileAttributes.BackupSemantics, null, FileMode.Open, FileSystemRights.ReadData, shareMode, true, PathFormat.LongFullPath);
            }


            try
            {
                if (!NativeMethods.IsValidHandle(safeHandle, Marshal.GetLastWin32Error(), !continueOnException))
                {
                    yield break;
                }

                var fileNameOffset = (int)Marshal.OffsetOf(typeof(NativeMethods.FILE_ID_BOTH_DIR_INFO), "FileName");

                using (var safeBuffer = new SafeGlobalMemoryBufferHandle(NativeMethods.DefaultFileBufferSize))
                {
                    while (true)
                    {
                        if (!NativeMethods.GetFileInformationByHandleEx(safeHandle, NativeMethods.FileInfoByHandleClass.FileIdBothDirectoryInfo, safeBuffer, (uint)safeBuffer.Capacity))
                        {
                            uint lastError = (uint)Marshal.GetLastWin32Error();
                            switch (lastError)
                            {
                            case Win32Errors.ERROR_SUCCESS:
                            case Win32Errors.ERROR_NO_MORE_FILES:
                            case Win32Errors.ERROR_HANDLE_EOF:
                                yield break;

                            case Win32Errors.ERROR_MORE_DATA:
                                continue;

                            default:
                                NativeError.ThrowException(lastError, path);
                                yield break; // we should never get to this yield break.
                            }
                        }

                        int offset = 0;
                        NativeMethods.FILE_ID_BOTH_DIR_INFO fibdi;
                        do
                        {
                            fibdi = safeBuffer.PtrToStructure <NativeMethods.FILE_ID_BOTH_DIR_INFO>(offset);
                            string fileName = safeBuffer.PtrToStringUni(offset + fileNameOffset, (int)(fibdi.FileNameLength / 2));

                            if (!fileName.Equals(Path.CurrentDirectoryPrefix, StringComparison.OrdinalIgnoreCase) &&
                                !fileName.Equals(Path.ParentDirectoryPrefix, StringComparison.OrdinalIgnoreCase))
                            {
                                yield return(new FileIdBothDirectoryInfo(fibdi, fileName));
                            }

                            offset += fibdi.NextEntryOffset;
                        }while (fibdi.NextEntryOffset != 0);
                    }
                }
            }
            finally
            {
                // Handle is ours, dispose.
                if (!callerHandle && safeHandle != null)
                {
                    safeHandle.Close();
                }
            }
        }
예제 #10
0
        internal static SafeFileHandle CreateFileCore(KernelTransaction transaction, string path, ExtendedFileAttributes attributes, FileSecurity fileSecurity, FileMode fileMode, FileSystemRights fileSystemRights, FileShare fileShare, bool checkPath, bool continueOnException, PathFormat pathFormat)
        {
            if (checkPath && pathFormat == PathFormat.RelativePath)
            {
                Path.CheckSupportedPathFormat(path, true, true);
            }


            // When isFile == null, we're working with a device.
            // When opening a VOLUME or removable media drive (for example, a floppy disk drive or flash memory thumb drive),
            // the path string should be the following form: "\\.\X:"
            // Do not use a trailing backslash ('\'), which indicates the root.

            var pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator);


            // CreateFileXxx() does not support FileMode.Append mode.
            var isAppend = fileMode == FileMode.Append;

            if (isAppend)
            {
                fileMode          = FileMode.OpenOrCreate;
                fileSystemRights |= FileSystemRights.AppendData;
            }


            if (null != fileSecurity)
            {
                fileSystemRights |= (FileSystemRights)SECURITY_INFORMATION.UNPROTECTED_SACL_SECURITY_INFORMATION;
            }


            using ((fileSystemRights & (FileSystemRights)SECURITY_INFORMATION.UNPROTECTED_SACL_SECURITY_INFORMATION) != 0 || (fileSystemRights & (FileSystemRights)SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION) != 0 ? new PrivilegeEnabler(Privilege.Security) : null)
                using (var securityAttributes = new Security.NativeMethods.SecurityAttributes(fileSecurity))
                {
                    var safeHandle = transaction == null || !NativeMethods.IsAtLeastWindowsVista

                                     // CreateFile() / CreateFileTransacted()
                                     // 2013-01-13: MSDN confirms LongPath usage.

               ? NativeMethods.CreateFile(pathLp, fileSystemRights, fileShare, securityAttributes, fileMode, attributes, IntPtr.Zero)
               : NativeMethods.CreateFileTransacted(pathLp, fileSystemRights, fileShare, securityAttributes, fileMode, attributes, IntPtr.Zero, transaction.SafeHandle, IntPtr.Zero, IntPtr.Zero);


                    var lastError = Marshal.GetLastWin32Error();

                    NativeMethods.IsValidHandle(safeHandle, lastError, pathLp, !continueOnException);


                    if (isAppend)
                    {
                        var success = NativeMethods.SetFilePointerEx(safeHandle, 0, IntPtr.Zero, SeekOrigin.End);

                        lastError = Marshal.GetLastWin32Error();

                        if (!success)
                        {
                            if (!safeHandle.IsClosed)
                            {
                                safeHandle.Close();
                            }

                            NativeError.ThrowException(lastError, path);
                        }
                    }

                    return(safeHandle);
                }
        }
예제 #11
0
        internal static void DeleteEmptySubdirectoriesCore(FileSystemEntryInfo fileSystemEntryInfo, KernelTransaction transaction, string path, bool recursive, bool ignoreReadOnly, bool initialize, PathFormat pathFormat)
        {
            #region Setup

            if (pathFormat == PathFormat.RelativePath)
            {
                Path.CheckSupportedPathFormat(path, true, true);
            }

            if (fileSystemEntryInfo == null)
            {
                if (!File.ExistsCore(true, transaction, path, pathFormat))
                {
                    NativeError.ThrowException(Win32Errors.ERROR_PATH_NOT_FOUND, path);
                }

                fileSystemEntryInfo = File.GetFileSystemEntryInfoCore(true, transaction, Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck), false, pathFormat);
            }

            if (fileSystemEntryInfo == null)
            {
                throw new ArgumentNullException("path");
            }

            string pathLp = fileSystemEntryInfo.LongFullPath;

            #endregion // Setup

            // Ensure path is a directory.
            if (!fileSystemEntryInfo.IsDirectory)
            {
                throw new IOException(string.Format(CultureInfo.CurrentCulture, Resources.Target_Directory_Is_A_File, pathLp));
            }


            var dirEnumOptions = DirectoryEnumerationOptions.Folders;

            if (recursive)
            {
                dirEnumOptions |= DirectoryEnumerationOptions.Recursive;
            }

            foreach (var fsei in EnumerateFileSystemEntryInfosCore <FileSystemEntryInfo>(transaction, pathLp, Path.WildcardStarMatchAll, dirEnumOptions, PathFormat.LongFullPath))
            {
                DeleteEmptySubdirectoriesCore(fsei, transaction, null, recursive, ignoreReadOnly, false, PathFormat.LongFullPath);
            }


            if (!EnumerateFileSystemEntryInfosCore <string>(transaction, pathLp, Path.WildcardStarMatchAll, DirectoryEnumerationOptions.FilesAndFolders, PathFormat.LongFullPath).Any())
            {
                // Prevent deleting path itself.
                if (!initialize)
                {
                    DeleteDirectoryCore(fileSystemEntryInfo, transaction, null, false, ignoreReadOnly, true, PathFormat.LongFullPath);
                }
            }
        }
        internal static void DeleteDirectoryCore(KernelTransaction transaction, FileSystemEntryInfo fsEntryInfo, string path, bool recursive, bool ignoreReadOnly, bool continueOnNotFound, PathFormat pathFormat)
        {
            if (null == fsEntryInfo)
            {
                if (null == path)
                {
                    throw new ArgumentNullException("path");
                }


                // MSDN: .NET 3.5+: DirectoryNotFoundException:
                // Path does not exist or could not be found.
                // Path refers to a file instead of a directory.
                // The specified path is invalid (for example, it is on an unmapped drive).

                if (pathFormat == PathFormat.RelativePath)
                {
                    Path.CheckSupportedPathFormat(path, true, true);
                }

                fsEntryInfo = File.GetFileSystemEntryInfoCore(transaction, true, Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator), continueOnNotFound, pathFormat);

                if (null == fsEntryInfo)
                {
                    return;
                }
            }

            pathFormat = PathFormat.LongFullPath;


            // Do not follow mount points nor symbolic links, but do delete the reparse point itself.
            // If directory is reparse point, disable recursion.

            if (recursive && !fsEntryInfo.IsReparsePoint)
            {
                var dirs = new Stack <string>(1000);

                foreach (var fsei in EnumerateFileSystemEntryInfosCore <FileSystemEntryInfo>(null, transaction, fsEntryInfo.LongFullPath, Path.WildcardStarMatchAll, SearchOption.AllDirectories, null, null, pathFormat))
                {
                    if (fsei.IsDirectory)
                    {
                        // Check to see if this is a mount point, and unmount it.
                        // Now it is safe to delete the actual directory.
                        if (fsei.IsMountPoint)
                        {
                            DeleteJunctionCore(transaction, fsei, null, false, pathFormat);
                        }
                        //Volume.DeleteVolumeMountPointCore(transaction, fsei.LongFullPath, false, true, pathFormat);

                        dirs.Push(fsei.LongFullPath);
                    }

                    else
                    {
                        File.DeleteFileCore(transaction, fsei.LongFullPath, ignoreReadOnly, pathFormat);
                    }
                }


                while (dirs.Count > 0)
                {
                    DeleteDirectoryCore(transaction, dirs.Pop(), ignoreReadOnly, continueOnNotFound);
                }
            }


            // Check to see if this is a mount point, and unmount it.
            // Now it is safe to delete the actual directory.
            if (fsEntryInfo.IsMountPoint)
            {
                DeleteJunctionCore(transaction, fsEntryInfo, null, false, pathFormat);
            }
            //Volume.DeleteVolumeMountPointCore(transaction, fsEntryInfo.LongFullPath, false, true, pathFormat);

            DeleteDirectoryCore(transaction, fsEntryInfo.LongFullPath, ignoreReadOnly, continueOnNotFound);
        }
예제 #13
0
        internal static void SetAccessControlCore(string path, SafeFileHandle handle, ObjectSecurity objectSecurity, AccessControlSections includeSections, PathFormat pathFormat)
        {
            if (pathFormat == PathFormat.RelativePath)
            {
                Path.CheckSupportedPathFormat(path, true, true);
            }

            if (objectSecurity == null)
            {
                throw new ArgumentNullException("objectSecurity");
            }


            var managedDescriptor = objectSecurity.GetSecurityDescriptorBinaryForm();

            using (var safeBuffer = new SafeGlobalMemoryBufferHandle(managedDescriptor.Length))
            {
                var pathLp = Path.GetExtendedLengthPathCore(null, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.CheckInvalidPathChars);

                safeBuffer.CopyFrom(managedDescriptor, 0, managedDescriptor.Length);

                SECURITY_DESCRIPTOR_CONTROL control;
                uint revision;


                var success = Security.NativeMethods.GetSecurityDescriptorControl(safeBuffer, out control, out revision);

                var lastError = Marshal.GetLastWin32Error();
                if (!success)
                {
                    NativeError.ThrowException(lastError, pathLp);
                }


                PrivilegeEnabler privilegeEnabler = null;

                try
                {
                    var securityInfo = SECURITY_INFORMATION.None;
                    var pDacl        = IntPtr.Zero;

                    if ((includeSections & AccessControlSections.Access) != 0)
                    {
                        bool daclDefaulted, daclPresent;


                        success = Security.NativeMethods.GetSecurityDescriptorDacl(safeBuffer, out daclPresent, out pDacl, out daclDefaulted);

                        lastError = Marshal.GetLastWin32Error();
                        if (!success)
                        {
                            NativeError.ThrowException(lastError, pathLp);
                        }


                        if (daclPresent)
                        {
                            securityInfo |= SECURITY_INFORMATION.DACL_SECURITY_INFORMATION;
                            securityInfo |= (control & SECURITY_DESCRIPTOR_CONTROL.SE_DACL_PROTECTED) != 0 ? SECURITY_INFORMATION.PROTECTED_DACL_SECURITY_INFORMATION : SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION;
                        }
                    }


                    var pSacl = IntPtr.Zero;

                    if ((includeSections & AccessControlSections.Audit) != 0)
                    {
                        bool saclDefaulted, saclPresent;


                        success = Security.NativeMethods.GetSecurityDescriptorSacl(safeBuffer, out saclPresent, out pSacl, out saclDefaulted);

                        lastError = Marshal.GetLastWin32Error();
                        if (!success)
                        {
                            NativeError.ThrowException(lastError, pathLp);
                        }


                        if (saclPresent)
                        {
                            securityInfo |= SECURITY_INFORMATION.SACL_SECURITY_INFORMATION;
                            securityInfo |= (control & SECURITY_DESCRIPTOR_CONTROL.SE_SACL_PROTECTED) != 0 ? SECURITY_INFORMATION.PROTECTED_SACL_SECURITY_INFORMATION : SECURITY_INFORMATION.UNPROTECTED_SACL_SECURITY_INFORMATION;

                            privilegeEnabler = new PrivilegeEnabler(Privilege.Security);
                        }
                    }


                    var pOwner = IntPtr.Zero;

                    if ((includeSections & AccessControlSections.Owner) != 0)
                    {
                        bool ownerDefaulted;


                        success = Security.NativeMethods.GetSecurityDescriptorOwner(safeBuffer, out pOwner, out ownerDefaulted);

                        lastError = Marshal.GetLastWin32Error();
                        if (!success)
                        {
                            NativeError.ThrowException(lastError, pathLp);
                        }


                        if (pOwner != IntPtr.Zero)
                        {
                            securityInfo |= SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION;
                        }
                    }


                    var pGroup = IntPtr.Zero;

                    if ((includeSections & AccessControlSections.Group) != 0)
                    {
                        bool groupDefaulted;


                        success = Security.NativeMethods.GetSecurityDescriptorGroup(safeBuffer, out pGroup, out groupDefaulted);

                        lastError = Marshal.GetLastWin32Error();
                        if (!success)
                        {
                            NativeError.ThrowException(lastError, pathLp);
                        }


                        if (pGroup != IntPtr.Zero)
                        {
                            securityInfo |= SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION;
                        }
                    }



                    if (!Utils.IsNullOrWhiteSpace(pathLp))
                    {
                        // SetNamedSecurityInfo()
                        // 2013-01-13: MSDN does not confirm LongPath usage but a Unicode version of this function exists.

                        lastError = (int)Security.NativeMethods.SetNamedSecurityInfo(pathLp, SE_OBJECT_TYPE.SE_FILE_OBJECT, securityInfo, pOwner, pGroup, pDacl, pSacl);

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

                    else
                    {
                        if (NativeMethods.IsValidHandle(handle))
                        {
                            lastError = (int)Security.NativeMethods.SetSecurityInfo(handle, SE_OBJECT_TYPE.SE_FILE_OBJECT, securityInfo, pOwner, pGroup, pDacl, pSacl);

                            if (lastError != Win32Errors.ERROR_SUCCESS)
                            {
                                NativeError.ThrowException(lastError);
                            }
                        }
                    }
                }
                finally
                {
                    if (null != privilegeEnabler)
                    {
                        privilegeEnabler.Dispose();
                    }
                }
            }
        }
예제 #14
0
        /// <summary>[AlphaFS] Creates an enumeration of all the hard links to the specified <paramref name="path"/>.</summary>
        /// <exception cref="PlatformNotSupportedException"/>
        /// <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> EnumerateHardlinksCore(KernelTransaction transaction, string path, PathFormat pathFormat)
        {
            if (!NativeMethods.IsAtLeastWindowsVista)
            {
                throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
            }

            string pathLp = Path.GetExtendedLengthPathCore(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))
            {
                int lastError = Marshal.GetLastWin32Error();

                if (handle.IsInvalid)
                {
                    handle.Close();

                    switch ((uint)lastError)
                    {
                    case Win32Errors.ERROR_MORE_DATA:
                        builder = new StringBuilder((int)length);
                        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))
                    {
                        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);
            }
        }
        internal static string CreateJunctionCore(KernelTransaction transaction, string junctionPath, string directoryPath, bool overwrite, bool copyTargetTimestamps, PathFormat pathFormat)
        {
            if (pathFormat != PathFormat.LongFullPath)
            {
                Path.CheckSupportedPathFormat(directoryPath, true, true);
                Path.CheckSupportedPathFormat(junctionPath, true, true);

                directoryPath = Path.GetExtendedLengthPathCore(transaction, directoryPath, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator);
                junctionPath  = Path.GetExtendedLengthPathCore(transaction, junctionPath, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator);

                pathFormat = PathFormat.LongFullPath;
            }


            // Directory Junction logic.


            // Check if drive letter is a mapped network drive.
            if (new DriveInfo(directoryPath).IsUnc)
            {
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.Network_Path_Not_Allowed, directoryPath), "directoryPath");
            }

            if (new DriveInfo(junctionPath).IsUnc)
            {
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.Network_Path_Not_Allowed, junctionPath), "junctionPath");
            }


            // Check for existing file.
            File.ThrowIOExceptionIfFsoExist(transaction, false, directoryPath, pathFormat);
            File.ThrowIOExceptionIfFsoExist(transaction, false, junctionPath, pathFormat);


            // Check for existing directory junction folder.
            if (File.ExistsCore(transaction, true, junctionPath, pathFormat))
            {
                if (overwrite)
                {
                    DeleteDirectoryCore(transaction, null, junctionPath, true, true, true, pathFormat);
                    CreateDirectoryCore(transaction, junctionPath, null, null, false, pathFormat);
                }

                else
                {
                    // Ensure the folder is empty.
                    if (!IsEmptyCore(transaction, junctionPath, pathFormat))
                    {
                        throw new DirectoryNotEmptyException(junctionPath, true);
                    }

                    throw new AlreadyExistsException(junctionPath, true);
                }
            }


            // Create the folder and convert it to a directory junction.
            CreateDirectoryCore(transaction, junctionPath, null, null, false, pathFormat);

            using (var safeHandle = OpenDirectoryJunction(transaction, junctionPath, pathFormat))
                Device.CreateDirectoryJunction(safeHandle, directoryPath);


            // Copy the target date and time stamps to the directory junction.
            if (copyTargetTimestamps)
            {
                File.CopyTimestampsCore(transaction, directoryPath, junctionPath, true, pathFormat);
            }


            return(junctionPath);
        }
예제 #16
0
        internal static void DeleteFileCore(KernelTransaction transaction, string path, bool ignoreReadOnly, PathFormat pathFormat)
        {
            #region Setup

            if (pathFormat == PathFormat.RelativePath)
            {
                Path.CheckSupportedPathFormat(path, true, true);
            }

            string pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator);

            // If the path points to a symbolic link, the symbolic link is deleted, not the target.

            #endregion // Setup

startDeleteFile:

            if (!(transaction == null || !NativeMethods.IsAtLeastWindowsVista

                  // DeleteFile() / DeleteFileTransacted()
                  // 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.DeleteFile(pathLp)
            : NativeMethods.DeleteFileTransacted(pathLp, transaction.SafeHandle)))
            {
                int lastError = Marshal.GetLastWin32Error();
                switch ((uint)lastError)
                {
                case Win32Errors.ERROR_FILE_NOT_FOUND:
                    // MSDN: .NET 3.5+: If the file to be deleted does not exist, no exception is thrown.
                    return;

                case Win32Errors.ERROR_PATH_NOT_FOUND:
                    // MSDN: .NET 3.5+: DirectoryNotFoundException: The specified path is invalid (for example, it is on an unmapped drive).
                    NativeError.ThrowException(lastError, pathLp);
                    return;

                case Win32Errors.ERROR_SHARING_VIOLATION:
                    // MSDN: .NET 3.5+: IOException: The specified file is in use or there is an open handle on the file.
                    NativeError.ThrowException(lastError, pathLp);
                    break;

                case Win32Errors.ERROR_ACCESS_DENIED:
                    var data            = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA();
                    int dataInitialised = FillAttributeInfoCore(transaction, pathLp, ref data, false, true);

                    if (data.dwFileAttributes != (FileAttributes)(-1))
                    {
                        if ((data.dwFileAttributes & FileAttributes.Directory) != 0)
                        {
                            // MSDN: .NET 3.5+: UnauthorizedAccessException: Path is a directory.
                            throw new UnauthorizedAccessException(string.Format(CultureInfo.CurrentCulture, "({0}) {1}",
                                                                                Win32Errors.ERROR_INVALID_PARAMETER, string.Format(CultureInfo.CurrentCulture, Resources.Target_File_Is_A_Directory, pathLp)));
                        }


                        if ((data.dwFileAttributes & FileAttributes.ReadOnly) != 0)
                        {
                            if (ignoreReadOnly)
                            {
                                // Reset file attributes.
                                SetAttributesCore(false, transaction, pathLp, FileAttributes.Normal, PathFormat.LongFullPath);
                                goto startDeleteFile;
                            }

                            // MSDN: .NET 3.5+: UnauthorizedAccessException: Path specified a read-only file.
                            throw new FileReadOnlyException(pathLp);
                        }
                    }

                    if (dataInitialised == Win32Errors.ERROR_SUCCESS)
                    {
                        // MSDN: .NET 3.5+: UnauthorizedAccessException: The caller does not have the required permission.
                        NativeError.ThrowException(lastError, pathLp);
                    }

                    break;
                }

                // MSDN: .NET 3.5+: IOException:
                // The specified file is in use.
                // There is an open handle on the file, and the operating system is Windows XP or earlier.

                NativeError.ThrowException(lastError, pathLp);
            }
        }
예제 #17
0
        internal static void ImportExportEncryptedFileDirectoryRawCore(bool isExport, bool isFolder, Stream stream, string destinationPath, PathFormat pathFormat, bool overwriteHidden)
        {
            string destinationPathLp = Path.GetExtendedLengthPathCore(null, destinationPath, pathFormat, GetFullPathOptions.FullCheck | GetFullPathOptions.TrimEnd);

            NativeMethods.EncryptedFileRawMode mode = isExport
            ? NativeMethods.EncryptedFileRawMode.CreateForExport
            : NativeMethods.EncryptedFileRawMode.CreateForImport;

            if (isFolder)
            {
                mode = mode | NativeMethods.EncryptedFileRawMode.CreateForDir;
            }

            if (overwriteHidden)
            {
                mode = mode | NativeMethods.EncryptedFileRawMode.OverwriteHidden;
            }


            // OpenEncryptedFileRaw()
            // 2015-08-02: MSDN does not confirm LongPath usage but a Unicode version of this function exists.

            SafeEncryptedFileRawHandle context;
            var lastError = NativeMethods.OpenEncryptedFileRaw(destinationPathLp, mode, out context);

            try
            {
                if (lastError != Win32Errors.ERROR_SUCCESS)
                {
                    NativeError.ThrowException(lastError, destinationPathLp);
                }


                lastError = isExport
               ? NativeMethods.ReadEncryptedFileRaw((pbData, pvCallbackContext, length) =>
                {
                    try
                    {
                        var data = new byte[length];

                        Marshal.Copy(pbData, data, 0, (int)length);

                        stream.Write(data, 0, (int)length);
                    }
                    catch (Exception ex)
                    {
                        return(Marshal.GetHRForException(ex) & NativeMethods.OverflowExceptionBitShift);
                    }

                    return((int)Win32Errors.ERROR_SUCCESS);
                }, IntPtr.Zero, context)


               : NativeMethods.WriteEncryptedFileRaw((IntPtr pbData, IntPtr pvCallbackContext, ref uint length) =>
                {
                    try
                    {
                        var data = new byte[length];

                        length = (uint)stream.Read(data, 0, (int)length);
                        if (length == 0)
                        {
                            return((int)Win32Errors.ERROR_SUCCESS);
                        }

                        Marshal.Copy(data, 0, pbData, (int)length);
                    }
                    catch (Exception ex)
                    {
                        return(Marshal.GetHRForException(ex) & NativeMethods.OverflowExceptionBitShift);
                    }

                    return((int)Win32Errors.ERROR_SUCCESS);
                }, IntPtr.Zero, context);


                if (lastError != Win32Errors.ERROR_SUCCESS)
                {
                    NativeError.ThrowException(lastError, destinationPathLp);
                }
            }
            finally
            {
                if (context != null)
                {
                    context.Dispose();
                }
            }
        }
예제 #18
0
        internal static void SetAccessControlCore(string path, SafeFileHandle handle, ObjectSecurity objectSecurity, AccessControlSections includeSections, PathFormat pathFormat)
        {
            if (pathFormat == PathFormat.RelativePath)
            {
                Path.CheckSupportedPathFormat(path, true, true);
            }

            if (objectSecurity == null)
            {
                throw new ArgumentNullException("objectSecurity");
            }


            byte[] managedDescriptor = objectSecurity.GetSecurityDescriptorBinaryForm();

            using (var safeBuffer = new SafeGlobalMemoryBufferHandle(managedDescriptor.Length))
            {
                string pathLp = Path.GetExtendedLengthPathCore(null, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.CheckInvalidPathChars);

                safeBuffer.CopyFrom(managedDescriptor, 0, managedDescriptor.Length);

                SecurityDescriptorControl control;
                uint revision;

                if (!Security.NativeMethods.GetSecurityDescriptorControl(safeBuffer, out control, out revision))
                {
                    NativeError.ThrowException(Marshal.GetLastWin32Error(), pathLp);
                }


                PrivilegeEnabler privilegeEnabler = null;

                try
                {
                    var    securityInfo = SecurityInformation.None;
                    IntPtr pDacl        = IntPtr.Zero;

                    if ((includeSections & AccessControlSections.Access) != 0)
                    {
                        bool daclDefaulted, daclPresent;

                        if (!Security.NativeMethods.GetSecurityDescriptorDacl(safeBuffer, out daclPresent, out pDacl, out daclDefaulted))
                        {
                            NativeError.ThrowException(Marshal.GetLastWin32Error(), pathLp);
                        }

                        if (daclPresent)
                        {
                            securityInfo |= SecurityInformation.Dacl;
                            securityInfo |= (control & SecurityDescriptorControl.DaclProtected) != 0
                        ? SecurityInformation.ProtectedDacl
                        : SecurityInformation.UnprotectedDacl;
                        }
                    }


                    IntPtr pSacl = IntPtr.Zero;

                    if ((includeSections & AccessControlSections.Audit) != 0)
                    {
                        bool saclDefaulted, saclPresent;

                        if (!Security.NativeMethods.GetSecurityDescriptorSacl(safeBuffer, out saclPresent, out pSacl, out saclDefaulted))
                        {
                            NativeError.ThrowException(Marshal.GetLastWin32Error(), pathLp);
                        }

                        if (saclPresent)
                        {
                            securityInfo |= SecurityInformation.Sacl;
                            securityInfo |= (control & SecurityDescriptorControl.SaclProtected) != 0
                        ? SecurityInformation.ProtectedSacl
                        : SecurityInformation.UnprotectedSacl;

                            privilegeEnabler = new PrivilegeEnabler(Privilege.Security);
                        }
                    }


                    IntPtr pOwner = IntPtr.Zero;

                    if ((includeSections & AccessControlSections.Owner) != 0)
                    {
                        bool ownerDefaulted;

                        if (!Security.NativeMethods.GetSecurityDescriptorOwner(safeBuffer, out pOwner, out ownerDefaulted))
                        {
                            NativeError.ThrowException(Marshal.GetLastWin32Error(), pathLp);
                        }

                        if (pOwner != IntPtr.Zero)
                        {
                            securityInfo |= SecurityInformation.Owner;
                        }
                    }


                    IntPtr pGroup = IntPtr.Zero;

                    if ((includeSections & AccessControlSections.Group) != 0)
                    {
                        bool groupDefaulted;

                        if (!Security.NativeMethods.GetSecurityDescriptorGroup(safeBuffer, out pGroup, out groupDefaulted))
                        {
                            NativeError.ThrowException(Marshal.GetLastWin32Error(), pathLp);
                        }

                        if (pGroup != IntPtr.Zero)
                        {
                            securityInfo |= SecurityInformation.Group;
                        }
                    }


                    uint lastError;

                    if (!Utils.IsNullOrWhiteSpace(pathLp))
                    {
                        // SetNamedSecurityInfo()
                        // 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.

                        lastError = Security.NativeMethods.SetNamedSecurityInfo(pathLp, ObjectType.FileObject, securityInfo, pOwner, pGroup, pDacl, pSacl);

                        if (lastError != Win32Errors.ERROR_SUCCESS)
                        {
                            NativeError.ThrowException(lastError, pathLp);
                        }
                    }
                    else
                    {
                        if (NativeMethods.IsValidHandle(handle))
                        {
                            lastError = Security.NativeMethods.SetSecurityInfo(handle, ObjectType.FileObject, securityInfo, pOwner, pGroup, pDacl, pSacl);

                            if (lastError != Win32Errors.ERROR_SUCCESS)
                            {
                                NativeError.ThrowException((int)lastError);
                            }
                        }
                    }
                }
                finally
                {
                    if (privilegeEnabler != null)
                    {
                        privilegeEnabler.Dispose();
                    }
                }
            }
        }
예제 #19
0
        internal static SafeFileHandle CreateFileCore(KernelTransaction transaction, string path, ExtendedFileAttributes attributes, FileSecurity fileSecurity, FileMode fileMode, FileSystemRights fileSystemRights, FileShare fileShare, bool checkPath, PathFormat pathFormat)
        {
            if (checkPath && pathFormat == PathFormat.RelativePath)
            {
                Path.CheckSupportedPathFormat(path, true, true);
            }

            // When isFile == null, we're working with a device.
            // When opening a VOLUME or removable media drive (for example, a floppy disk drive or flash memory thumb drive),
            // the path string should be the following form: "\\.\X:"
            // Do not use a trailing backslash (\), which indicates the root.

            var pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator);

            PrivilegeEnabler privilegeEnabler = null;


            var isAppend = fileMode == FileMode.Append;


            // CreateFileXxx() does not support FileMode.Append mode.
            if (isAppend)
            {
                fileMode          = FileMode.OpenOrCreate;
                fileSystemRights &= FileSystemRights.AppendData; // Add right.
            }


            if (fileSecurity != null)
            {
                fileSystemRights |= (FileSystemRights)0x1000000; // Set right.
            }
            // AccessSystemSecurity = 0x1000000    AccessSystemAcl access type.
            // MaximumAllowed       = 0x2000000    MaximumAllowed  access type.

            if ((fileSystemRights & (FileSystemRights)0x1000000) != 0 ||
                (fileSystemRights & (FileSystemRights)0x2000000) != 0)
            {
                privilegeEnabler = new PrivilegeEnabler(Privilege.Security);
            }


            using (privilegeEnabler)
                using (var securityAttributes = new Security.NativeMethods.SecurityAttributes(fileSecurity))
                {
                    var handle = transaction == null || !NativeMethods.IsAtLeastWindowsVista

                                 // CreateFile() / CreateFileTransacted()
                                 // 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.CreateFile(pathLp, fileSystemRights, fileShare, securityAttributes, fileMode, attributes, IntPtr.Zero)
               : NativeMethods.CreateFileTransacted(pathLp, fileSystemRights, fileShare, securityAttributes, fileMode, attributes, IntPtr.Zero, transaction.SafeHandle, IntPtr.Zero, IntPtr.Zero);

                    var lastError = Marshal.GetLastWin32Error();

                    if (handle.IsInvalid)
                    {
                        handle.Close();
                        NativeError.ThrowException(lastError, pathLp);
                    }


                    if (isAppend)
                    {
                        var stream = new FileStream(handle, FileAccess.Write, NativeMethods.DefaultFileBufferSize, (attributes & ExtendedFileAttributes.Overlapped) != 0);
                        stream.Seek(0, SeekOrigin.End);
                    }

                    return(handle);
                }
        }
예제 #20
0
        internal static Collection <Process> GetProcessForFileLockCore(KernelTransaction transaction, Collection <string> filePaths, PathFormat pathFormat)
        {
            if (!NativeMethods.IsAtLeastWindowsVista)
            {
                throw new PlatformNotSupportedException(new Win32Exception((int)Win32Errors.ERROR_OLD_WIN_VERSION).Message);
            }

            if (null == filePaths)
            {
                throw new ArgumentNullException("filePaths");
            }

            if (filePaths.Count == 0)
            {
                throw new ArgumentOutOfRangeException("filePaths", "No paths specified.");
            }


            var isLongPath = pathFormat == PathFormat.LongFullPath;
            var allPaths   = isLongPath ? new Collection <string>(filePaths) : new Collection <string>();

            if (!isLongPath)
            {
                foreach (var path in filePaths)
                {
                    allPaths.Add(Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck));
                }
            }



            uint sessionHandle;
            var  success = NativeMethods.RmStartSession(out sessionHandle, 0, Guid.NewGuid().ToString()) == Win32Errors.ERROR_SUCCESS;

            var lastError = Marshal.GetLastWin32Error();

            if (!success)
            {
                NativeError.ThrowException(lastError);
            }



            var processes = new Collection <Process>();

            try
            {
                // A snapshot count of all running processes.
                var  processesFound    = (uint)Process.GetProcesses().Length;
                uint lpdwRebootReasons = 0;


                success = NativeMethods.RmRegisterResources(sessionHandle, (uint)allPaths.Count, allPaths.ToArray(), 0, null, 0, null) == Win32Errors.ERROR_SUCCESS;

                lastError = Marshal.GetLastWin32Error();
                if (!success)
                {
                    NativeError.ThrowException(lastError);
                }


GetList:

                var processInfo = new NativeMethods.RM_PROCESS_INFO[processesFound];
                var processesTotal = processesFound;


                lastError = NativeMethods.RmGetList(sessionHandle, out processesFound, ref processesTotal, processInfo, ref lpdwRebootReasons);


                // There would be no need for this because we already have a/the total number of running processes.
                if (lastError == Win32Errors.ERROR_MORE_DATA)
                {
                    goto GetList;
                }


                if (lastError != Win32Errors.ERROR_SUCCESS)
                {
                    NativeError.ThrowException(lastError);
                }


                for (var i = 0; i < processesTotal; i++)
                {
                    try
                    {
                        processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
                    }

                    // MSDN: The process specified by the processId parameter is not running. The identifier might be expired.
                    catch (ArgumentException) {}
                }
            }
            finally
            {
                NativeMethods.RmEndSession(sessionHandle);
            }


            return(processes.Count == 0 ? null : processes);
        }