Re: [PATCH] Cygwin: Add /dev/disk/by-drive and /dev/disk/by-uuid symlinks
On Nov 16 18:02, Christian Franke wrote: > Corinna Vinschen wrote: > > On Nov 16 12:50, Christian Franke wrote: > > ... > > > > I also tried an NTFS partition and the output looks like this: > > > > > > > > 0FD4F62866CFBF09 -> ../../sdc1 > > > > > > > > This is the 64 bit volume serial number as returned by > > > > DeviceIoControl(FSCTL_GET_NTFS_VOLUME_DATA)(*). > > > > > > > > Wouldn't that be what we want to see, too? > > > Hmm.. yes. Should both information be provided in by-uuid or only the > > > serial numbers? In the latter case, should we add e.g. by-voluuid for the > > > volume GUIDs ? > > Good question... by-voluuid sounds like a nice idea. It's a Windows-only > > concept anyway, so it might make sense to present it in its own directory. > > Then by-voluuid is easy, changed patch is attached. Pushed. > I try to provide a patch > for a new by-uuid with filesystem serial numbers soon. Cool! Thanks, Corinna
Re: [PATCH] Cygwin: Add /dev/disk/by-drive and /dev/disk/by-uuid symlinks
Corinna Vinschen wrote: On Nov 16 12:50, Christian Franke wrote: ... I also tried an NTFS partition and the output looks like this: 0FD4F62866CFBF09 -> ../../sdc1 This is the 64 bit volume serial number as returned by DeviceIoControl(FSCTL_GET_NTFS_VOLUME_DATA)(*). Wouldn't that be what we want to see, too? Hmm.. yes. Should both information be provided in by-uuid or only the serial numbers? In the latter case, should we add e.g. by-voluuid for the volume GUIDs ? Good question... by-voluuid sounds like a nice idea. It's a Windows-only concept anyway, so it might make sense to present it in its own directory. Then by-voluuid is easy, changed patch is attached. I try to provide a patch for a new by-uuid with filesystem serial numbers soon. From 39cdbadeacfb226ad082f4f635285298aa5ad1bb Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 16 Nov 2023 17:51:08 +0100 Subject: [PATCH] Cygwin: Add /dev/disk/by-drive and /dev/disk/by-voluuid symlinks The new directory '/dev/disk/by-drive' provides symlinks for each disk related drive letter: 'x' -> '../../sdXN' The new directory '/dev/disk/by-voluuid' provides symlinks for each disk related storage volume: 'MBR_SERIAL-OFFSET' -> '../../sdXN' 'VOLUME_GUID' -> '../../sdXN' Both directories provide Windows specific information and do not exist on Linux. Signed-off-by: Christian Franke --- winsup/cygwin/fhandler/dev_disk.cc | 143 winsup/cygwin/local_includes/fhandler.h | 3 +- 2 files changed, 126 insertions(+), 20 deletions(-) diff --git a/winsup/cygwin/fhandler/dev_disk.cc b/winsup/cygwin/fhandler/dev_disk.cc index 11b24042f..5f79ab5e9 100644 --- a/winsup/cygwin/fhandler/dev_disk.cc +++ b/winsup/cygwin/fhandler/dev_disk.cc @@ -158,6 +158,92 @@ storprop_to_id_name (HANDLE devhdl, const UNICODE_STRING *upath, return 1; } +/* ("HarddiskN", PART_NUM) -> "?\\Volume{GUID}\\" */ +static bool +partition_to_volpath (const UNICODE_STRING *drive_uname, DWORD part_num, + WCHAR (& volpath)[MAX_PATH]) +{ + WCHAR gpath[MAX_PATH]; + __small_swprintf (gpath, L"?\\GLOBALROOT\\Device\\%S\\Partition%u\\", + drive_uname, part_num); + if (!GetVolumeNameForVolumeMountPointW (gpath, volpath, sizeof(volpath))) +{ + debug_printf ("GetVolumeNameForVolumeMountPointW(%W): %E", gpath); + return false; +} + debug_printf ("%W -> %W", gpath, volpath); + return true; +} + +/* ("HarddiskN", PART_NUM) -> "x" */ +static bool +partition_to_drive(const UNICODE_STRING *drive_uname, DWORD part_num, + WCHAR *w_buf, char *name) +{ + WCHAR volpath[MAX_PATH]; + if (!partition_to_volpath (drive_uname, part_num, volpath)) +return false; + + DWORD len; + if (!GetVolumePathNamesForVolumeNameW (volpath, w_buf, NT_MAX_PATH, )) +{ + debug_printf ("GetVolumePathNamesForVolumeNameW(%W): %E", volpath); + return false; +} + debug_printf ("%W -> '%W'%s", volpath, w_buf, + (w_buf[0] && wcschr (w_buf, L'\0')[1] ? ", ..." : "")); + + /* Find first "X:\\", skip if not found. + FIXME: Support multiple drive letters. */ + WCHAR *p; + for (p = w_buf; ; p = wcschr (p, L'\0') + 1) +{ + if (!*p) + return false; + if (L'A' <= p[0] && p[0] <= L'Z' && p[1] == L':' && p[2] == L'\\' && !p[3]) + break; +} + name[0] = (p[0] - L'A') + 'a'; + name[1] = '\0'; + return true; +} + +/* ("HarddiskN", PART_NUM) -> "VOLUME_GUID" */ +static bool +partition_to_voluuid(const UNICODE_STRING *drive_uname, DWORD part_num, +char *name) +{ + WCHAR volpath[MAX_PATH]; + if (!partition_to_volpath (drive_uname, part_num, volpath)) +return false; + + /* Skip if not "?\\Volume{GUID}...". */ + static const WCHAR prefix[] = L"?\\Volume{"; + const size_t prefix_len = sizeof (prefix) / sizeof(WCHAR) - 1, uuid_len = 36; + if (!(!wcsncmp (volpath, prefix, prefix_len) + && volpath[prefix_len + uuid_len] == L'}')) +return false; + + /* Extract GUID. */ + volpath[prefix_len + uuid_len] = 0; + __small_sprintf (name, "%W", volpath + prefix_len); + + if (!strncmp (name + 9, "--00", 12) && !strcmp (name + 32, "")) +{ + /* MBR "GUID": Use same SERIAL-OFFSET format as in by-partuuid directory. + SERIAL---009a-78563412 -> SERIAL-123456789a00 */ + for (int i = 9, j = 30; i < 19; i += 2, j -= 2) + { + if (j == 22) // name[j + 1] == '-' + j--; + name[i] = name[j]; + name[i + 1] = name[j + 1]; + } + name[21] = '\0'; +} + return true; +} + struct by_id_entry { char name[NAME_MAX + 1]; @@ -208,6 +294,7 @@ format_partuuid (char *name, const PARTITION_INFORMATION_EX *pix) guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6],
Re: [PATCH] Cygwin: Add /dev/disk/by-drive and /dev/disk/by-uuid symlinks
On Nov 16 12:50, Christian Franke wrote: > Corinna Vinschen wrote: > > Hi Christian, > > > > On Nov 15 18:23, Christian Franke wrote: > > > This is the next (and possibly last for now) extension to the /dev/disk > > > directory. Limited to disk related entries which allowed a straightforward > > > extension of the existing code. > > > > > > My original idea was to add also other drive letters and volume GUIDs. Too > > > complex for now. > > > > > > Interestingly the volume GUID (by-uuid) for partitions on MBR disks is > > > sometimes identical to the partition "GUID" (by-partuuid), sometimes > > > (always > > > for C:?) not. With GPT disks, both GUIDs are possibly always identical. > > That looks great, but in terms of by-uuid, I'm not sure it's the > > right thing to do. On Linux I have a vfat partition (/boot/efi). > > The uuid in /dev/disk/by-uuid is the volume serial number, just > > with an extra dash, i.e. > > > >057A-B3A7 -> ../../sda1 > > > > That's what you get for FAT/FAT32/exFAT. > > What is the best way to retrieve a FAT* serial? There is > GetVolumeInformation{ByHandleW}(), but this may not work with the NT Layer > pathnames / handles used here. It will work, because Windows and NT handles are the same thing as long as you created the handle using an operation opening kernel objects, as, for instance, files or volumes. Actually, GetVolumeInformation() is the combination of multiple NtQueryVolumeInformationFile calls. The call retrieving the serial number is NtQueryVolumeInformationFile(..., FileFsVolumeInformation), as is used in fs_info::update, mount.cc, line 250 ATM. > > I also tried an NTFS partition and the output looks like this: > > > >0FD4F62866CFBF09 -> ../../sdc1 > > > > This is the 64 bit volume serial number as returned by > > DeviceIoControl(FSCTL_GET_NTFS_VOLUME_DATA)(*). > > > > Wouldn't that be what we want to see, too? > > Hmm.. yes. Should both information be provided in by-uuid or only the > serial numbers? In the latter case, should we add e.g. by-voluuid for the > volume GUIDs ? Good question... by-voluuid sounds like a nice idea. It's a Windows-only concept anyway, so it might make sense to present it in its own directory. Corinna
Re: [PATCH] Cygwin: Add /dev/disk/by-drive and /dev/disk/by-uuid symlinks
Corinna Vinschen wrote: Hi Christian, On Nov 15 18:23, Christian Franke wrote: This is the next (and possibly last for now) extension to the /dev/disk directory. Limited to disk related entries which allowed a straightforward extension of the existing code. My original idea was to add also other drive letters and volume GUIDs. Too complex for now. Interestingly the volume GUID (by-uuid) for partitions on MBR disks is sometimes identical to the partition "GUID" (by-partuuid), sometimes (always for C:?) not. With GPT disks, both GUIDs are possibly always identical. That looks great, but in terms of by-uuid, I'm not sure it's the right thing to do. On Linux I have a vfat partition (/boot/efi). The uuid in /dev/disk/by-uuid is the volume serial number, just with an extra dash, i.e. 057A-B3A7 -> ../../sda1 That's what you get for FAT/FAT32/exFAT. What is the best way to retrieve a FAT* serial? There is GetVolumeInformation{ByHandleW}(), but this may not work with the NT Layer pathnames / handles used here. In Cygwin tree, GetVolumeInformation only appears in cygcheck.cc and very old ChangeLogs. I also tried an NTFS partition and the output looks like this: 0FD4F62866CFBF09 -> ../../sdc1 This is the 64 bit volume serial number as returned by DeviceIoControl(FSCTL_GET_NTFS_VOLUME_DATA)(*). Wouldn't that be what we want to see, too? Hmm.. yes. Should both information be provided in by-uuid or only the serial numbers? In the latter case, should we add e.g. by-voluuid for the volume GUIDs ? Christian
Re: [PATCH] Cygwin: Add /dev/disk/by-drive and /dev/disk/by-uuid symlinks
Hi Christian, On Nov 15 18:23, Christian Franke wrote: > This is the next (and possibly last for now) extension to the /dev/disk > directory. Limited to disk related entries which allowed a straightforward > extension of the existing code. > > My original idea was to add also other drive letters and volume GUIDs. Too > complex for now. > > Interestingly the volume GUID (by-uuid) for partitions on MBR disks is > sometimes identical to the partition "GUID" (by-partuuid), sometimes (always > for C:?) not. With GPT disks, both GUIDs are possibly always identical. That looks great, but in terms of by-uuid, I'm not sure it's the right thing to do. On Linux I have a vfat partition (/boot/efi). The uuid in /dev/disk/by-uuid is the volume serial number, just with an extra dash, i.e. 057A-B3A7 -> ../../sda1 That's what you get for FAT/FAT32/exFAT. I also tried an NTFS partition and the output looks like this: 0FD4F62866CFBF09 -> ../../sdc1 This is the 64 bit volume serial number as returned by DeviceIoControl(FSCTL_GET_NTFS_VOLUME_DATA)(*). Wouldn't that be what we want to see, too? Thanks, Corinna (*) Incidentally the last 8 digits represent the crippled 4 byte serial number returned by NtQueryVolumeInformationFile(..., FileFsVolumeInformation).
[PATCH] Cygwin: Add /dev/disk/by-drive and /dev/disk/by-uuid symlinks
This is the next (and possibly last for now) extension to the /dev/disk directory. Limited to disk related entries which allowed a straightforward extension of the existing code. My original idea was to add also other drive letters and volume GUIDs. Too complex for now. Interestingly the volume GUID (by-uuid) for partitions on MBR disks is sometimes identical to the partition "GUID" (by-partuuid), sometimes (always for C:?) not. With GPT disks, both GUIDs are possibly always identical. I will provide a related new-features doc patch later. -- Regards, Christian From 1dc3d3a8378ab2aeff766ea2d211750079fd27f8 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 15 Nov 2023 17:54:18 +0100 Subject: [PATCH] Cygwin: Add /dev/disk/by-drive and /dev/disk/by-uuid symlinks The new directory '/dev/disk/by-drive' provides symlinks for each disk related drive letter: 'x' -> '../../sdXN' The new directory '/dev/disk/by-uuid' provides symlinks for each disk related storage volume: 'MBR_SERIAL-OFFSET' -> '../../sdXN' 'VOLUME_GUID' -> '../../sdXN' Signed-off-by: Christian Franke --- winsup/cygwin/fhandler/dev_disk.cc | 143 winsup/cygwin/local_includes/fhandler.h | 3 +- 2 files changed, 126 insertions(+), 20 deletions(-) diff --git a/winsup/cygwin/fhandler/dev_disk.cc b/winsup/cygwin/fhandler/dev_disk.cc index 11b24042f..977e8a64f 100644 --- a/winsup/cygwin/fhandler/dev_disk.cc +++ b/winsup/cygwin/fhandler/dev_disk.cc @@ -158,6 +158,92 @@ storprop_to_id_name (HANDLE devhdl, const UNICODE_STRING *upath, return 1; } +/* ("HarddiskN", PART_NUM) -> "?\\Volume{GUID}\\" */ +static bool +partition_to_volpath (const UNICODE_STRING *drive_uname, DWORD part_num, + WCHAR (& volpath)[MAX_PATH]) +{ + WCHAR gpath[MAX_PATH]; + __small_swprintf (gpath, L"?\\GLOBALROOT\\Device\\%S\\Partition%u\\", + drive_uname, part_num); + if (!GetVolumeNameForVolumeMountPointW (gpath, volpath, sizeof(volpath))) +{ + debug_printf ("GetVolumeNameForVolumeMountPointW(%W): %E", gpath); + return false; +} + debug_printf ("%W -> %W", gpath, volpath); + return true; +} + +/* ("HarddiskN", PART_NUM) -> "x" */ +static bool +partition_to_drive(const UNICODE_STRING *drive_uname, DWORD part_num, + WCHAR *w_buf, char *name) +{ + WCHAR volpath[MAX_PATH]; + if (!partition_to_volpath (drive_uname, part_num, volpath)) +return false; + + DWORD len; + if (!GetVolumePathNamesForVolumeNameW (volpath, w_buf, NT_MAX_PATH, )) +{ + debug_printf ("GetVolumePathNamesForVolumeNameW(%W): %E", volpath); + return false; +} + debug_printf ("%W -> '%W'%s", volpath, w_buf, + (w_buf[0] && wcschr (w_buf, L'\0')[1] ? ", ..." : "")); + + /* Find first "X:\\", skip if not found. + FIXME: Support multiple drive letters. */ + WCHAR *p; + for (p = w_buf; ; p = wcschr (p, L'\0') + 1) +{ + if (!*p) + return false; + if (L'A' <= p[0] && p[0] <= L'Z' && p[1] == L':' && p[2] == L'\\' && !p[3]) + break; +} + name[0] = (p[0] - L'A') + 'a'; + name[1] = '\0'; + return true; +} + +/* ("HarddiskN", PART_NUM) -> "VOLUME_GUID" */ +static bool +partition_to_voluuid(const UNICODE_STRING *drive_uname, DWORD part_num, +char *name) +{ + WCHAR volpath[MAX_PATH]; + if (!partition_to_volpath (drive_uname, part_num, volpath)) +return false; + + /* Skip if not "?\\Volume{GUID}...". */ + static const WCHAR prefix[] = L"?\\Volume{"; + const size_t prefix_len = sizeof (prefix) / sizeof(WCHAR) - 1, uuid_len = 36; + if (!(!wcsncmp (volpath, prefix, prefix_len) + && volpath[prefix_len + uuid_len] == L'}')) +return false; + + /* Extract GUID. */ + volpath[prefix_len + uuid_len] = 0; + __small_sprintf (name, "%W", volpath + prefix_len); + + if (!strncmp (name + 9, "--00", 12) && !strcmp (name + 32, "")) +{ + /* MBR "GUID": Use same SERIAL-OFFSET format as in by-partuuid directory. + SERIAL---009a-78563412 -> SERIAL-123456789a00 */ + for (int i = 9, j = 30; i < 19; i += 2, j -= 2) + { + if (j == 22) // name[j + 1] == '-' + j--; + name[i] = name[j]; + name[i + 1] = name[j + 1]; + } + name[21] = '\0'; +} + return true; +} + struct by_id_entry { char name[NAME_MAX + 1]; @@ -208,6 +294,7 @@ format_partuuid (char *name, const PARTITION_INFORMATION_EX *pix) guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + return true; } @@ -237,6 +324,7 @@ get_by_id_table (by_id_entry * , fhandler_dev_disk::dev_disk_location loc) unsigned alloc_size = 0, table_size = 0; tmp_pathbuf tp; char *ioctl_buf = tp.c_get (); + WCHAR *w_buf = tp.w_get ();