Allows programs to query if disk has a seek penalty.
Signed-off-by: David Koolhoven david@koolhoven-home.net --- v3: Linux side/sysfs logic is contained file. --- dlls/mountmgr.sys/Makefile.in | 1 + dlls/mountmgr.sys/device.c | 24 +++ dlls/mountmgr.sys/unix/device_seek_penalty.c | 145 +++++++++++++++++++ include/ntddstor.h | 9 +- 4 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 dlls/mountmgr.sys/unix/device_seek_penalty.c
diff --git a/dlls/mountmgr.sys/Makefile.in b/dlls/mountmgr.sys/Makefile.in index 83204e66504..61b462ddd7b 100644 --- a/dlls/mountmgr.sys/Makefile.in +++ b/dlls/mountmgr.sys/Makefile.in @@ -7,6 +7,7 @@ EXTRALIBS = $(DISKARBITRATION_LIBS) $(SYSTEMCONFIGURATION_LIBS) $(CORESERVICES_L
C_SRCS = \ dbus.c \ + unix/device_seek_penalty.c \ device.c \ diskarb.c \ mountmgr.c diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c index 04e8fe3c0f5..90c73b13139 100644 --- a/dlls/mountmgr.sys/device.c +++ b/dlls/mountmgr.sys/device.c @@ -1894,6 +1894,30 @@ static NTSTATUS query_property( struct disk_device *device, IRP *irp )
break; } + case StorageDeviceSeekPenaltyProperty: + { + DEVICE_SEEK_PENALTY_DESCRIPTOR *descriptor; + int ret; + + memset( irp->AssociatedIrp.SystemBuffer, 0, irpsp->Parameters.DeviceIoControl.OutputBufferLength ); + descriptor = irp->AssociatedIrp.SystemBuffer; + descriptor->Version = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR); + descriptor->Size = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR); + irp->IoStatus.Information = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR); + + ret = device_seek_penalty(device->unix_mount); + if (ret < 0) { + FIXME( "Unsupported property StorageDeviceSeekPenalty\n" ); + status = STATUS_NOT_SUPPORTED; + } else if (ret == 0) { + descriptor->IncursSeekPenalty = FALSE; + status = STATUS_SUCCESS; + } else if (ret == 1) { + descriptor->IncursSeekPenalty = TRUE; + status = STATUS_SUCCESS; + } + break; + } default: FIXME( "Unsupported property %#x\n", query->PropertyId ); status = STATUS_NOT_SUPPORTED; diff --git a/dlls/mountmgr.sys/unix/device_seek_penalty.c b/dlls/mountmgr.sys/unix/device_seek_penalty.c new file mode 100644 index 00000000000..eefb4d67e65 --- /dev/null +++ b/dlls/mountmgr.sys/unix/device_seek_penalty.c @@ -0,0 +1,145 @@ +/* + * System information APIs + * + * Copyright 1996-1998 Marcus Meissner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#ifdef linux +#include <assert.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> + +#define NONAMELESSUNION +#include "ntstatus.h" +#include "mountmgr.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" +#endif +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mountmgr); + +int device_seek_penalty (char *unix_mount) +{ +#ifdef linux + FILE *fp; + char isrotapathstr[260]; + char evpath[260]; + char ueventbufstr[260]; + char isrotastrbuf[2]; + char *fgetsret = NULL; + int ret = 0; + char *rptr = NULL; + char *sptr = NULL; + char *devstr_edited = NULL; + char mountpath[260]; + char *part_dev = NULL; + int c = 0; + struct stat statbuf; + int seekpen; + + const char *home = getenv( "HOME" ); + const char *prefix = getenv( "WINEPREFIX" ); + size_t len = (prefix ? strlen(prefix) : strlen(home) + strlen("/.wine")) + sizeof("/dosdevices/com256"); + char *path = HeapAlloc( GetProcessHeap(), 0, len ); + + if (path) + { + if (prefix) strcpy( path, prefix ); + else + { + strcpy( path, home ); + strcat( path, "/.wine" ); + } + strcat( path, "/dosdevices/" ); + } + + if (!unix_mount) { + return -1; + } + + snprintf (mountpath, 260, "%s%s", path, unix_mount); + ret = stat (mountpath, &statbuf); + if (ret == -1) { + return -1; + } + HeapFree( GetProcessHeap(), 0, path ); + sprintf (evpath, "/sys/dev/block/%d:%d/uevent", major(statbuf.st_dev), minor(statbuf.st_dev)); + fp = fopen(evpath, "r"); + if (!fp) { + return -1; + } + while ((rptr = fgets (ueventbufstr, 260, fp))) { + sptr = strstr (rptr, "DEVNAME="); + if (sptr) { + sptr += strlen ("DEVNAME="); + break; + } + } + fclose (fp); + devstr_edited = sptr; + if (!devstr_edited) { + return -1; + } + /* Find first character after forwardslash '/' */ + part_dev = strrchr (devstr_edited, '/'); + if (!part_dev || (part_dev == devstr_edited)) part_dev = devstr_edited; + else part_dev++; + /* Trim off trailing digits and whitespace */ + c = strlen (devstr_edited); + c--; + while ((devstr_edited[c] >= '0' && devstr_edited[c] <= '9') + || (devstr_edited[c] == '\n' || devstr_edited[c] == '\r')) + devstr_edited[c--] = '\0'; + + ret = snprintf (isrotapathstr, 260, "/sys/block/%s/queue/rotational", part_dev); + if (ret < 1 || ret == 260) { + return -1; + } + + fp = fopen(isrotapathstr, "r"); + if (!fp) { + return -1; + } + + fgetsret = fgets(isrotastrbuf, 2, fp); + if (!fgetsret) { + return -1; + } + + fclose (fp); + + if (isrotastrbuf[0] == '1') { + seekpen = 1; + } else if (isrotastrbuf[0] == '0') { + seekpen = 0; + } else { + return -1; + } + + return seekpen; +#else + return -1; +#endif +} diff --git a/include/ntddstor.h b/include/ntddstor.h index b8c4bb73b0d..836def413fe 100644 --- a/include/ntddstor.h +++ b/include/ntddstor.h @@ -214,7 +214,8 @@ typedef enum _STORAGE_QUERY_TYPE {
typedef enum _STORAGE_PROPERTY_ID { StorageDeviceProperty = 0, - StorageAdapterProperty + StorageAdapterProperty = 1, + StorageDeviceSeekPenaltyProperty = 7, } STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
typedef struct _STORAGE_PROPERTY_QUERY { @@ -272,6 +273,12 @@ typedef struct _STORAGE_ADAPTER_DESCRIPTOR { USHORT BusMinorVersion; } STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR;
+typedef struct _DEVICE_SEEK_PENALTY_DESCRIPTOR { + ULONG Version; + ULONG Size; + BOOLEAN IncursSeekPenalty; +} DEVICE_SEEK_PENALTY_DESCRIPTOR, *PDEVICE_SEEK_PENALTY_DESCRIPTOR; + #ifdef __cplusplus } #endif