From 3cc6704954c34f4341454307a2f4c1c3bb047f34 Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Sun, 2 May 2004 14:47:05 +0000 Subject: [PATCH] ported GetBinaryType() from wine svn path=/trunk/; revision=9279 --- reactos/include/defines.h | 1 + reactos/lib/kernel32/file/bintype.c | 337 ++++++++++++++++++++++++ reactos/lib/kernel32/include/kernel32.h | 10 + reactos/lib/kernel32/makefile | 4 +- reactos/lib/kernel32/misc/stubs.c | 31 +-- 5 files changed, 351 insertions(+), 32 deletions(-) create mode 100644 reactos/lib/kernel32/file/bintype.c diff --git a/reactos/include/defines.h b/reactos/include/defines.h index 3c6b00db51a..ffd0b5fc647 100644 --- a/reactos/include/defines.h +++ b/reactos/include/defines.h @@ -1314,6 +1314,7 @@ extern "C" { #define SCS_PIF_BINARY (3) #define SCS_POSIX_BINARY (4) #define SCS_WOW_BINARY (2) +#define SCS_64BIT_BINARY (6) /* GetBoundsRect, SetBoundsRect */ #define DCB_DISABLE (8) diff --git a/reactos/lib/kernel32/file/bintype.c b/reactos/lib/kernel32/file/bintype.c new file mode 100644 index 00000000000..fa8e6cec88e --- /dev/null +++ b/reactos/lib/kernel32/file/bintype.c @@ -0,0 +1,337 @@ +/* $Id: bintype.c,v 1.1 2004/05/02 14:47:05 weiden Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/kernel32/file/bintype.c + * PURPOSE: Binary detection functions + * PROGRAMMER: Alexandre Julliard (WINE) + * Thomas Weidenmueller (w3seek@users.sourceforge.net) + * UPDATE HISTORY: + * 02/05/2004 - Ported/Adapted from WINE + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#define NDEBUG +#include "../include/debug.h" + + +/* FUNCTIONS ****************************************************************/ + +/* Check whether a file is an OS/2 or a very old Windows executable + * by testing on import of KERNEL. + * + * FIXME: is reading the module imports the only way of discerning + * old Windows binaries from OS/2 ones ? At least it seems so... + */ +STATIC DWORD STDCALL +InternalIsOS2OrOldWin(HANDLE hFile, IMAGE_DOS_HEADER *mz, IMAGE_OS2_HEADER *ne) +{ + DWORD CurPos; + LPWORD modtab = NULL; + LPSTR nametab = NULL; + DWORD Read, Ret; + int i; + + Ret = BINARY_OS216; + CurPos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); + + /* read modref table */ + if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_modtab, NULL, FILE_BEGIN) == -1) || + (!(modtab = HeapAlloc(GetProcessHeap(), 0, ne->ne_cmod * sizeof(WORD)))) || + (!(ReadFile(hFile, modtab, ne->ne_cmod * sizeof(WORD), &Read, NULL))) || + (Read != ne->ne_cmod * sizeof(WORD))) + { + goto broken; + } + + /* read imported names table */ + if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_imptab, NULL, FILE_BEGIN) == -1) || + (!(nametab = HeapAlloc(GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab))) || + (!(ReadFile(hFile, nametab, ne->ne_enttab - ne->ne_imptab, &Read, NULL))) || + (Read != ne->ne_enttab - ne->ne_imptab)) + { + goto broken; + } + + for(i = 0; i < ne->ne_cmod; i++) + { + LPSTR module; + module = &nametab[modtab[i]]; + if(!strncmp(&module[1], "KERNEL", module[0])) + { + /* very old windows file */ + Ret = BINARY_WIN16; + goto done; + } + } + + broken: + DPRINT("InternalIsOS2OrOldWin(): Binary file seems to be broken\n"); + + done: + HeapFree(GetProcessHeap(), 0, modtab); + HeapFree(GetProcessHeap(), 0, nametab); + SetFilePointer(hFile, CurPos, NULL, FILE_BEGIN); + return Ret; +} + +STATIC DWORD STDCALL +InternalGetBinaryType(HANDLE hFile) +{ + union + { + struct + { + unsigned char magic[4]; + unsigned char ignored[12]; + unsigned short type; + } elf; + struct + { + unsigned long magic; + unsigned long cputype; + unsigned long cpusubtype; + unsigned long filetype; + } macho; + IMAGE_DOS_HEADER mz; + } Header; + char magic[4]; + DWORD Read; + + if((SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == -1) || + (!ReadFile(hFile, &Header, sizeof(Header), &Read, NULL) || + (Read != sizeof(Header)))) + { + return BINARY_UNKNOWN; + } + + if(!memcmp(Header.elf.magic, "\177ELF", sizeof(Header.elf.magic))) + { + /* FIXME: we don't bother to check byte order, architecture, etc. */ + switch(Header.elf.type) + { + case 2: + return BINARY_UNIX_EXE; + case 3: + return BINARY_UNIX_LIB; + } + return BINARY_UNKNOWN; + } + + /* Mach-o File with Endian set to Big Endian or Little Endian*/ + if(Header.macho.magic == 0xFEEDFACE || + Header.macho.magic == 0xECAFDEEF) + { + switch(Header.macho.filetype) + { + case 0x8: + /* MH_BUNDLE */ + return BINARY_UNIX_LIB; + } + return BINARY_UNKNOWN; + } + + /* Not ELF, try DOS */ + if(Header.mz.e_magic == IMAGE_DOS_SIGNATURE) + { + /* We do have a DOS image so we will now try to seek into + * the file by the amount indicated by the field + * "Offset to extended header" and read in the + * "magic" field information at that location. + * This will tell us if there is more header information + * to read or not. + */ + if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == -1) || + (!ReadFile(hFile, magic, sizeof(magic), &Read, NULL) || + (Read != sizeof(magic)))) + { + return BINARY_DOS; + } + + /* Reading the magic field succeeded so + * we will try to determine what type it is. + */ + if(!memcmp(magic, "PE\0\0", sizeof(magic))) + { + IMAGE_FILE_HEADER FileHeader; + if(!ReadFile(hFile, &FileHeader, sizeof(IMAGE_FILE_HEADER), &Read, NULL) || + (Read == sizeof(IMAGE_FILE_HEADER))) + { + return BINARY_DOS; + } + + /* FIXME - detect 32/64 bit */ + + if(FileHeader.Characteristics & IMAGE_FILE_DLL) + return BINARY_PE_DLL32; + return BINARY_PE_EXE32; + } + + if(!memcmp(magic, "NE", 1)) + { + /* This is a Windows executable (NE) header. This can + * mean either a 16-bit OS/2 or a 16-bit Windows or even a + * DOS program (running under a DOS extender). To decide + * which, we'll have to read the NE header. + */ + IMAGE_OS2_HEADER ne; + if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == 1) || + !ReadFile(hFile, &ne, sizeof(IMAGE_OS2_HEADER), &Read, NULL) || + (Read == sizeof(IMAGE_OS2_HEADER))) + { + /* Couldn't read header, so abort. */ + return BINARY_DOS; + } + + switch(ne.ne_exetyp) + { + case 2: + return BINARY_WIN16; + case 5: + return BINARY_DOS; + default: + return InternalIsOS2OrOldWin(hFile, &Header.mz, &ne); + } + } + return BINARY_DOS; + } + return BINARY_UNKNOWN; +} + +/* + * @implemented + */ +BOOL +STDCALL +GetBinaryTypeW ( + LPCWSTR lpApplicationName, + LPDWORD lpBinaryType + ) +{ + HANDLE hFile; + DWORD BinType; + + if(!lpApplicationName || !lpBinaryType) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + hFile = CreateFileW(lpApplicationName, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, 0); + if(hFile == INVALID_HANDLE_VALUE) + { + return FALSE; + } + + BinType = InternalGetBinaryType(hFile); + CloseHandle(hFile); + + switch(BinType) + { + case BINARY_UNKNOWN: + { + WCHAR *dot; + + /* + * guess from filename + */ + if(!(dot = wcsrchr(lpApplicationName, L'.'))) + { + return FALSE; + } + if(!lstrcmpiW(dot, L".COM")) + { + *lpBinaryType = SCS_DOS_BINARY; + return TRUE; + } + if(!lstrcmpiW(dot, L".PIF")) + { + *lpBinaryType = SCS_PIF_BINARY; + return TRUE; + } + return FALSE; + } + case BINARY_PE_EXE32: + case BINARY_PE_DLL32: + { + *lpBinaryType = SCS_32BIT_BINARY; + return TRUE; + } + case BINARY_PE_EXE64: + case BINARY_PE_DLL64: + { + *lpBinaryType = SCS_64BIT_BINARY; + return TRUE; + } + case BINARY_WIN16: + { + *lpBinaryType = SCS_WOW_BINARY; + return TRUE; + } + case BINARY_OS216: + { + *lpBinaryType = SCS_OS216_BINARY; + return TRUE; + } + case BINARY_DOS: + { + *lpBinaryType = SCS_DOS_BINARY; + return TRUE; + } + case BINARY_UNIX_EXE: + case BINARY_UNIX_LIB: + { + return FALSE; + } + } + + DPRINT1("Invalid binary type returned!\n", BinType); + return FALSE; +} + + +/* + * @implemented + */ +BOOL +STDCALL +GetBinaryTypeA ( + LPCSTR lpApplicationName, + LPDWORD lpBinaryType + ) +{ + ANSI_STRING FileNameA; + UNICODE_STRING FileName; + NTSTATUS Status; + BOOL Ret; + + if(!lpApplicationName || !lpBinaryType) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + RtlInitAnsiString(&FileNameA, (LPSTR)lpApplicationName); + + if(bIsFileApiAnsi) + Status = RtlAnsiStringToUnicodeString(&FileName, &FileNameA, TRUE); + else + Status = RtlOemStringToUnicodeString(&FileName, &FileNameA, TRUE); + if(!NT_SUCCESS(Status)) + { + SetLastErrorByStatus(Status); + return FALSE; + } + + Ret = GetBinaryTypeW(FileName.Buffer, lpBinaryType); + + RtlFreeUnicodeString(&FileName); + return Ret; +} + +/* EOF */ diff --git a/reactos/lib/kernel32/include/kernel32.h b/reactos/lib/kernel32/include/kernel32.h index 66ec9d1faf9..41ecdfcb3ce 100755 --- a/reactos/lib/kernel32/include/kernel32.h +++ b/reactos/lib/kernel32/include/kernel32.h @@ -1,6 +1,16 @@ #ifndef _KERNEL32_INCLUDE_KERNEL32_H #define _KERNEL32_INCLUDE_KERNEL32_H +#define BINARY_UNKNOWN (0) +#define BINARY_PE_EXE32 (1) +#define BINARY_PE_DLL32 (2) +#define BINARY_PE_EXE64 (3) +#define BINARY_PE_DLL64 (4) +#define BINARY_WIN16 (5) +#define BINARY_OS216 (6) +#define BINARY_DOS (7) +#define BINARY_UNIX_EXE (8) +#define BINARY_UNIX_LIB (9) #define MAGIC(c1,c2,c3,c4) ((c1) + ((c2)<<8) + ((c3)<<16) + ((c4)<<24)) diff --git a/reactos/lib/kernel32/makefile b/reactos/lib/kernel32/makefile index 30af6359d4d..ba3a3f9ee0a 100644 --- a/reactos/lib/kernel32/makefile +++ b/reactos/lib/kernel32/makefile @@ -1,4 +1,4 @@ -# $Id: makefile,v 1.78 2004/03/14 09:21:41 weiden Exp $ +# $Id: makefile,v 1.79 2004/05/02 14:47:05 weiden Exp $ PATH_TO_TOP = ../.. @@ -41,7 +41,7 @@ FILE_OBJECTS = file/file.o file/curdir.o file/lfile.o file/dir.o \ file/create.o file/find.o file/copy.o file/pipe.o \ file/move.o file/lock.o file/rw.o file/delete.o \ file/npipe.o file/tape.o file/mailslot.o file/backup.o \ - file/cnotify.o file/hardlink.o + file/cnotify.o file/hardlink.o file/bintype.o MEM_OBJECTS = mem/global.o mem/heap.o mem/isbad.o mem/local.o \ mem/procmem.o mem/section.o mem/virtual.o diff --git a/reactos/lib/kernel32/misc/stubs.c b/reactos/lib/kernel32/misc/stubs.c index 6bb2e5d607b..974b5d46cc5 100644 --- a/reactos/lib/kernel32/misc/stubs.c +++ b/reactos/lib/kernel32/misc/stubs.c @@ -1,4 +1,4 @@ -/* $Id: stubs.c,v 1.73 2004/04/22 02:20:52 jimtabor Exp $ +/* $Id: stubs.c,v 1.74 2004/05/02 14:47:05 weiden Exp $ * * KERNEL32.DLL stubs (unimplemented functions) * Remove from this file, if you implement them. @@ -171,35 +171,6 @@ FreeVirtualBuffer ( return FALSE; } -/* - * @unimplemented - */ -BOOL -STDCALL -GetBinaryTypeW ( - LPCWSTR lpApplicationName, - LPDWORD lpBinaryType - ) -{ - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - - -/* - * @unimplemented - */ -BOOL -STDCALL -GetBinaryTypeA ( - LPCSTR lpApplicationName, - LPDWORD lpBinaryType - ) -{ - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - #ifndef _OLE2NLS_IN_BUILD_