ChangeLog: * dlls/winedos/int21.c * msdos/int21.c Move drive functions to winedos. nog.
--- msdos/int21.c.4 2002-11-27 15:52:16.000000000 +0200 +++ msdos/int21.c 2002-11-27 15:52:41.000000000 +0200 @@ -199,31 +199,6 @@ } } -static int INT21_GetFreeDiskSpace( CONTEXT86 *context ) -{ - DWORD cluster_sectors, sector_bytes, free_clusters, total_clusters; - char root[] = "A:\\"; - - *root += DOS_GET_DRIVE( DL_reg(context) ); - if (!GetDiskFreeSpaceA( root, &cluster_sectors, §or_bytes, - &free_clusters, &total_clusters )) return 0; - SET_AX( context, cluster_sectors ); - SET_BX( context, free_clusters ); - SET_CX( context, sector_bytes ); - SET_DX( context, total_clusters ); - return 1; -} - -static int INT21_GetDriveAllocInfo( CONTEXT86 *context ) -{ - if (!INT21_GetFreeDiskSpace( context )) return 0; - if (!heap && !INT21_CreateHeap()) return 0; - heap->mediaID = 0xf0; - context->SegDs = DosHeapHandle; - SET_BX( context, (int)&heap->mediaID - (int)heap ); - return 1; -} - static int FillInDrivePB( int drive ) { if(!DRIVE_IsValid(drive)) @@ -263,21 +238,6 @@ 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 void ioctlGetDeviceInfo( CONTEXT86 *context ) { int curr_drive; @@ -574,22 +534,6 @@ return TRUE; } - -static void INT21_GetDBCSLeadTable( CONTEXT86 *context ) -{ - if (heap || INT21_CreateHeap()) - { /* return an empty table just as DOS 4.0+ does */ - context->SegDs = DosHeapHandle; - SET_SI( context, (int)&heap->DummyDBCSLeadTable - (int)heap ); - } - else - { - SET_AX( context, 0x1 ); /* error */ - SET_CFLAG(context); - } -} - - static int INT21_GetDiskSerialNumber( CONTEXT86 *context ) { BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx); @@ -783,19 +727,6 @@ } break; - case 0x1b: /* GET ALLOCATION INFORMATION FOR DEFAULT DRIVE */ - SET_DL( context, 0 ); - if (!INT21_GetDriveAllocInfo(context)) SET_AX( context, 0xffff ); - break; - - case 0x1c: /* GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE */ - if (!INT21_GetDriveAllocInfo(context)) SET_AX( context, 0xffff ); - break; - - case 0x1f: /* GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE */ - GetDrivePB(context, DRIVE_GetCurrentDrive()); - break; - case 0x2a: /* GET SYSTEM DATE */ INT21_GetSystemDate(context); break; @@ -843,12 +774,6 @@ FIXME("TERMINATE AND STAY RESIDENT stub\n"); 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 0x33: /* MULTIPLEXED */ switch (AL_reg(context)) { @@ -898,13 +823,6 @@ } break; - case 0x34: /* GET ADDRESS OF INDOS FLAG */ - TRACE("GET ADDRESS OF INDOS FLAG\n"); - if (!heap) INT21_CreateHeap(); - context->SegEs = DosHeapHandle; - SET_BX( context, (int)&heap->InDosFlag - (int)heap ); - break; - case 0x37: { unsigned char switchchar='/'; @@ -1189,14 +1107,6 @@ } break; - case 0x61: /* UNUSED */ - case 0x63: /* misc. language support */ - switch (AL_reg(context)) { - case 0x00: /* GET DOUBLE BYTE CHARACTER SET LEAD-BYTE TABLE */ - INT21_GetDBCSLeadTable(context); - break; - } - break; case 0x64: /* OS/2 DOS BOX */ INT_BARF( context, 0x21 ); SET_CFLAG(context); --- dlls/winedos/int21.c.4 2002-11-27 15:52:24.000000000 +0200 +++ dlls/winedos/int21.c 2002-11-27 15:52:41.000000000 +0200 @@ -41,6 +41,94 @@ WINE_DEFAULT_DEBUG_CHANNEL(int21); +/* 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 */ +}; + +struct DosHeap { + BYTE InDosFlag; + BYTE mediaID; + BYTE biosdate[8]; + struct DPB dpb; + BYTE DummyDBCSLeadTable[6]; +}; +static struct DosHeap *heap; +static WORD DosHeapHandle; + +DWORD dpbsegptr; + +/*********************************************************************** + * INT21_CreateHeap [internal] + * + * Allocates a heap for us to use internally. + * + * PARAMS: + * None. + * + * RETURNS + * Handle to heap. + */ +static BOOL INT21_CreateHeap(void) +{ + if (!(DosHeapHandle = GlobalAlloc16(GMEM_FIXED, sizeof(struct DosHeap)))) { + WARN("Out of memory\n"); + return FALSE; + } + heap = (struct DosHeap *)GlobalLock16(DosHeapHandle); + dpbsegptr = MAKESEGPTR(DosHeapHandle, (int)&heap->dpb - (int)heap); + heap->InDosFlag = 0; + strcpy(heap->biosdate, "01/01/80"); + memset(heap->DummyDBCSLeadTable, 0, 6); + return TRUE; +} + /*********************************************************************** * GetDosDrive [internal] * @@ -362,6 +450,122 @@ } /*********************************************************************** + * INT21_GetDriveAllocInfo [internal] + * + * Returns drive allocation info. + * + * PARAMS: + * context [I]: Pointer to structure holding registers. + * + * RETURNS: + * 1: Success. + */ +static int INT21_GetDriveAllocInfo(CONTEXT86 *context) +{ + if (!INT21_GetFreeDiskSpace(context)) return 0; + if (!heap && !INT21_CreateHeap()) return 0; + heap->mediaID = 0xf0; + context->SegDs = DosHeapHandle; + SET_BX(context, (int)&heap->mediaID - (int)heap); + return 1; +} + +/*********************************************************************** + * FillInDrivePB [internal] + * + * Initializes a Drive Parameter Block. + * + * PARAMS: + * context [I]: Pointer to structure holding registers. + * + * RETURNS: + * 0: Failure. + * 1: Success. + */ +static int FillInDrivePB(int drive) +{ + if(!IsDriveValid(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.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; +} + +/*********************************************************************** + * GetDrivePB [internal] + * + * Returns a drive parameter block for a certain drive. + * + * PARAMS: + * context [I]: Pointer to structure holding registers. + * drive [I]: Drive who's DPB to retrieve. + * + * RETURNS: + * Nothing. + */ +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); + } +} + +/*********************************************************************** + * INT21_GetDBCSLeadTable [internal] + * + * Returns a DBCS Table. + * + * PARAMS: + * context [I]: Pointer to structure holding registers. + * + * RETURNS: + * Nothing. + */ +static void INT21_GetDBCSLeadTable(CONTEXT86 *context) +{ + if(heap || INT21_CreateHeap()) { + /* return an empty table just as DOS 4.0+ does */ + context->SegDs = DosHeapHandle; + SET_SI(context, (int)&heap->DummyDBCSLeadTable - (int)heap); + } else { + SET_AX(context, 0x1); /* error */ + SET_CFLAG(context); + } +} + +/*********************************************************************** * GetCurrentDTA [internal] * * Returns a pointer to the current DTA. @@ -1070,6 +1274,19 @@ SET_AL(context, GetDosDrive(0)); break; + case 0x1b: /* GET ALLOCATION INFORMATION FOR DEFAULT DRIVE */ + SET_DL(context, 0); + if(!INT21_GetDriveAllocInfo(context)) SET_AX(context, 0xffff); + break; + + case 0x1c: /* GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE */ + if(!INT21_GetDriveAllocInfo(context)) SET_AX(context, 0xffff); + break; + + case 0x1f: /* GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE */ + GetDrivePB(context, GetDosDrive(0)); + break; + case 0x25: /* SET INTERRUPT VECTOR */ if(DOSVM_IsWin16()) DOSVM_SetPMHandler16(AL_reg(context), (FARPROC16)MAKESEGPTR(context->SegDs, @@ -1094,6 +1311,19 @@ } 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, GetDosDrive(DL_reg(context))); + break; + + case 0x34: /* GET ADDRESS OF INDOS FLAG */ + TRACE("GET ADDRESS OF INDOS FLAG\n"); + if(!heap) INT21_CreateHeap(); + context->SegEs = DosHeapHandle; + SET_BX(context, (int)&heap->InDosFlag - (int)heap); + break; + case 0x35: /* GET INTERRUPT VECTOR */ { FARPROC16 addr; @@ -1502,6 +1732,14 @@ else SET_BX(context, DOSVM_psp); break; + case 0x63: /* misc. language support */ + switch (AL_reg(context)) { + case 0x00: /* GET DOUBLE BYTE CHARACTER SET LEAD-BYTE TABLE */ + INT21_GetDBCSLeadTable(context); + break; + } + break; + case 0x68: /* "FFLUSH" - COMMIT FILE */ TRACE("FFLUSH/COMMIT handle %d\n",BX_reg(context)); bSetDOSExtendedError = (!FlushFileBuffers(DosFileHandleToWin32Handle(