/* (C) 2003-2007 Willem Jan Hengeveld * Web: http://www.xs4all.nl/~itsme/ * http://wiki.xda-developers.com/ * * $Id: tffsreader.cpp 1916 2008-07-30 14:06:20Z itsme $ */ #include #include #include #include "tffsreader.h" #include "ceioctl.h" #include "debug.h" #include "ptrutils.h" #include "stringutils.h" #define tffsdebug while(0) debug #include "diskio.h" // for SG_REQ // c:\local\WINCE420\PUBLIC\COMMON\SDK\INC\storemgr.h // // in itsutils // // todo: // make r/w disk so that the start/end do not need to be on sector boundaries. int GetDiskInfo(HANDLE hDsk, DISK_INFO &info); #include "cenk.h" #include "kernelmisc.h" bool Disk_GetDiskParams(HANDLE hDisk, DWORD dwBinaryPartitionNr, DWORD &dwBlockSize, DWORD &dwSectorSize); bool Disk_GetDiskSize(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG &llDiskSize); DWORD *g_pWriteEnableFlag; std::string cinfostring(const CINFO *ci) { if (ci) return stringformat("cinfo{%c%c%c%c, n=%d, svr=%08lx}", ci->acName[0], ci->acName[1], ci->acName[2], ci->acName[3], ci->cMethods, ci->pServer); else return "(null)"; } std::string handleinfostring(HANDLE h) { HDATA *hi= cvHandle2HDataPtr(h); return stringformat("hdata{hv=%08lx ci=%hs pvo=%08lx}", hi->hValue, cinfostring(hi->pci).c_str(), hi->pvObj); } HANDLE FindFirstStore(STOREINFO *psi) { return (FindFirstFileW( L"\\StoreMgr", (WIN32_FIND_DATA *)psi)); } bool GetStoreMgrList(std::vector& list) { STOREINFO si; memset(&si, 0, sizeof(STOREINFO)); si.cbSize= sizeof(STOREINFO); int currentStore = 0; HANDLE hEnumStores = FindFirstStore(&si); if (hEnumStores == INVALID_HANDLE_VALUE) { error("FindFirstFile"); return false; } list.push_back(si); while (PSLFindNextStore(hEnumStores, &si)) { list.push_back(si); } if (GetLastError()!=ERROR_NO_MORE_ITEMS) { error("PSLFindNextStore"); return !list.empty(); } if (!PSLFindCloseStore(hEnumStores)) { error("PSLFindCloseStore"); return !list.empty(); } return true; } void cvSTOREINFO2DevStoreinfo(const STOREINFO& si, DevStoreInfo& dsi) { dsi.llStoreSize= si.snNumSectors * si.dwBytesPerSector; wcsncpy(dsi.szDeviceName, si.szDeviceName, DEVICENAMESIZE); tffsdebug("STOREINFO dev='%ls' store='%ls'", si.szDeviceName, si.szStoreName); tffsdebug(" nsect=%x bpsect=%x free=%x maxpartsize=%x\n", (DWORD)si.snNumSectors, si.dwBytesPerSector, (DWORD)si.snFreeSectors, (DWORD)si.snBiggestPartCreatable); } ITSUTILS_API HRESULT STDAPICALLTYPE ITGetStoreMgrList( DWORD cbInput, void *pbInput, DWORD *pcbOutput, GetStoreMgrListResult **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; GetStoreMgrListResult *pOut= *ppbOutput= NULL; std::vector list; if (!GetStoreMgrList(list)) { error("GetStoreMgrList"); return GetLastError(); } *pcbOutput= PTR_DIFF(pOut, pOut->storeInfo+list.size()); pOut= *ppbOutput= (GetStoreMgrListResult*)LocalAlloc(LPTR, *pcbOutput); if (pOut==NULL) { error("LocalAlloc(%d)", *pcbOutput); return GetLastError(); } pOut->nStores = list.size(); for (size_t i=0 ; istoreInfo[i]); } return 0; } bool ReadVirtMemDword(void *pdw, DWORD *pdwVal) { if (!isValidPtr((DWORD)pdw)) return false; *pdwVal= *(DWORD*)pdw; return true; } bool GetSTRGHandleList(std::vector &list) { HDATA *hi= cvHandle2HDataPtr((HANDLE)GetCurrentThreadId()); HDATA *ha; ha=hi; KernelMode _km; do { DWORD dw; if (memcmp(ha->pci->acName, "STRG", 4)==0 && ReadVirtMemDword(MapPtrProc(ha->pvObj, ha->pci->pServer), &dw) && dw == 0x64615900) { list.push_back((DWORD)ha->hValue); } ha= (HDATA*)ha->linkage.fwd; } while (ha!=hi && ha!=NULL); return true; } ITSUTILS_API HRESULT STDAPICALLTYPE ITGetSTRGHandleList( DWORD cbInput, void *pbInput, DWORD *pcbOutput, GetSTRGHandleListResult **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; GetSTRGHandleListResult *pOut= *ppbOutput= NULL; std::vector list; if (!GetSTRGHandleList(list)) { debug("ERROR: GetSTRGHandleList failed\n"); return ERROR_INTERNAL_ERROR; } *pcbOutput= PTR_DIFF(pOut, pOut->handle+list.size()); pOut= *ppbOutput= (GetSTRGHandleListResult*)LocalAlloc(LPTR, *pcbOutput); if (pOut==NULL) { error("LocalAlloc(%d)", *pcbOutput); return GetLastError(); } pOut->nHandles= list.size(); for (size_t i=0 ; ihandle[i]= list[i]; } return 0; } HANDLE WINAPI OpenStore(LPCTSTR szDeviceName) { TCHAR szFileName[MAX_PATH]; memset( szFileName, 0, sizeof(szFileName)); wcscpy( szFileName, L"\\StoreMgr\\"); __try { wcsncat( szFileName, szDeviceName, MAX_PATH-15); } __except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(ERROR_BAD_ARGUMENTS); } return CreateFile( szFileName, 0, 0, NULL, 0, 0, NULL); } bool GetStorePartitionlist(HANDLE hStore, std::vector& list) { PARTINFO pi; memset(&pi, 0, sizeof(pi)); pi.cbSize= sizeof(PARTINFO); HANDLE hEnumPartitions = PSLFindFirstPartition(hStore, &pi); if (hEnumPartitions == INVALID_HANDLE_VALUE) { if (GetLastError()==ERROR_NO_MORE_ITEMS) { return true; } error("PSLFindFirstPartition"); return false; } list.push_back(pi); while (PSLFindNextPartition(hEnumPartitions, &pi)) list.push_back(pi); if (GetLastError()!=ERROR_NO_MORE_ITEMS) { error("PSLFindNextPartition"); return !list.empty(); } if (!PSLFindClosePartition(hEnumPartitions)) { error("PSLFindClosePartition"); return !list.empty(); } return true; } void cvPARTINFO2DevPartitioninfo(const STOREINFO& si, const PARTINFO& pi, DevPartitionInfo& dpi) { dpi.llPartitionSize= pi.snNumSectors * si.dwBytesPerSector; wcsncpy(dpi.szPartitionName, pi.szPartitionName, PARTITIONNAMESIZE); tffsdebug("PARTINFO name='%ls' filesys='%ls' volname='%ls'", pi.szPartitionName, pi.szFileSys, pi.szVolumeName); tffsdebug(" end=%x type=%02x\n", (DWORD)pi.snNumSectors, pi.bPartType); } bool GetStoreInfo(HANDLE hStore, STOREINFO& si) { memset(&si, 0, sizeof(STOREINFO)); si.cbSize= sizeof(STOREINFO); if (!PSLGetStoreInfo(hStore, &si)) { error("PSLGetStoreInfo"); return false; } return true; } bool GetPartitionInfo(HANDLE hPartition, PARTINFO& pi) { memset(&pi, 0, sizeof(PARTINFO)); pi.cbSize= sizeof(PARTINFO); if (!PSLGetPartitionInfo(hPartition, &pi)) { error("PSLGetPartitionInfo"); return false; } return true; } ITSUTILS_API HRESULT STDAPICALLTYPE ITGetPartitionList( DWORD cbInput, GetPartitionListParams *pbInput, DWORD *pcbOutput, GetPartitionListResult **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; GetPartitionListResult *pOut= *ppbOutput= NULL; std::vector list; HANDLE hStore = pbInput->hStore ? (HANDLE)pbInput->hStore : OpenStore(pbInput->szDeviceName); if (hStore == INVALID_HANDLE_VALUE) { error("GetStorePartitionlist: OpenStore('%ls')", pbInput->szDeviceName); return false; } STOREINFO si; if (!GetStoreInfo(hStore, si)) return GetLastError(); if (!GetStorePartitionlist(hStore, list)) return GetLastError(); if (pbInput->hStore==NULL) CloseHandle(hStore); *pcbOutput= PTR_DIFF(pOut, pOut->partInfo+list.size()); pOut= *ppbOutput= (GetPartitionListResult*)LocalAlloc(LPTR, *pcbOutput); if (pOut==NULL) { error("LocalAlloc(%d)", *pcbOutput); return GetLastError(); } pOut->nPartitions = list.size(); for (size_t i=0 ; ipartInfo[i]); } return 0; } char BDK_SIGNATURE[5]= "BIPO"; // if partition=="" -> open device as file. bool OpenTFFSDisk(const WCHAR *szDeviceName, const WCHAR *szPartitionName, HANDLE& hStore, HANDLE& hPartition) { if (szPartitionName && wcslen(szPartitionName)) { hStore = OpenStore(szDeviceName); if (hStore == INVALID_HANDLE_VALUE || hStore == NULL) { error("OpenTFFSDisk: OpenStore('%ls')", szDeviceName); return false; } hPartition = PSLOpenPartition(hStore, szPartitionName); if (hPartition == INVALID_HANDLE_VALUE || hPartition == NULL) { error("PSLOpenPartition('%ls')", szPartitionName); CloseHandle(hStore); hStore= NULL; return false; } } else { hStore= NULL; hPartition= CreateFile( szDeviceName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); if (hPartition == INVALID_HANDLE_VALUE || hPartition == NULL) { error("OpenTFFSDisk: OpenStore('%ls')", szDeviceName); return false; } } return true; } bool CloseTFFSDisk(HANDLE hStore, HANDLE hPartition) { CloseHandle(hPartition); CloseHandle(hStore); return true; } bool TFFS_BDK_GetInfo(HANDLE hDisk, DWORD dwBinaryPartitionNr, DWORD &dwLength, DWORD &dwCount) { flBDKOperationInput in; memset(&in, 0, sizeof(in)); in.partitionNumber = (BYTE)dwBinaryPartitionNr; in.type = BDK_GET_INFO; memcpy(in.bdkStruct.oldSign, BDK_SIGNATURE, 4); in.bdkStruct.signOffset = 8; in.bdkStruct.startingBlock = 0; flOutputStatusRecord out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_BDK_OPERATION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_GET_INFO)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_GET_INFO) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } // used length: in.bdkStruct.length dwLength= in.bdkStruct.startingBlock; dwCount= in.bdkStruct.flags; return true; } bool TFFS_OTP_GetSize(HANDLE hDisk, DWORD& dwSize, DWORD &dwMaxSize) { flOtpInput in; memset(&in, 0, sizeof(in)); flOutputStatusRecord out; memset(&out, 0, sizeof(out)); in.type= OTP_SIZE; DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_OTP, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_SIZE)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_SIZE) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } // in.lockedFlag dwSize= in.usedSize; dwMaxSize= in.length; return true; } bool TFFS_GetCustomerId(HANDLE hDisk, DWORD &id) { flCustomerIdOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_CUSTOMER_ID, NULL, 0, &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_CUSTOMER_ID)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_CUSTOMER_ID) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } memcpy(&id, out.id, 4); return true; } std::string GuidAsString(GUID& id) { return stringformat("{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", id.Data1, id.Data2, id.Data3, id.Data4[0], id.Data4[1], id.Data4[2], id.Data4[3], id.Data4[4], id.Data4[5], id.Data4[6], id.Data4[7]); } bool TFFS_GetUniqueId(HANDLE hDisk, GUID& id) { flUniqueIdOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_UNIQUE_ID, NULL, 0, &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_UNIQUE_ID)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_UNIQUE_ID) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } memcpy(&id, out.id, 16); return true; } bool TFFS_GetNrOfPartitions(HANDLE hDisk, DWORD& dwPartitionCount) { flCountPartitionsOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_NUMBER_OF_PARTITIONS, NULL, 0, &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_NUMBER_OF_PARTITIONS)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_NUMBER_OF_PARTITIONS) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } dwPartitionCount= out.noOfPartitions; return true; } //////////////////////////////////////////////////////////////////////////////////// // read functions bool TFFS_BDK_InitRead(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG llOffset, DWORD dwSize, DWORD dwSectorSize) { flBDKOperationInput in; memset(&in, 0, sizeof(in)); in.partitionNumber = (BYTE)dwBinaryPartitionNr; in.type = BDK_INIT_READ; memcpy(in.bdkStruct.oldSign, BDK_SIGNATURE, 4); in.bdkStruct.signOffset = 8; in.bdkStruct.startingBlock = (DWORD)(llOffset/dwSectorSize); in.bdkStruct.length = dwSize; in.bdkStruct.flags = 2; // ??? flOutputStatusRecord out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_BDK_OPERATION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(%d, FL_IOCTL_BDK_OPERATION, BDK_INIT_READ, start=%d, size=0x%x)", dwBinaryPartitionNr, (DWORD)(llOffset/dwSectorSize), dwSize); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_INIT_READ) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } return true; } bool TFFS_BDK_ReadNextSector(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG llOffset, DWORD dwLength, BYTE *buffer, DWORD &dwRead) { flBDKOperationInput in; memset(&in, 0, sizeof(in)); // limit to 512 bytes per call for stable operation if (dwLength>512) dwLength= 512; BYTE *localbuf= (BYTE*)alloca(dwLength); memset(localbuf, 0, dwLength); in.partitionNumber = (BYTE)dwBinaryPartitionNr; in.type = BDK_READ; memcpy(in.bdkStruct.oldSign, BDK_SIGNATURE, 4); in.bdkStruct.signOffset = 8; in.bdkStruct.startingBlock = 0; // is ignored ?? (DWORD)(llOffset/dwSectorSize); in.bdkStruct.length = dwLength; in.bdkStruct.bdkBuffer = localbuf; // !!! this must be allocated on the stack. in.bdkStruct.flags = 2; // ??? flOutputStatusRecord out; memset(&out, 0, sizeof(out)); //debug("disk_bdk_readnext: reading %I64x %08lx ss=%08lx\n", llOffset, dwLength, dwSectorSize); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_BDK_OPERATION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_READ)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_READ) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } memcpy(buffer, localbuf, dwLength); dwRead= dwLength; //debug("disk_bdk_readnext: read %08lx\n", dwRead); return true; } bool TFFS_OTP_Read(HANDLE hDisk, ULONGLONG llOffset, DWORD dwLength, BYTE *buffer, DWORD &dwRead) { flOtpInput in; memset(&in, 0, sizeof(in)); flOutputStatusRecord out; memset(&out, 0, sizeof(out)); BYTE *localbuf= (BYTE*)alloca(dwLength); memset(localbuf, 0, dwLength); in.type = OTP_READ; in.usedSize= 0; in.length = dwLength; in.buffer= localbuf; tffsdebug("tffs_otp_read: reading %I64x %08lx\n", llOffset, dwLength); debug("otpcmd: %s\n", hexdump((BYTE*)&in, sizeof(in)).c_str()); DWORD nReturned=0; // NOTE: ignoring the errors returned by this api // it always seems to return 'crc-error' if (!DeviceIoControl(hDisk, FL_IOCTL_OTP, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_READ) - nr=0x%x, st=%08lx : %s", nReturned, out.status, localbuf); //return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_READ) - status=%08lx", out.status); //SetLastError(ERROR_INTERNAL_ERROR); //return false; } strncpy((char*)buffer, (char*)localbuf, in.length); dwRead= strlen((char*)buffer); tffsdebug("tffs_otp_read: read %08lx\n", dwRead); return true; } //.......... bool TFFS_ReadSectors(HANDLE hDisk, ULONGLONG llOffset, DWORD dwLength, BYTE *buffer, DWORD &dwBytesRead, DWORD dwSectorSize) { flReadWriteInput in; memset(&in, 0, sizeof(in)); BYTE *localbuf= (BYTE*)alloca(dwLength); if (localbuf==NULL) { debug("ERROR allocating stack buffer\n", localbuf); return false; } memset(localbuf, 0, dwLength); if (dwLength > dwLength) dwLength= dwLength; in.firstSector= (DWORD)(llOffset/dwSectorSize); in.numberOfSectors= dwLength/dwSectorSize; in.buf= localbuf; flReadWriteOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_READ_SECTORS, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_READ_SECTORS)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_READ_SECTORS) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } dwBytesRead= out.numberOfSectors*dwSectorSize; if (dwBytesRead > dwLength) dwBytesRead= dwLength; memcpy(buffer, localbuf, dwBytesRead); return true; } //............................... bool Disk_ReadSectors(HANDLE hDisk, ULONGLONG llOffset, DWORD dwLength, BYTE *buffer, DWORD &dwBytesRead, DWORD dwSectorSize) { SG_REQ req; req.sr_start= (DWORD)(llOffset/dwSectorSize); req.sr_num_sec= dwLength/dwSectorSize; req.sr_num_sg= 1; req.sr_status= 0; req.sr_callback= NULL; req.sr_sglist[0].sb_len= dwLength; req.sr_sglist[0].sb_buf= const_cast(buffer); tffsdebug("disk_readsectors: reading %I64x %08lx ss=%08lx\n", llOffset, dwLength, dwSectorSize); DWORD nReturned=0; if (!DeviceIoControl(hDisk, DISK_IOCTL_READ, &req, sizeof(req), NULL, NULL, &nReturned, NULL)) { error("DISK_IOCTL_READ"); return false; } dwBytesRead= req.sr_sglist[0].sb_len; tffsdebug("disk_readsectors: read %08lx\n", dwBytesRead); return true; } bool ReadDisk_Init(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG llOffset, DWORD dwLength, DWORD dwSectorSize) { switch (dwBinaryPartitionNr) { case BP_TFFSSECTOR: return true; case BP_WINCESECTOR: return true; case BP_OTPSECTOR: return true; default: return TFFS_BDK_InitRead(hDisk, dwBinaryPartitionNr, llOffset, dwLength, dwSectorSize); } } bool ReadDisk(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG llOffset, DWORD dwLength, BYTE *buffer, DWORD &dwRead, DWORD dwSectorSize) { tffsdebug("readdisk: %d : %I64x %08lx ss=%08lx\n", dwBinaryPartitionNr, llOffset, dwLength, dwSectorSize); switch(dwBinaryPartitionNr) { case BP_TFFSSECTOR: return TFFS_ReadSectors(hDisk, llOffset, dwLength, buffer, dwRead, dwSectorSize); case BP_WINCESECTOR: return Disk_ReadSectors(hDisk, llOffset, dwLength, buffer, dwRead, dwSectorSize); case BP_OTPSECTOR: return TFFS_OTP_Read(hDisk, llOffset, dwLength, buffer, dwRead); default: return TFFS_BDK_ReadNextSector(hDisk, dwBinaryPartitionNr, llOffset, dwLength, buffer, dwRead); } } ITSUTILS_API HRESULT STDAPICALLTYPE ITReadDisk( DWORD cbInput, ReadDiskParams *pbInput, DWORD *pcbOutput, ReadDiskResult **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; ReadDiskResult *pOut= *ppbOutput= NULL; HANDLE hStore, hPartition; if (pbInput->hDisk) { hPartition= (HANDLE)pbInput->hDisk; hStore= NULL; } else if (!OpenTFFSDisk(pbInput->szDeviceName, pbInput->szPartitionName, hStore, hPartition)) return GetLastError(); KernelMode _km; memcpy(BDK_SIGNATURE, pbInput->bdksign, 4); DWORD dwBlockSize, dwSectorSize; if (!Disk_GetDiskParams(hPartition, pbInput->dwBinaryPartitionNr, dwBlockSize, dwSectorSize)) { if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return GetLastError(); } // allow user override of sectorsize if (pbInput->dwSectorSize) dwSectorSize= pbInput->dwSectorSize; if (pbInput->dwBlockSize) dwBlockSize= pbInput->dwBlockSize; if (pbInput->llOffset % dwSectorSize) { debug("ERROR: ITReadDisk: startoffset not on sector boundary(%04x): sector nr %I64x ofs %04I64x\n", dwSectorSize, pbInput->llOffset / dwSectorSize, pbInput->llOffset % dwSectorSize); if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return ERROR_INVALID_PARAMETER; } if ((pbInput->llOffset+pbInput->dwSize) % dwSectorSize) { debug("ERROR: ITReadDisk: endoffset not on sector boundary(%04x): sector nr %I64x ofs %04I64x\n", dwSectorSize, (pbInput->llOffset+pbInput->dwSize)/ dwSectorSize, (pbInput->llOffset+pbInput->dwSize)% dwSectorSize); if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return ERROR_INVALID_PARAMETER; } if (!ReadDisk_Init(hPartition, pbInput->dwBinaryPartitionNr, pbInput->llOffset, pbInput->dwSize, dwSectorSize)) { if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return GetLastError(); } *pcbOutput= PTR_DIFF(pOut, pOut->buffer+pbInput->dwSize); pOut= *ppbOutput= (ReadDiskResult*)LocalAlloc(LPTR, *pcbOutput); if (pOut==NULL) { error("LocalAlloc(%d)", *pcbOutput); if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return GetLastError(); } DWORD dwRes= 0; tffsdebug("reading %I64x : %08lx bytes bs=%08lx ss=%08lx\n", pbInput->llOffset, pbInput->dwSize, dwBlockSize, dwSectorSize); DWORD dwRemainingLength= pbInput->dwSize; DWORD dwBufOffset= 0; ULONGLONG llDiskOffset= pbInput->llOffset; while (dwRemainingLength) { // make sure first wanted makes diskoffset allign to blocksize DWORD dwWanted= dwBlockSize - ((DWORD)llDiskOffset&(dwBlockSize-1)); if (dwWanted > dwRemainingLength) dwWanted= dwRemainingLength; tffsdebug("w=%08lx b=%08lx o=%I64x r=%08lx\n", dwWanted, dwBlockSize, llDiskOffset, dwRemainingLength); DWORD dwRead; if (!ReadDisk(hPartition, pbInput->dwBinaryPartitionNr, llDiskOffset, dwWanted, pOut->buffer+dwBufOffset, dwRead, dwSectorSize)) { dwRes= GetLastError(); if (dwRes==0) dwRes= ERROR_INTERNAL_ERROR; break; } if (dwRead==0) break; dwBufOffset += dwRead; llDiskOffset += dwRead; // ?? maybe don't add dwRead for BDK read? dwRemainingLength -= dwRead; } tffsdebug("done reading: remaining: %08lx endofs=%08lx\n", dwRemainingLength, llDiskOffset); if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); pOut->dwNumberOfBytesRead= dwBufOffset; return dwRes; } //////////////////////////////////////////////////////////////////////////////////// // write functions bool TFFS_BDK_InitWrite(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG llOffset, DWORD dwSize, DWORD dwSectorSize) { flBDKOperationInput in; memset(&in, 0, sizeof(in)); in.partitionNumber = (BYTE)dwBinaryPartitionNr; in.type = BDK_INIT_WRITE; memcpy(in.bdkStruct.oldSign, BDK_SIGNATURE, 4); in.bdkStruct.signOffset = 8; in.bdkStruct.startingBlock = (DWORD)(llOffset/dwSectorSize); in.bdkStruct.length = dwSize; in.bdkStruct.flags = 0x0a; // ERASE_BEFORE_WRITE flOutputStatusRecord out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_BDK_OPERATION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_INIT_WRITE, start=%08x len=%08x)", (DWORD)(llOffset/dwSectorSize), dwSize); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_INIT_WRITE, start=%08x len=%08x) - status=%08lx", (DWORD)(llOffset/dwSectorSize), dwSize, out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } return true; } bool TFFS_BDK_WriteNextSector(HANDLE hDisk, DWORD dwBinaryPartitionNr, DWORD dwStartSector, ULONGLONG llOffset, DWORD dwLength, const BYTE *buffer, DWORD &dwWritten) { flBDKOperationInput in; memset(&in, 0, sizeof(in)); // limit to 512 bytes per call for stable operation if (dwLength>512) dwLength= 512; BYTE *localbuf= (BYTE*)alloca(dwLength); memcpy(localbuf, buffer, dwLength); in.partitionNumber = (BYTE)dwBinaryPartitionNr; in.type = BDK_WRITE; memcpy(in.bdkStruct.oldSign, BDK_SIGNATURE, 4); in.bdkStruct.signOffset = 8; in.bdkStruct.startingBlock = dwStartSector; in.bdkStruct.length = dwLength; in.bdkStruct.bdkBuffer = localbuf; // !!! this must be allocated on the stack. in.bdkStruct.flags = 0x0a; // ??? flOutputStatusRecord out; memset(&out, 0, sizeof(out)); //debug("disk_bdk_writenext: writing %I64x %08lx\n", llOffset, dwLength); // special for herald //*(DWORD*)0xB0027354= 1; // special for artemis //*(DWORD*)0xB0027350= 1; if (g_pWriteEnableFlag) *g_pWriteEnableFlag= 1; DWORD nReturned=0; if (!DeviceIoControl(hDisk, FL_IOCTL_BDK_OPERATION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_WRITE, l=0x%x nret=0x%x, start=0x%x ofs=0x%I64x)", dwLength, nReturned, dwStartSector, llOffset); if (nReturned==4) { debug("BDK_WRITE return value: %08lx\n", *(DWORD*)&out); } return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_WRITE) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } dwWritten= in.bdkStruct.length; //debug("disk_bdk_writenext: wrote %08lx\n", dwWritten); return true; } bool TFFS_OTP_Write(HANDLE hDisk, ULONGLONG llOffset, DWORD dwLength, const BYTE *buffer, DWORD &dwWritten) { flOtpInput in; memset(&in, 0, sizeof(in)); flOutputStatusRecord out; memset(&out, 0, sizeof(out)); BYTE *localbuf= (BYTE*)alloca(dwLength); memcpy(localbuf, buffer, dwLength); in.type = OTP_WRITE_LOCK; in.usedSize= 0; in.length = dwLength; in.buffer= localbuf; tffsdebug("tffs_otp_write: writing %I64x %08lx\n", llOffset, dwLength); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_OTP, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_WRITE)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_WRITE) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } dwWritten= in.length; tffsdebug("tffs_otp_write: wrote %08lx\n", dwWritten); return true; } //.......... bool TFFS_WriteSectors(HANDLE hDisk, ULONGLONG llOffset, DWORD dwLength, const BYTE *buffer, DWORD &dwBytesWritten, DWORD dwSectorSize) { flReadWriteInput in; memset(&in, 0, sizeof(in)); BYTE *localbuf= (BYTE*)alloca(dwLength); memcpy(localbuf, buffer, dwLength); if (dwLength > dwLength) dwLength= dwLength; in.firstSector= (DWORD)(llOffset/dwSectorSize); in.numberOfSectors= dwLength/dwSectorSize; in.buf= localbuf; flReadWriteOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_WRITE_SECTORS, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_WRITE_SECTORS)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_WRITE_SECTORS) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } dwBytesWritten= out.numberOfSectors*dwSectorSize; if (dwBytesWritten > dwLength) dwBytesWritten= dwLength; return true; } //............................... bool Disk_WriteSectors(HANDLE hDisk, ULONGLONG llOffset, DWORD dwLength, const BYTE *buffer, DWORD &dwBytesWritten, DWORD dwSectorSize) { SG_REQ req; req.sr_start= (DWORD)(llOffset/dwSectorSize); req.sr_num_sec= dwLength/dwSectorSize; req.sr_num_sg= 1; req.sr_status= 0; req.sr_callback= NULL; req.sr_sglist[0].sb_len= dwLength; req.sr_sglist[0].sb_buf= const_cast(buffer); tffsdebug("disk_writesectors: writing %I64x %08lx ss=%08lx\n", llOffset, dwLength, dwSectorSize); DWORD nReturned=0; if (!DeviceIoControl(hDisk, DISK_IOCTL_WRITE, &req, sizeof(req), NULL, NULL, &nReturned, NULL)) { error("DISK_IOCTL_WRITE"); return false; } dwBytesWritten= req.sr_sglist[0].sb_len; tffsdebug("disk_writesectors: wrote %08lx\n", dwBytesWritten); return true; } bool WriteDisk_Init(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG llOffset, DWORD dwLength, DWORD dwSectorSize) { switch (dwBinaryPartitionNr) { case BP_TFFSSECTOR: return true; case BP_WINCESECTOR: return true; case BP_OTPSECTOR: return true; default: return TFFS_BDK_InitWrite(hDisk, dwBinaryPartitionNr, llOffset, dwLength, dwSectorSize); } } bool WriteDisk(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG llStartOffset, ULONGLONG llOffset, DWORD dwLength, const BYTE *buffer, DWORD &dwWritten, DWORD dwSectorSize) { tffsdebug("writedisk: %d : %I64x %08lx ss=%08lx\n", dwBinaryPartitionNr, llOffset, dwLength, dwSectorSize); switch(dwBinaryPartitionNr) { case BP_TFFSSECTOR: return TFFS_WriteSectors(hDisk, llOffset, dwLength, buffer, dwWritten, dwSectorSize); case BP_WINCESECTOR: return Disk_WriteSectors(hDisk, llOffset, dwLength, buffer, dwWritten, dwSectorSize); case BP_OTPSECTOR: return TFFS_OTP_Write(hDisk, llOffset, dwLength, buffer, dwWritten); default: return TFFS_BDK_WriteNextSector(hDisk, dwBinaryPartitionNr, (DWORD)(llStartOffset/dwSectorSize), llOffset, dwLength, buffer, dwWritten); } } ITSUTILS_API HRESULT STDAPICALLTYPE ITWriteDisk( DWORD cbInput, WriteDiskParams *pbInput, DWORD *pcbOutput, WriteDiskResult **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; WriteDiskResult *pOut= *ppbOutput= NULL; HANDLE hStore, hPartition; if (pbInput->hDisk) { hPartition= (HANDLE)pbInput->hDisk; hStore= NULL; } else if (!OpenTFFSDisk(pbInput->szDeviceName, pbInput->szPartitionName, hStore, hPartition)) return GetLastError(); KernelMode _km; memcpy(BDK_SIGNATURE, pbInput->bdksign, 4); DWORD dwBlockSize, dwSectorSize; if (!Disk_GetDiskParams(hPartition, pbInput->dwBinaryPartitionNr, dwBlockSize, dwSectorSize)) { if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return GetLastError(); } // allow user override of sectorsize if (pbInput->dwSectorSize) dwSectorSize= pbInput->dwSectorSize; if (pbInput->dwBlockSize) dwBlockSize= pbInput->dwBlockSize; if (pbInput->llOffset % dwSectorSize) { debug("ERROR: ITWriteDisk: startoffset not on sector boundary(%04x): sector nr %I64x ofs %04I64x\n", dwSectorSize, pbInput->llOffset / dwSectorSize, pbInput->llOffset % dwSectorSize); if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return ERROR_INVALID_PARAMETER; } if ((pbInput->llOffset+pbInput->dwSize) % dwSectorSize) { debug("ERROR: ITWriteDisk: endoffset not on sector boundary(%04x): sector nr %I64x ofs %04I64x\n", dwSectorSize, (pbInput->llOffset+pbInput->dwSize)/ dwSectorSize, (pbInput->llOffset+pbInput->dwSize)% dwSectorSize); if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return ERROR_INVALID_PARAMETER; } if (!WriteDisk_Init(hPartition, pbInput->dwBinaryPartitionNr, pbInput->llOffset, pbInput->dwSize, dwSectorSize)) { if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return GetLastError(); } *pcbOutput= sizeof(WriteDiskResult); pOut= *ppbOutput= (WriteDiskResult*)LocalAlloc(LPTR, *pcbOutput); if (pOut==NULL) { error("LocalAlloc(%d)", *pcbOutput); if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return GetLastError(); } DWORD dwRes= 0; g_pWriteEnableFlag= (DWORD*)pbInput->pWriteEnableFlag; tffsdebug("writing %I64x : %08lx bytes bs=%08lx ss=%08lx\n", pbInput->llOffset, pbInput->dwSize, dwBlockSize, dwSectorSize); DWORD dwRemainingLength= pbInput->dwSize; DWORD dwBufOffset= 0; ULONGLONG llDiskOffset= pbInput->llOffset; while (dwRemainingLength) { // make sure first wanted makes diskoffset allign to blocksize DWORD dwWanted= dwBlockSize - ((DWORD)llDiskOffset&(dwBlockSize-1)); if (dwWanted > dwRemainingLength) dwWanted= dwRemainingLength; tffsdebug("w=%08lx b=%08lx o=%I64x r=%08lx\n", dwWanted, dwBlockSize, llDiskOffset, dwRemainingLength); DWORD dwWritten; if (!WriteDisk(hPartition, pbInput->dwBinaryPartitionNr, pbInput->llOffset, llDiskOffset, dwWanted, pbInput->buffer+dwBufOffset, dwWritten, dwSectorSize)) { dwRes= GetLastError(); if (dwRes==0) dwRes= ERROR_INTERNAL_ERROR; break; } if (dwWritten==0) break; dwBufOffset += dwWritten; llDiskOffset += dwWritten; // ?? maybe don't add dwWritten for BDK write? dwRemainingLength -= dwWritten; } if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); pOut->dwNumberOfBytesWritten= dwBufOffset; return dwRes; } const char *doctypenames[]= { "NOT_DOC", "DOC", "MDOC", "DOC2000TSOP", "MDOCP_16", "MDOCP", "DOC_H1", "MDOC512_G3", "MDOC256_P3", "MDOC256_G3", "MDOC128_P3", "AMD_NOR", "SEIJA", "MDOC_G4", "MDOC_P4", }; #define NDOCTYPENAMES (sizeof(doctypenames)/sizeof(*doctypenames)) //////////////////////////////////////////////////////////////////////// // info functions bool TFFS_GetInfo(HANDLE hDisk) { flDiskInfoOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_GET_INFO, NULL, 0, &out, sizeof(out), &nReturned, NULL)) { debug("get_info - out: %hs\n", hexdump((BYTE*)&out, sizeof(out)).c_str()); error("DeviceIoControl(FL_IOCTL_GET_INFO)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_GET_INFO) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } debug("getinfo: logical=%08lx boot=%08lx base=%08lx ft=%04x phys=%08lx unitsize=%08lx\n", out.info.logicalSectors, out.info.bootAreaSize, out.info.baseAddress, out.info.flashType, out.info.physicalSize, out.info.physicalUnitSize); debug("getinfo: doctype=%02x(%s) lifetime=%02x driver='%s' osak='%s' cyl=%d hd=%d sc=%d\n", out.info.DOCType, (out.info.DOCType>=0 && out.info.DOCType<= NDOCTYPENAMES)? doctypenames[out.info.DOCType]: "", out.info.lifeTime, out.info.driverVer, out.info.OSAKVer, out.info.cylinders, out.info.heads, out.info.sectors); return true; } std::string SI_DeviceClassString(DWORD dw) { switch(dw) { case STORAGE_DEVICE_CLASS_BLOCK : return "BLOCK"; case STORAGE_DEVICE_CLASS_MULTIMEDIA: return "MULTIMEDIA"; default: return stringformat("UNKNOWNDEVCLASS_%08lx", dw); } } std::string SI_DeviceTypeString(DWORD dw) { if (dw==0) return "(none)"; StringList list; if (dw&STORAGE_DEVICE_TYPE_PCIIDE ) list.push_back("PCIIDE"); if (dw&STORAGE_DEVICE_TYPE_FLASH ) list.push_back("FLASH"); if (dw&STORAGE_DEVICE_TYPE_ATA ) list.push_back("ATA"); if (dw&STORAGE_DEVICE_TYPE_ATAPI ) list.push_back("ATAPI"); if (dw&STORAGE_DEVICE_TYPE_PCCARD ) list.push_back("PCCARD"); if (dw&STORAGE_DEVICE_TYPE_CFCARD ) list.push_back("CFCARD"); if (dw&STORAGE_DEVICE_TYPE_SRAM ) list.push_back("SRAM"); if (dw&STORAGE_DEVICE_TYPE_DVD ) list.push_back("DVD"); if (dw&STORAGE_DEVICE_TYPE_CDROM ) list.push_back("CDROM"); if (dw&STORAGE_DEVICE_TYPE_USB ) list.push_back("USB"); if (dw&STORAGE_DEVICE_TYPE_1394 ) list.push_back("1394"); if (dw&STORAGE_DEVICE_TYPE_DOC ) list.push_back("DOC"); if (dw&STORAGE_DEVICE_TYPE_UNKNOWN ) list.push_back("UNKNOWN"); if (dw&STORAGE_DEVICE_TYPE_REMOVABLE_DRIVE) list.push_back("REMOVABLE_DRIVE"); if (dw&STORAGE_DEVICE_TYPE_REMOVABLE_MEDIA) list.push_back("REMOVABLE_MEDIA"); const DWORD knownflags= STORAGE_DEVICE_TYPE_PCIIDE|STORAGE_DEVICE_TYPE_FLASH|STORAGE_DEVICE_TYPE_ATA|STORAGE_DEVICE_TYPE_ATAPI|STORAGE_DEVICE_TYPE_PCCARD|STORAGE_DEVICE_TYPE_CFCARD|STORAGE_DEVICE_TYPE_SRAM|STORAGE_DEVICE_TYPE_DVD|STORAGE_DEVICE_TYPE_CDROM|STORAGE_DEVICE_TYPE_USB|STORAGE_DEVICE_TYPE_1394|STORAGE_DEVICE_TYPE_DOC|STORAGE_DEVICE_TYPE_UNKNOWN|STORAGE_DEVICE_TYPE_REMOVABLE_DRIVE|STORAGE_DEVICE_TYPE_REMOVABLE_MEDIA; if (dw&~knownflags) list.push_back(stringformat("UNKNOWNDEVTYPE_%08lx", dw&~knownflags)); return JoinStringList(list, ","); } std::string SI_DeviceFlagsString(DWORD dw) { if (dw==0) return "(none)"; StringList list; if (dw&STORAGE_DEVICE_FLAG_READWRITE ) list.push_back("READWRITE"); if (dw&STORAGE_DEVICE_FLAG_READONLY ) list.push_back("READONLY"); if (dw&STORAGE_DEVICE_FLAG_TRANSACTED) list.push_back("TRANSACTED"); if (dw&STORAGE_DEVICE_FLAG_MEDIASENSE) list.push_back("MEDIASENSE"); const DWORD knownflags= STORAGE_DEVICE_FLAG_READWRITE|STORAGE_DEVICE_FLAG_READONLY|STORAGE_DEVICE_FLAG_TRANSACTED|STORAGE_DEVICE_FLAG_MEDIASENSE; if (dw&~knownflags) list.push_back(stringformat("UNKNOWNDEVFLAGS_%08lx", dw&~knownflags)); return JoinStringList(list, ","); } std::string GetStorageDeviceInfoString(const STORAGEDEVICEINFO& sdi) { if (sdi.cbSize!=sizeof(STORAGEDEVICEINFO)) debug("WARNING: sdi.cbSize=%d (!= %d)\n", sdi.cbSize, sizeof(STORAGEDEVICEINFO)); return stringformat("profile='%ls' class=%s type=%s flags=%s", sdi.szProfile, SI_DeviceClassString(sdi.dwDeviceClass).c_str(), SI_DeviceTypeString(sdi.dwDeviceType).c_str(), SI_DeviceFlagsString(sdi.dwDeviceFlags).c_str()); } std::string SectorNumString(const SECTORNUM& sn) { return stringformat("%I64x", sn); } std::string FileTimeString(const FILETIME& ft) { if (ft.dwLowDateTime==0 && ft.dwHighDateTime==0) return "(null)"; SYSTEMTIME systime; FILETIME lfiletime; FileTimeToLocalFileTime(&ft, &lfiletime); FileTimeToSystemTime(&lfiletime, &systime); return stringformat("%04d-%02d-%02d %02d:%02d:%02d.%03d", systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond,systime.wMilliseconds); } std::string SI_AttributesString(DWORD dw) { if (dw==0) return "(none)"; StringList list; if (dw&STORE_ATTRIBUTE_READONLY ) list.push_back("READONLY"); if (dw&STORE_ATTRIBUTE_REMOVABLE ) list.push_back("REMOVABLE"); if (dw&STORE_ATTRIBUTE_UNFORMATTED) list.push_back("UNFORMATTED"); if (dw&STORE_ATTRIBUTE_AUTOFORMAT ) list.push_back("AUTOFORMAT"); if (dw&STORE_ATTRIBUTE_AUTOPART ) list.push_back("AUTOPART"); if (dw&STORE_ATTRIBUTE_AUTOMOUNT ) list.push_back("AUTOMOUNT"); const DWORD knownflags= STORE_ATTRIBUTE_READONLY|STORE_ATTRIBUTE_REMOVABLE|STORE_ATTRIBUTE_UNFORMATTED|STORE_ATTRIBUTE_AUTOFORMAT|STORE_ATTRIBUTE_AUTOPART|STORE_ATTRIBUTE_AUTOMOUNT; if (dw&~knownflags) list.push_back(stringformat("UNKNOWNSATTRS_%08lx", dw&~knownflags)); return JoinStringList(list, ","); } std::string PI_AttributesString(DWORD dw) { if (dw==0) return "(none)"; StringList list; if (dw&PARTITION_ATTRIBUTE_EXPENDABLE) list.push_back("EXPENDABLE"); if (dw&PARTITION_ATTRIBUTE_READONLY ) list.push_back("READONLY"); if (dw&PARTITION_ATTRIBUTE_AUTOFORMAT) list.push_back("AUTOFORMAT"); if (dw&PARTITION_ATTRIBUTE_ACTIVE ) list.push_back("ACTIVE"); if (dw&PARTITION_ATTRIBUTE_BOOT ) list.push_back("BOOT"); if (dw&PARTITION_ATTRIBUTE_MOUNTED ) list.push_back("MOUNTED"); const DWORD knownflags= PARTITION_ATTRIBUTE_EXPENDABLE|PARTITION_ATTRIBUTE_READONLY|PARTITION_ATTRIBUTE_AUTOFORMAT|PARTITION_ATTRIBUTE_ACTIVE|PARTITION_ATTRIBUTE_BOOT|PARTITION_ATTRIBUTE_MOUNTED; if (dw&~knownflags) list.push_back(stringformat("UNKNOWNPATTRS_%08lx", dw&~knownflags)); return JoinStringList(list, ","); } std::string StoreInfoString(const STOREINFO& si) { std::string str; if (si.cbSize!=sizeof(STOREINFO)) debug("WARNING: si.cbSize=%d (!= %d)\n", si.cbSize, sizeof(STOREINFO)); str += stringformat("dev='%ls' store='%ls' ", si.szDeviceName, si.szStoreName); str += stringformat(" nsect=%s bpsect=%x free=%s maxpartsize=%s", SectorNumString(si.snNumSectors).c_str(), si.dwBytesPerSector, SectorNumString(si.snFreeSectors).c_str(), SectorNumString(si.snBiggestPartCreatable).c_str()); str += stringformat(" created=%s modified=%s", FileTimeString(si.ftCreated).c_str(), FileTimeString(si.ftLastModified).c_str()); str += stringformat(" attribs=%s partitions=%d mounts=%d\n", SI_AttributesString(si.dwAttributes).c_str(), si.dwPartitionCount, si.dwMountCount); str += stringformat(" si=%08lx -> class=%08lx type=%08lx\n", &si, si.dwDeviceClass, si.dwDeviceType); str += stringformat(" class=%s type=%s flags=%s\n", SI_DeviceClassString(si.dwDeviceClass).c_str(), SI_DeviceTypeString(si.dwDeviceType).c_str(), SI_DeviceFlagsString(si.dwDeviceFlags).c_str()); str += stringformat(" sdi: %s\n", GetStorageDeviceInfoString(si.sdi).c_str()); return str; } std::string PartitionInfoString(const PARTINFO& pi) { std::string str; if (pi.cbSize!=sizeof(PARTINFO)) debug("WARNING: pi.cbSize=%d (!= %d)\n", pi.cbSize, sizeof(PARTINFO)); str += stringformat("name='%ls' filesys='%ls' volname='%ls'", pi.szPartitionName, pi.szFileSys, pi.szVolumeName); str += stringformat(" end=%s created=%s modified=%s", SectorNumString(pi.snNumSectors).c_str(), FileTimeString(pi.ftCreated).c_str(), FileTimeString(pi.ftLastModified).c_str()); str += stringformat(" attr=%s type=%02x\n", PI_AttributesString(pi.dwAttributes).c_str(), pi.bPartType); return str; } bool GetStorageDeviceInfo(HANDLE hDisk, STORAGEDEVICEINFO &sdi) { DWORD dwReturned; sdi.cbSize= sizeof(STORAGEDEVICEINFO); if (DeviceIoControl(hDisk, IOCTL_DISK_DEVICE_INFO, &sdi, sizeof(STORAGEDEVICEINFO), NULL, 0, &dwReturned, NULL)) return true; error("IOCTL_DISK_DEVICE_INFO(in)"); sdi.cbSize= sizeof(STORAGEDEVICEINFO); if (DeviceIoControl(hDisk, IOCTL_DISK_DEVICE_INFO, NULL, 0, &sdi, sizeof(STORAGEDEVICEINFO), &dwReturned, NULL)) return true; error("IOCTL_DISK_DEVICE_INFO(out)"); return false; } std::string DiskInfoFlagsString(DWORD dw) { if (dw==0) return "(none)"; StringList list; if (dw&DISK_INFO_FLAG_MBR ) list.push_back("MBR"); if (dw&DISK_INFO_FLAG_CHS_UNCERTAIN ) list.push_back("CHS_UNCERTAIN"); if (dw&DISK_INFO_FLAG_UNFORMATTED ) list.push_back("UNFORMATTED"); if (dw&DISK_INFO_FLAG_PAGEABLE ) list.push_back("PAGEABLE"); const DWORD knownflags= DISK_INFO_FLAG_MBR|DISK_INFO_FLAG_CHS_UNCERTAIN|DISK_INFO_FLAG_UNFORMATTED|DISK_INFO_FLAG_PAGEABLE; if (dw&~knownflags) list.push_back(stringformat("UNKNOWNFLAGS_%08lx", dw&~knownflags)); return JoinStringList(list, ","); } std::string DiskInfoString(const DISK_INFO &di) { return stringformat("tot=0x%08lx bps=0x%x cyls=0x%x hds=0x%x sectpcyl=0x%x flags=%hs", di.di_total_sectors, di.di_bytes_per_sect, di.di_cylinders, di.di_heads, di.di_sectors, DiskInfoFlagsString(di.di_flags).c_str()); } bool GetDiskStorageId(HANDLE hDisk, ByteVector &mfid, ByteVector &serialnr) { ByteVector data; STORAGE_IDENTIFICATION *sid= NULL; data.resize(sizeof(STORAGE_IDENTIFICATION)+256); sid= (STORAGE_IDENTIFICATION*)vectorptr(data); DWORD dwReturned; while (!DeviceIoControl(hDisk, IOCTL_DISK_GET_STORAGEID, NULL, 0, sid, data.size(), &dwReturned, NULL)) { if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER) { error("IOCTL_DISK_GET_STORAGEID(out)"); return false; } data.resize(data.size()*2); sid= (STORAGE_IDENTIFICATION*)vectorptr(data); } if ((sid->dwFlags&MANUFACTUREID_INVALID)==0) { mfid.resize(sid->dwManufactureIDOffset < sid->dwSerialNumOffset ? sid->dwSerialNumOffset-sid->dwManufactureIDOffset : sid->dwSize-sid->dwManufactureIDOffset ); memcpy(vectorptr(mfid), &data[sid->dwManufactureIDOffset], mfid.size()); } if ((sid->dwFlags&SERIALNUM_INVALID)==0) { serialnr.resize(sid->dwSerialNumOffset < sid->dwManufactureIDOffset ? sid->dwManufactureIDOffset-sid->dwSerialNumOffset : sid->dwSize-sid->dwSerialNumOffset); memcpy(vectorptr(serialnr), &data[sid->dwSerialNumOffset], serialnr.size()); } const DWORD dwKnownFlags= MANUFACTUREID_INVALID|SERIALNUM_INVALID; if (sid->dwFlags&~dwKnownFlags) debug("WARNING: STORAGE_IDENTIFICATION: unknown flags: %08lx\n", sid->dwFlags&~dwKnownFlags); return true; } bool GetDiskName(HANDLE hDisk, std::string &name) { WCHAR namebuf[MAX_PATH]; DWORD dwReturned; if (!DeviceIoControl(hDisk, IOCTL_DISK_GETNAME, NULL, 0, namebuf, sizeof(namebuf), &dwReturned, NULL)) { error("IOCTL_DISK_GETNAME(out)"); return false; } name= ToString(namebuf); return true; } ITSUTILS_API HRESULT STDAPICALLTYPE ITTFFSGetInfo( DWORD cbInput, TFFSGetInfoParams *pbInput, DWORD *pcbOutput, TFFSGetInfoResult **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; TFFSGetInfoResult *pOut= *ppbOutput= NULL; HANDLE hStore, hPartition; if (pbInput->hDisk) { hPartition= (HANDLE)pbInput->hDisk; hStore= NULL; } else if (!OpenTFFSDisk(pbInput->szDeviceName, pbInput->szPartitionName, hStore, hPartition)) return GetLastError(); KernelMode _km; memcpy(BDK_SIGNATURE, pbInput->bdksign, 4); DWORD dwBlockSize, dwSectorSize; if (!Disk_GetDiskParams(hPartition, pbInput->dwBinaryPartitionNr, dwBlockSize, dwSectorSize)) { if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return GetLastError(); } tffsdebug("diskparams: bs=%08lx ss=%08lx\n", dwBlockSize, dwSectorSize); ULONGLONG llDiskSize; if (!Disk_GetDiskSize(hPartition, pbInput->dwBinaryPartitionNr, llDiskSize)) { if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return GetLastError(); } tffsdebug("disksize: %I64x\n", llDiskSize); DWORD dwNrParts=0; if (TFFS_GetNrOfPartitions(hPartition, dwNrParts)) tffsdebug("tffs: %d partitions\n", dwNrParts); DWORD dwNrBParts=0; DWORD dwBPLength=0; if (TFFS_BDK_GetInfo(hPartition, 0, dwBPLength, dwNrBParts)) tffsdebug("%d binary partitions, first=%08lx\n", dwNrBParts, dwBPLength); DWORD custid=0; if (TFFS_GetCustomerId(hPartition, custid)) tffsdebug("tffs custid: %08lx\n", custid); GUID tffsid; memset(&tffsid, 0, sizeof(tffsid)); if (TFFS_GetUniqueId(hPartition, tffsid)) tffsdebug("tffs uniqueid: %hs\n", GuidAsString(tffsid).c_str()); if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); *pcbOutput= sizeof(TFFSGetInfoResult); pOut= *ppbOutput= (TFFSGetInfoResult*)LocalAlloc(LPTR, *pcbOutput); if (pOut==NULL) { error("LocalAlloc(%d)", *pcbOutput); return GetLastError(); } pOut->dwSectorSize= dwSectorSize; pOut->llDiskSize= llDiskSize; pOut->uniqueid= tffsid; pOut->customerid= custid; pOut->dwNrofBinPartitions= dwNrBParts; pOut->dwNrPartitions= dwNrParts; return 0; } ITSUTILS_API HRESULT STDAPICALLTYPE ITLogDiskInfo( DWORD cbInput, LogDiskInfoParams *pbInput, DWORD *pcbOutput, BYTE **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; *ppbOutput= NULL; HANDLE hStore, hPartition; if (pbInput->hDisk) { hPartition= (HANDLE)pbInput->hDisk; hStore= NULL; debug("listing diskinfo for existing handle %08lx\n", hPartition); } else if (!OpenTFFSDisk(pbInput->szDeviceName, pbInput->szPartitionName, hStore, hPartition)) return GetLastError(); else debug("listing diskinfo for %08lx:%08lx %ls/%ls\n", hStore, hPartition, pbInput->szDeviceName, pbInput->szPartitionName); KernelMode _km; memcpy(BDK_SIGNATURE, pbInput->bdksign, 4); TFFS_GetInfo(hPartition); DWORD dwNrParts; if (TFFS_GetNrOfPartitions(hPartition, dwNrParts)) debug("tffs: %d partitions\n", dwNrParts); DWORD dwNrBParts=0; DWORD dwLength=0; if (TFFS_BDK_GetInfo(hPartition, 0, dwLength, dwNrBParts)) { debug("tffs: %d binary partitions\n", dwNrBParts); debug("bdk%d: %08lx\n", 0, dwLength); for (DWORD p=1 ; phDisk==NULL) CloseTFFSDisk(hStore, hPartition); return 0; } bool Disk_GetDiskSize(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG &llDiskSize) { switch (dwBinaryPartitionNr) { case BP_TFFSSECTOR: case BP_WINCESECTOR: { DISK_INFO di; if (!GetDiskInfo(hDisk, di)) { error("GetDiskInfo"); llDiskSize= 0; return false; } llDiskSize= UInt32x32To64(di.di_total_sectors, di.di_bytes_per_sect); return true; } case BP_OTPSECTOR: { DWORD dwOtpSize, dwMaxOtpSize; if (!TFFS_OTP_GetSize(hDisk, dwOtpSize, dwMaxOtpSize)) { error("TFFS_OTP_GetSize"); llDiskSize= 0; return false; } llDiskSize= dwOtpSize; // returning current size, .. or should i return max size here? return true; } default: { DWORD dwLength, dwNrBParts; if (!TFFS_BDK_GetInfo(hDisk, dwBinaryPartitionNr, dwLength, dwNrBParts)) { error("TFFS_BDK_GetInfo(%d)", dwBinaryPartitionNr); llDiskSize= 0; return false; } llDiskSize= dwLength; return true; } } } bool Disk_GetDiskParams(HANDLE hDisk, DWORD dwBinaryPartitionNr, DWORD &dwBlockSize, DWORD &dwSectorSize) { switch (dwBinaryPartitionNr) { case BP_TFFSSECTOR: dwBlockSize= TFFS_SECTOR_SIZE*16; dwSectorSize= TFFS_SECTOR_SIZE; return true; case BP_WINCESECTOR: // todo: read this from GetStoreInfo. dwBlockSize= TFFS_SECTOR_SIZE*16; dwSectorSize= TFFS_SECTOR_SIZE; return true; case BP_OTPSECTOR: dwBlockSize= TFFS_BLOCK_SIZE; dwSectorSize= TFFS_SECTOR_SIZE; return true; default: // for bdk partitions: dwBlockSize= TFFS_BLOCK_SIZE; dwSectorSize= TFFS_BLOCK_SIZE; return true; } } bool TFFS_ChangeType(HANDLE hDisk, bool bInsert, BYTE *password) { //flChangeTypeionInput in; memset(&in, 0, sizeof(in)); BYTE in[10]; in[0]= PROTECTABLE | (bInsert ? 0 : WRITE_PROTECTED); memcpy(in+1, password, 8); in[9]= PROTECTION_CHANGE_TYPE; flProtectionOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned=0; if (!DeviceIoControl(hDisk, FL_IOCTL_BDTL_HW_PROTECTION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("FL_IOCTL_BDTL_HW_PROTECTION-%s-key", bInsert?"insert":"remove"); return false; } return true; } bool TFFS_BDK_ChangeType(HANDLE hDisk, DWORD dwBinaryPartitionNr, bool bInsert, BYTE *password) { //flBDKChangeTypeionInput in; memset(&in, 0, sizeof(in)); BYTE in[11]; in[0]= dwBinaryPartitionNr; in[1]= PROTECTABLE | (bInsert ? 0 : WRITE_PROTECTED); memcpy(in+2, password, 8); in[10]= PROTECTION_CHANGE_TYPE; flProtectionOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned=0; if (!DeviceIoControl(hDisk, FL_IOCTL_BINARY_HW_PROTECTION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("FL_IOCTL_BINARY_HW_PROTECTION-%s-key", bInsert?"insert":"remove"); return false; } return true; } bool TFFS_Protect(HANDLE hDisk, bool bInsert, BYTE *password) { //flProtectionInput in; memset(&in, 0, sizeof(in)); BYTE in[10]; in[0]= 0; memcpy(in+1, password, 8); in[9]= bInsert?PROTECTION_INSERT_KEY:PROTECTION_REMOVE_KEY; flProtectionOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned=0; if (!DeviceIoControl(hDisk, FL_IOCTL_BDTL_HW_PROTECTION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("FL_IOCTL_BDTL_HW_PROTECTION-%s-key", bInsert?"insert":"remove"); return false; } return true; } bool TFFS_BDK_Protect(HANDLE hDisk, DWORD dwBinaryPartitionNr, bool bInsert, BYTE *password) { //flBDKProtectionInput in; memset(&in, 0, sizeof(in)); BYTE in[11]; in[0]= dwBinaryPartitionNr; in[1]= 0; memcpy(in+2, password, 8); in[10]= bInsert?PROTECTION_INSERT_KEY:PROTECTION_REMOVE_KEY; flProtectionOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned=0; if (!DeviceIoControl(hDisk, FL_IOCTL_BINARY_HW_PROTECTION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("FL_IOCTL_BINARY_HW_PROTECTION-%s-key", bInsert?"insert":"remove"); return false; } return true; } bool DiskProtect(HANDLE hDisk, DWORD dwBinaryPartitionNr, bool bInsert, BYTE *password) { tffsdebug("protect: %d : %d %s\n", dwBinaryPartitionNr, bInsert, password); switch(dwBinaryPartitionNr) { case BP_TFFSSECTOR: if (bInsert) { TFFS_BDK_Protect(hDisk, 0, bInsert, password); TFFS_BDK_ChangeType(hDisk, 0, bInsert, password); TFFS_Protect(hDisk, bInsert, password); TFFS_ChangeType(hDisk, bInsert, password); } else { TFFS_ChangeType(hDisk, bInsert, password); TFFS_Protect(hDisk, bInsert, password); TFFS_BDK_ChangeType(hDisk, 0, bInsert, password); TFFS_BDK_Protect(hDisk, 0, bInsert, password); } return true; case BP_WINCESECTOR: return true; case BP_OTPSECTOR: return true; default: if (bInsert) { TFFS_BDK_Protect(hDisk, dwBinaryPartitionNr, bInsert, password); TFFS_BDK_ChangeType(hDisk, dwBinaryPartitionNr, bInsert, password); TFFS_Protect(hDisk, bInsert, password); TFFS_ChangeType(hDisk, bInsert, password); } else { TFFS_ChangeType(hDisk, bInsert, password); TFFS_Protect(hDisk, bInsert, password); TFFS_BDK_ChangeType(hDisk, dwBinaryPartitionNr, bInsert, password); TFFS_BDK_Protect(hDisk, dwBinaryPartitionNr, bInsert, password); } } return true; } ITSUTILS_API HRESULT STDAPICALLTYPE ITDiskProtect( DWORD cbInput, DiskProtectParams *pbInput, DWORD *pcbOutput, DiskProtectResult **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; DiskProtectResult *pOut= *ppbOutput= NULL; HANDLE hStore, hPartition; if (pbInput->hDisk) { hPartition= (HANDLE)pbInput->hDisk; hStore= NULL; } else if (!OpenTFFSDisk(pbInput->szDeviceName, pbInput->szPartitionName, hStore, hPartition)) return GetLastError(); KernelMode _km; memcpy(BDK_SIGNATURE, pbInput->bdksign, 4); if (!DiskProtect(hPartition, pbInput->dwBinaryPartitionNr, pbInput->bInsert, pbInput->password)) { if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return GetLastError(); } *pcbOutput= sizeof(DiskProtectResult); pOut= *ppbOutput= (DiskProtectResult*)LocalAlloc(LPTR, *pcbOutput); if (pOut==NULL) { error("LocalAlloc(%d)", *pcbOutput); if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return GetLastError(); } if (pbInput->hDisk==NULL) CloseTFFSDisk(hStore, hPartition); return 0; }