winedos / Migrate drive parameter block stuff to winedos

Jukka Heinonen jhei at iki.fi
Sun Oct 26 03:54:19 CST 2003


This patch moves some int21 code into winedos.
DPB handling seemed to be pretty broken earlier,
especially in the case of DOS7 functions. It is
likely DPB handling is still somewhat broken, but
hopefully not as much.




Changelog:
  Move drive parameter block (DPB) routines to winedos.




Index: dlls/winedos/int21.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int21.c,v
retrieving revision 1.43
diff -u -r1.43 int21.c
--- dlls/winedos/int21.c	16 Oct 2003 19:12:49 -0000	1.43
+++ dlls/winedos/int21.c	26 Oct 2003 09:46:52 -0000
@@ -59,6 +59,42 @@
 #include "pshpack1.h"
 
 /*
+ * Extended Drive Parameter Block.
+ * This structure is compatible with standard DOS4+ DPB and 
+ * extended DOS7 DPB.
+ */
+typedef struct _INT21_DPB {
+    BYTE   drive;                /* 00 drive number (0=A, ...) */
+    BYTE   unit;                 /* 01 unit number within device driver */
+    WORD   sector_bytes;         /* 02 bytes per sector */
+    BYTE   cluster_sectors;      /* 04 highest sector number within a cluster */
+    BYTE   shift;                /* 05 shift count to convert clusters into sectors */
+    WORD   num_reserved;         /* 06 reserved sectors at beginning of drive */
+    BYTE   num_FAT;              /* 08 number of FATs */
+    WORD   num_root_entries;     /* 09 number of root directory entries */
+    WORD   first_data_sector;    /* 0b number of first sector containing user data */
+    WORD   num_clusters1;        /* 0d highest cluster number (number of data clusters + 1) */
+    WORD   sectors_per_FAT;      /* 0f number of sectors per FAT */
+    WORD   first_dir_sector;     /* 11 sector number of first directory sector */
+    SEGPTR driver_header;        /* 13 address of device driver header */
+    BYTE   media_ID;             /* 17 media ID byte */
+    BYTE   access_flag;          /* 18 0x00 if disk accessed, 0xff if not */
+    SEGPTR next;                 /* 19 pointer to next DPB */
+    WORD   search_cluster1;      /* 1d cluster at which to start search for free space */
+    WORD   free_clusters_lo;     /* 1f number of free clusters on drive or 0xffff if unknown */
+    WORD   free_clusters_hi;     /* 21 hiword of clusters_free */
+    WORD   mirroring_flags;      /* 23 active FAT/mirroring flags */
+    WORD   info_sector;          /* 25 sector number of file system info sector or 0xffff for none */
+    WORD   spare_boot_sector;    /* 27 sector number of backup boot sector or 0xffff for none */
+    DWORD  first_cluster_sector; /* 29 sector number of the first cluster */
+    DWORD  num_clusters2;        /* 2d maximum cluster number */
+    DWORD  fat_clusters;         /* 31 number of clusters occupied by FAT */
+    DWORD  root_cluster;         /* 35 cluster number of start of root directory */
+    DWORD  search_cluster2;      /* 39 cluster at which to start searching for free space */
+} INT21_DPB;
+
+
+/*
  * Structure for DOS data that can be accessed directly from applications.
  * Real and protected mode pointers will be returned to this structure so
  * the structure must be correctly packed.
@@ -87,7 +123,11 @@
     WORD dbcs_size;                  /* Number of valid ranges in the following table */
     BYTE dbcs_table[16];             /* Start/end bytes for N ranges and 00/00 as terminator */
 
-    BYTE misc_indos;                 /* Interrupt 21 nesting flag */
+    BYTE      misc_indos;                    /* Interrupt 21 nesting flag */
+    WORD      misc_segment;                  /* Real mode segment for INT21_HEAP */
+    WORD      misc_selector;                 /* Protected mode selector for INT21_HEAP */
+    INT21_DPB misc_dpb_list[MAX_DOS_DRIVES]; /* Drive parameter blocks for all drives */
+
 } INT21_HEAP;
 
 
