1 /* 2 * PROJECT: ReactOS Setup Library 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Volume utility functions 5 * COPYRIGHT: Copyright 2024 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org> 6 */ 7 8 /* INCLUDES ******************************************************************/ 9 10 #include "precomp.h" 11 12 #include "volutil.h" 13 #include "fsrec.h" 14 #include "devutils.h" 15 16 #define NDEBUG 17 #include <debug.h> 18 19 20 /* FUNCTIONS *****************************************************************/ 21 22 NTSTATUS 23 MountVolume( 24 _Inout_ PVOLINFO Volume, 25 _In_opt_ UCHAR MbrPartitionType) 26 { 27 NTSTATUS Status; 28 HANDLE VolumeHandle; 29 30 /* If the volume is already mounted, just return success */ 31 if (*Volume->FileSystem) 32 return STATUS_SUCCESS; 33 34 /* Try to open the volume so as to mount it */ 35 VolumeHandle = NULL; 36 Status = pOpenDevice(Volume->DeviceName, &VolumeHandle); 37 if (!NT_SUCCESS(Status)) 38 { 39 DPRINT1("pOpenDevice() failed, Status 0x%08lx\n", Status); 40 41 /* We failed, reset some data and bail out */ 42 Volume->DriveLetter = UNICODE_NULL; 43 Volume->VolumeLabel[0] = UNICODE_NULL; 44 Volume->FileSystem[0] = UNICODE_NULL; 45 46 return Status; 47 } 48 ASSERT(VolumeHandle); 49 50 /* We don't have a FS, try to guess one */ 51 Status = InferFileSystem(NULL, VolumeHandle, 52 Volume->FileSystem, 53 sizeof(Volume->FileSystem)); 54 if (!NT_SUCCESS(Status)) 55 DPRINT1("InferFileSystem() failed, Status 0x%08lx\n", Status); 56 57 if (*Volume->FileSystem) 58 { 59 /* 60 * Handle volume mounted with RawFS: it is 61 * either unformatted or has an unknown format. 62 */ 63 if (IsUnformatted(Volume)) // FileSystem is "RAW" 64 { 65 /* 66 * True unformatted partitions on NT are created with their 67 * partition type set to either one of the following values, 68 * and are mounted with RawFS. This is done this way since we 69 * are assured to have FAT support, which is the only FS that 70 * uses these partition types. Therefore, having a partition 71 * mounted with RawFS and with these partition types means that 72 * the FAT FS was unable to mount it beforehand and thus the 73 * partition is unformatted. 74 * However, any partition mounted by RawFS that does NOT have 75 * any of these partition types must be considered as having 76 * an unknown format. 77 */ 78 if (MbrPartitionType == PARTITION_FAT_12 || 79 MbrPartitionType == PARTITION_FAT_16 || 80 MbrPartitionType == PARTITION_HUGE || 81 MbrPartitionType == PARTITION_XINT13 || 82 MbrPartitionType == PARTITION_FAT32 || 83 MbrPartitionType == PARTITION_FAT32_XINT13) 84 { 85 /* The volume is unformatted */ 86 } 87 else 88 { 89 /* Close the volume before dismounting */ 90 NtClose(VolumeHandle); 91 VolumeHandle = NULL; 92 /* 93 * Dismount the volume since RawFS owns it, and reset its 94 * format (it is unknown, may or may not be actually formatted). 95 */ 96 DismountVolume(Volume, TRUE); 97 Volume->FileSystem[0] = UNICODE_NULL; 98 } 99 } 100 /* Else, the volume is formatted */ 101 } 102 /* Else, the volume has an unknown format */ 103 104 /* Retrieve the volume label */ 105 if (VolumeHandle) 106 { 107 IO_STATUS_BLOCK IoStatusBlock; 108 struct 109 { 110 FILE_FS_VOLUME_INFORMATION; 111 WCHAR Data[255]; 112 } LabelInfo; 113 114 Status = NtQueryVolumeInformationFile(VolumeHandle, 115 &IoStatusBlock, 116 &LabelInfo, 117 sizeof(LabelInfo), 118 FileFsVolumeInformation); 119 if (NT_SUCCESS(Status)) 120 { 121 /* Copy the (possibly truncated) volume label and NULL-terminate it */ 122 RtlStringCbCopyNW(Volume->VolumeLabel, sizeof(Volume->VolumeLabel), 123 LabelInfo.VolumeLabel, LabelInfo.VolumeLabelLength); 124 } 125 else 126 { 127 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status); 128 } 129 } 130 131 /* Close the volume */ 132 if (VolumeHandle) 133 NtClose(VolumeHandle); 134 135 return STATUS_SUCCESS; 136 } 137 138 /** 139 * @brief 140 * Attempts to dismount the designated volume. 141 * 142 * @param[in,out] Volume 143 * The volume to dismount. 144 * 145 * @param[in] Force 146 * Whether the volume is forcibly dismounted, even 147 * if there are open handles to files on this volume. 148 * 149 * @return An NTSTATUS code indicating success or failure. 150 **/ 151 NTSTATUS 152 DismountVolume( 153 _Inout_ PVOLINFO Volume, 154 _In_ BOOLEAN Force) 155 { 156 NTSTATUS Status, LockStatus; 157 IO_STATUS_BLOCK IoStatusBlock; 158 HANDLE VolumeHandle; 159 160 /* If the volume is not mounted, just return success */ 161 if (!*Volume->FileSystem) 162 return STATUS_SUCCESS; 163 164 /* Open the volume */ 165 Status = pOpenDeviceEx(Volume->DeviceName, &VolumeHandle, 166 GENERIC_READ | GENERIC_WRITE, 167 FILE_SHARE_READ | FILE_SHARE_WRITE); 168 if (!NT_SUCCESS(Status)) 169 { 170 DPRINT1("ERROR: Cannot open volume %S for dismounting! (Status 0x%lx)\n", 171 Volume->DeviceName, Status); 172 return Status; 173 } 174 175 /* Lock the volume (succeeds only if there are no open handles to files) */ 176 LockStatus = NtFsControlFile(VolumeHandle, 177 NULL, NULL, NULL, 178 &IoStatusBlock, 179 FSCTL_LOCK_VOLUME, 180 NULL, 0, 181 NULL, 0); 182 if (!NT_SUCCESS(LockStatus)) 183 DPRINT1("WARNING: Failed to lock volume (Status 0x%lx)\n", LockStatus); 184 185 /* Dismount the volume (succeeds even when lock fails and there are open handles) */ 186 Status = STATUS_ACCESS_DENIED; // Suppose dismount failure. 187 if (NT_SUCCESS(LockStatus) || Force) 188 { 189 Status = NtFsControlFile(VolumeHandle, 190 NULL, NULL, NULL, 191 &IoStatusBlock, 192 FSCTL_DISMOUNT_VOLUME, 193 NULL, 0, 194 NULL, 0); 195 if (!NT_SUCCESS(Status)) 196 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status); 197 } 198 199 /* Unlock the volume */ 200 if (NT_SUCCESS(LockStatus)) 201 { 202 LockStatus = NtFsControlFile(VolumeHandle, 203 NULL, NULL, NULL, 204 &IoStatusBlock, 205 FSCTL_UNLOCK_VOLUME, 206 NULL, 0, 207 NULL, 0); 208 if (!NT_SUCCESS(LockStatus)) 209 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus); 210 } 211 212 /* Close the volume */ 213 NtClose(VolumeHandle); 214 215 /* Reset some data only if dismount succeeded */ 216 if (NT_SUCCESS(Status)) 217 { 218 Volume->DriveLetter = UNICODE_NULL; 219 Volume->VolumeLabel[0] = UNICODE_NULL; 220 Volume->FileSystem[0] = UNICODE_NULL; 221 } 222 223 return Status; 224 } 225 226 /* EOF */ 227