| /* |
| * Win32 kernel functions |
| * |
| * Copyright 1995 Martin von Loewis, Sven Verdoolaege, and Cameron Heide |
| */ |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/mman.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <time.h> |
| #include "windows.h" |
| #include "winbase.h" |
| #include "winerror.h" |
| #include "handle32.h" |
| #include "dos_fs.h" |
| #include "stddebug.h" |
| #define DEBUG_WIN32 |
| #include "debug.h" |
| |
| |
| extern FILE_OBJECT *hstdin; |
| extern FILE_OBJECT *hstdout; |
| extern FILE_OBJECT *hstderr; |
| |
| static void UnixTimeToFileTime(time_t unix_time, FILETIME *filetime); |
| static int TranslateCreationFlags(DWORD create_flags); |
| static int TranslateAccessFlags(DWORD access_flags); |
| #ifndef MAP_ANON |
| #define MAP_ANON 0 |
| #endif |
| |
| /*********************************************************************** |
| * OpenFileMappingA (KERNEL32.397) |
| * |
| */ |
| HANDLE32 OpenFileMapping(DWORD access, BOOL inherit,const char *fname) |
| { |
| return 0; |
| } |
| /*********************************************************************** |
| * CreateFileMappingA (KERNEL32.46) |
| * |
| */ |
| int TranslateProtectionFlags(DWORD); |
| HANDLE32 CreateFileMapping(HANDLE32 h,SECURITY_ATTRIBUTES *ats, |
| DWORD pot, DWORD sh, DWORD hlow, const char * lpName ) |
| { |
| FILE_OBJECT *file_obj; |
| FILEMAP_OBJECT *filemap_obj; |
| int fd; |
| |
| if (sh) |
| { |
| SetLastError(ErrnoToLastError(errno)); |
| return INVALID_HANDLE_VALUE; |
| } |
| fd = open(lpName, O_CREAT, 0666); |
| if(fd == -1) |
| { |
| SetLastError(ErrnoToLastError(errno)); |
| return INVALID_HANDLE_VALUE; |
| } |
| file_obj = (FILE_OBJECT *) |
| CreateKernelObject(sizeof(FILE_OBJECT)); |
| if(file_obj == NULL) |
| { |
| SetLastError(ERROR_UNKNOWN); |
| return 0; |
| } |
| filemap_obj = (FILEMAP_OBJECT *) |
| CreateKernelObject(sizeof(FILEMAP_OBJECT)); |
| if(filemap_obj == NULL) |
| { |
| ReleaseKernelObject(file_obj); |
| SetLastError(ERROR_UNKNOWN); |
| return 0; |
| } |
| file_obj->common.magic = KERNEL_OBJECT_FILE; |
| file_obj->fd = fd; |
| file_obj->type = FILE_TYPE_DISK; |
| filemap_obj->common.magic = KERNEL_OBJECT_FILEMAP; |
| filemap_obj->file_obj = file_obj; |
| filemap_obj->prot = TranslateProtectionFlags(pot); |
| filemap_obj->size = hlow; |
| return (HANDLE32)filemap_obj;; |
| } |
| |
| /*********************************************************************** |
| * MapViewOfFileEx (KERNEL32.386) |
| * |
| */ |
| void *MapViewOfFileEx(HANDLE32 handle, DWORD access, DWORD offhi, |
| DWORD offlo, DWORD size, DWORD st) |
| { |
| if (!size) size = ((FILEMAP_OBJECT *)handle)->size; |
| return mmap ((caddr_t)st, size, ((FILEMAP_OBJECT *)handle)->prot, |
| MAP_ANON|MAP_PRIVATE, |
| ((FILEMAP_OBJECT *)handle)->file_obj->fd, |
| offlo); |
| } |
| |
| /*********************************************************************** |
| * GetFileInformationByHandle (KERNEL32.219) |
| * |
| */ |
| DWORD GetFileInformationByHandle(FILE_OBJECT *hFile, |
| BY_HANDLE_FILE_INFORMATION *lpfi) |
| { |
| struct stat file_stat; |
| int rc; |
| |
| if(ValidateKernelObject((HANDLE32)hFile) != 0) |
| { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return 0; |
| } |
| if(hFile->common.magic != KERNEL_OBJECT_FILE) |
| { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return 0; |
| } |
| |
| rc = fstat(hFile->fd, &file_stat); |
| if(rc == -1) |
| { |
| SetLastError(ErrnoToLastError(errno)); |
| return 0; |
| } |
| |
| /* Translate the file attributes. |
| */ |
| lpfi->dwFileAttributes = 0; |
| if(file_stat.st_mode & S_IFREG) |
| lpfi->dwFileAttributes |= FILE_ATTRIBUTE_NORMAL; |
| if(file_stat.st_mode & S_IFDIR) |
| lpfi->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; |
| if((file_stat.st_mode & S_IWRITE) == 0) |
| lpfi->dwFileAttributes |= FILE_ATTRIBUTE_READONLY; |
| |
| /* Translate the file times. Use the last modification time |
| * for both the creation time and write time. |
| */ |
| UnixTimeToFileTime(file_stat.st_mtime, &(lpfi->ftCreationTime)); |
| UnixTimeToFileTime(file_stat.st_mtime, &(lpfi->ftLastWriteTime)); |
| UnixTimeToFileTime(file_stat.st_atime, &(lpfi->ftLastAccessTime)); |
| |
| lpfi->nFileSizeLow = file_stat.st_size; |
| lpfi->nNumberOfLinks = file_stat.st_nlink; |
| lpfi->nFileIndexLow = file_stat.st_ino; |
| |
| /* Zero out currently unused fields. |
| */ |
| lpfi->dwVolumeSerialNumber = 0; |
| lpfi->nFileSizeHigh = 0; |
| lpfi->nFileIndexHigh = 0; |
| |
| return 1; |
| } |
| |
| |
| static void UnixTimeToFileTime(time_t unix_time, FILETIME *filetime) |
| { |
| /* This isn't anywhere close to being correct, but should |
| * work for now. |
| */ |
| filetime->dwLowDateTime = (unix_time & 0x0000FFFF) << 16; |
| filetime->dwHighDateTime = (unix_time & 0xFFFF0000) >> 16; |
| } |
| |
| |
| /*********************************************************************** |
| * GetFileType (KERNEL32.222) |
| * |
| * GetFileType currently only supports stdin, stdout, and stderr, which |
| * are considered to be of type FILE_TYPE_CHAR. |
| */ |
| DWORD GetFileType(FILE_OBJECT *hFile) |
| { |
| if(ValidateKernelObject((HANDLE32)hFile) != 0) |
| { |
| SetLastError(ERROR_UNKNOWN); |
| return FILE_TYPE_UNKNOWN; |
| } |
| if(hFile->common.magic != KERNEL_OBJECT_FILE) |
| { |
| SetLastError(ERROR_UNKNOWN); |
| return FILE_TYPE_UNKNOWN; |
| } |
| |
| return hFile->type; |
| } |
| |
| /*********************************************************************** |
| * GetStdHandle (KERNEL32.276) |
| */ |
| HANDLE32 GetStdHandle(DWORD nStdHandle) |
| { |
| HANDLE32 rc; |
| |
| switch(nStdHandle) |
| { |
| case STD_INPUT_HANDLE: |
| rc = (HANDLE32)hstdin; |
| break; |
| |
| case STD_OUTPUT_HANDLE: |
| rc = (HANDLE32)hstdout; |
| break; |
| |
| case STD_ERROR_HANDLE: |
| rc = (HANDLE32)hstderr; |
| break; |
| |
| default: |
| rc = INVALID_HANDLE_VALUE; |
| SetLastError(ERROR_INVALID_HANDLE); |
| break; |
| } |
| |
| return rc; |
| } |
| |
| /*********************************************************************** |
| * SetFilePointer (KERNEL32.492) |
| * |
| * Luckily enough, this function maps almost directly into an lseek |
| * call, the exception being the use of 64-bit offsets. |
| */ |
| DWORD SetFilePointer(FILE_OBJECT *hFile, LONG distance, LONG *highword, |
| DWORD method) |
| { |
| int rc; |
| |
| if(ValidateKernelObject((HANDLE32)hFile) != 0) |
| { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return ((DWORD)0xFFFFFFFF); |
| } |
| if(hFile->common.magic != KERNEL_OBJECT_FILE) |
| { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return ((DWORD)0xFFFFFFFF); |
| } |
| |
| if(highword != NULL) |
| { |
| if(*highword != 0) |
| { |
| dprintf_win32(stddeb, "SetFilePointer: 64-bit offsets not yet supported.\n"); |
| return -1; |
| } |
| } |
| |
| rc = lseek(hFile->fd, distance, method); |
| if(rc == -1) |
| SetLastError(ErrnoToLastError(errno)); |
| return rc; |
| } |
| |
| /*********************************************************************** |
| * WriteFile (KERNEL32.578) |
| */ |
| BOOL WriteFile(FILE_OBJECT *hFile, LPVOID lpBuffer, DWORD numberOfBytesToWrite, |
| LPDWORD numberOfBytesWritten, LPOVERLAPPED lpOverlapped) |
| { |
| int written; |
| |
| if(ValidateKernelObject((HANDLE32)hFile) != 0) |
| { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return 0; |
| } |
| if(hFile->common.magic != KERNEL_OBJECT_FILE) |
| { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return 0; |
| } |
| |
| written = write(hFile->fd, lpBuffer, numberOfBytesToWrite); |
| if(numberOfBytesWritten) |
| *numberOfBytesWritten = written; |
| |
| return 1; |
| } |
| |
| /*********************************************************************** |
| * ReadFile (KERNEL32.428) |
| */ |
| BOOL ReadFile(FILE_OBJECT *hFile, LPVOID lpBuffer, DWORD numtoread, |
| LPDWORD numread, LPOVERLAPPED lpOverlapped) |
| { |
| int actual_read; |
| |
| if(ValidateKernelObject((HANDLE32)hFile) != 0) |
| { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return 0; |
| } |
| if(hFile->common.magic != KERNEL_OBJECT_FILE) |
| { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return 0; |
| } |
| |
| actual_read = read(hFile->fd, lpBuffer, numtoread); |
| if(actual_read == -1) |
| { |
| SetLastError(ErrnoToLastError(errno)); |
| return 0; |
| } |
| if(numread) |
| *numread = actual_read; |
| |
| return 1; |
| } |
| |
| /************************************************************************* |
| * CreateFile (KERNEL32.45) |
| * |
| * Doesn't support character devices, pipes, template files, or a |
| * lot of the 'attributes' flags yet. |
| */ |
| HANDLE32 CreateFileA(LPSTR filename, DWORD access, DWORD sharing, |
| LPSECURITY_ATTRIBUTES security, DWORD creation, |
| DWORD attributes, HANDLE32 template) |
| { |
| int access_flags, create_flags; |
| int fd; |
| FILE_OBJECT *file_obj; |
| int type; |
| |
| /* Translate the various flags to Unix-style. |
| */ |
| access_flags = TranslateAccessFlags(access); |
| create_flags = TranslateCreationFlags(creation); |
| |
| if(template) |
| dprintf_win32(stddeb, "CreateFile: template handles not supported.\n"); |
| |
| /* If the name starts with '\\?' or '\\.', ignore the first 3 chars. |
| */ |
| if(!strncmp(filename, "\\\\?", 3) || !strncmp(filename, "\\\\.", 3)) |
| filename += 3; |
| |
| /* If the name still starts with '\\', it's a UNC name. |
| */ |
| if(!strncmp(filename, "\\\\", 2)) |
| { |
| dprintf_win32(stddeb, "CreateFile: UNC names not supported.\n"); |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); |
| return INVALID_HANDLE_VALUE; |
| } |
| |
| /* If the name is either CONIN$ or CONOUT$, give them stdin |
| * or stdout, respectively. |
| */ |
| if(!strcmp(filename, "CONIN$")) |
| { |
| type = FILE_TYPE_CHAR; |
| fd = 0; |
| } |
| else if(!strcmp(filename, "CONOUT$")) |
| { |
| type = FILE_TYPE_CHAR; |
| fd = 1; |
| } |
| else |
| { |
| const char *unixName = DOSFS_GetUnixFileName( filename, FALSE ); |
| type = FILE_TYPE_DISK; |
| |
| /* Try to open the file. |
| */ |
| if (!unixName || |
| ((fd = open(unixName, access_flags | create_flags, 0666)) == -1)) |
| { |
| SetLastError(ErrnoToLastError(errno)); |
| return INVALID_HANDLE_VALUE; |
| } |
| } |
| |
| /* We seem to have succeeded, so allocate a kernel object |
| * and set it up. |
| */ |
| file_obj = (FILE_OBJECT *)CreateKernelObject(sizeof(FILE_OBJECT)); |
| if(file_obj == NULL) |
| { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return INVALID_HANDLE_VALUE; |
| } |
| file_obj->common.magic = KERNEL_OBJECT_FILE; |
| file_obj->fd = fd; |
| file_obj->type = type; |
| file_obj->misc_flags = attributes; |
| file_obj->access_flags = access_flags; |
| file_obj->create_flags = create_flags; |
| |
| return (HANDLE32)file_obj; |
| } |
| |
| /************************************************************************* |
| * W32_SetHandleCount (KERNEL32.??) |
| * |
| */ |
| UINT W32_SetHandleCount(UINT cHandles) |
| { |
| return SetHandleCount(cHandles); |
| } |
| |
| int CloseFileHandle(FILE_OBJECT *hFile) |
| { |
| /* If it's one of the 3 standard handles, don't really |
| * close it. |
| */ |
| if(hFile->fd > 2) |
| close(hFile->fd); |
| |
| return 1; |
| } |
| |
| static int TranslateAccessFlags(DWORD access_flags) |
| { |
| int rc = 0; |
| |
| switch(access_flags) |
| { |
| case GENERIC_READ: |
| rc = O_RDONLY; |
| break; |
| |
| case GENERIC_WRITE: |
| rc = O_WRONLY; |
| break; |
| |
| case (GENERIC_READ | GENERIC_WRITE): |
| rc = O_RDWR; |
| break; |
| } |
| |
| return rc; |
| } |
| |
| static int TranslateCreationFlags(DWORD create_flags) |
| { |
| int rc = 0; |
| |
| switch(create_flags) |
| { |
| case CREATE_NEW: |
| rc = O_CREAT | O_EXCL; |
| break; |
| |
| case CREATE_ALWAYS: |
| rc = O_CREAT | O_TRUNC; |
| break; |
| |
| case OPEN_EXISTING: |
| rc = 0; |
| break; |
| |
| case OPEN_ALWAYS: |
| rc = O_CREAT; |
| break; |
| |
| case TRUNCATE_EXISTING: |
| rc = O_TRUNC; |
| break; |
| } |
| |
| return rc; |
| } |
| |
| /************************************************************************** |
| * GetFileAttributes |
| */ |
| DWORD GetFileAttributesA(LPCSTR lpFileName) |
| { |
| struct stat buf; |
| DWORD res=0; |
| char *fn; |
| |
| dprintf_win32(stddeb,"GetFileAttributesA(%s)\n",lpFileName); |
| fn=DOSFS_GetUnixFileName(lpFileName,FALSE); |
| /* fn points to a static buffer, don't free it */ |
| if(stat(fn,&buf)==-1) { |
| SetLastError(ErrnoToLastError(errno)); |
| return 0xFFFFFFFF; |
| } |
| if(buf.st_mode & S_IFREG) |
| res |= FILE_ATTRIBUTE_NORMAL; |
| if(buf.st_mode & S_IFDIR) |
| res |= FILE_ATTRIBUTE_DIRECTORY; |
| if((buf.st_mode & S_IWRITE) == 0) |
| res |= FILE_ATTRIBUTE_READONLY; |
| return res; |
| } |
| |
| /************************************************************************** |
| * SetFileAttributes |
| */ |
| BOOL SetFileAttributes32A(LPCSTR lpFileName, DWORD attributes) |
| |
| { |
| struct stat buf; |
| DWORD res=0; |
| char *fn; |
| |
| fprintf(stdnimp,"Call to stub function SetFileAttributesA(%s, %08x)\n",lpFileName, attributes); |
| return TRUE; |
| } |
| |