@@ -353,6 +393,39 @@
      * Initialize InDos flag.
      */
     heap->misc_indos = 0;
+
+    /*
+     * FIXME: Should drive parameter blocks (DPB) be
+     *        initialized here and linked to DOS LOL?
+     */
+}
+
+
+/***********************************************************************
+ *           INT21_GetHeapPointer
+ *
+ * Get pointer for DOS heap (INT21_HEAP).
+ * Creates and initializes heap on first call.
+ */
+static INT21_HEAP *INT21_GetHeapPointer( void )
+{
+    static INT21_HEAP *heap_pointer = NULL;
+
+    if (!heap_pointer)
+    {
+        WORD heap_segment;
+        WORD heap_selector;
+
+        heap_pointer = DOSVM_AllocDataUMB( sizeof(INT21_HEAP), 
+                                           &heap_segment,
+                                           &heap_selector );
+
+        heap_pointer->misc_segment  = heap_segment;
+        heap_pointer->misc_selector = heap_selector;
+        INT21_FillHeap( heap_pointer );
+    }
+
+    return heap_pointer;
 }
 
 
@@ -364,23 +437,94 @@
  */
 static WORD INT21_GetHeapSelector( CONTEXT86 *context )
 {
-    static WORD heap_segment = 0;
-    static WORD heap_selector = 0;
-    static BOOL heap_initialized = FALSE;
-
-    if (!heap_initialized)
-    {
-        INT21_HEAP *ptr = DOSVM_AllocDataUMB( sizeof(INT21_HEAP), 
-                                              &heap_segment,
-                                              &heap_selector );
-        INT21_FillHeap( ptr );
-        heap_initialized = TRUE;
-    }
+    INT21_HEAP *heap = INT21_GetHeapPointer();
 
     if (!ISV86(context) && DOSVM_IsWin16())
-        return heap_selector;
+        return heap->misc_selector;
     else
-        return heap_segment;
+        return heap->misc_segment;
+}
+
+
+/***********************************************************************
+ *           INT21_FillDrivePB
+ *
+ * Fill DOS heap drive parameter block for the specified drive.
+ * Return TRUE if drive was valid and there were
+ * no errors while reading drive information.
+ */
+static BOOL INT21_FillDrivePB( BYTE drive )
+{
+    WCHAR       drivespec[3] = {'A', ':', 0};
+    INT21_HEAP *heap = INT21_GetHeapPointer();
+    INT21_DPB  *dpb;
+    UINT        drivetype;
+    DWORD       cluster_sectors;
+    DWORD       sector_bytes;
+    DWORD       free_clusters;
+    DWORD       total_clusters;
+
+    if (drive >= MAX_DOS_DRIVES)
+        return FALSE;
+
+    dpb = &heap->misc_dpb_list[drive];
+    drivespec[0] += drive;
+    drivetype = GetDriveTypeW( drivespec );
+
+    /*
+     * FIXME: Does this check work correctly with floppy/cdrom drives?
+     */
+    if (drivetype == DRIVE_NO_ROOT_DIR || drivetype == DRIVE_UNKNOWN)
+        return FALSE;
+
+    /*
+     * FIXME: Does this check work correctly with floppy/cdrom drives?
+     */
+    if (!GetDiskFreeSpaceW( drivespec, &cluster_sectors, &sector_bytes,
+                            &free_clusters, &total_clusters ))
+        return FALSE;
+
+    /*
+     * FIXME: Most of the values listed below are incorrect.
+     *        All values should be validated.
+     */
+ 
+    dpb->drive           = drive;
+    dpb->unit            = 0;
+    dpb->sector_bytes    = sector_bytes;
+    dpb->cluster_sectors = cluster_sectors - 1;
+
+    dpb->shift = 0;
+    while (cluster_sectors > 1)
+    {
+        cluster_sectors /= 2;
+        dpb->shift++;
+    }
+
+    dpb->num_reserved         = 0;
+    dpb->num_FAT              = 1;
+    dpb->num_root_entries     = 2;
+    dpb->first_data_sector    = 2;
+    dpb->num_clusters1        = total_clusters;
+    dpb->sectors_per_FAT      = 1;
+    dpb->first_dir_sector     = 1;
+    dpb->driver_header        = 0;
+    dpb->media_ID             = (drivetype == DRIVE_FIXED) ? 0xF8 : 0xF0;
+    dpb->access_flag          = 0;
+    dpb->next                 = 0;
+    dpb->search_cluster1      = 0;
+    dpb->free_clusters_lo     = LOWORD(free_clusters);
+    dpb->free_clusters_hi     = HIWORD(free_clusters);
+    dpb->mirroring_flags      = 0;
+    dpb->info_sector          = 0xffff;
+    dpb->spare_boot_sector    = 0xffff;
+    dpb->first_cluster_sector = 0;
+    dpb->num_clusters2        = total_clusters;
+    dpb->fat_clusters         = 32;
+    dpb->root_cluster         = 0;
+    dpb->search_cluster2      = 0;
+
+    return TRUE;
 }
 
 
