Re: [PATCH] Cygwin: Add /dev/disk/by-drive and /dev/disk/by-uuid symlinks

2023-11-17 Thread Corinna Vinschen
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

2023-11-16 Thread Christian Franke

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

2023-11-16 Thread Corinna Vinschen
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

2023-11-16 Thread Christian Franke

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

2023-11-16 Thread Corinna Vinschen
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

2023-11-15 Thread Christian Franke
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 ();