Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227/* * PROJECT: ReactOS Setup Library * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Volume utility functions * COPYRIGHT: Copyright 2024 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org> */
/* INCLUDES ******************************************************************/
#include "precomp.h"
#include "volutil.h"#include "fsrec.h"#include "devutils.h"
#define NDEBUG#include <debug.h>
/* FUNCTIONS *****************************************************************/
NTSTATUSMountVolume( _Inout_ PVOLINFO Volume, _In_opt_ UCHAR MbrPartitionType){ NTSTATUS Status; HANDLE VolumeHandle;
/* If the volume is already mounted, just return success */ if (*Volume->FileSystem) return STATUS_SUCCESS;
/* Try to open the volume so as to mount it */ VolumeHandle = NULL; Status = pOpenDevice(Volume->DeviceName, &VolumeHandle); if (!NT_SUCCESS(Status)) { DPRINT1("pOpenDevice() failed, Status 0x%08lx\n", Status);
/* We failed, reset some data and bail out */ Volume->DriveLetter = UNICODE_NULL; Volume->VolumeLabel[0] = UNICODE_NULL; Volume->FileSystem[0] = UNICODE_NULL;
return Status; } ASSERT(VolumeHandle);
/* We don't have a FS, try to guess one */ Status = InferFileSystem(NULL, VolumeHandle, Volume->FileSystem, sizeof(Volume->FileSystem)); if (!NT_SUCCESS(Status)) DPRINT1("InferFileSystem() failed, Status 0x%08lx\n", Status);
if (*Volume->FileSystem) { /* * Handle volume mounted with RawFS: it is * either unformatted or has an unknown format. */ if (IsUnformatted(Volume)) // FileSystem is "RAW" { /* * True unformatted partitions on NT are created with their * partition type set to either one of the following values, * and are mounted with RawFS. This is done this way since we * are assured to have FAT support, which is the only FS that * uses these partition types. Therefore, having a partition * mounted with RawFS and with these partition types means that * the FAT FS was unable to mount it beforehand and thus the * partition is unformatted. * However, any partition mounted by RawFS that does NOT have * any of these partition types must be considered as having * an unknown format. */ if (MbrPartitionType == PARTITION_FAT_12 || MbrPartitionType == PARTITION_FAT_16 || MbrPartitionType == PARTITION_HUGE || MbrPartitionType == PARTITION_XINT13 || MbrPartitionType == PARTITION_FAT32 || MbrPartitionType == PARTITION_FAT32_XINT13) { /* The volume is unformatted */ } else { /* Close the volume before dismounting */ NtClose(VolumeHandle); VolumeHandle = NULL; /* * Dismount the volume since RawFS owns it, and reset its * format (it is unknown, may or may not be actually formatted). */ DismountVolume(Volume, TRUE); Volume->FileSystem[0] = UNICODE_NULL; } } /* Else, the volume is formatted */ } /* Else, the volume has an unknown format */
/* Retrieve the volume label */ if (VolumeHandle) { IO_STATUS_BLOCK IoStatusBlock; struct { FILE_FS_VOLUME_INFORMATION; WCHAR Data[255]; } LabelInfo;
Status = NtQueryVolumeInformationFile(VolumeHandle, &IoStatusBlock, &LabelInfo, sizeof(LabelInfo), FileFsVolumeInformation); if (NT_SUCCESS(Status)) { /* Copy the (possibly truncated) volume label and NULL-terminate it */ RtlStringCbCopyNW(Volume->VolumeLabel, sizeof(Volume->VolumeLabel), LabelInfo.VolumeLabel, LabelInfo.VolumeLabelLength); } else { DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status); } }
/* Close the volume */ if (VolumeHandle) NtClose(VolumeHandle);
return STATUS_SUCCESS;}
/** * @brief * Attempts to dismount the designated volume. * * @param[in,out] Volume * The volume to dismount. * * @param[in] Force * Whether the volume is forcibly dismounted, even * if there are open handles to files on this volume. * * @return An NTSTATUS code indicating success or failure. **/NTSTATUSDismountVolume( _Inout_ PVOLINFO Volume, _In_ BOOLEAN Force){ NTSTATUS Status, LockStatus; IO_STATUS_BLOCK IoStatusBlock; HANDLE VolumeHandle;
/* If the volume is not mounted, just return success */ if (!*Volume->FileSystem) return STATUS_SUCCESS;
/* Open the volume */ Status = pOpenDeviceEx(Volume->DeviceName, &VolumeHandle, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE); if (!NT_SUCCESS(Status)) { DPRINT1("ERROR: Cannot open volume %S for dismounting! (Status 0x%lx)\n", Volume->DeviceName, Status); return Status; }
/* Lock the volume (succeeds only if there are no open handles to files) */ LockStatus = NtFsControlFile(VolumeHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0); if (!NT_SUCCESS(LockStatus)) DPRINT1("WARNING: Failed to lock volume (Status 0x%lx)\n", LockStatus);
/* Dismount the volume (succeeds even when lock fails and there are open handles) */ Status = STATUS_ACCESS_DENIED; // Suppose dismount failure. if (NT_SUCCESS(LockStatus) || Force) { Status = NtFsControlFile(VolumeHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0); if (!NT_SUCCESS(Status)) DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status); }
/* Unlock the volume */ if (NT_SUCCESS(LockStatus)) { LockStatus = NtFsControlFile(VolumeHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0); if (!NT_SUCCESS(LockStatus)) DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus); }
/* Close the volume */ NtClose(VolumeHandle);
/* Reset some data only if dismount succeeded */ if (NT_SUCCESS(Status)) { Volume->DriveLetter = UNICODE_NULL; Volume->VolumeLabel[0] = UNICODE_NULL; Volume->FileSystem[0] = UNICODE_NULL; }
return Status;}
/* EOF */