@@ -2283,6 +2427,62 @@
 
 
 /***********************************************************************
+ *           INT21_Fat32
+ *
+ * Handler for function 0x73.
+ */
+static BOOL INT21_Fat32( CONTEXT86 *context )
+{
+    switch (AL_reg(context))
+    {
+    case 0x02: /* FAT32 - GET EXTENDED DPB */
+        {
+            BYTE drive = INT21_MapDrive( DL_reg(context) );
+            WORD *ptr = CTX_SEG_OFF_TO_LIN(context, 
+                                           context->SegEs, context->Edi);
+            INT21_DPB *target = (INT21_DPB*)(ptr + 1);
+            INT21_DPB *source;
+
+            TRACE( "FAT32 - GET EXTENDED DPB %d\n", DL_reg(context) );
+
+            if ( CX_reg(context) < sizeof(INT21_DPB) + 2 || *ptr < sizeof(INT21_PDB) )
+            {
+                SetLastError( ERROR_BAD_LENGTH );
+                return FALSE;
+            }
+
+            if ( !INT21_FillDrivePB( drive ) )
+            {
+                SetLastError( ERROR_INVALID_DRIVE );
+                return FALSE;
+            }
+
+            source = &INT21_GetHeapPointer()->misc_dpb_list[drive];
+
+            *ptr = sizeof(INT21_DPB);
+            memcpy( target, source, sizeof(INT21_DPB));
+
+            if (LOWORD(context->Esi) != 0xF1A6)
+            {
+                target->driver_header = 0;
+                target->next          = 0;
+            }
+            else
+            {
+                FIXME( "Caller requested driver and next DPB pointers!\n" );
+            }
+        }
+        break;
+
+    default:
+        INT_BARF( context, 0x21 );
+    }
+
+    return TRUE;
+}
+
+
+/***********************************************************************
  *           INT21_LongFilename
  *
  * Handler for function 0x71.
@@ -2862,7 +3062,21 @@
         break;
 
     case 0x1f: /* GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE */
-        INT_Int21Handler( context );
+        {
+            BYTE drive = INT21_MapDrive( 0 ); 
+            TRACE( "GET DPB FOR DEFAULT DRIVE\n" );
+
+            if (INT21_FillDrivePB( drive ))
+            {
+                SET_AL( context, 0x00 ); /* success */
+                SET_BX( context, offsetof( INT21_HEAP, misc_dpb_list[drive] ) );
+                context->SegDs = INT21_GetHeapSelector( context );
+            }
+            else
+            {
+                SET_AL( context, 0xff ); /* invalid or network drive */
+            }
+        }
         break;
 
     case 0x20: /* NULL FUNCTION FOR CP/M COMPATIBILITY */
