IDE disk geometry

Michael Ost most at museresearch.com
Tue Sep 20 19:11:49 CDT 2005


Any suggestions for a good "wineish" way to implement an IOCTL_ call for
an IDE disk?
 
My winelib app is hosting a Windows DLL that is making an
IOCTL_DISK_DRIVE_GET_GEOMETRY call on an IDE hard disk. ntdll/file.c
NtDeviceIoControlFile is passing this off to ntdll/cdrom.c
CDROM_DeviceIoControl and, of course, since it is not a cdrom disk, that
fails.

I have some code that reads geometry information out of
/proc/ide/hd?/geometry that is working fine. But I am not sure how to
integrate it into ntdll. 

Should I put my code in CDROM_DeviceIoControl? Or handle it in
NtDeviceIoControlFile? Should I pass all other IoControlCodes except
IOCTL_DISK_DRIVE_GET_GEOMETRY for a verifiable IDE drive on to the
CDROM_... function?

If anyone has a background in this code, you probably have an idea
straight off how best to fit it in.

Thanks for any help. Patch against wine-20050419 is attached for
illustrative purposes. ... mo

-------------- next part --------------
--- dlls/ntdll/file.c.20050419	2005-09-20 09:49:54.000000000 -0700
+++ dlls/ntdll/file.c	2005-09-20 17:10:17.000000000 -0700
@@ -790,6 +790,113 @@
     return io_status->u.Status;
 }
 
+/***********************************************************************
+ *             FILE_IdeDeviceIoControlFile      (INTERNAL)
+ *
+ *  Handle device IO control for ide disks. Returns TRUE if
+ *  DeviceHandle is an IDE disk, else FALSE. 
+ */
+static BOOL FILE_IdeDeviceIoControlFile(HANDLE DeviceHandle, HANDLE hEvent,
+                                        PIO_APC_ROUTINE UserApcRoutine, 
+                                        PVOID UserApcContext,
+                                        PIO_STATUS_BLOCK IoStatusBlock,
+                                        ULONG IoControlCode,
+                                        PVOID InputBuffer,
+                                        ULONG InputBufferSize,
+                                        PVOID OutputBuffer,
+                                        ULONG OutputBufferSize)
+{
+#if !linux
+	return FALSE;
+#else
+	BOOL releaseFd = FALSE;
+	BOOL isIde = FALSE;
+	NTSTATUS status = STATUS_SUCCESS;
+	DWORD sz = 0;
+
+	int fd;
+	FILE* file;
+	int length;
+	char linkPath[64];
+	char path[MAX_PATH];
+ 	char letter;
+	struct stat st;
+ 
+	if ((status = wine_server_handle_to_fd( DeviceHandle, 0, &fd, NULL )) != STATUS_SUCCESS)
+		goto out;
+	releaseFd = TRUE;
+
+	// does the file descriptor point to an entry in /proc/ide?
+	// todo - isn't there a system call to get a name from a dev_t and ino_t?
+	snprintf(linkPath, sizeof(linkPath), "/proc/%d/fd/%d", getpid(), fd);
+	length = readlink(linkPath, path, sizeof(path));
+	if (length != -1)
+		path[length] = '\0';
+	else {
+		// bad proc format? 
+		goto out;
+	}
+
+	// see if the device exists in /proc/ide
+puts(path); //todo
+	if (sscanf(path, "/dev/hd%c", &letter) != 1)
+		goto out;
+	snprintf(path, sizeof(path), "/proc/ide/hd%c", letter);
+	if (stat(path, &st) == -1)
+		goto out;
+	isIde = TRUE;
+
+    IoStatusBlock->Information = 0;
+	switch (IoControlCode)
+	{
+	case IOCTL_DISK_GET_DRIVE_GEOMETRY:
+		strcat(path, "/geometry");
+
+		if (OutputBuffer == 0)
+			IoStatusBlock->u.Status = STATUS_INVALID_PARAMETER;
+		else if (OutputBufferSize < sizeof(DISK_GEOMETRY))
+			IoStatusBlock->u.Status = STATUS_BUFFER_TOO_SMALL;
+		else if ((file = fopen(path, "r")) != 0) {
+			int cylinders, heads, sectors;
+			if (fscanf(file, "physical %d/%d/%d", &cylinders, &heads, &sectors) == 3) {
+				DISK_GEOMETRY* geometry = (DISK_GEOMETRY*) OutputBuffer;
+				geometry->Cylinders.QuadPart = cylinders;
+				geometry->MediaType = FixedMedia;
+				geometry->TracksPerCylinder = heads;
+				geometry->SectorsPerTrack = sectors;
+				// todo - is this always 512, or where is it?
+				geometry->BytesPerSector = 512;
+
+				sz = sizeof(DISK_GEOMETRY);
+		        IoStatusBlock->u.Status = STATUS_SUCCESS;
+			}
+			else // unknown proc format
+				IoStatusBlock->u.Status = STATUS_INVALID_PARAMETER;
+
+			fclose(file);
+		}
+		else // unknown proc format
+			IoStatusBlock->u.Status = STATUS_INVALID_PARAMETER;
+		break;
+
+    default:
+        FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n", 
+              IoControlCode, IoControlCode >> 16, (IoControlCode >> 14) & 3,
+              (IoControlCode >> 2) & 0xFFF, IoControlCode & 3);
+        IoStatusBlock->u.Status = STATUS_INVALID_PARAMETER;
+        break;
+    }
+
+out:
+	if (releaseFd)
+	    wine_server_release_fd( DeviceHandle, fd );
+	if (isIde && hEvent) 
+   		NtSetEvent(hEvent, NULL);
+
+    return isIde;
+#endif
+}
+
 /**************************************************************************
  *		NtDeviceIoControlFile			[NTDLL.@]
  *		ZwDeviceIoControlFile			[NTDLL.@]
@@ -827,6 +934,12 @@
           IoStatusBlock, IoControlCode, 
           InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize);
 
+	if (FILE_IdeDeviceIoControlFile(DeviceHandle, hEvent, UserApcRoutine, UserApcContext,
+			IoStatusBlock, IoControlCode, InputBuffer, InputBufferSize,
+			OutputBuffer, OutputBufferSize)) {
+		return IoStatusBlock->u.Status;
+	}
+
     if (CDROM_DeviceIoControl(DeviceHandle, hEvent,
                               UserApcRoutine, UserApcContext,
                               IoStatusBlock, IoControlCode,
@@ -1878,3 +1991,4 @@
  
     return ret;
 }
+


More information about the wine-devel mailing list