/* $Id: hmfile.cpp,v 1.46 2004-04-02 15:14:54 sandervl Exp $ */ /* * File IO win32 apis * * Copyright 1999-2000 Sander van Leeuwen * * * Project Odin Software License can be found in LICENSE.TXT * */ /***************************************************************************** * Remark * ***************************************************************************** */ //#define DEBUG_LOCAL #ifdef DEBUG_LOCAL # define dprintfl(a) dprintf(a) #else inline void ignore_dprintf(...){} # define dprintfl(a) ignore_dprintf(a) #endif /***************************************************************************** * Includes * *****************************************************************************/ #include #include #include "HandleManager.h" #include "HMFile.h" #include "mmap.h" #include "oslibdos.h" #include #define DBG_LOCALLOG DBG_hmfile #include "dbglocal.h" static void ParsePath(LPCSTR lpszFileName, LPSTR lpszParsedFileName, DWORD length); class HMFileInfo { public: HMFileInfo(HANDLE hFile, LPSTR lpszFileName, PVOID lpSecurityAttributes); ~HMFileInfo(); char *lpszFileName; PVOID lpSecurityAttributes; DWORD dwLXOffset; }; /***************************************************************************** * Name : DWORD HMDeviceFileClass::CreateFile * Purpose : this is called from the handle manager if a CreateFile() is * performed on a handle * Parameters: LPCSTR lpFileName name of the file / device * PHMHANDLEDATA pHMHandleData data of the NEW handle * PVOID lpSecurityAttributes ignored * PHMHANDLEDATA pHMHandleDataTemplate data of the template handle * Variables : * Result : * Remark : * Status : NO_ERROR - API succeeded * other - what is to be set in SetLastError * * Author : Patrick Haller [Wed, 1998/02/11 20:44] *****************************************************************************/ DWORD HMDeviceFileClass::CreateFile (LPCSTR lpFileName, PHMHANDLEDATA pHMHandleData, PVOID lpSecurityAttributes, PHMHANDLEDATA pHMHandleDataTemplate) { HFILE hFile; HFILE hTemplate; char filepath[260]; dprintfl(("KERNEL32: HMDeviceFileClass::CreateFile %s(%s,%08x,%08x,%08x)\n", lpHMDeviceName, lpFileName, pHMHandleData, lpSecurityAttributes, pHMHandleDataTemplate)); ParsePath(lpFileName, filepath, sizeof(filepath)); //convert to long file name if in 8.3 hashed format GetLongPathNameA(filepath, filepath, sizeof(filepath)); lpFileName = filepath; // create from template if (pHMHandleDataTemplate != NULL) hTemplate = pHMHandleDataTemplate->hHMHandle; else hTemplate = 0; //TODO: FILE_SHARE_DELETE hFile = OSLibDosCreateFile((LPSTR)lpFileName, pHMHandleData->dwAccess, pHMHandleData->dwShare, (LPSECURITY_ATTRIBUTES)lpSecurityAttributes, pHMHandleData->dwCreation, pHMHandleData->dwFlags, hTemplate); if (hFile != INVALID_HANDLE_ERROR) { pHMHandleData->dwUserData = (DWORD) new HMFileInfo(hFile, (LPSTR)lpFileName, lpSecurityAttributes); pHMHandleData->hHMHandle = hFile; return (NO_ERROR); } else { dprintf(("CreateFile failed; error %d", GetLastError())); return(GetLastError()); } } /***************************************************************************** * Name : DWORD HMDeviceFileClass::OpenFile * Purpose : this is called from the handle manager if a OpenFile() is * performed on a handle * Parameters: LPCSTR lpFileName name of the file / device * PHMHANDLEDATA pHMHandleData data of the NEW handle * PVOID lpSecurityAttributes ignored * PHMHANDLEDATA pHMHandleDataTemplate data of the template handle * Variables : * Result : * Remark : TODO: Check if this implementation is complete and 100% correct * UTC Time or Localtime ? * GetFileTime is changed, Returns UTC-time yet !!!!! * Status : NO_ERROR - API succeeded * other - what is to be set in SetLastError * * Author : Patrick Haller [Wed, 1998/02/11 20:44] *****************************************************************************/ DWORD HMDeviceFileClass::OpenFile (LPCSTR lpszFileName, PHMHANDLEDATA pHMHandleData, OFSTRUCT *pOFStruct, UINT fuMode) { HFILE hFile; FILETIME filetime; WORD filedatetime[2]; char filepath[260]; LPSTR lpFileName = (LPSTR)lpszFileName; SetLastError(ERROR_SUCCESS); //Re-open using name in OFSTRUCT if(fuMode & OF_REOPEN) lpFileName = (LPSTR)pOFStruct->szPathName; else memset(pOFStruct, 0, sizeof(OFSTRUCT)); dprintf(("KERNEL32: HMDeviceFileClass::OpenFile %s(%s,%08x,%08x,%08x)", lpHMDeviceName, lpFileName, pHMHandleData, pOFStruct, fuMode)); if(lpFileName == NULL) { dprintf(("Invalid name (NULL)!")); SetLastError(ERROR_INVALID_NAME); return HFILE_ERROR; } if(!strchr(lpFileName, ':') && !strchr(lpFileName, '\\')) { //filename only; search for file in following order //1: dir from which the app loaded //2: current dir //3: windows system dir //4: windows dir //5: dirs in path path environment variable //SearchPath does exactly that LPSTR filenameinpath; if (SearchPathA(NULL, lpFileName, NULL, sizeof(filepath), filepath, &filenameinpath) == 0) { if (!(fuMode & (OF_CREATE | OF_PARSE))) { pOFStruct->nErrCode = ERROR_FILE_NOT_FOUND; /* What about initializing the struct? */ SetLastError(ERROR_FILE_NOT_FOUND); return HFILE_ERROR; } /* * OF_PARSE | OF_CREATE: * Assume file in current directory. */ GetCurrentDirectoryA(sizeof(filepath), filepath); strcat(strcat(filepath, "\\"), lpFileName); GetLongPathNameA(filepath, filepath, sizeof(filepath)); } lpFileName = filepath; } else { #if 1 /* Canonicalize the path should be the right thing to do I think... */ GetFullPathNameA(lpFileName, sizeof(filepath), filepath, NULL); #else ParsePath(lpFileName, filepath, sizeof(filepath)); #endif //convert to long file name if in 8.3 hashed format GetLongPathNameA(filepath, filepath, sizeof(filepath)); lpFileName = filepath; } // filling OFSTRUCT pOFStruct->cBytes = sizeof(OFSTRUCT); pOFStruct->nErrCode = 0; strncpy((char *)pOFStruct->szPathName, lpFileName, OFS_MAXPATHNAME); pOFStruct->szPathName[OFS_MAXPATHNAME-1] = 0; /* * Do the parse stuff now and do a quick exit. * Based on testcase (5) and MSDN: * "OF_PARSE Fills the OFSTRUCT structure but carries out no other action." */ if (fuMode & OF_PARSE) { CHAR szDrive[4]; *(PULONG)&szDrive[0] = *(PULONG)&pOFStruct->szPathName[0]; szDrive[3] = '\0'; pOFStruct->fFixedDisk = (GetDriveTypeA(szDrive) != DRIVE_REMOVABLE); SetLastError(NO_ERROR); return NO_ERROR; } hFile = OSLibDosOpenFile((LPSTR)lpFileName, fuMode); if(hFile != INVALID_HANDLE_ERROR) { //Needed for GetFileTime pHMHandleData->hHMHandle = hFile; GetFileTime(pHMHandleData, NULL, NULL, &filetime ); /* UTC Time or Localtime ? GetFileTime Returns UTC-time yet ? !!!!! */ FileTimeToDosDateTime(&filetime, &filedatetime[0], &filedatetime[1] ); memcpy(pOFStruct->reserved, filedatetime, sizeof(pOFStruct->reserved)); if(fuMode & OF_DELETE) { OSLibDosClose(hFile); OSLibDosDelete((LPSTR)lpFileName); } else if(fuMode & OF_EXIST) { OSLibDosClose(hFile); hFile = HFILE_ERROR; } if((fuMode & OF_VERIFY)) {//TODO: what's this?? we copy the time above... if(memcmp(pOFStruct->reserved, filedatetime, sizeof(pOFStruct->reserved))) { OSLibDosClose(hFile); SetLastError(ERROR_FILE_NOT_FOUND); } hFile = HFILE_ERROR; } pOFStruct->nErrCode = GetLastError(); pHMHandleData->hHMHandle = hFile; if(hFile != HFILE_ERROR) { pHMHandleData->dwUserData = (DWORD) new HMFileInfo(hFile, (LPSTR)lpFileName, NULL); } return (NO_ERROR); } else { DWORD rc = GetLastError(); if(fuMode & OF_EXIST) { if(rc == ERROR_OPEN_FAILED) { SetLastError(ERROR_FILE_NOT_FOUND); } } //todo: OF_PROMPT handling (pop up message box) } // error branch pOFStruct->nErrCode = GetLastError(); dprintf(("KERNEL32: HMDeviceFileClass::OpenFile Error %08xh\n", pOFStruct->nErrCode)); // return != NO_ERROR => error code return(hFile); } /***************************************************************************** * Name : HMDeviceFileClass::DuplicateHandle * Purpose : * Parameters: * various parameters as required * Variables : * Result : * Remark : DUPLICATE_CLOSE_SOURCE flag handled in HMDuplicateHandle * * Status : partially implemented * * Author : SvL *****************************************************************************/ BOOL HMDeviceFileClass::DuplicateHandle(HANDLE srchandle, PHMHANDLEDATA pHMHandleData, HANDLE srcprocess, PHMHANDLEDATA pHMSrcHandle, HANDLE destprocess, DWORD fdwAccess, BOOL fInherit, DWORD fdwOptions, DWORD fdwOdinOptions) { HMFileInfo *srcfileinfo = (HMFileInfo *)pHMSrcHandle->dwUserData; DWORD rc; dprintf(("KERNEL32:HMDeviceFileClass::DuplicateHandle (%08x,%08x,%08x,%08x)", pHMHandleData, srcprocess, pHMSrcHandle->hHMHandle, destprocess)); //TODO: Inheritance of file handles won't work! if(destprocess != srcprocess) { //TODO:!!!! dprintf(("ERROR: DuplicateHandle; different processes not yet supported!!")); return FALSE; } if(srcfileinfo) { //SvL: Special duplicatehandle option used by memory mapped class to duplicate // file handle // Can't use DosDupHandle or else there can be a sharing violation // when an app tries to access the same file again if(fdwOdinOptions) { HMHANDLEDATA duphdata; memcpy(&duphdata, pHMHandleData, sizeof(duphdata)); duphdata.dwCreation = OPEN_EXISTING; if(CreateFile(srcfileinfo->lpszFileName, &duphdata, srcfileinfo->lpSecurityAttributes, NULL) == NO_ERROR) { memcpy(pHMHandleData, &duphdata, sizeof(duphdata)); SetHandleInformation(pHMHandleData, HANDLE_FLAG_INHERIT, (fInherit) ? HANDLE_FLAG_INHERIT : 0); SetLastError(ERROR_SUCCESS); return TRUE; } dprintf(("ERROR: DuplicateHandle; CreateFile %s failed -> trying DosDupHandle instead!", srcfileinfo->lpszFileName)); //SvL: IE5 setup opens file with DENYREADWRITE, so CreateFile can't // be used for duplicating the handle; try DosDupHandle instead } if(!(fdwOptions & DUPLICATE_SAME_ACCESS) && fdwAccess != pHMSrcHandle->dwAccess) { dprintf(("WARNING: DuplicateHandle; app wants different access permission; Not supported!! (%x, %x)", fdwAccess, pHMSrcHandle->dwAccess)); } pHMHandleData->hHMHandle = 0; rc = OSLibDosDupHandle(pHMSrcHandle->hHMHandle, &pHMHandleData->hHMHandle); if (rc) { dprintf(("ERROR: DuplicateHandle: OSLibDosDupHandle(%s) failed = %u", srcfileinfo->lpszFileName, rc)); SetLastError(rc); return FALSE; // ERROR } else { SetHandleInformation(pHMHandleData, HANDLE_FLAG_INHERIT, (fInherit) ? HANDLE_FLAG_INHERIT : 0); // Duplicate file information as well -- this is e.g. needed in // CloseHandle() for the FILE_FLAG_DELETE_ON_CLOSE emulation to work if (srcfileinfo) { pHMHandleData->dwUserData = (DWORD) new HMFileInfo(pHMHandleData->hHMHandle, srcfileinfo->lpszFileName, NULL); } SetLastError(ERROR_SUCCESS); return TRUE; // OK } } else { dprintf(("ERROR: DuplicateHandle; invalid parameter!!")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } } /***************************************************************************** * Name : BOOL HMDeviceFileClass::SetHandleInformation * Purpose : The SetHandleInformation function sets certain properties of an * object handle. The information is specified as a set of bit flags. * Parameters: HANDLE hObject handle to an object * DWORD dwMask specifies flags to change * DWORD dwFlags specifies new values for flags * Variables : * Result : TRUE / FALSE * Remark : * Status : * * Author : SvL *****************************************************************************/ BOOL HMDeviceFileClass::SetHandleInformation(PHMHANDLEDATA pHMHandleData, DWORD dwMask, DWORD dwFlags) { DWORD rc; pHMHandleData->dwHandleInformation &= ~dwMask; pHMHandleData->dwHandleInformation |= (dwFlags & dwMask); rc = OSLibDosSetFHState(pHMHandleData->hHMHandle, pHMHandleData->dwHandleInformation); if (rc) { dprintf(("ERROR: SetHandleInformation: OSLibDosSetFHState failed with %d", rc)); SetLastError(rc); return FALSE; } SetLastError(ERROR_SUCCESS); return TRUE; } /***************************************************************************** * Name : BOOL HMDeviceFileClass::CloseHandle * Purpose : close the handle * Parameters: PHMHANDLEDATA pHMHandleData * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1998/02/11 20:44] *****************************************************************************/ BOOL HMDeviceFileClass::CloseHandle(PHMHANDLEDATA pHMHandleData) { HMFileInfo *fileInfo = (HMFileInfo *)pHMHandleData->dwUserData; BOOL bRC; dprintfl(("KERNEL32: HMDeviceFileClass::CloseHandle(%08x)\n", pHMHandleData->hHMHandle)); bRC = OSLibDosClose(pHMHandleData->hHMHandle); if(pHMHandleData->dwFlags & FILE_FLAG_DELETE_ON_CLOSE) { //TODO: should only do this after all handles have been closed if(fileInfo) { DeleteFileA(fileInfo->lpszFileName); } } if(fileInfo) { delete fileInfo; } dprintf(("KERNEL32: HMDeviceFileClass::CloseHandle returned %08xh\n", bRC)); return (DWORD)bRC; } /***************************************************************************** * Name : BOOL HMDeviceFileClass::ReadFile * Purpose : read data from handle / device * Parameters: PHMHANDLEDATA pHMHandleData, * LPCVOID lpBuffer, * DWORD nNumberOfBytesToRead, * LPDWORD lpNumberOfBytesRead, * LPOVERLAPPED lpOverlapped * Variables : * Result : Boolean * Remark : * Status : * * Author : Patrick Haller [Wed, 1998/02/11 20:44] *****************************************************************************/ BOOL HMDeviceFileClass::ReadFile(PHMHANDLEDATA pHMHandleData, LPCVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { LPVOID lpRealBuf; Win32MemMap *map; DWORD offset, bytesread; BOOL bRC; dprintfl(("KERNEL32: HMDeviceFileClass::ReadFile %s(%08x,%08x,%08x,%08x,%08x) - stub?\n", lpHMDeviceName, pHMHandleData, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped)); //SvL: It's legal for this pointer to be NULL if(lpNumberOfBytesRead) *lpNumberOfBytesRead = 0; else lpNumberOfBytesRead = &bytesread; if((pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && !lpOverlapped) { dprintf(("FILE_FLAG_OVERLAPPED flag set, but lpOverlapped NULL!!")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if(!(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && lpOverlapped) { dprintf(("Warning: lpOverlapped != NULL & !FILE_FLAG_OVERLAPPED; sync operation")); } if(lpCompletionRoutine) { dprintf(("!WARNING!: lpCompletionRoutine not supported -> fall back to sync IO")); } //SvL: DosRead doesn't like writing to memory addresses returned by // DosAliasMem -> search for original memory mapped pointer and use // that one + commit pages if not already present map = Win32MemMapView::findMapByView((ULONG)lpBuffer, &offset, MEMMAP_ACCESS_WRITE); if(map) { lpRealBuf = (LPVOID)((ULONG)map->getMappingAddr() + offset); DWORD nrpages = nNumberOfBytesToRead/4096; if((nNumberOfBytesToRead+offset) & 0xfff) nrpages++; map->commitRange((ULONG)lpBuffer, offset & ~0xfff, TRUE, nrpages); map->Release(); } else lpRealBuf = (LPVOID)lpBuffer; //If this file is also used in a memory map somewhere, then we need //to tell the map to flush all modified contents to disk right NOW map = Win32MemMap::findMapByFile(pHMHandleData->hWin32Handle); if(map) { DWORD curpos = SetFilePointer(pHMHandleData, 0, NULL, FILE_CURRENT); dprintf(("Flush memory maps to disk before reading!!")); map->flushView(MMAP_FLUSHVIEW_ALL, curpos, nNumberOfBytesToRead); map->Release(); } if(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) { dprintf(("ERROR: Overlapped IO not yet implememented!!")); } // else { bRC = OSLibDosRead(pHMHandleData->hHMHandle, (PVOID)lpRealBuf, nNumberOfBytesToRead, lpNumberOfBytesRead); // } if(bRC == 0) { dprintf(("KERNEL32: HMDeviceFileClass::ReadFile returned %08xh %x\n", bRC, GetLastError())); dprintf(("%x -> %d", lpBuffer, IsBadWritePtr((LPVOID)lpBuffer, nNumberOfBytesToRead))); } return bRC; } /***************************************************************************** * Name : BOOL HMDeviceFileClass::WriteFile * Purpose : write data to handle / device * Parameters: PHMHANDLEDATA pHMHandleData, * LPCVOID lpBuffer, * DWORD nNumberOfBytesToWrite, * LPDWORD lpNumberOfBytesWritten, * LPOVERLAPPED lpOverlapped * Variables : * Result : Boolean * Remark : * Status : * * Author : Patrick Haller [Wed, 1998/02/11 20:44] *****************************************************************************/ BOOL HMDeviceFileClass::WriteFile(PHMHANDLEDATA pHMHandleData, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { LPVOID lpRealBuf; Win32MemMap *map; DWORD offset, byteswritten; BOOL bRC; dprintfl(("KERNEL32: HMDeviceFileClass::WriteFile %s(%08x,%08x,%08x,%08x,%08x) - stub?\n", lpHMDeviceName, pHMHandleData, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped)); //SvL: It's legal for this pointer to be NULL if(lpNumberOfBytesWritten) *lpNumberOfBytesWritten = 0; else lpNumberOfBytesWritten = &byteswritten; if((pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && !lpOverlapped) { dprintf(("FILE_FLAG_OVERLAPPED flag set, but lpOverlapped NULL!!")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if(!(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && lpOverlapped) { dprintf(("Warning: lpOverlapped != NULL & !FILE_FLAG_OVERLAPPED; sync operation")); } //SvL: DosWrite doesn't like reading from memory addresses returned by // DosAliasMem -> search for original memory mapped pointer and use // that one + commit pages if not already present map = Win32MemMapView::findMapByView((ULONG)lpBuffer, &offset, MEMMAP_ACCESS_READ); if(map) { lpRealBuf = (LPVOID)((ULONG)map->getMappingAddr() + offset); DWORD nrpages = nNumberOfBytesToWrite/4096; if((nNumberOfBytesToWrite+offset) & 0xfff) nrpages++; map->commitRange((ULONG)lpBuffer, offset & ~0xfff, FALSE, nrpages); map->Release(); } else lpRealBuf = (LPVOID)lpBuffer; if(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) { dprintf(("ERROR: Overlapped IO not yet implememented!!")); } // else { bRC = OSLibDosWrite(pHMHandleData->hHMHandle, (PVOID)lpRealBuf, nNumberOfBytesToWrite, lpNumberOfBytesWritten); // } if (bRC) { //If this file is also used in a memory map somewhere, then we need //to invalidate memory pages that we just wrote DWORD curfilepos; map = Win32MemMap::findMapByFile(pHMHandleData->hWin32Handle); if(map) { curfilepos = SetFilePointer(pHMHandleData, 0, NULL, FILE_CURRENT); dprintf(("Invalidate memory map after file writing!!")); map->invalidatePages(curfilepos, *lpNumberOfBytesWritten); map->Release(); } } dprintf(("KERNEL32: HMDeviceFileClass::WriteFile returned %08xh\n", bRC)); return bRC; } /***************************************************************************** * Name : DWORD HMDeviceFileClass::GetFileType * Purpose : determine the handle type * Parameters: PHMHANDLEDATA pHMHandleData * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1998/02/11 20:44] *****************************************************************************/ DWORD HMDeviceFileClass::GetFileType(PHMHANDLEDATA pHMHandleData) { dprintfl(("KERNEL32: HMDeviceFileClass::GetFileType %s(%08x)\n", lpHMDeviceName, pHMHandleData)); return FILE_TYPE_DISK; } /***************************************************************************** * Name : BOOL HMDeviceFileClass::GetFileInformationByHandle * Purpose : determine the handle type * Parameters: PHMHANDLEDATA pHMHandleData * BY_HANDLE_FILE_INFORMATION* pHFI * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1999/06/17 20:44] *****************************************************************************/ BOOL HMDeviceFileClass::GetFileInformationByHandle(PHMHANDLEDATA pHMHandleData, BY_HANDLE_FILE_INFORMATION* pHFI) { dprintfl(("KERNEL32: HMDeviceFileClass::GetFileInformationByHandle %s(%08xh,%08xh)\n", lpHMDeviceName, pHMHandleData, pHFI)); HMFileInfo *fileInfo = (HMFileInfo *)pHMHandleData->dwUserData; if(OSLibDosGetFileInformationByHandle(fileInfo->lpszFileName, pHMHandleData->hHMHandle, pHFI)) { return TRUE; } dprintf(("GetFileInformationByHandle failed with error %d", GetLastError())); return FALSE; } /***************************************************************************** * Name : BOOL HMDeviceFileClass::SetEndOfFile * Purpose : set end of file marker * Parameters: PHMHANDLEDATA pHMHandleData * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1999/06/17 20:44] *****************************************************************************/ BOOL HMDeviceFileClass::SetEndOfFile(PHMHANDLEDATA pHMHandleData) { dprintfl(("KERNEL32: HMDeviceFileClass::SetEndOfFile %s(%08xh)\n", lpHMDeviceName, pHMHandleData)); if(OSLibDosSetEndOfFile(pHMHandleData->hHMHandle)) { return TRUE; } dprintf(("SetEndOfFile failed with error %d", GetLastError())); return FALSE; } //****************************************************************************** /***************************************************************************** * Name : BOOL HMDeviceFileClass::SetFileTime * Purpose : set file time * Parameters: PHMHANDLEDATA pHMHandleData * PFILETIME pFT1 * PFILETIME pFT2 * PFILETIME pFT3 * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1999/06/17 20:44] mod. DT *****************************************************************************/ BOOL HMDeviceFileClass::SetFileTime(PHMHANDLEDATA pHMHandleData, LPFILETIME pFT1, LPFILETIME pFT2, LPFILETIME pFT3) { dprintfl(("KERNEL32: HMDeviceFileClass::SetFileTime %s(%08xh,%08xh,%08xh,%08xh)\n", lpHMDeviceName, pHMHandleData, pFT1, pFT2, pFT3)); if(OSLibDosSetFileTime(pHMHandleData->hHMHandle, pFT1, pFT2, pFT3)) return TRUE; dprintf(("SetFileTime failed with error %d", GetLastError())); return FALSE; } /***************************************************************************** * Name : BOOL HMDeviceFileClass::GetFileTime * Purpose : get file time * Parameters: PHMHANDLEDATA pHMHandleData * PFILETIME pFT1 * PFILETIME pFT2 * PFILETIME pFT3 * Variables : * Result : API returncode * Remark : * Status : * * Author : SvL mod. DT *****************************************************************************/ BOOL HMDeviceFileClass::GetFileTime(PHMHANDLEDATA pHMHandleData, LPFILETIME pFT1, LPFILETIME pFT2, LPFILETIME pFT3) { if(!pFT1 && !pFT2 && !pFT3) {//TODO: does NT do this? dprintf(("ERROR: GetFileTime: invalid parameter!")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if(OSLibDosGetFileTime(pHMHandleData->hHMHandle, pFT1, pFT2, pFT3)) return TRUE; dprintf(("GetFileTime failed with error %d", GetLastError())); return FALSE; } /***************************************************************************** * Name : DWORD HMDeviceFileClass::GetFileSize * Purpose : set file time * Parameters: PHMHANDLEDATA pHMHandleData * PDWORD pSize * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1999/06/17 20:44] *****************************************************************************/ DWORD HMDeviceFileClass::GetFileSize(PHMHANDLEDATA pHMHandleData, PDWORD lpdwFileSizeHigh) { dprintfl(("KERNEL32: HMDeviceFileClass::GetFileSize %s(%08xh,%08xh)\n", lpHMDeviceName, pHMHandleData, lpdwFileSizeHigh)); if(lpdwFileSizeHigh) *lpdwFileSizeHigh = 0; return OSLibDosGetFileSize(pHMHandleData->hHMHandle, lpdwFileSizeHigh); } /***************************************************************************** * Name : DWORD HMDeviceFileClass::SetFilePointer * Purpose : set file pointer * Parameters: PHMHANDLEDATA pHMHandleData * LONG lDistanceToMove * PLONG lpDistanceToMoveHigh * DWORD dwMoveMethod * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1999/06/17 20:44] *****************************************************************************/ DWORD HMDeviceFileClass::SetFilePointer(PHMHANDLEDATA pHMHandleData, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) { DWORD ret; HMFileInfo *fileInfo = (HMFileInfo *)pHMHandleData->dwUserData; dprintfl(("KERNEL32: HMDeviceFileClass::SetFilePointer %s(%08xh,%08xh,%08xh,%08xh)\n", lpHMDeviceName, pHMHandleData, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod)); if(fileInfo && fileInfo->dwLXOffset) { switch(dwMoveMethod) { case FILE_BEGIN: dprintf(("SetFilePointer FILE_BEGIN (LX) -> change offset from %x to %x", lDistanceToMove, lDistanceToMove+fileInfo->dwLXOffset)); lDistanceToMove += fileInfo->dwLXOffset; break; case FILE_END: //Could overshoot the virtual beginning of the PE file lDistanceToMove -= MAGIC_STUBEXE_SIZE; dprintf(("SetFilePointer FILE_END -> might be dangerous!!")); break; } } ret = OSLibDosSetFilePointer(pHMHandleData->hHMHandle, lDistanceToMove, (DWORD *)lpDistanceToMoveHigh, dwMoveMethod); if(ret == -1) { dprintf(("SetFilePointer failed (error = %d)", GetLastError())); } return ret; } /***************************************************************************** * Name : BOOL HMDeviceFileClass::LockFile * Purpose : file locking * Parameters: PHMHANDLEDATA pHMHandleData * DWORD arg2 * DWORD arg3 * DWORD arg4 * DWORD arg5 * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1999/06/17 20:44] *****************************************************************************/ BOOL HMDeviceFileClass::LockFile(PHMHANDLEDATA pHMHandleData, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD cbLockLow, DWORD cbLockHigh) { dprintfl(("KERNEL32: HMDeviceFileClass::LockFile %s(%08xh,%08xh,%08xh,%08xh,%08xh)\n", lpHMDeviceName, pHMHandleData, dwFileOffsetLow, dwFileOffsetHigh, cbLockLow, cbLockHigh)); return OSLibDosLockFile(pHMHandleData->hHMHandle, LOCKFILE_EXCLUSIVE_LOCK, dwFileOffsetLow, dwFileOffsetHigh, cbLockLow, cbLockHigh, NULL); } /***************************************************************************** * Name : DWORD HMDeviceFileClass::LockFileEx * Purpose : file locking * Parameters: PHMHANDLEDATA pHMHandleData * DWORD dwFlags * DWORD dwReserved * DWORD nNumberOfBytesToLockLow * DWORD nNumberOfBytesToLockHigh * LPOVERLAPPED lpOverlapped * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1999/06/17 20:44] *****************************************************************************/ BOOL HMDeviceFileClass::LockFileEx(PHMHANDLEDATA pHMHandleData, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped) { dprintfl(("KERNEL32: HMDeviceFileClass::LockFileEx %s(%08xh,%08xh,%08xh,%08xh,%08xh,%08xh) not completely implemented!", lpHMDeviceName, pHMHandleData, dwFlags, dwReserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh, lpOverlapped)); return(OSLibDosLockFile(pHMHandleData->hHMHandle, dwFlags, lpOverlapped->Offset, lpOverlapped->OffsetHigh, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh, lpOverlapped)); } /***************************************************************************** * Name : DWORD HMDeviceFileClass::UnlockFile * Purpose : file locking * Parameters: PHMHANDLEDATA pHMHandleData * DWORD arg2 * DWORD arg3 * DWORD arg4 * DWORD arg5 * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1999/06/17 20:44] *****************************************************************************/ BOOL HMDeviceFileClass::UnlockFile(PHMHANDLEDATA pHMHandleData, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD cbLockLow, DWORD cbLockHigh) { dprintfl(("KERNEL32: HMDeviceFileClass::UnlockFile %s(%08xh,%08xh,%08xh,%08xh,%08xh)\n", lpHMDeviceName, pHMHandleData, dwFileOffsetLow, dwFileOffsetHigh, cbLockLow, cbLockHigh)); return OSLibDosUnlockFile(pHMHandleData->hHMHandle, dwFileOffsetLow, dwFileOffsetHigh, cbLockLow, cbLockHigh, NULL); } /***************************************************************************** * Name : DWORD HMDeviceFileClass::UnlockFileEx * Purpose : file locking * Parameters: PHMHANDLEDATA pHMHandleData * DWORD dwFlags * DWORD dwReserved * DWORD nNumberOfBytesToLockLow * DWORD nNumberOfBytesToLockHigh * LPOVERLAPPED lpOverlapped * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1999/06/17 20:44] *****************************************************************************/ BOOL HMDeviceFileClass::UnlockFileEx(PHMHANDLEDATA pHMHandleData, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped) { dprintfl(("KERNEL32: HMDeviceFileClass::UnlockFileEx %s(%08xh,%08xh,%08xh,%08xh,%08xh) not completely implemented!", lpHMDeviceName, pHMHandleData, dwReserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh, lpOverlapped)); return(OSLibDosUnlockFile(pHMHandleData->hHMHandle, lpOverlapped->Offset, lpOverlapped->OffsetHigh, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh, lpOverlapped)); } /***************************************************************************** * Name : DWORD HMDeviceFileClass::FlushFileBuffers * Purpose : flush the buffers of a file * Parameters: PHMHANDLEDATA pHMHandleData * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1999/06/17 20:44] *****************************************************************************/ BOOL HMDeviceFileClass::FlushFileBuffers(PHMHANDLEDATA pHMHandleData) { dprintfl(("KERNEL32: HMDeviceFileClass:FlushFileBuffers(%08xh)\n", pHMHandleData->hHMHandle)); return(OSLibDosFlushFileBuffers(pHMHandleData->hHMHandle)); } /***************************************************************************** * Name : DWORD HMDeviceFileClass::GetOverlappedResult * Purpose : asynchronus I/O * Parameters: PHMHANDLEDATA pHMHandleData * LPOVERLAPPED arg2 * LPDWORD arg3 * BOOL arg4 * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1999/06/17 20:44] *****************************************************************************/ BOOL HMDeviceFileClass::GetOverlappedResult(PHMHANDLEDATA pHMHandleData, LPOVERLAPPED arg2, LPDWORD arg3, BOOL arg4) { dprintfl(("KERNEL32-WARNING: HMDeviceFileClass::GetOverlappedResult(%08xh,%08xh,%08xh,%08xh) STUB!!", pHMHandleData->hHMHandle, arg2, arg3, arg4)); return FALSE; // return(O32_GetOverlappedResult(pHMHandleData->hHMHandle, // arg2, // arg3, // arg4)); } /****************************************************************************** * Name : DWORD HMDeviceFileClass::GetFileNameFromHandle * Purpose : the name of the file associated with the system handle (if any) * Parameters: PHMHANDLEDATA pHMHandleData * Variables : * Result : BOOLEAN * Remark : * Status : * * Author : SvL ******************************************************************************/ BOOL HMDeviceFileClass::GetFileNameFromHandle(PHMHANDLEDATA pHMHandleData, LPSTR lpszFileName, DWORD cbFileName) { HMFileInfo *fileInfo = (HMFileInfo *)pHMHandleData->dwUserData; if(fileInfo == NULL || strlen(fileInfo->lpszFileName) >= cbFileName) { if(fileInfo) DebugInt3(); return FALSE; } strcpy(lpszFileName, fileInfo->lpszFileName); return TRUE; } //****************************************************************************** //****************************************************************************** // File information handle class // // When the application opens a file with CreateFile and 0 for desired access, // then we need to create a handle with limited access. // // MSDN: // // If this parameter is zero, the application can query file and device attributes // without accessing the device. This is useful if an application wants to determine // the size of a floppy disk drive and the formats it supports without requiring // a floppy in the drive. It can also be used to test for the file's or directory's // existence without opening it for read or write access. // //****************************************************************************** //****************************************************************************** /****************************************************************************** * Name : DWORD HMDeviceInfoFileClass::CreateFile * Purpose : this is called from the handle manager if a CreateFile() is * performed on a handle * Parameters: LPCSTR lpFileName name of the file / device * PHMHANDLEDATA pHMHandleData data of the NEW handle * PVOID lpSecurityAttributes ignored * PHMHANDLEDATA pHMHandleDataTemplate data of the template handle * Variables : * Result : * Remark : * Status : NO_ERROR - API succeeded * other - what is to be set in SetLastError * * Author : SvL *****************************************************************************/ DWORD HMDeviceInfoFileClass::CreateFile (LPCSTR lpFileName, PHMHANDLEDATA pHMHandleData, PVOID lpSecurityAttributes, PHMHANDLEDATA pHMHandleDataTemplate) { char filepath[260]; DWORD dwAttr; dprintfl(("KERNEL32: HMDeviceInfoFileClass::CreateFile %s(%s,%08x,%08x,%08x)\n", lpHMDeviceName, lpFileName, pHMHandleData, lpSecurityAttributes, pHMHandleDataTemplate)); ParsePath(lpFileName, filepath, sizeof(filepath)); //convert to long file name if in 8.3 hashed format GetLongPathNameA(filepath, filepath, sizeof(filepath)); lpFileName = filepath; dwAttr = GetFileAttributesA(lpFileName); if(dwAttr == -1) { return GetLastError(); } pHMHandleData->dwUserData = (DWORD) new HMFileInfo(INVALID_HANDLE_VALUE, (LPSTR)lpFileName, lpSecurityAttributes); pHMHandleData->hHMHandle = 0x80000000; // make sure _HMHandleQuery won't fail return (NO_ERROR); } /****************************************************************************** * Name : BOOL HMDeviceFileClass::CloseHandle * Purpose : close the handle * Parameters: PHMHANDLEDATA pHMHandleData * Variables : * Result : API returncode * Remark : * Status : * * Author : Patrick Haller [Wed, 1998/02/11 20:44] *****************************************************************************/ BOOL HMDeviceInfoFileClass::CloseHandle(PHMHANDLEDATA pHMHandleData) { HMFileInfo *fileInfo = (HMFileInfo *)pHMHandleData->dwUserData; dprintfl(("KERNEL32: HMDeviceInfoFileClass::CloseHandle(%08x)\n", pHMHandleData->hHMHandle)); if(fileInfo) { delete fileInfo; } return TRUE; } /****************************************************************************** * Name : BOOL HMDeviceInfoFileClass::GetFileTime * Purpose : Get file time * Parameters: PHMHANDLEDATA pHMHandleData * PFILETIME pFT1 * PFILETIME pFT2 * PFILETIME pFT3 * Variables : * Result : API returncode * Remark : * Status : * * Author : SvL *****************************************************************************/ BOOL HMDeviceInfoFileClass::GetFileTime (PHMHANDLEDATA pHMHandleData, LPFILETIME pFT1, LPFILETIME pFT2, LPFILETIME pFT3) { HMFileInfo *fileInfo = (HMFileInfo *)pHMHandleData->dwUserData; if(!pFT1 && !pFT2 && !pFT3) {//TODO: does NT do this? dprintf(("ERROR: GetFileTime: invalid parameter!")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } WIN32_FIND_DATAA finddata; HANDLE hFind; hFind = FindFirstFileA(fileInfo->lpszFileName, &finddata); if(hFind == INVALID_HANDLE_VALUE) { return GetLastError(); } if(pFT1) { *pFT1 = finddata.ftCreationTime; } if(pFT2) { *pFT2 = finddata.ftLastAccessTime; } if(pFT3) { *pFT3 = finddata.ftLastWriteTime; } FindClose(hFind); SetLastError(ERROR_SUCCESS); return TRUE; } /****************************************************************************** * Name : DWORD HMDeviceInfoFileClass::GetFileSize * Purpose : get file size * Parameters: PHMHANDLEDATA pHMHandleData * PDWORD pSize * Variables : * Result : API returncode * Remark : Doesn't fail for directories; just returns 0 (verified in NT4, SP6) * Status : * * Author : SvL *****************************************************************************/ DWORD HMDeviceInfoFileClass::GetFileSize(PHMHANDLEDATA pHMHandleData, PDWORD lpdwFileSizeHigh) { HMFileInfo *fileInfo = (HMFileInfo *)pHMHandleData->dwUserData; SetLastError(ERROR_SUCCESS); if(lpdwFileSizeHigh) *lpdwFileSizeHigh = 0; if(fileInfo == NULL) { DebugInt3(); SetLastError(ERROR_INVALID_PARAMETER); //TODO return -1; //INVALID_FILE_SIZE; } WIN32_FIND_DATAA finddata; HANDLE hFind; hFind = FindFirstFileA(fileInfo->lpszFileName, &finddata); if(hFind == INVALID_HANDLE_VALUE) { return GetLastError(); } if(lpdwFileSizeHigh) { *lpdwFileSizeHigh = finddata.nFileSizeHigh; } FindClose(hFind); if(fileInfo->dwLXOffset) { //subtract the LX header and magic qword from the file size dprintf(("GetFileSize (LX) -> change size from %x to %x", finddata.nFileSizeLow, finddata.nFileSizeLow-fileInfo->dwLXOffset-MAGIC_STUBEXE_SIZE)); finddata.nFileSizeLow -= (fileInfo->dwLXOffset+MAGIC_STUBEXE_SIZE); } return finddata.nFileSizeLow; } /***************************************************************************** * Name : BOOL HMDeviceFileInfoClass::GetFileInformationByHandle * Purpose : determine the handle type * Parameters: PHMHANDLEDATA pHMHandleData * BY_HANDLE_FILE_INFORMATION* pHFI * Variables : * Result : API returncode * Remark : * Status : *****************************************************************************/ BOOL HMDeviceInfoFileClass::GetFileInformationByHandle(PHMHANDLEDATA pHMHandleData, BY_HANDLE_FILE_INFORMATION* pHFI) { dprintfl(("KERNEL32: HMDeviceInfoFileClass::GetFileInformationByHandle %s(%08xh,%08xh)\n", lpHMDeviceName, pHMHandleData, pHFI)); HMFileInfo *fileInfo = (HMFileInfo *)pHMHandleData->dwUserData; if(OSLibDosGetFileInformationByHandle(fileInfo->lpszFileName, INVALID_HANDLE_VALUE, pHFI)) { return TRUE; } dprintf(("GetFileInformationByHandle failed with error %d", GetLastError())); return FALSE; } /****************************************************************************** * Name : DWORD HMDeviceFileClass::GetFileNameFromHandle * Purpose : the name of the file associated with the system handle (if any) * Parameters: PHMHANDLEDATA pHMHandleData * Variables : * Result : BOOLEAN * Remark : * Status : * * Author : SvL ******************************************************************************/ BOOL HMDeviceInfoFileClass::GetFileNameFromHandle(PHMHANDLEDATA pHMHandleData, LPSTR lpszFileName, DWORD cbFileName) { HMFileInfo *fileInfo = (HMFileInfo *)pHMHandleData->dwUserData; if(fileInfo == NULL || strlen(fileInfo->lpszFileName) >= cbFileName) { if(fileInfo) DebugInt3(); return FALSE; } strcpy(lpszFileName, fileInfo->lpszFileName); return TRUE; } /****************************************************************************** * Name : DWORD HMDeviceFileClass::GetFileType * Purpose : determine the handle type * Parameters: PHMHANDLEDATA pHMHandleData * Variables : * Result : API returncode * Remark : Returns FILE_TYPE_DISK for both files and directories * Status : * * Author : Patrick Haller [Wed, 1998/02/11 20:44] ******************************************************************************/ DWORD HMDeviceInfoFileClass::GetFileType(PHMHANDLEDATA pHMHandleData) { dprintfl(("KERNEL32: HMDeviceInfoFileClass::GetFileType %s(%08x)\n", lpHMDeviceName, pHMHandleData)); return FILE_TYPE_DISK; } //****************************************************************************** //****************************************************************************** HMFileInfo::HMFileInfo(HANDLE hFile, LPSTR lpszFileName, PVOID lpSecurityAttributes) { // get the full path (this is necessary in particular for GetFileInformationByHandle) char fullPath[260]; if (!OSLibDosQueryPathInfo(lpszFileName, FIL_QUERYFULLNAME, fullPath, sizeof(fullPath))) { lpszFileName = fullPath; } this->lpszFileName = (LPSTR)malloc(strlen(lpszFileName)+1); if(!this->lpszFileName) { DebugInt3(); } strcpy(this->lpszFileName, lpszFileName); this->lpSecurityAttributes = lpSecurityAttributes; dwLXOffset = 0; //Only check files that end with .exe for now; they might be prepended with //an LX header. We need to skip that to present the original file to the //caller if((hFile != INVALID_HANDLE_VALUE) && !stricmp(lpszFileName + strlen(lpszFileName) - 4, ".EXE")) { ULONG action, ulRead, signature, ulFileSize; ULONG magic[2]; IMAGE_DOS_HEADER doshdr; //read dos header if(!OSLibDosRead(hFile, (LPVOID)&doshdr, sizeof(doshdr), &ulRead)) { goto failure; } if(OSLibDosSetFilePointer(hFile, doshdr.e_lfanew, NULL, FILE_BEGIN) != doshdr.e_lfanew) { goto failure; } //read signature dword if(!OSLibDosRead(hFile, (LPVOID)&signature, sizeof(signature), &ulRead)) { goto failure; } //Make sure it's an LX executable before continueing if(doshdr.e_magic != IMAGE_DOS_SIGNATURE || (WORD)signature != IMAGE_OS2_SIGNATURE_LX) { goto failure; } //magic signature located at 8 bytes from file end if(OSLibDosSetFilePointer(hFile, -8, NULL, FILE_END) == -1) { goto failure; } //read magic signature + pe offset if(!OSLibDosRead(hFile, (LPVOID)&magic[0], sizeof(magic), &ulRead)) { goto failure; } if(magic[0] != MAGIC_STUBEXE_SIGNATURE || magic[1] > ulFileSize) { goto failure; } //this is the offset of the PE image inside our LX executable dwLXOffset = magic[1]; dprintf(("LX wrapper: PE file %s starts at %x", lpszFileName, dwLXOffset)); //reset file pointer to PE image start if(OSLibDosSetFilePointer(hFile, dwLXOffset, NULL, FILE_BEGIN) != dwLXOffset) { DebugInt3(); } goto end; failure: //reset file pointer to file start if(OSLibDosSetFilePointer(hFile, 0, NULL, FILE_BEGIN) != 0) { DebugInt3(); } } end: return; } //****************************************************************************** //****************************************************************************** HMFileInfo::~HMFileInfo() { if(lpszFileName) { free(lpszFileName); lpszFileName = NULL; } } //***************************************************************************** //Parses and copies path //OpenFile in NT4, SP6 accepts double (or more) backslashes as separators for directories! //(OS/2 doesn't) //Girotel 2.0 (Dutch banking app) seems to depend on this behaviour //***************************************************************************** static void ParsePath(LPCSTR lpszFileName, LPSTR lpszParsedFileName, DWORD length) { int i=0; while(*lpszFileName != 0 && i < length-1) { *lpszParsedFileName++ = *lpszFileName; if(*lpszFileName == '\\') { while(*lpszFileName == '\\') { lpszFileName++; } } else { lpszFileName++; } i++; } *lpszParsedFileName = 0; } //****************************************************************************** //******************************************************************************