@@ -3008,7 +3222,21 @@
         break;
 
     case 0x32: /* GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE */
-        INT_Int21Handler( context );
+        {
+            BYTE drive = INT21_MapDrive( DL_reg(context) );           
+            TRACE( "GET DPB FOR SPECIFIC DRIVE %d\n", DL_reg(context) );
+
+            if (INT21_FillDrivePB( drive ))
+            {
+                SET_AL( context, 0x00 ); /* success */
+                SET_DX( context, offsetof( INT21_HEAP, misc_dpb_list[drive] ) );
+                context->SegDs = INT21_GetHeapSelector( context );
+            }
+            else
+            {
+                SET_AL( context, 0xff ); /* invalid or network drive */
+            }
+        }
         break;
 
     case 0x33: /* MULTIPLEXED */
@@ -3695,7 +3923,8 @@
         break;
 
     case 0x73: /* MSDOS7 - FAT32 */
-        INT_Int21Handler( context );
+        if (!INT21_Fat32( context ))
+            bSetDOSExtendedError = TRUE;
         break;
 
     case 0xdc: /* CONNECTION SERVICES - GET CONNECTION NUMBER */




Index: msdos/int21.c
===================================================================
RCS file: /home/wine/wine/msdos/int21.c,v
retrieving revision 1.99
diff -u -r1.99 int21.c
--- msdos/int21.c	22 Sep 2003 21:18:11 -0000	1.99
+++ msdos/int21.c	26 Oct 2003 09:46:58 -0000
@@ -73,62 +73,9 @@
 
 #define DOS_GET_DRIVE(reg) ((reg) ? (reg) - 1 : DRIVE_GetCurrentDrive())
 
-/* Define the drive parameter block, as used by int21/1F
- * and int21/32.  This table can be accessed through the
- * global 'dpb' pointer, which points into the local dos
- * heap.
- */
-struct DPB
-{
-    BYTE drive_num;         /* 0=A, etc. */
-    BYTE unit_num;          /* Drive's unit number (?) */
-    WORD sector_size;       /* Sector size in bytes */
-    BYTE high_sector;       /* Highest sector in a cluster */
-    BYTE shift;             /* Shift count (?) */
-    WORD reserved;          /* Number of reserved sectors at start */
-    BYTE num_FAT;           /* Number of FATs */
-    WORD dir_entries;       /* Number of root dir entries */
-    WORD first_data;        /* First data sector */
-    WORD high_cluster;      /* Highest cluster number */
-    WORD sectors_in_FAT;    /* Number of sectors per FAT */
-    WORD start_dir;         /* Starting sector of first dir */
-    DWORD driver_head;      /* Address of device driver header (?) */
-    BYTE media_ID;          /* Media ID */
-    BYTE access_flag;       /* Prev. accessed flag (0=yes,0xFF=no) */
-    DWORD next;             /* Pointer to next DPB in list */
-    WORD free_search;       /* Free cluster search start */
-    WORD free_clusters;     /* Number of free clusters (0xFFFF=unknown) */
-};
-
-struct EDPB			/* FAT32 extended Drive Parameter Block */
-{				/* from Ralf Brown's Interrupt List */
-	struct DPB dpb;		/* first 24 bytes = original DPB */
-
-	BYTE edpb_flags;	/* undocumented/unknown flags */
-	DWORD next_edpb;	/* pointer to next EDPB */
-	WORD free_cluster;	/* cluster to start search for free space on write, typically
-	                           the last cluster allocated */
-	WORD clusters_free;	/* number of free clusters on drive or FFFF = unknown */
-	WORD clusters_free_hi;	/* hiword of clusters_free */
-	WORD mirroring_flags;	/* mirroring flags: bit 7 set = do not mirror active FAT */
-				/* bits 0-3 = 0-based number of the active FAT */
-	WORD info_sector;	/* sector number of file system info sector, or FFFF for none */
-	WORD spare_boot_sector;	/* sector number of backup boot sector, or FFFF for none */
-	DWORD first_cluster;	/* sector number of the first cluster */
-	DWORD max_cluster;	/* sector number of the last cluster */
-	DWORD fat_clusters;	/* number of clusters occupied by FAT */
-	DWORD root_cluster;	/* cluster number of start of root directory */
-	DWORD free_cluster2;	/* same as free_cluster: cluster at which to start
-	                           search for free space when writing */
-
-};
-
-DWORD dpbsegptr;
-
 struct DosHeap {
         BYTE mediaID;
 	BYTE biosdate[8];
-        struct DPB dpb;
 };
 static struct DosHeap *heap;
 static WORD DosHeapHandle;
