Corinna Vinschen wrote:
On Nov 3 12:10, Corinna Vinschen wrote:
On Nov 3 11:09, Corinna Vinschen wrote:
On Nov 3 10:55, Corinna Vinschen wrote:
On Oct 3 14:39, Christian Franke wrote:
According to NtQueryObject(., ObjectBasicInformation, ...), using
NtOpenFile(., MAXIMUM_ALLOWED, ...) without admin rights sets GrantedAccess
to 0x001200a0 (FILE_EXECUTE|FILE_READ_ATTRIBUTES|READ_CONTROL|SYNCHRONIZE).
For some unknown reason, NVMe drives behind stornvme.sys additionally
require SYNCHRONIZE to use IOCTL_STORAGE_QUERY_PROPERTY. Possibly a harmless
bug in the access check somewhere in the NVMe stack.
The disk scanning from the first patch has been reworked based on code
borrowed from proc.cc:format_proc_partitions(). For the longer term, it may
make sense to provide one flexible scanning function for /dev/sdXN,
/proc/partitions and /proc/disk/by-id.
I applied your patch locally (patch looks pretty well, btw) but found
that /dev/disk/by-id is empty, even when running with admin rights.
I ran this on Windows 11 and Windows 2K19 in a QEMU/KVM VM. A
\Device\Harddisk0\Partition0 symlink pointing to \Device\Harddisk0\DR0
exists in both cases. I straced it, and found the following debug
output:
1015 1155432 [main] ls 361 stordesc_to_id_name: Harddisk0\Partition0:
'Red_Hat' 'VirtIO' '' (ignored)
Is that really desired?
We could fake a serial number dependent on the path. See
https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=winsup/cygwin/mount.cc;hb=main#l253
Alternatively, there's also a symlink in GLOBAL?? pointing
to the same target as \Device\Harddisk0\Partition0, i. e.:
\Device\Harddisk0\Partition0 -> \Device\Harddisk0\DR0
and
\GLOBAL??\Disk{4c622943-27e4-e81d-3fc7-c43fc9c7e126} -> \Device\Harddisk0\DR0
We could use that UUID from that path, but that's quite a hassle
to grab, because it requires to enumerate GLOBAL??.
But then again, where does Windows get the UUID from? Something to
find out...
I haven't found out where the UUID is coming from, yet, but based on the
description from
https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/device-unique-identifiers--duids--for-storage-devices
I came up with this Q&D solution:
=============== SNIP ================
diff --git a/winsup/cygwin/fhandler/dev_disk.cc
b/winsup/cygwin/fhandler/dev_disk.cc
index caca57d63216..74abfb8a3288 100644
--- a/winsup/cygwin/fhandler/dev_disk.cc
+++ b/winsup/cygwin/fhandler/dev_disk.cc
@@ -36,29 +36,51 @@ sanitize_id_string (char *s)
return i;
}
+typedef struct _STORAGE_DEVICE_UNIQUE_IDENTIFIER {
+ ULONG Version;
+ ULONG Size;
+ ULONG StorageDeviceIdOffset;
+ ULONG StorageDeviceOffset;
+ ULONG DriveLayoutSignatureOffset;
+} STORAGE_DEVICE_UNIQUE_IDENTIFIER, *PSTORAGE_DEVICE_UNIQUE_IDENTIFIER;
+
+typedef struct _STORAGE_DEVICE_LAYOUT_SIGNATURE {
+ ULONG Version;
+ ULONG Size;
+ BOOLEAN Mbr;
+ union {
+ ULONG MbrSignature;
+ GUID GptDiskId;
+ } DeviceSpecific;
+} STORAGE_DEVICE_LAYOUT_SIGNATURE, *PSTORAGE_DEVICE_LAYOUT_SIGNATURE;
+
These are available in storduid.h
/* Get ID string from STORAGE_DEVICE_DESCRIPTIOR. */
static bool
stordesc_to_id_name (const UNICODE_STRING *upath, char *ioctl_buf,
char (& name)[NAME_MAX + 1])
{
+ const STORAGE_DEVICE_UNIQUE_IDENTIFIER *id =
+ reinterpret_cast<const STORAGE_DEVICE_UNIQUE_IDENTIFIER *>(ioctl_buf);
+ char *desc_buf = ioctl_buf + id->StorageDeviceOffset;
const STORAGE_DEVICE_DESCRIPTOR *desc =
[...]
strcat (name, "_");
- strcat (name, ioctl_buf + desc->SerialNumberOffset);
+ if (1) /* Utilize the DUID as defined by MSDN */
+ {
+ unsigned long hash = 0;
+
+ for (ULONG i = 0; i < id->Size; ++i)
+ hash = ioctl_buf[i] + (hash << 6) + (hash << 16) - hash;
+ __small_sprintf (name + strlen (name), "%X", hash);
+ }
+ else
+ strcat (name, desc_buf + desc->SerialNumberOffset);
return true;
}
@@ -212,7 +243,7 @@ get_by_id_table (by_id_entry * &table)
/* Fetch vendor, product and serial number. */
DWORD bytes_read;
STORAGE_PROPERTY_QUERY query =
- { StorageDeviceProperty, PropertyStandardQuery, { 0 } };
+ { StorageDeviceUniqueIdProperty, PropertyStandardQuery, { 0 } };
if (!DeviceIoControl (devhdl, IOCTL_STORAGE_QUERY_PROPERTY,
&query, sizeof (query),
ioctl_buf, NT_MAX_PATH,
=============== SNAP ================
Thanks. Using this makes plenty of sense as a fallback if the serial
number is unavailable. But if available, the serial number should be in
the generated name as on Linux. This would provide a persistent name
which reflects the actual device without a number invented by MS.
The serial number is usually available with (S)ATA and NVMe (namespace
uuid in the latter case). I'm not familiar with QEMU/KVM details. The
fact that both 'vendor' and 'product' are returned on your system
suggests that a SCSI/SAS controller is emulated. Unlike (S)ATA and NVMe,
the serial number is not available for free in the device identify data
block but requires an extra command (SCSI INQUIRY of VPD page 0x80).
This might not be supported by the emulated controller or Windows does
not use this command.
IIRC the serial number is sometimes available via WMI even if missing in
IOCTL_STORAGE_QUERY_PROPERTY:
wmic diskdrive get manufacturer,model,serialnumber
And, btw, rather than using strcpy/strcat, can you please utilize
stpcpy? You just have to keep the pointer around and you can
concat w/o always having to go over the full length of the string.
Of course.
Christian