Exemple #1
0
        /*-----------------------------------------------------------------------------
        *  AssignTemporaryDriveLetter([In] pszDriveLetter, [In] pszDeviceName)
        *
        *  Description:
        *  Creates a temporary drive letter that refers to a specified device. This
        *  drive letter will exist only until the system is shut down or restarted.
        *
        *  Parameters:
        *  pszDriveLetter
        *  The new drive letter to create. Must be in the form X: or X:\
        *
        *  pszDeviceName
        *  The NT device name to which the drive letter will be assigned.
        *
        *  Return Value:
        *  Returns true if the temporary drive letter was assigned, or false if it
        *  could not be.
        *
        *  Notes:
        *  A temporary drive letter is just a symbolic link. It can be removed at any
        *  time by deleting the symbolic link. If it exists when the system is shut
        *  down or restarted, it will be removed automatically.
        *
        *  AssignTemporaryDriveLetter requires device to be present.
        *  -----------------------------------------------------------------------------*/
        private static bool AssignTemporaryDriveLetter(string pszDriveLetter, string pszDeviceName)
        {
            /* Verify that caller passed a drive letter and device name. */
            if (0 == pszDriveLetter.Length || 0 == pszDeviceName.Length || !IsDriveLetter(pszDriveLetter))
            {
                SetLastError(Win32Error.ERROR_INVALID_PARAMETER);
                return(false);
            }

            /*
             * Make sure the drive letter isn't already in use. If not in use,
             * create the symbolic link to establish the temporary drive letter.
             *
             * pszDriveLetter could be in the format X: or X:\; QueryDosDevice and
             * DefineDosDevice need X:
             */
            var szDriveLetter = pszDriveLetter[0] + ":";

            if (QueryDosDevice(szDriveLetter, out _).Failed)
            {
                /*
                 * If we can create the symbolic link, verify that it points to a real
                 * device. If not, remove the link and return an error. CreateFile sets
                 * the last error code to ERROR_FILE_NOT_FOUND.
                 */
                if (DefineDosDevice(DDD.DDD_RAW_TARGET_PATH, szDriveLetter, pszDeviceName))
                {
                    var szDriveName = "\\\\.\\" + szDriveLetter;

                    using SafeHFILE hDevice = CreateFile(szDriveName, FileAccess.GENERIC_READ, System.IO.FileShare.ReadWrite,
                                                         default, System.IO.FileMode.Open, 0);
                    if (hDevice.IsInvalid)
                    {
                        DefineDosDevice(DDD.DDD_RAW_TARGET_PATH | DDD.DDD_REMOVE_DEFINITION | DDD.DDD_EXACT_MATCH_ON_REMOVE, szDriveLetter, pszDeviceName);
                        return(false);
                    }
                    return(true);
                }
            }
            else
            {
                SetLastError(PRIV_ERROR_DRIVE_LETTER_IN_USE);
            }
            return(false);
        }
Exemple #2
0
        public void WriteLineToLog(string text)
        {
            if (logFile is null)
            {
                return;
            }
            using SafeHFILE hStream = CreateFile(logFile.Path,
                                                 FileAccess.GENERIC_WRITE, System.IO.FileShare.Read, null, System.IO.FileMode.OpenOrCreate, Vanara.PInvoke.FileFlagsAndAttributes.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero);
            if (hStream.IsInvalid)
            {
                return;
            }
            byte[] buff = Encoding.UTF8.GetBytes("\n" + text);
            SetFilePointer(hStream, 0, IntPtr.Zero, System.IO.SeekOrigin.End);
            WriteFile(hStream, buff, (uint)buff.Length, out var dwBytesWritten, IntPtr.Zero);

            Debug.WriteLine($"Logged event: {text}");
        }