@@ -143,7 +90,6 @@
         return FALSE;
     }
     heap = (struct DosHeap *) GlobalLock16(DosHeapHandle);
-    dpbsegptr = MAKESEGPTR(DosHeapHandle,(int)&heap->dpb-(int)heap);
     strcpy(heap->biosdate, "01/01/80");
     return TRUE;
 }
@@ -223,60 +169,6 @@
     return 1;
 }
 
-static int FillInDrivePB( int drive )
-{
-        if(!DRIVE_IsValid(drive))
-        {
-            SetLastError( ERROR_INVALID_DRIVE );
-			return 0;
-        }
-        else if (heap || INT21_CreateHeap())
-        {
-                /* FIXME: I have no idea what a lot of this information should
-                 * say or whether it even really matters since we're not allowing
-                 * direct block access.  However, some programs seem to depend on
-                 * getting at least _something_ back from here.  The 'next' pointer
-                 * does worry me, though.  Should we have a complete table of
-                 * separate DPBs per drive?  Probably, but I'm lazy. :-)  -CH
-                 */
-                heap->dpb.drive_num = heap->dpb.unit_num = drive; /*The same?*/
-                heap->dpb.sector_size = 512;
-                heap->dpb.high_sector = 1;
-                heap->dpb.shift = drive < 2 ? 0 : 6; /*6 for HD, 0 for floppy*/
-                heap->dpb.reserved = 0;
-                heap->dpb.num_FAT = 1;
-                heap->dpb.dir_entries = 2;
-                heap->dpb.first_data = 2;
-                heap->dpb.high_cluster = 64000;
-                heap->dpb.sectors_in_FAT = 1;
-                heap->dpb.start_dir = 1;
-                heap->dpb.driver_head = 0;
-                heap->dpb.media_ID = (drive > 1) ? 0xF8 : 0xF0;
-                heap->dpb.access_flag = 0;
-                heap->dpb.next = 0;
-                heap->dpb.free_search = 0;
-                heap->dpb.free_clusters = 0xFFFF;    /* unknown */
-				return 1;
-		}
-
-		return 0;
-}
-
-static void GetDrivePB( CONTEXT86 *context, int drive )
-{
-	if (FillInDrivePB( drive ))
-	{
-                SET_AL( context, 0x00 );
-                context->SegDs = SELECTOROF(dpbsegptr);
-                SET_BX( context, OFFSETOF(dpbsegptr) );
-        }
-	else
-	{
-        SET_AX( context, 0x00ff );
-	}
-}
-
-
 static BOOL ioctlGenericBlkDevReq( CONTEXT86 *context )
 {
 	BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
@@ -722,20 +614,10 @@
         if (!INT21_GetDriveAllocInfo(context)) SET_AX( context, 0xffff );
         break;
 
-    case 0x1f: /* GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE */
-        GetDrivePB(context, DRIVE_GetCurrentDrive());
-        break;
-
     case 0x29: /* PARSE FILENAME INTO FCB */
         INT21_ParseFileNameIntoFCB(context);
         break;
 
-    case 0x32: /* GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE */
-        TRACE("GET DOS DRIVE PARAMETER BLOCK FOR DRIVE %s\n",
-	      INT21_DriveName( DL_reg(context)));
-        GetDrivePB(context, DOS_GET_DRIVE( DL_reg(context) ) );
-        break;
-
     case 0x36: /* GET FREE DISK SPACE */
 	TRACE("GET FREE DISK SPACE FOR DRIVE %s\n",
 	      INT21_DriveName( DL_reg(context)));
@@ -940,86 +822,6 @@
             break;
         }
         break;
