#include #include #include #include #include #include #include NTSTATUS NTAPI NtOpenDirectoryObject (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); NTSTATUS NTAPI NtQueryDirectoryObject (HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG); typedef struct _DIRECTORY_BASIC_INFORMATION { UNICODE_STRING ObjectName; UNICODE_STRING ObjectTypeName; } DIRECTORY_BASIC_INFORMATION, *PDIRECTORY_BASIC_INFORMATION; #define DIRECTORY_QUERY 1 #define NT_MAX_PATH 32768 char buf[NT_MAX_PATH]; char ioctl_buf[NT_MAX_PATH]; WCHAR mp_buf[NT_MAX_PATH]; typedef enum { false, true } bool; int main () { OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; NTSTATUS status; HANDLE dirhdl; WCHAR fpath[MAX_PATH]; WCHAR gpath[MAX_PATH]; DWORD len; /* Note that device ids and names are just faked here, not using the internal Cygwin code to generate device major/minor numbers and device names. There's *no* guarantee that the device name and the device major number is the same as in Cygwin. */ char dev_name = '`'; /* Open \Device object directory. */ wchar_t wpath[MAX_PATH] = L"\\Device"; UNICODE_STRING upath = {14, 16, wpath}; InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL); status = NtOpenDirectoryObject (&dirhdl, DIRECTORY_QUERY, &attr); if (!NT_SUCCESS (status)) { fprintf (stderr, "NtOpenDirectoryObject, status 0x%08x", status); return 1; } /* Traverse \Device directory ... */ PDIRECTORY_BASIC_INFORMATION dbi_buf = (PDIRECTORY_BASIC_INFORMATION) alloca (65536); PDIRECTORY_BASIC_INFORMATION dbi = dbi_buf; BOOLEAN restart = TRUE; bool got_one = false; bool last_run = false; ULONG context = 0; ULONG bytes_read = 0; while (!last_run) { status = NtQueryDirectoryObject (dirhdl, dbi_buf, 65536, FALSE, restart, &context, &bytes_read); if (!NT_SUCCESS (status)) { fprintf (stderr, "NtQueryDirectoryObject(), status 0x%08x", status); return 1; } if (status != STATUS_MORE_ENTRIES) last_run = true; restart = FALSE; printf ("bytes_read = %lu, context = %lu, status = 0x%08x\n", (unsigned long) bytes_read, (unsigned long) context, status); for (dbi = dbi_buf; dbi->ObjectName.Length > 0; dbi++) { HANDLE devhdl; PARTITION_INFORMATION_EX *pix = NULL; PARTITION_INFORMATION *pi = NULL; DWORD bytes_read; DWORD part_cnt = 0; unsigned long long size; /* ... and check for a "Harddisk[0-9]*" entry. */ if (dbi->ObjectName.Length < 9 * sizeof (WCHAR) || wcsncasecmp (dbi->ObjectName.Buffer, L"Harddisk", 8) != 0 || !iswdigit (dbi->ObjectName.Buffer[8])) continue; /* Got it. Now construct the path to the entire disk, which is "\\Device\\HarddiskX\\Partition0", and open the disk with minimum permissions. */ //unsigned long drive_num = wcstoul (dbi->ObjectName.Buffer + 8, NULL, 10); wcscpy (wpath, dbi->ObjectName.Buffer); PWCHAR wpart = wpath + dbi->ObjectName.Length / sizeof (WCHAR); wcpcpy (wpart, L"\\Partition0"); upath.Length = dbi->ObjectName.Length + 22; upath.MaximumLength = upath.Length + sizeof (WCHAR); InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, dirhdl, NULL); status = NtOpenFile (&devhdl, READ_CONTROL, &attr, &io, FILE_SHARE_VALID_FLAGS, 0); if (!NT_SUCCESS (status)) { fprintf (stderr, "NtOpenFile(%ls), status 0x%08x", upath.Buffer, status); continue; } if (!got_one) { printf ("major minor #blocks name win-mounts\n\n"); got_one = true; } /* Fetch partition info for the entire disk to get its size. */ if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL)) { pix = (PARTITION_INFORMATION_EX *) ioctl_buf; size = pix->PartitionLength.QuadPart; } else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL)) { pi = (PARTITION_INFORMATION *) ioctl_buf; size = pi->PartitionLength.QuadPart; } else { fprintf (stderr, "DeviceIoControl (%ls, " "IOCTL_DISK_GET_PARTITION_INFO{_EX}) %lu", upath.Buffer, (unsigned long) GetLastError ()); size = 0; } //device dev (drive_num, 0); ++dev_name; printf ("%5d %5d %9llu sd%c (%lu, %ls)\n", 8, (dev_name - 'a') * 16, size >> 10, dev_name, (unsigned long) context, dbi->ObjectName.Buffer); /* Fetch drive layout info to get size of all partitions on the disk. */ if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL)) { PDRIVE_LAYOUT_INFORMATION_EX pdlix = (PDRIVE_LAYOUT_INFORMATION_EX) ioctl_buf; part_cnt = pdlix->PartitionCount; pix = pdlix->PartitionEntry; } else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL)) { PDRIVE_LAYOUT_INFORMATION pdli = (PDRIVE_LAYOUT_INFORMATION) ioctl_buf; part_cnt = pdli->PartitionCount; pi = pdli->PartitionEntry; } else fprintf (stderr, "DeviceIoControl(%ls, " "IOCTL_DISK_GET_DRIVE_LAYOUT{_EX}): %lu", upath.Buffer, (unsigned long) GetLastError ()); /* Loop over partitions. */ if (pix || pi) for (DWORD i = 0; i < part_cnt && i < 64; ++i) { DWORD part_num; if (pix) { size = pix->PartitionLength.QuadPart; part_num = pix->PartitionNumber; ++pix; } else { size = pi->PartitionLength.QuadPart; part_num = pi->PartitionNumber; ++pi; } /* A partition number of 0 denotes an extended partition or a filler entry as described in fhandler_dev_floppy::lock_partition. Just skip. */ if (part_num == 0) continue; //device dev (drive_num, part_num); printf ("%5d %5d %9llu sd%c%d ", 8, (dev_name - 'a') * 16 + part_num, size >> 10, dev_name, part_num); /* Check if the partition is mounted in Windows and, if so, print the mount point list. */ swprintf (fpath, sizeof fpath, L"\\\\?\\GLOBALROOT\\Device\\%ls\\Partition%u\\", dbi->ObjectName.Buffer, part_num); if (GetVolumeNameForVolumeMountPointW (fpath, gpath, MAX_PATH) && GetVolumePathNamesForVolumeNameW (gpath, mp_buf, NT_MAX_PATH, &len)) { for (PWCHAR p = mp_buf; *p; p = wcschr (p, L'\0') + 1) printf (" %ls", p); } puts (""); } NtClose (devhdl); } } NtClose (dirhdl); if (!got_one) return 1; return 0; }