Exemple #3
0
        public void Initalize(string path, Action <IEnumerable <string> > callback)
        {
            _path     = path;
            _callback = callback;

            _dir = CreateFile(path, Kernel32.FileAccess.FILE_LIST_DIRECTORY, FileShare.ReadWrite | FileShare.Delete, default,
Exemple #4
0
        /*-----------------------------------------------------------------------------
        *  AssignPersistentDriveLetter ([In] pszDriveLetter, [In] pszDeviceName)
        *
        *  Description:
        *  Creates a persistent drive letter that refers to a specified device. This
        *  drive letter will remain even when the system is restarted.
        *
        *  Parameters:
        *  pszDriveLetter
        *  The new drive letter to create. Must be in the form X: or X:\
        *
        *  pszDeviceName
        *  The NT device name to which the drive letter will be assigned.
        *
        *  Return Value:
        *  Returns true if the drive letter was added, or false if it wasn't.
        *  -----------------------------------------------------------------------------*/
        private static bool AssignPersistentDriveLetter(string pszDriveLetter, string pszDeviceName)
        {
            /*
             * Make sure we are passed a drive letter and a device name. lstrlen
             * is useful because it will return zero if the pointer points to memory
             * that can't be read or a string that causes an invalid page fault before
             * the terminating default.
             */
            if (0 == pszDriveLetter.Length || 0 == pszDeviceName.Length || !IsDriveLetter(pszDriveLetter))
            {
                SetLastError(Win32Error.ERROR_INVALID_PARAMETER);
                return(false);
            }

            /*
             * GetVolumeNameForVolumeMountPoint, SetVolumeMountPoint, and
             * DeleteVolumeMountPoint require drive letters to have a trailing backslash.
             * However, DefineDosDevice and QueryDosDevice require that the trailing
             * backslash be absent. So, we'll set up the following variables:
             *
             * szDriveLetterAndSlash for the mount point APIs
             * szDriveLetter for DefineDosDevice
             */
            var szDriveLetter         = pszDriveLetter[0] + ":";
            var szDriveLetterAndSlash = szDriveLetter + '\\';

            /*
             * Determine if the drive letter is currently in use. If so, return the
             * error to the caller. NOTE: we temporarily reuse szUniqueVolumeName
             * instead of allocating a large array for this one call.
             */
            if (QueryDosDevice(szDriveLetter, out _).Succeeded)
            {
                SetLastError(PRIV_ERROR_DRIVE_LETTER_IN_USE);
                return(false);
            }

            /*
             * To map a persistent drive letter, we must make sure that the target
             * device is one of the following:
             *
             * A recognized partition and is not hidden
             * A dynamic volume
             * A non-partitionable device such as CD-ROM
             *
             * Start by using the drive letter as a symbolic link to the device. Then,
             * open the device to gather the information necessary to determine if the
             * drive can have a persistent drive letter.
             */
            if (DefineDosDevice(DDD.DDD_RAW_TARGET_PATH, szDriveLetter, pszDeviceName))
            {
                VOLUME_GET_GPT_ATTRIBUTES_INFORMATION volinfo;
                PARTITION_INFORMATION partinfo;

                var szDriveName = "\\\\.\\" + szDriveLetter;                 // holds \\.\X: plus default.

                using SafeHFILE hDevice = CreateFile(szDriveName, FileAccess.GENERIC_READ, System.IO.FileShare.ReadWrite, default, System.IO.FileMode.Open, 0);
                if (hDevice.IsInvalid)
                {
                    /*
                     * Remove the drive letter symbolic link we created, let caller know
                     * we couldn't open the drive.
                     */
                    DefineDosDevice(DDD.DDD_RAW_TARGET_PATH | DDD.DDD_REMOVE_DEFINITION | DDD.DDD_EXACT_MATCH_ON_REMOVE, szDriveLetter, pszDeviceName);
                    return(false);
                }
                else
                {
                    /*
                     * See if drive is partitionable and retrieve the partition type.
                     * If the device doesn't have a partition, note it by setting the
                     * partition type to unused.
                     */
                    if (!DeviceIoControl(hDevice, IOControlCode.IOCTL_DISK_GET_PARTITION_INFO, out partinfo))
                    {
                        partinfo.PartitionType = PartitionType.PARTITION_ENTRY_UNUSED;
                    }

                    /*
                     * On Windows XP, partition entries on Guid Partition Table drives
                     * have an attribute that determines whether partitions are hidden.
                     * Therefore, we must check this bit on the target partition.
                     *
                     * If we're running on Windows 2000, there are no GPT drives, so
                     * set flags to none. This is important for the check for hidden
                     * partitions later.
                     */
                    if (!IsWindowsXP_orLater() || !DeviceIoControl(hDevice, IOControlCode.IOCTL_VOLUME_GET_GPT_ATTRIBUTES, out volinfo))
                    {
                        volinfo.GptAttributes = 0;
                    }
                }

                /*
                 * Now, make sure drive meets requirements for receiving a persistent
                 * drive letter.
                 *
                 * Note: on Windows XP, partitions that were hidden when the system
                 * booted are not assigned a unique volume name. They will not be given
                 * one until they are marked as not hidden and the system rebooted.
                 * Therefore, we cannot create a mount point hidden partitions.
                 *
                 * On Windows 2000, hidden partitions are assigned unique volume names
                 * and so can have persistent drive letters. However, we will not allow
                 * that behavior in this tool as hidden partitions should not be assigned
                 * drive letters.
                 */
                if (IsPartitionHidden(partinfo.PartitionType, volinfo.GptAttributes))
                {
                    // remove the drive letter we created, let caller know what happened.
                    DefineDosDevice(DDD.DDD_RAW_TARGET_PATH | DDD.DDD_REMOVE_DEFINITION | DDD.DDD_EXACT_MATCH_ON_REMOVE, szDriveLetter, pszDeviceName);

                    SetLastError(PRIV_ERROR_PARTITION_HIDDEN);
                    return(false);
                }

                /*
                 * Verify that the drive letter must refer to a recognized partition,
                 * a dynamic volume, or a non-partitionable device such as CD-ROM.
                 */
                if (IsRecognizedPartition(partinfo.PartitionType) ||
                    PartitionType.PARTITION_LDM == partinfo.PartitionType ||
                    PartitionType.PARTITION_ENTRY_UNUSED == partinfo.PartitionType)
                {
                    /*
                     * Now add the drive letter by calling on the volume mount manager.
                     * Once we have the unique volume name that the new drive letter
                     * will point to, delete the symbolic link because the Mount Manager
                     * allows only one reference to a device at a time (the new one to
                     * be added).
                     */
                    var szUniqueVolumeName = new StringBuilder(MAX_PATH);
                    var fResult            = GetVolumeNameForVolumeMountPoint(szDriveLetterAndSlash, szUniqueVolumeName, MAX_PATH);

                    DefineDosDevice(DDD.DDD_RAW_TARGET_PATH | DDD.DDD_REMOVE_DEFINITION | DDD.DDD_EXACT_MATCH_ON_REMOVE, szDriveLetter, pszDeviceName);

                    if (fResult)
                    {
                        fResult = SetVolumeMountPoint(szDriveLetterAndSlash, szUniqueVolumeName.ToString());
                    }

                    return(fResult);
                }
                else
                {
                    /*
                     * Device doesn't meet the criteria for persistent drive letter.
                     * Remove the drive letter symbolic link we created.
                     */
                    DefineDosDevice(DDD.DDD_RAW_TARGET_PATH | DDD.DDD_REMOVE_DEFINITION | DDD.DDD_EXACT_MATCH_ON_REMOVE, szDriveLetter, pszDeviceName);
                    SetLastError(PRIV_ERROR_PARTITION_NOT_RECOGNIZED);
                    return(false);
                }
            }
            else
            {
                return(false);
            }
        }
        /*++
         *
         * Routine Description:
         *
         * Function that calls CreateFileW in a cancellation section and therefore
         * can be canceled using IoCancellationSignal from another thread.
         *
         * Arguments:
         *
         * phFile - Pointer to a handle that will be returned on successful create.
         * On failure this will be INVALID_HANDLE_VALUE.
         *
         *
         * pCancellationObject - Pointer to cancellation object created with
         * IoCancellationCreate.
         *
         * wszFileName - File name to open.
         *
         * dwDesiredAccess - Desired access for handle.
         *
         * dwShareMode - Share mode.
         *
         * lpSecurityAttributes - Optional pointer to security attributes.
         *
         * dwCreationDisposition - Disposition for create.
         *
         * dwFlagsAndAttributes - Flags for create.
         *
         * hTemplateFile - Optional handle to template file.
         *
         * Return value:
         *
         * Win32Error.ERROR_SUCCESS on success.
         * Win32Error.ERROR_OPERATION_ABORTED on cancellation.
         * Otherwise use GetLastError to determine the cause of failure.
         *
         * --*/
        public Win32Error CancelableCreateFile(out SafeHFILE hFile,
                                               string wszFileName,
                                               FileAccess dwDesiredAccess,
                                               System.IO.FileShare dwShareMode,
                                               SECURITY_ATTRIBUTES lpSecurityAttributes,
                                               System.IO.FileMode dwCreationDisposition,
                                               FileFlagsAndAttributes dwFlagsAndAttributes,
                                               HFILE hTemplateFile)
        {
            Win32Error err = 0;

            lock (lockObj)
            {
                //
                // GetCurrentThread returns pseudo handle for the calling thread
                // and it always refers to the current thread; therefore it can't
                // be used for CancelSynchronousIo.
                // DuplicateHandle will return a normal handle that can
                // be used cross thread.
                //
                if (hThread.IsNull)
                {
                    //
                    // CancelSynchronousIo actually requires only THREAD_TERMINATE
                    //
                    bool fOK = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), out hThread,
                                               ThreadAccess.THREAD_ALL_ACCESS);
                    if (!fOK)
                    {
                        err = GetLastError();
                    }
                    else
                    {
                        dwThreadId = GetCurrentThreadId();
                    }
                }

                fPendingIo = true;

                //
                // Cancellation section contains a single call to CreateFileW
                //
                hFile = CreateFile(wszFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
                if (hFile.IsInvalid)
                {
                    err = GetLastError();
                }

                fPendingIo = false;

                if (fCanceled)
                {
                    err = Win32Error.ERROR_OPERATION_ABORTED;
                }
            }

            if (err.Failed)
            {
                hFile?.Dispose();
                hFile = new SafeHFILE((IntPtr)HFILE.INVALID_HANDLE_VALUE, false);
            }

            return(err);
        }