- moved the remaining of int21 calls to dlls/winedos

- disabled drive enabling/disabling as well as disk serial number
  writing (for DLL separation issues)
- added volume management prototypes to include/winbase.h
- started DefineDosDevice (needed by first item in this list)
- removed int21 specific code from dlls/kernel
oldstable
Eric Pouech 2003-11-14 04:54:39 +00:00 committed by Alexandre Julliard
parent 0196861349
commit 8ca6cadab1
10 changed files with 1039 additions and 1052 deletions

View File

@ -26,7 +26,6 @@ C_SRCS = \
$(TOPOBJDIR)/misc/options.c \
$(TOPOBJDIR)/misc/registry.c \
$(TOPOBJDIR)/msdos/dpmi.c \
$(TOPOBJDIR)/msdos/int21.c \
atom.c \
change.c \
comm.c \

View File

@ -221,7 +221,7 @@
@ stdcall DebugActiveProcess(long)
@ stdcall DebugBreak()
@ stdcall DefineDosDeviceA(long str str)
@ stub DefineDosDeviceW
@ stdcall DefineDosDeviceW(long wstr wstr)
@ stub DelayLoadFailureHook
@ stdcall DeleteAtom(long)
@ stdcall DeleteCriticalSection(ptr) ntdll.RtlDeleteCriticalSection
@ -1150,7 +1150,6 @@
@ cdecl DOSMEM_ResizeBlock(ptr long long)
@ cdecl DRIVE_OpenDevice(long long)
@ cdecl FILE_Dup2(long long)
@ stdcall INT_Int21Handler(ptr)
@ cdecl LOCAL_Alloc(long long long)
@ cdecl LOCAL_Compact(long long long)
@ cdecl LOCAL_CountFree(long)

File diff suppressed because it is too large Load Diff

View File