-
-
-    case 0x73: /* MULTIPLEXED: Win95 OSR2/Win98 FAT32 calls */
-        TRACE("windows95 function AX %04x\n",
-                    AX_reg(context));
-
-        switch (AL_reg(context))
-		{
-		case 0x02:	/* Get Extended Drive Parameter Block for specific drive */
-		    		/* ES:DI points to word with length of data (should be 0x3d) */
-			{
-				WORD *buffer;
-				struct EDPB *edpb;
-			    DWORD cluster_sectors, sector_bytes, free_clusters, total_clusters;
-			    char root[] = "A:\\";
-
-				buffer = (WORD *)CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edi);
-
-				TRACE("Get Extended DPB: linear buffer address is %p\n", buffer);
-
-				/* validate passed-in buffer lengths */
-				if ((*buffer != 0x3d) || (context->Ecx != 0x3f))
-				{
-					WARN("Get Extended DPB: buffer lengths incorrect\n");
-					WARN("CX = %lx, buffer[0] = %x\n", context->Ecx, *buffer);
-					SET_CFLAG(context);
-					SET_AL( context, 0x18 );		/* bad buffer length */
-				}
-
-				/* buffer checks out */
-				buffer++;		/* skip over length word now */
-				if (FillInDrivePB( DX_reg(context) ) )
-				{
-				 	edpb = (struct EDPB *)buffer;
-
-					/* copy down the old-style DPB portion first */
-					memcpy(&edpb->dpb, &heap->dpb, sizeof(struct DPB));
-
-					/* now fill in the extended entries */
-					edpb->edpb_flags = 0;
-					edpb->next_edpb = 0;
-					edpb->free_cluster = edpb->free_cluster2 = 0;
-
-					/* determine free disk space */
-				    *root += DOS_GET_DRIVE( DX_reg(context) );
-				    GetDiskFreeSpaceA( root, &cluster_sectors, &sector_bytes,
-                              &free_clusters, &total_clusters );
-
-					edpb->clusters_free = (free_clusters&0xffff);
-
-					edpb->clusters_free_hi = free_clusters >> 16;
-					edpb->mirroring_flags = 0;
-					edpb->info_sector = 0xffff;
-					edpb->spare_boot_sector = 0xffff;
-					edpb->first_cluster = 0;
-					edpb->max_cluster = total_clusters;
-					edpb->fat_clusters = 32;	/* made-up value */
-					edpb->root_cluster = 0;
-
-					RESET_CFLAG(context);	/* clear carry */
-					SET_AX( context, 0 );
-				}
-				else
-				{
-                                    SET_AX( context, 0x00ff );
-                                    SET_CFLAG(context);
-				}
-			}
-			break;
-
-		case 0x03:	/* Get Extended free space on drive */
-		case 0x04:  /* Set DPB for formatting */
-		case 0x05:  /* extended absolute disk read/write */
-			FIXME("Unimplemented FAT32 int32 function %04x\n", AX_reg(context));
-			SET_CFLAG(context);
-			SET_AL( context, 0 );
-			break;
-		}
-
-		break;
 
     default:
         INT_BARF( context, 0x21 );




-- 
Jukka Heinonen <http://www.iki.fi/jhei/>



More information about the wine-patches mailing list