windows-nt/Source/XPSP1/NT/base/fs/sis/groveler/sisdrive.cpp

382 lines
8.6 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
sisdrive.cpp
Abstract:
SIS Groveler SIS drive checker class
Authors:
John Douceur, 1998
Environment:
User Mode
Revision History:
--*/
#include "all.hxx"
SISDrives::SISDrives()
{
num_partitions = 0;
num_lettered_partitions = 0;
partition_guid_names = 0;
partition_mount_names = 0;
buffer_size = 0;
buffer_index = 0;
buffer = 0;
}
void
SISDrives::open()
{
num_partitions = 0;
num_lettered_partitions = 0;
partition_mount_names = 0;
int name_array_size = 1;
partition_guid_names = new int[name_array_size];
buffer_size = 256;
buffer_index = 0;
buffer = new _TCHAR[buffer_size];
SERVICE_CHECKPOINT();
Volumes volumes;
bool done = false;
//
// Enumerate all existing volumes getting their GUID names
//
while (!done)
{
DWORD error_code =
volumes.find(&buffer[buffer_index], buffer_size - buffer_index);
while (error_code != NO_ERROR)
{
if (error_code != ERROR_INSUFFICIENT_BUFFER &&
error_code != ERROR_BUFFER_OVERFLOW &&
error_code != ERROR_FILENAME_EXCED_RANGE)
{
done = true;
break;
}
resize_buffer();
SERVICE_CHECKPOINT();
error_code =
volumes.find(&buffer[buffer_index], buffer_size - buffer_index);
}
if (!done)
{
if (num_partitions >= name_array_size)
{
name_array_size *= 2;
int *new_name_array = new int[name_array_size];
memcpy(new_name_array,partition_guid_names,num_partitions * sizeof(int));
delete[] partition_guid_names;
partition_guid_names = new_name_array;
}
partition_guid_names[num_partitions] = buffer_index;
num_partitions++;
buffer_index += _tcslen(&buffer[buffer_index]) + 1;
}
SERVICE_CHECKPOINT();
}
//
// Setup to scan for DRIVE LETTERS and MOUNT POINTS and correlate
// them with the drive letters.
//
partition_mount_names = new int[num_partitions];
int *next_indices = new int[num_partitions + 3];
int *work_list = &next_indices[num_partitions + 1];
int *scan_list = &next_indices[num_partitions + 2];
*scan_list = 0;
for (int index = 0; index < num_partitions; index++)
{
partition_mount_names[index] = -1;
next_indices[index] = index + 1;
}
next_indices[num_partitions - 1] = -1;
*work_list = num_partitions;
next_indices[num_partitions] = -1;
int work_list_end = num_partitions;
//
// Now that we have the GUID names, this will correlate the GUID names
// with the MOUNT names, this does both direct drive letters and
// mount point names.
//
while (*scan_list != -1 && *work_list != -1)
{
_TCHAR *mount_name = 0;
int mount_size = 0;
if (*work_list < num_partitions)
{
mount_name = &buffer[partition_mount_names[*work_list]];
mount_size = _tcslen(mount_name);
while (buffer_size - buffer_index <= mount_size)
{
resize_buffer();
}
_tcscpy(&buffer[buffer_index], mount_name);
}
VolumeMountPoints mount_points(mount_name);
//
// We have the next name, scan the list looking for that name
//
done = false;
while (!done)
{
DWORD error_code = mount_points.find(
&buffer[buffer_index + mount_size],
buffer_size - buffer_index - mount_size);
while (error_code != NO_ERROR)
{
if (error_code != ERROR_INSUFFICIENT_BUFFER &&
error_code != ERROR_BUFFER_OVERFLOW &&
error_code != ERROR_FILENAME_EXCED_RANGE)
{
done = true;
break;
}
resize_buffer();
SERVICE_CHECKPOINT();
error_code = mount_points.find(
&buffer[buffer_index + mount_size],
buffer_size - buffer_index - mount_size);
}
if (!done)
{
_TCHAR volume_guid_name[MAX_PATH + 1];
BOOL ok = GetVolumeNameForVolumeMountPoint(
&buffer[buffer_index], volume_guid_name, MAX_PATH + 1);
if (!ok)
{
continue;
}
int scan_index = *scan_list;
int prev_index = num_partitions + 2;
while (scan_index >= 0)
{
_TCHAR *scan_name =
&buffer[partition_guid_names[scan_index]];
if (_tcscmp(scan_name, volume_guid_name) == 0)
{
partition_mount_names[scan_index] = buffer_index;
buffer_index += _tcslen(&buffer[buffer_index]) + 1;
next_indices[prev_index] = next_indices[scan_index];
next_indices[scan_index] = -1;
next_indices[work_list_end] = scan_index;
work_list_end = scan_index;
if (mount_name) {
_tcscpy(&buffer[buffer_index], mount_name); //get ready for next time through the loop
}
break;
}
prev_index = scan_index;
scan_index = next_indices[scan_index];
SERVICE_CHECKPOINT();
}
}
SERVICE_CHECKPOINT();
}
*work_list = next_indices[*work_list];
SERVICE_CHECKPOINT();
}
delete[] next_indices;
next_indices = 0;
//
// We are now going to sort all of the drive letter entries to the front
// this does keep the driver letter/guid name correlation intact.
//
index = 0;
while (index < num_partitions)
{
if (partition_mount_names[index] < 0 ||
!is_sis_drive(&buffer[partition_guid_names[index]]))
{
//
// The given entry either doesn't have a name or SIS is
// not currently running on the volume. Move it to the end
// of the list.
int temp = partition_guid_names[index];
partition_guid_names[index] =
partition_guid_names[num_partitions - 1];
partition_guid_names[num_partitions - 1] = temp;
temp = partition_mount_names[index];
partition_mount_names[index] =
partition_mount_names[num_partitions - 1];
partition_mount_names[num_partitions - 1] = temp;
num_partitions--;
continue;
}
if (buffer[partition_mount_names[index] + 3] == _T('\0'))
{
//
// If this is a drive letter (not a mount point) then
// it will be moved to the front of the list
//
int temp = partition_guid_names[index];
partition_guid_names[index] =
partition_guid_names[num_lettered_partitions];
partition_guid_names[num_lettered_partitions] = temp;
temp = partition_mount_names[index];
partition_mount_names[index] =
partition_mount_names[num_lettered_partitions];
partition_mount_names[num_lettered_partitions] = temp;
num_lettered_partitions++;
}
index++;
SERVICE_CHECKPOINT();
}
#if DBG
TRACE_PRINTF(TC_sisdrive,2,
(_T("Num Partitions=%d\nNum Lettered_partitions=%d\n"),
num_partitions,
num_lettered_partitions));
for (index=0;index < num_partitions;index++)
{
TRACE_PRINTF(TC_sisdrive,2,
(_T("Name=\"%s\" GuidName=\"%s\"\n"),
&buffer[partition_mount_names[index]],
&buffer[partition_guid_names[index]]));
}
#endif
}
SISDrives::~SISDrives()
{
if (partition_guid_names != 0)
{
delete[] partition_guid_names;
partition_guid_names = 0;
}
if (partition_mount_names != 0)
{
delete[] partition_mount_names;
partition_mount_names = 0;
}
if (buffer != 0)
{
delete[] buffer;
buffer = 0;
}
}
int SISDrives::partition_count() const
{
return num_partitions;
}
int SISDrives::lettered_partition_count() const
{
return num_lettered_partitions;
}
_TCHAR * SISDrives::partition_guid_name(
int partition_index) const
{
if (partition_index < num_partitions)
{
return &buffer[partition_guid_names[partition_index]];
}
else
{
return 0;
}
}
_TCHAR * SISDrives::partition_mount_name(
int partition_index) const
{
if (partition_index < num_partitions)
{
return &buffer[partition_mount_names[partition_index]];
}
else
{
return 0;
}
}
bool
SISDrives::is_sis_drive(
_TCHAR *drive_name)
{
UINT drive_type = GetDriveType(drive_name);
if (drive_type != DRIVE_FIXED)
{
return false;
}
_TCHAR fs_name[8];
BOOL ok = GetVolumeInformation(drive_name, 0, 0, 0, 0, 0, fs_name, 8);
if (!ok)
{
DWORD err = GetLastError();
PRINT_DEBUG_MSG((_T("GROVELER: GetVolumeInformation() failed with error %d\n"),
err));
return false;
}
if (_tcsicmp(fs_name, _T("NTFS")) != 0)
{
return false;
}
int drive_name_len = _tcslen(drive_name);
_TCHAR *sis_directory =
new _TCHAR[SIS_CSDIR_STRING_NCHARS + drive_name_len];
_tcscpy(sis_directory, drive_name);
_tcscpy(&sis_directory[drive_name_len - 1], SIS_CSDIR_STRING);
ok = SetCurrentDirectory(sis_directory);
delete[] sis_directory;
sis_directory = 0;
if (!ok)
{
return false;
}
BOOL sis_installed = Groveler::is_sis_installed(drive_name);
if (!sis_installed)
{
return false;
}
return true;
}
void SISDrives::resize_buffer()
{
buffer_size *= 2;
_TCHAR *new_buffer = new _TCHAR[buffer_size];
memcpy(new_buffer, buffer, buffer_index * sizeof(_TCHAR));
delete[] buffer;
buffer = new_buffer;
}