@ -53,7 +53,6 @@
#include "wine/winbase16.h"
#include "drive.h"
#include "file.h"
#include "heap.h"
#include "msdos.h"
#include "winternl.h"
#include "wine/server.h"
@ -143,8 +142,6 @@ typedef struct
{
char *path; /* unix path */
LPWSTR long_mask;
LPWSTR short_mask;
BYTE attr;
int drive;
int cur_pos;
CRITICAL_SECTION cs;
@ -332,20 +329,6 @@ static void DOSFS_ToDosDTAFormat( LPCWSTR name, LPWSTR buffer )
}
/***********************************************************************
* DOSFS_MatchShort
*
* Check a DOS file name against a mask (both in FCB format).
*/
static int DOSFS_MatchShort( LPCWSTR mask, LPCWSTR name )
{
int i;
for (i = 11; i > 0; i--, mask++, name++)
if ((*mask != '?') && (*mask != *name)) return 0;
return 1;
}
/***********************************************************************
* DOSFS_MatchLong
*
@ -1777,35 +1760,14 @@ static BOOL get_show_dir_symlinks_option(void)
*/
static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry )
{
DWORD attr = info->attr | FA_UNUSED | FA_ARCHIVE | FA_RDONLY;
UINT flags = DRIVE_GetFlags( info->drive );
char *p, buffer[MAX_PATHNAME_LEN];
const char *drive_path;
int drive_root;
LPCWSTR long_name, short_name;
BY_HANDLE_FILE_INFORMATION fileinfo;
WCHAR dos_name[13];
BOOL is_symlink;
if ((info->attr & ~(FA_UNUSED | FA_ARCHIVE | FA_RDONLY)) == FA_LABEL)
{
if (info->cur_pos) return 0;
entry->dwFileAttributes = FILE_ATTRIBUTE_LABEL;
RtlSecondsSince1970ToTime( (time_t)0, (LARGE_INTEGER *)&entry->ftCreationTime );
RtlSecondsSince1970ToTime( (time_t)0, (LARGE_INTEGER *)&entry->ftLastAccessTime );
RtlSecondsSince1970ToTime( (time_t)0, (LARGE_INTEGER *)&entry->ftLastWriteTime );
entry->nFileSizeHigh = 0;
entry->nFileSizeLow = 0;
entry->dwReserved0 = 0;
entry->dwReserved1 = 0;
DOSFS_ToDosDTAFormat( DRIVE_GetLabel( info->drive ), entry->cFileName );
strcpyW( entry->cAlternateFileName, entry->cFileName );
info->cur_pos++;
TRACE("returning %s (%s) as label\n",
debugstr_w(entry->cFileName), debugstr_w(entry->cAlternateFileName));
return 1;
}
drive_path = info->path + strlen(DRIVE_GetRoot( info->drive ));
while ((*drive_path == '/') || (*drive_path == '\\')) drive_path++;
drive_root = !*drive_path;
@ -1831,19 +1793,6 @@ static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry )
flags & DRIVE_CASE_SENSITIVE )) continue;
}
/* Check the short mask */
if (info->short_mask)
{
if (!short_name)
{
DOSFS_Hash( long_name, dos_name, TRUE,
!(flags & DRIVE_CASE_SENSITIVE) );
short_name = dos_name;
}
if (!DOSFS_MatchShort( info->short_mask, short_name )) continue;
}
/* Check the file attributes */
WideCharToMultiByte(CP_UNIXCP, 0, long_name, -1,
p, sizeof(buffer) - (int)(p - buffer), NULL, NULL);
@ -1860,8 +1809,6 @@ static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry )
if (!show_dir_symlinks) continue;
}
if (fileinfo.dwFileAttributes & ~attr) continue;
/* We now have a matching entry; fill the result and return */
entry->dwFileAttributes = fileinfo.dwFileAttributes;
@ -1887,94 +1834,6 @@ static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry )
return 0; /* End of directory */
}
/***********************************************************************
* DOSFS_FindNext
*
* Find the next matching file. Return the number of entries read to find
* the matching one, or 0 if no more entries.
* 'short_mask' is the 8.3 mask (in FCB format), 'long_mask' is the long
* file name mask. Either or both can be NULL.
*
* NOTE: This is supposed to be only called by the int21 emulation
* routines, and so assumes that the Win16Mutex is held to
* protect the static directory cache.
*/
int DOSFS_FindNext( const char *path, const char *short_mask,
const char *long_mask, int drive, BYTE attr,
int skip, WIN32_FIND_DATAA *entry )
{
static FIND_FIRST_INFO info;
LPCWSTR short_name, long_name;
int count;
UNICODE_STRING short_maskW, long_maskW;
WIN32_FIND_DATAW entryW;
TRACE("(%s, %s, %s, %x, %x, %x, %p)\n", debugstr_a(path),
debugstr_a(short_mask), debugstr_a(long_mask), drive, attr, skip,
entry);
RtlCreateUnicodeStringFromAsciiz(&short_maskW, short_mask);
RtlCreateUnicodeStringFromAsciiz(&long_maskW, long_mask);
/* Check the cached directory */
if (!(info.u.dos_dir && info.path == path && !strcmpW(info.short_mask, short_maskW.Buffer)
&& !strcmpW(info.long_mask, long_maskW.Buffer) && info.drive == drive
&& info.attr == attr && info.cur_pos <= skip))
{
/* Not in the cache, open it anew */
if (info.u.dos_dir) DOSFS_CloseDir( info.u.dos_dir );
info.path = (LPSTR)path;
RtlFreeHeap(GetProcessHeap(), 0, info.long_mask);
RtlFreeHeap(GetProcessHeap(), 0, info.short_mask);
info.long_mask = long_maskW.Buffer;
info.short_mask = short_maskW.Buffer;
info.attr = attr;
info.drive = drive;
info.cur_pos = 0;
info.u.dos_dir = DOSFS_OpenDir( info.path );
}
else
{
RtlFreeUnicodeString(&short_maskW);
RtlFreeUnicodeString(&long_maskW);
}
/* Skip to desired position */
while (info.cur_pos < skip)
if (info.u.dos_dir && DOSFS_ReadDir( info.u.dos_dir, &long_name, &short_name ))
info.cur_pos++;
else
break;
if (info.u.dos_dir && info.cur_pos == skip && DOSFS_FindNextEx( &info, &entryW ))
{
WideCharToMultiByte(CP_ACP, 0, entryW.cFileName, -1,
entry->cFileName, sizeof(entry->cFileName), NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, entryW.cAlternateFileName, -1,
entry->cAlternateFileName, sizeof(entry->cAlternateFileName), NULL, NULL);
count = info.cur_pos - skip;
entry->dwFileAttributes = entryW.dwFileAttributes;
entry->nFileSizeHigh = entryW.nFileSizeHigh;
entry->nFileSizeLow = entryW.nFileSizeLow;
entry->ftCreationTime = entryW.ftCreationTime;
entry->ftLastAccessTime = entryW.ftLastAccessTime;
entry->ftLastWriteTime = entryW.ftLastWriteTime;
}
else
count = 0;
if (!count)
{
if (info.u.dos_dir) DOSFS_CloseDir( info.u.dos_dir );
memset( &info, '\0', sizeof(info) );
}
return count;
}
/*************************************************************************
* FindFirstFileExW (KERNEL32.@)
*/
@ -2048,8 +1907,6 @@ HANDLE WINAPI FindFirstFileExW(
info->long_mask = HeapAlloc( GetProcessHeap(), 0, long_mask_len * sizeof(WCHAR) );
MultiByteToWideChar(CP_UNIXCP, 0, p, -1, info->long_mask, long_mask_len);
info->short_mask = NULL;
info->attr = 0xff;
info->drive = full_name.drive;
info->cur_pos = 0;
@ -2469,13 +2326,3 @@ DWORD WINAPI QueryDosDeviceW(LPCWSTR devname,LPWSTR target,DWORD bufsize)
}
return ret;
}
/***********************************************************************
* DefineDosDeviceA (KERNEL32.@)
*/
BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath) {
FIXME("(0x%08lx,%s,%s),stub!\n",flags,devname,targetpath);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}

View File

