From 181a7cca2b734e6768be483abb03912732ed4b1d Mon Sep 17 00:00:00 2001 From: Jukka Heinonen Date: Mon, 27 Oct 2003 22:06:10 +0000 Subject: [PATCH] Moved drive parameter block (DPB) routines to winedos. --- dlls/winedos/int21.c | 265 ++++++++++++++++++++++++++++++++++++++++--- msdos/int21.c | 198 -------------------------------- 2 files changed, 247 insertions(+), 216 deletions(-) diff --git a/dlls/winedos/int21.c b/dlls/winedos/int21.c index 3c8beb54a0c..e3a79eb9db4 100644 --- a/dlls/winedos/int21.c +++ b/dlls/winedos/int21.c @@ -58,6 +58,42 @@ WINE_DEFAULT_DEBUG_CHANNEL(int21); #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 @@ -87,7 +123,11 @@ typedef struct _INT21_HEAP { 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 @@ static void INT21_FillHeap( INT21_HEAP *heap ) * 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 void INT21_FillHeap( INT21_HEAP *heap ) */ 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, §or_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; } @@ -2282,6 +2426,62 @@ static void INT21_Ioctl( CONTEXT86 *context ) } +/*********************************************************************** + * 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_DPB) ) + { + 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 * @@ -2862,7 +3062,21 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) 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 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) 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 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) break; case 0x73: /* MSDOS7 - FAT32 */ - INT_Int21Handler( context ); + if (!INT21_Fat32( context )) + bSetDOSExtendedError = TRUE; break; case 0xdc: /* CONNECTION SERVICES - GET CONNECTION NUMBER */ diff --git a/msdos/int21.c b/msdos/int21.c index e4bfd7de2e5..4115a5f95b0 100644 --- a/msdos/int21.c +++ b/msdos/int21.c @@ -73,62 +73,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(int21); #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 @@ static BOOL INT21_CreateHeap(void) 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 @@ static int INT21_GetDriveAllocInfo( CONTEXT86 *context ) 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 @@ void WINAPI INT_Int21Handler( CONTEXT86 *context ) 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))); @@ -941,86 +823,6 @@ void WINAPI INT_Int21Handler( CONTEXT86 *context ) } 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, §or_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 ); break;