/*----------------------------------------------------------------------------- * 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); }
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}"); }
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,
/*----------------------------------------------------------------------------- * 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); }