@ -1283,21 +1283,54 @@ int DRIVE_Enable( int drive )
/***********************************************************************
* DRIVE_SetLogicalMapping
* DefineDosDeviceA (KERNEL32.@)
*/
int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive )
BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath)
{
/* If new_drive is already valid, do nothing and return 0
otherwise, copy DOSDrives[existing_drive] to DOSDrives[new_drive] */
UNICODE_STRING d, t;
BOOL ret;
if (!RtlCreateUnicodeStringFromAsciiz(&d, devname))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
if (!RtlCreateUnicodeStringFromAsciiz(&t, targetpath))
{
RtlFreeUnicodeString(&d);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
ret = DefineDosDeviceW(flags, d.Buffer, t.Buffer);
RtlFreeUnicodeString(&d);
RtlFreeUnicodeString(&t);
return ret;
}
/***********************************************************************
* DefineDosDeviceA (KERNEL32.@)
*/
BOOL WINAPI DefineDosDeviceW(DWORD flags,LPCWSTR devname,LPCWSTR targetpath)
{
DOSDRIVE *old, *new;
old = DOSDrives + existing_drive;
new = DOSDrives + new_drive;
/* this is a temporary hack for int21 support. better implementation has to be done */
if (flags != DDD_RAW_TARGET_PATH ||
!(toupperW(devname[0]) >= 'A' && toupperW(devname[0]) <= 'Z') ||
devname[1] != ':' || devname[2] != 0 ||
!(toupperW(targetpath[0]) >= 'A' && toupperW(targetpath[0]) <= 'Z') ||
targetpath[1] != ':' || targetpath[2] != '\\' || targetpath[3] != 0)
{
FIXME("(0x%08lx,%s,%s),stub!\n", flags, debugstr_w(devname), debugstr_w(targetpath));
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
if ((existing_drive < 0) || (existing_drive >= MAX_DOS_DRIVES) ||
!old->root ||
(new_drive < 0) || (new_drive >= MAX_DOS_DRIVES))
old = DOSDrives + devname[0] - 'A';
new = DOSDrives + targetpath[0] - 'A';
if (!old->root)
{
SetLastError( ERROR_INVALID_DRIVE );
return 0;
@ -1306,7 +1339,7 @@ int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive )
if ( new->root )
{
TRACE("Can't map drive %c: to already existing drive %c:\n",
'A' + existing_drive, 'A' + new_drive );
devname[0], targetpath[0] );
/* it is already mapped there, so return success */
if (!strcmp(old->root,new->root))
return 1;
@ -1327,7 +1360,7 @@ int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive )
new->ino = old->ino;
TRACE("Drive %c: is now equal to drive %c:\n",
'A' + new_drive, 'A' + existing_drive );
targetpath[0], devname[0] );
return 1;
}
@ -2126,8 +2159,8 @@ BOOL WINAPI SetVolumeLabelA(LPCSTR root, LPCSTR volname)
/***********************************************************************
* GetVolumeNameForVolumeMountPointW (KERNEL32.@)
*/
DWORD WINAPI GetVolumeNameForVolumeMountPointW(LPWSTR str, DWORD a, DWORD b)
BOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR str, LPWSTR dst, DWORD size)
{
FIXME("(%s, %lx, %lx): stub\n", debugstr_w(str), a, b);
FIXME("(%s, %p, %lx): stub\n", debugstr_w(str), dst, size);
return 0;
}

View File

@ -51,7 +51,6 @@ extern UINT DRIVE_GetFlags( int drive );
extern int DRIVE_Chdir( int drive, LPCWSTR path );
extern int DRIVE_Disable( int drive );
extern int DRIVE_Enable( int drive );
extern int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive );
extern int DRIVE_OpenDevice( int drive, int flags );
extern WCHAR *DRIVE_BuildEnv(void);

View File

@ -97,9 +97,6 @@ extern BOOL DOSFS_FindUnixName( const DOS_FULL_NAME *path, LPCWSTR name, char *l
INT long_len, LPWSTR short_buf, BOOL ignore_case );
extern BOOL DOSFS_GetFullName( LPCWSTR name, BOOL check_last,
DOS_FULL_NAME *full );
extern int DOSFS_FindNext( const char *path, const char *short_mask,
const char *long_mask, int drive, BYTE attr,
int skip, WIN32_FIND_DATAA *entry );
/* win32/device.c */
extern HANDLE DEVICE_Open( LPCWSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa );

View File

@ -44,7 +44,7 @@ typedef struct
BYTE search_attr; /* 0c search attributes */
WORD count; /* 0d entry count within directory */
WORD cluster; /* 0f cluster of parent directory */
char *unixPath; /* 11 unix path (was: reserved) */
WCHAR *fullPath; /* 11 full path (was: reserved) */
BYTE fileattr; /* 15 file attributes */
WORD filetime; /* 16 file time */
WORD filedate; /* 18 file date */
@ -58,7 +58,7 @@ typedef struct
BYTE drive; /* 00 drive letter */
char filename[11]; /* 01 filename 8+3 format */
int count; /* 0c entry count (was: reserved) */
char *unixPath; /* 10 unix path (was: reserved) */
WCHAR *fullPath; /* 10 full path (was: reserved) */
} FINDFILE_FCB;
/* DOS directory entry for FindFirstFCB/FindNextFCB */

View File

@ -1090,6 +1090,13 @@ BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType );
BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType );
#define GetBinaryType WINELIB_NAME_AW(GetBinaryType)
/* flags for DefineDosDevice */
#define DDD_RAW_TARGET_PATH 0x00000001
#define DDD_REMOVE_DEFINITION 0x00000002
#define DDD_EXACT_MATCH_ON_REMOVE 0x00000004
#define DDD_NO_BROADCAST_SYSTEM 0x00000008
#define DDD_LUID_BROADCAST_DRIVE 0x00000010
BOOL WINAPI AddAccessAllowedAce(PACL,DWORD,DWORD,PSID);
PVOID WINAPI AddVectoredExceptionHandler(ULONG,PVECTORED_EXCEPTION_HANDLER);
BOOL WINAPI AttachThreadInput(DWORD,DWORD,BOOL);
@ -1182,10 +1189,16 @@ BOOL WINAPI DebugActiveProcessStop(DWORD);
void WINAPI DebugBreak(void);
BOOL WINAPI DebugBreakProcess(HANDLE);
BOOL WINAPI DebugSetProcessKillOnExit(BOOL);
BOOL WINAPI DefineDosDeviceA(DWORD,LPCSTR,LPCSTR);
BOOL WINAPI DefineDosDeviceW(DWORD,LPCWSTR,LPCWSTR);
#define DefineDosDevice WINELIB_NAME_AW(DefineDosDevice)
BOOL WINAPI DeleteAce(PACL,DWORD);
void WINAPI DeleteFiber(LPVOID);
BOOL WINAPI DeleteTimerQueueEx(HANDLE,HANDLE);
BOOL WINAPI DeleteTimerQueueTimer(HANDLE,HANDLE,HANDLE);
BOOL WINAPI DeleteVolumeMountPointA(LPCSTR);
BOOL WINAPI DeleteVolumeMountPointW(LPCWSTR);
#define DeleteVolumeMountPoint WINELIB_NAME_AW(DeleteVolumeMountPoint)
BOOL WINAPI DeregisterEventSource(HANDLE);
BOOL WINAPI DeviceIoControl(HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPDWORD,LPOVERLAPPED);
BOOL WINAPI DisableThreadLibraryCalls(HMODULE);
@ -1224,6 +1237,20 @@ BOOL WINAPI FindCloseChangeNotification(HANDLE);
HRSRC WINAPI FindResourceExA(HMODULE,LPCSTR,LPCSTR,WORD);
HRSRC WINAPI FindResourceExW(HMODULE,LPCWSTR,LPCWSTR,WORD);
#define FindResourceEx WINELIB_NAME_AW(FindResourceEx)
HANDLE WINAPI FindFirstVolumeA(LPSTR,DWORD);
HANDLE WINAPI FindFirstVolumeW(LPWSTR,DWORD);
#define FindFirstVolume WINELIB_NAME_AW(FindFirstVolume)
HANDLE WINAPI FindFirstVolumeMountPointA(LPCSTR,LPSTR,DWORD);
HANDLE WINAPI FindFirstVolumeMountPointW(LPCWSTR,LPWSTR,DWORD);
#define FindFirstVolumeMountPoint WINELIB_NAME_AW(FindFirstVolumeMountPoint)
BOOL WINAPI FindNextVolumeA(HANDLE,LPSTR,DWORD);
BOOL WINAPI FindNextVolumeW(HANDLE,LPWSTR,DWORD);
#define FindNextVolume WINELIB_NAME_AW(FindNextVolume)
BOOL WINAPI FindNextVolumeMountPointA(HANDLE,LPSTR,DWORD);
BOOL WINAPI FindNextVolumeMountPointW(HANDLE,LPWSTR,DWORD);
#define FindNextVolumeMountPoint WINELIB_NAME_AW(FindNextVolumeMountPoint)
BOOL WINAPI FindVolumeClose(HANDLE);
BOOL WINAPI FindVolumeMountPointClose(HANDLE);
BOOL WINAPI FlushFileBuffers(HANDLE);
BOOL WINAPI FlushViewOfFile(LPCVOID,SIZE_T);
DWORD WINAPI FormatMessageA(DWORD,LPCVOID,DWORD,DWORD,LPSTR,DWORD,va_list*);
@ -1323,6 +1350,15 @@ BOOL WINAPI GetTokenInformation(HANDLE,TOKEN_INFORMATION_CLASS,LPVOID,DWO
BOOL WINAPI GetUserNameA(LPSTR,LPDWORD);
BOOL WINAPI GetUserNameW(LPWSTR,LPDWORD);
#define GetUserName WINELIB_NAME_AW(GetUserName)
BOOL WINAPI GetVolumeNameForVolumeMountPointA(LPCSTR,LPSTR,DWORD);
BOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR,LPWSTR,DWORD);
#define GetVolumeNameForVolumeMountPoint WINELIB_NAME_AW(GetVolumeNameForVolumeMountPoint)
BOOL WINAPI GetVolumePathNameA(LPCSTR,LPSTR,DWORD);
BOOL WINAPI GetVolumePathNameW(LPCWSTR,LPWSTR,DWORD);
#define GetVolumePathName WINELIB_NAME_AW(GetVolumePathName)
BOOL WINAPI GetVolumePathNamesForVolumeNameA(LPCSTR,LPSTR,DWORD,PDWORD);
BOOL WINAPI GetVolumePathNamesForVolumeNameW(LPCWSTR,LPWSTR,DWORD,PDWORD);
#define GetVolumePathNamesForVolumeName WINELIB_NAME_AW(GetVolumePathNamesForVolumeName)
VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS);
LPVOID WINAPI HeapAlloc(HANDLE,DWORD,SIZE_T);
SIZE_T WINAPI HeapCompact(HANDLE,DWORD);
@ -1473,6 +1509,9 @@ BOOL WINAPI SetThreadPriority(HANDLE,INT);
BOOL WINAPI SetThreadPriorityBoost(HANDLE,BOOL);
BOOL WINAPI SetThreadToken(PHANDLE,HANDLE);
BOOL WINAPI SetTimeZoneInformation(const LPTIME_ZONE_INFORMATION);
BOOL WINAPI SetVolumeMountPointA(LPCSTR,LPCSTR);
BOOL WINAPI SetVolumeMountPointW(LPCSTR,LPCSTR);
#define SetVolumeMountPoint WINELIB_NAME_AW(SetVolumeMountPoint)
BOOL WINAPI SetWaitableTimer(HANDLE,const LARGE_INTEGER*,LONG,PTIMERAPCROUTINE,LPVOID,BOOL);
BOOL WINAPI SetupComm(HANDLE,DWORD,DWORD);
DWORD WINAPI SignalObjectAndWait(HANDLE,HANDLE,DWORD,BOOL);

View File

@ -1,837 +0,0 @@
/*
* DOS interrupt 21h handler
*
* Copyright 1993, 1994 Erik Bos
* Copyright 1996 Alexandre Julliard
* Copyright 1997 Andreas Mohr
* Copyright 1998 Uwe Bonnes
* Copyright 1998, 1999 Ove Kaaven
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "wine/port.h"
#include <time.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef HAVE_SYS_FILE_H
# include <sys/file.h>
#endif
#include <string.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_UTIME_H
# include <utime.h>
#endif
#include <ctype.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winternl.h"
#include "wingdi.h"
#include "winuser.h" /* SW_NORMAL */
#include "wine/winbase16.h"
#include "winerror.h"
#include "drive.h"
#include "file.h"
#include "msdos.h"
#include "miscemu.h"
#include "task.h"
#include "kernel_private.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(int21);
#if defined(__svr4__) || defined(_SCO_DS)
/* SVR4 DOESNT do locking the same way must implement properly */
#define LOCK_EX 0
#define LOCK_SH 1
#define LOCK_NB 8
#endif
#define DOS_GET_DRIVE(reg) ((reg) ? (reg) - 1 : DRIVE_GetCurrentDrive())
struct DosHeap {
BYTE mediaID;
BYTE biosdate[8];
};
static struct DosHeap *heap;
static WORD DosHeapHandle;
extern char TempDirectory[];
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);
strcpy(heap->biosdate, "01/01/80");
return TRUE;
}
static BYTE *GetCurrentDTA( CONTEXT86 *context )
{
TDB *pTask = GlobalLock16(GetCurrentTask());
/* FIXME: This assumes DTA was set correctly! */
return (BYTE *)CTX_SEG_OFF_TO_LIN( context, SELECTOROF(pTask->dta),
(DWORD)OFFSETOF(pTask->dta) );
}
static void CreateBPB(int drive, BYTE *data, BOOL16 limited)
/* limited == TRUE is used with INT 0x21/0x440d */
{
if (drive > 1) {
setword(data, 512);
data[2] = 2;
setword(&data[3], 0);
data[5] = 2;
setword(&data[6], 240);
setword(&data[8], 64000);
data[0x0a] = 0xf8;
setword(&data[0x0b], 40);
setword(&data[0x0d], 56);
setword(&data[0x0f], 2);
setword(&data[0x11], 0);
if (!limited) {
setword(&data[0x1f], 800);
data[0x21] = 5;
setword(&data[0x22], 1);
}
} else { /* 1.44mb */
setword(data, 512);
data[2] = 2;
setword(&data[3], 0);
data[5] = 2;
setword(&data[6], 240);
setword(&data[8], 2880);
data[0x0a] = 0xf8;
setword(&data[0x0b], 6);
setword(&data[0x0d], 18);
setword(&data[0x0f], 2);
setword(&data[0x11], 0);
if (!limited) {
setword(&data[0x1f], 80);
data[0x21] = 7;
setword(&data[0x22], 2);
}
}
}
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, &sector_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 BOOL ioctlGenericBlkDevReq( CONTEXT86 *context )
{
BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
int drive = DOS_GET_DRIVE( BL_reg(context) );
if (!DRIVE_IsValid(drive))
{
SetLastError( ERROR_FILE_NOT_FOUND );
return TRUE;
}
if (CH_reg(context) != 0x08)
{
INT_BARF( context, 0x21 );
return FALSE;
}
switch (CL_reg(context))
{
case 0x60: /* get device parameters */
/* used by w4wgrp's winfile */
memset(dataptr, 0, 0x20); /* DOS 6.22 uses 0x20 bytes */
dataptr[0] = 0x04;
dataptr[6] = 0; /* media type */
if (drive > 1)
{
dataptr[1] = 0x05; /* fixed disk */
setword(&dataptr[2], 0x01); /* non removable */
setword(&dataptr[4], 0x300); /* # of cylinders */
}
else
{
dataptr[1] = 0x07; /* block dev, floppy */
setword(&dataptr[2], 0x02); /* removable */
setword(&dataptr[4], 80); /* # of cylinders */
}
CreateBPB(drive, &dataptr[7], TRUE);
RESET_CFLAG(context);
break;
case 0x66:/* get disk serial number */
{
char label[12],fsname[9],path[4];
DWORD serial;
strcpy(path,"x:\\");path[0]=drive+'A';
GetVolumeInformationA(
path,label,12,&serial,NULL,NULL,fsname,9
);
*(WORD*)dataptr = 0;
memcpy(dataptr+2,&serial,4);
memcpy(dataptr+6,label ,11);
memcpy(dataptr+17,fsname,8);
}
break;
case 0x6f:
memset(dataptr+1, '\0', dataptr[0]-1);
dataptr[1] = dataptr[0];
dataptr[2] = 0x07; /* protected mode driver; no eject; no notification */
dataptr[3] = 0xFF; /* no physical drive */
break;
case 0x72:
/* Trail on error implementation */
SET_AX( context, GetDriveType16(BL_reg(context)) == DRIVE_UNKNOWN ? 0x0f : 0x01 );
SET_CFLAG(context); /* Seems to be set all the time */
break;
default:
INT_BARF( context, 0x21 );
}
return FALSE;
}
static void INT21_ParseFileNameIntoFCB( CONTEXT86 *context )
{
char *filename =
CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Esi );
char *fcb =
CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edi );
char *s;
WCHAR *buffer;
WCHAR fcbW[12];
INT buffer_len, len;
SET_AL( context, 0xff ); /* failed */
TRACE("filename: '%s'\n", filename);
s = filename;
len = 0;
while (*s)
{
if ((*s != ' ') && (*s != '\r') && (*s != '\n'))
{
s++;
len++;
}
else
break;
}
buffer_len = MultiByteToWideChar(CP_OEMCP, 0, filename, len, NULL, 0);
buffer = HeapAlloc( GetProcessHeap(), 0, (buffer_len + 1) * sizeof(WCHAR));
len = MultiByteToWideChar(CP_OEMCP, 0, filename, len, buffer, buffer_len);
buffer[len] = 0;
DOSFS_ToDosFCBFormat(buffer, fcbW);
HeapFree(GetProcessHeap(), 0, buffer);
WideCharToMultiByte(CP_OEMCP, 0, fcbW, 12, fcb + 1, 12, NULL, NULL);
*fcb = 0;
TRACE("FCB: '%s'\n", fcb + 1);
SET_AL( context, ((strchr(filename, '*')) || (strchr(filename, '$'))) != 0 );
/* point DS:SI to first unparsed character */
SET_SI( context, context->Esi + (int)s - (int)filename );
}
/* Many calls translate a drive argument like this:
drive number (00h = default, 01h = A:, etc)
*/
static const char *INT21_DriveName(int drive)
{
if (drive > 0) return wine_dbg_sprintf( "%c:", 'A' + drive - 1 );
return "default";
}
static HFILE16 _lcreat16_uniq( LPCSTR path, INT attr )
{
/* Mask off all flags not explicitly allowed by the doc */
attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
return Win32HandleToDosFileHandle( CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
CREATE_NEW, attr, 0 ));
}
static int INT21_FindFirst( CONTEXT86 *context )
{
char *p;
const char *path;
DOS_FULL_NAME full_name;
FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
WCHAR pathW[MAX_PATH];
WCHAR maskW[12];
path = (const char *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
MultiByteToWideChar(CP_OEMCP, 0, path, -1, pathW, MAX_PATH);
dta->unixPath = NULL;
if (!DOSFS_GetFullName( pathW, FALSE, &full_name ))
{
SET_AX( context, GetLastError() );
SET_CFLAG(context);
return 0;
}
dta->unixPath = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
strcpy( dta->unixPath, full_name.long_name );
p = strrchr( dta->unixPath, '/' );
*p = '\0';
MultiByteToWideChar(CP_OEMCP, 0, p + 1, -1, pathW, MAX_PATH);
/* Note: terminating NULL in dta->mask overwrites dta->search_attr
* (doesn't matter as it is set below anyway)
*/
if (!DOSFS_ToDosFCBFormat( pathW, maskW ))
{
HeapFree( GetProcessHeap(), 0, dta->unixPath );
dta->unixPath = NULL;
SetLastError( ERROR_FILE_NOT_FOUND );
SET_AX( context, ERROR_FILE_NOT_FOUND );
SET_CFLAG(context);
return 0;
}
WideCharToMultiByte(CP_OEMCP, 0, maskW, 12, dta->mask, sizeof(dta->mask), NULL, NULL);
dta->drive = (path[0] && (path[1] == ':')) ? toupper(path[0]) - 'A'
: DRIVE_GetCurrentDrive();
dta->count = 0;
dta->search_attr = CL_reg(context);
return 1;
}
static int INT21_FindNext( CONTEXT86 *context )
{
FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
WIN32_FIND_DATAA entry;
int count;
if (!dta->unixPath) return 0;
if (!(count = DOSFS_FindNext( dta->unixPath, dta->mask, NULL, dta->drive,
dta->search_attr, dta->count, &entry )))
{
HeapFree( GetProcessHeap(), 0, dta->unixPath );
dta->unixPath = NULL;
return 0;
}
if ((int)dta->count + count > 0xffff)
{
WARN("Too many directory entries in %s\n", dta->unixPath );
HeapFree( GetProcessHeap(), 0, dta->unixPath );
dta->unixPath = NULL;
return 0;
}
dta->count += count;
dta->fileattr = entry.dwFileAttributes;
dta->filesize = entry.nFileSizeLow;
FileTimeToDosDateTime( &entry.ftLastWriteTime,
&dta->filedate, &dta->filetime );
strcpy( dta->filename, entry.cAlternateFileName );
if (!memchr(dta->mask,'?',11)) {
/* wildcardless search, release resources in case no findnext will
* be issued, and as a workaround in case file creation messes up
* findnext, as sometimes happens with pkunzip */
HeapFree( GetProcessHeap(), 0, dta->unixPath );
dta->unixPath = NULL;
}
return 1;
}
static BOOL INT21_CreateTempFile( CONTEXT86 *context )
{
static int counter = 0;
char *name = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx );
char *p = name + strlen(name);
/* despite what Ralf Brown says, some programs seem to call without
* ending backslash (DOS accepts that, so we accept it too) */
if ((p == name) || (p[-1] != '\\')) *p++ = '\\';
for (;;)
{
sprintf( p, "wine%04x.%03d", (int)getpid(), counter );
counter = (counter + 1) % 1000;
SET_AX( context, _lcreat16_uniq( name, 0 ) );
if (AX_reg(context) != HFILE_ERROR16)
{
TRACE("created %s\n", name );
return TRUE;
}
if (GetLastError() != ERROR_FILE_EXISTS) return FALSE;
}
}
static int INT21_GetDiskSerialNumber( CONTEXT86 *context )
{
BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
int drive = DOS_GET_DRIVE( BL_reg(context) );
if (!DRIVE_IsValid(drive))
{
SetLastError( ERROR_INVALID_DRIVE );
return 0;
}
*(WORD *)dataptr = 0;
*(DWORD *)(dataptr + 2) = DRIVE_GetSerialNumber( drive );
memcpy( dataptr + 6, DRIVE_GetLabel( drive ), 11 );
strncpy(dataptr + 0x11, "FAT16 ", 8);
return 1;
}
static int INT21_SetDiskSerialNumber( CONTEXT86 *context )
{
BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
int drive = DOS_GET_DRIVE( BL_reg(context) );
if (!DRIVE_IsValid(drive))
{
SetLastError( ERROR_INVALID_DRIVE );
return 0;
}
DRIVE_SetSerialNumber( drive, *(DWORD *)(dataptr + 2) );
return 1;
}
/* microsoft's programmers should be shot for using CP/M style int21
calls in Windows for Workgroup's winfile.exe */
static int INT21_FindFirstFCB( CONTEXT86 *context )
{
BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
FINDFILE_FCB *pFCB;
LPCSTR root, cwd;
int drive;
if (*fcb == 0xff) pFCB = (FINDFILE_FCB *)(fcb + 7);
else pFCB = (FINDFILE_FCB *)fcb;
drive = DOS_GET_DRIVE( pFCB->drive );
if (!DRIVE_IsValid( drive )) return 0;
root = DRIVE_GetRoot( drive );
cwd = DRIVE_GetUnixCwd( drive );
pFCB->unixPath = HeapAlloc( GetProcessHeap(), 0,
strlen(root)+strlen(cwd)+2 );
if (!pFCB->unixPath) return 0;
strcpy( pFCB->unixPath, root );
strcat( pFCB->unixPath, "/" );
strcat( pFCB->unixPath, cwd );
pFCB->count = 0;
return 1;
}
static int INT21_FindNextFCB( CONTEXT86 *context )
{
BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
FINDFILE_FCB *pFCB;
DOS_DIRENTRY_LAYOUT *pResult = (DOS_DIRENTRY_LAYOUT *)GetCurrentDTA(context);
WIN32_FIND_DATAA entry;
BYTE attr;
int count;
if (*fcb == 0xff) /* extended FCB ? */
{
attr = fcb[6];
pFCB = (FINDFILE_FCB *)(fcb + 7);
}
else
{
attr = 0;
pFCB = (FINDFILE_FCB *)fcb;
}
if (!pFCB->unixPath) return 0;
if (!(count = DOSFS_FindNext( pFCB->unixPath, pFCB->filename, NULL,
DOS_GET_DRIVE( pFCB->drive ), attr,
pFCB->count, &entry )))
{
HeapFree( GetProcessHeap(), 0, pFCB->unixPath );
pFCB->unixPath = NULL;
return 0;
}
pFCB->count += count;
if (*fcb == 0xff) { /* place extended FCB header before pResult if called with extended FCB */
*(BYTE *)pResult = 0xff;
(BYTE *)pResult +=6; /* leave reserved field behind */
*(BYTE *)pResult = entry.dwFileAttributes;
((BYTE *)pResult)++;
}
*(BYTE *)pResult = DOS_GET_DRIVE( pFCB->drive ); /* DOS_DIRENTRY_LAYOUT after current drive number */
((BYTE *)pResult)++;
pResult->fileattr = entry.dwFileAttributes;
pResult->cluster = 0; /* what else? */
pResult->filesize = entry.nFileSizeLow;
memset( pResult->reserved, 0, sizeof(pResult->reserved) );
FileTimeToDosDateTime( &entry.ftLastWriteTime,
&pResult->filedate, &pResult->filetime );
/* Convert file name to FCB format */
memset( pResult->filename, ' ', sizeof(pResult->filename) );
if (!strcmp( entry.cAlternateFileName, "." )) pResult->filename[0] = '.';
else if (!strcmp( entry.cAlternateFileName, ".." ))
pResult->filename[0] = pResult->filename[1] = '.';
else
{
char *p = strrchr( entry.cAlternateFileName, '.' );
if (p && p[1] && (p != entry.cAlternateFileName))
{
memcpy( pResult->filename, entry.cAlternateFileName,
min( (p - entry.cAlternateFileName), 8 ) );
memcpy( pResult->filename + 8, p + 1, min( strlen(p), 3 ) );
}
else
memcpy( pResult->filename, entry.cAlternateFileName,
min( strlen(entry.cAlternateFileName), 8 ) );
}
return 1;
}
static BOOL
INT21_networkfunc (CONTEXT86 *context)
{
switch (AL_reg(context)) {
case 0x00: /* Get machine name. */
{
char *dst = CTX_SEG_OFF_TO_LIN (context,context->SegDs,context->Edx);
TRACE("getting machine name to %p\n", dst);
if (gethostname (dst, 15))
{
WARN("failed!\n");
SetLastError( ER_NoNetwork );
return TRUE;
} else {
int len = strlen (dst);
while (len < 15)
dst[len++] = ' ';
dst[15] = 0;
SET_CH( context, 1 ); /* Valid */
SET_CL( context, 1 ); /* NETbios number??? */
TRACE("returning %s\n", debugstr_an (dst, 16));
return FALSE;
}
}
default:
SetLastError( ER_NoNetwork );
return TRUE;
}
}
/***********************************************************************
* INT_Int21Handler
*/
void WINAPI INT_Int21Handler( CONTEXT86 *context )
{
BOOL bSetDOSExtendedError = FALSE;
switch(AH_reg(context))
{
case 0x11: /* FIND FIRST MATCHING FILE USING FCB */
TRACE("FIND FIRST MATCHING FILE USING FCB %p\n",
CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
if (!INT21_FindFirstFCB(context))
{
SET_AL( context, 0xff );
break;
}
/* else fall through */
case 0x12: /* FIND NEXT MATCHING FILE USING FCB */
SET_AL( context, INT21_FindNextFCB(context) ? 0x00 : 0xff );
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 0x29: /* PARSE FILENAME INTO FCB */
INT21_ParseFileNameIntoFCB(context);
break;
case 0x36: /* GET FREE DISK SPACE */
TRACE("GET FREE DISK SPACE FOR DRIVE %s\n",
INT21_DriveName( DL_reg(context)));
if (!INT21_GetFreeDiskSpace(context)) SET_AX( context, 0xffff );
break;
case 0x44: /* IOCTL */
switch (AL_reg(context))
{
case 0x0d:
TRACE("IOCTL - GENERIC BLOCK DEVICE REQUEST %s\n",
INT21_DriveName( BL_reg(context)));
bSetDOSExtendedError = ioctlGenericBlkDevReq(context);
break;
case 0x0F: /* Set logical drive mapping */
{
int drive;
TRACE("IOCTL - SET LOGICAL DRIVE MAP for drive %s\n",
INT21_DriveName( BL_reg(context)));
drive = DOS_GET_DRIVE ( BL_reg(context) );
if ( ! DRIVE_SetLogicalMapping ( drive, drive+1 ) )
{
SET_CFLAG(context);
SET_AX( context, 0x000F ); /* invalid drive */
}
break;
}
}
break;
case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
TRACE("FINDFIRST mask 0x%04x spec %s\n",CX_reg(context),
(LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
if (!INT21_FindFirst(context)) break;
/* fall through */
case 0x4f: /* "FINDNEXT" - FIND NEXT MATCHING FILE */
TRACE("FINDNEXT\n");
if (!INT21_FindNext(context))
{
SetLastError( ERROR_NO_MORE_FILES );
SET_AX( context, ERROR_NO_MORE_FILES );
SET_CFLAG(context);
}
else SET_AX( context, 0 ); /* OK */
break;
case 0x5a: /* CREATE TEMPORARY FILE */
TRACE("CREATE TEMPORARY FILE\n");
bSetDOSExtendedError = !INT21_CreateTempFile(context);
break;
case 0x5e:
bSetDOSExtendedError = INT21_networkfunc (context);
break;
case 0x5f: /* NETWORK */
switch (AL_reg(context))
{
case 0x07: /* ENABLE DRIVE */
TRACE("ENABLE DRIVE %c:\n",(DL_reg(context)+'A'));
if (!DRIVE_Enable( DL_reg(context) ))
{
SetLastError( ERROR_INVALID_DRIVE );
bSetDOSExtendedError = TRUE;
}
break;
case 0x08: /* DISABLE DRIVE */
TRACE("DISABLE DRIVE %c:\n",(DL_reg(context)+'A'));
if (!DRIVE_Disable( DL_reg(context) ))
{
SetLastError( ERROR_INVALID_DRIVE );
bSetDOSExtendedError = TRUE;
}
break;
default:
/* network software not installed */
TRACE("NETWORK function AX=%04x not implemented\n",AX_reg(context));
SetLastError( ER_NoNetwork );
bSetDOSExtendedError = TRUE;
break;
}
break;
case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */
TRACE("TRUENAME %s\n",
(LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Esi));
{
if (!GetFullPathNameA( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
context->Esi), 128,
CTX_SEG_OFF_TO_LIN(context, context->SegEs,
context->Edi),NULL))
bSetDOSExtendedError = TRUE;
else SET_AX( context, 0 );
}
break;
case 0x69: /* DISK SERIAL NUMBER */
switch (AL_reg(context))
{
case 0x00:
TRACE("GET DISK SERIAL NUMBER for drive %s\n",
INT21_DriveName(BL_reg(context)));
if (!INT21_GetDiskSerialNumber(context)) bSetDOSExtendedError = TRUE;
else SET_AX( context, 0 );
break;
case 0x01:
TRACE("SET DISK SERIAL NUMBER for drive %s\n",
INT21_DriveName(BL_reg(context)));
if (!INT21_SetDiskSerialNumber(context)) bSetDOSExtendedError = TRUE;
else SET_AX( context, 1 );
break;
}
break;
case 0x71: /* MS-DOS 7 (Windows95) - LONG FILENAME FUNCTIONS */
switch(AL_reg(context))
{
case 0x4e: /* Find first file */
TRACE(" LONG FILENAME - FIND FIRST MATCHING FILE for %s\n",
(LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx));
/* FIXME: use attributes in CX */
SET_AX( context, FindFirstFile16(
CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx),
(WIN32_FIND_DATAA *)CTX_SEG_OFF_TO_LIN(context, context->SegEs,
context->Edi)));
if (AX_reg(context) == INVALID_HANDLE_VALUE16)
bSetDOSExtendedError = TRUE;
break;
case 0x4f: /* Find next file */
TRACE("LONG FILENAME - FIND NEXT MATCHING FILE for handle %d\n",
BX_reg(context));
if (!FindNextFile16( BX_reg(context),
(WIN32_FIND_DATAA *)CTX_SEG_OFF_TO_LIN(context, context->SegEs,
context->Edi)))
bSetDOSExtendedError = TRUE;
break;
case 0xa0:
{
LPCSTR driveroot = (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx);
LPSTR buffer = (LPSTR)CTX_SEG_OFF_TO_LIN(context, context->SegEs,context->Edi);
DWORD filename_len, flags;
TRACE("LONG FILENAME - GET VOLUME INFORMATION for drive having root dir '%s'.\n", driveroot);
SET_AX( context, 0 );
if (!GetVolumeInformationA( driveroot, NULL, 0, NULL, &filename_len,
&flags, buffer, 8 ))
{
INT_BARF( context, 0x21 );
SET_CFLAG(context);
break;
}
SET_BX( context, flags | 0x4000 ); /* support for LFN functions */
SET_CX( context, filename_len );
SET_DX( context, MAX_PATH ); /* FIXME: which len if DRIVE_SHORT_NAMES ? */
}
break;
case 0xa1: /* Find close */
TRACE("LONG FILENAME - FINDCLOSE for handle %d\n",
BX_reg(context));
bSetDOSExtendedError = (!FindClose16( BX_reg(context) ));
break;
case 0x60:
switch(CL_reg(context))
{
case 0x01: /* Get short filename or path */
if (!GetShortPathNameA
( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
context->Esi),
CTX_SEG_OFF_TO_LIN(context, context->SegEs,
context->Edi), 67))
bSetDOSExtendedError = TRUE;
else SET_AX( context, 0 );
break;
case 0x02: /* Get canonical long filename or path */
if (!GetFullPathNameA
( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
context->Esi), 128,
CTX_SEG_OFF_TO_LIN(context, context->SegEs,
context->Edi),NULL))
bSetDOSExtendedError = TRUE;
else SET_AX( context, 0 );
break;
default:
FIXME("Unimplemented long file name function:\n");
INT_BARF( context, 0x21 );
SET_CFLAG(context);
SET_AL( context, 0 );
break;
}
break;
default:
FIXME("Unimplemented long file name function:\n");
INT_BARF( context, 0x21 );
SET_CFLAG(context);
SET_AL( context, 0 );
break;
}
break;
default:
INT_BARF( context, 0x21 );
break;
} /* END OF SWITCH */
if( bSetDOSExtendedError ) /* set general error condition */
{
SET_AX( context, GetLastError() );
SET_CFLAG(context);
}
}