/* (C) 2003-2007 Willem Jan Hengeveld * Web: http://www.xs4all.nl/~itsme/ * http://wiki.xda-developers.com/ * * $Id: pdblist.cpp 1749 2008-03-11 17:12:13Z itsme $ * * this program allows you to list/modify databases, volumes, records * on wm2003 devices. * * on wm2005 the internal database api changed, and unfortunately the * external database api was not changed. leading to a not working api * */ #include #include #include #include #include "debug.h" #include "stringutils.h" #include "args.h" // todo: // - add itsutils interface for wm2005 edb databases // *DONE -> PoomInterface // - add delete record function // - add import database from text file function //----------------------------- void DumpObjectInfo(const CEGUID& guid, CEOID oid, bool bRecurse); void DumpDBRecord(const CEGUID& guid, CEOID recid); BOOL DumpDatabaseByOid(const CEGUID& guid, CEOID oid); void DumpDatabaseByName(const CEGUID& guid, char *name); void SearchDatabase(const CEGUID& guid, char *szDatabaseName, DWORD dwOrdering, DWORD dwFieldId, char *seektype, char *szValue); void SetFieldValue(const CEGUID& guid, CEOID dwObjectId, DWORD dwFieldId, char *szValue); void EnumDatabases(const CEGUID& guid, bool bRecurse); void EnumVolumes(bool bDoListDatabases, bool bDoRecursiveDump); void PrintFileInfo(const std::string& szFileName); BOOL isOid(const CEGUID& guid, CEOID oid); std::string guidstring(const CEGUID& guid); void usage() { printf("(C) 2003-2008 Willem jan Hengeveld itsme@xs4all.nl\n"); printf("pdblist [options]\n" " -d : dump all databases\n" " -D : dump all databases of all volumes\n" " -d {oid | name} : dump specific db\n" " -o oid : info about object [db, file, record]\n" " -v : list volumes\n" " -v name : operate on volume\n" " -r : recurse [dirs.files, db.rec.fields]\n" " -f field : operate on field [for assign or seek]\n" " -e value : operate on value [for assign or seek]\n" " -a : assign value to field\n" " -s type : seek value\n" " -i ordering : use ordering\n" ); } int main( int argc, char *argv[]) { DebugStdOut(); CEOID dwObjectId=0; char *szDatabaseName=NULL ; char *szVolumeName=NULL ; bool bDoListDatabases=false; bool bDoRecursiveDump=false; bool bDoListVolumes=false; DWORD dwFieldId= 0; char *szValue= NULL; bool bDoSet= false; char *szSeekType= NULL; char *szFileName= NULL; DWORD dwOrdering= 0; int argsfound=0; for (int i=1 ; i0) { usage(); return 1; } if (FAILED(CeRapiInit())) { error("CeRapiInit"); return 1; } CEGUID guid; if (szVolumeName) { if (!CeMountDBVol(&guid, const_cast(ToWString(szVolumeName).c_str()), 0x80000000|OPEN_EXISTING)) { ceerror("CeMountDBVol(%hs)\n", szVolumeName); CeRapiUninit(); return 1; } debug("mounted %hs - %hs\n", guidstring(guid).c_str(), szVolumeName); } else if (bDoListDatabases) { CREATE_SYSTEMGUID(&guid); } else { CREATE_INVALIDGUID(&guid); } if (szFileName) PrintFileInfo(szFileName); else if (bDoListVolumes) EnumVolumes(bDoListDatabases, bDoRecursiveDump); else if (bDoListDatabases) EnumDatabases(guid, bDoRecursiveDump); else if (bDoSet) SetFieldValue(guid, dwObjectId, dwFieldId, szValue); else if (szDatabaseName) { if (dwFieldId) { if (szSeekType==NULL) { error("need seektype when searching database\n"); return 1; } SearchDatabase(guid, szDatabaseName, dwOrdering, dwFieldId, szSeekType, szValue); } else DumpDatabaseByName(guid, szDatabaseName); } else DumpObjectInfo(guid, dwObjectId, bDoRecursiveDump); if (szVolumeName) { if (!CeUnmountDBVol(&guid)) { ceerror("CeUnmountDBVol(%hs)\n", szVolumeName); } } CeRapiUninit(); return 0; } void EnumDatabases(const CEGUID& guid, bool bRecurse) { CEGUID volid= guid; HANDLE hEnumDb= CeFindFirstDatabaseEx(&volid, 0); // 0=alltypes if (hEnumDb==INVALID_HANDLE_VALUE) { ceerror("CeFindFirstDatabase"); return; } CEOID dbid; while (0!=(dbid=CeFindNextDatabaseEx(hEnumDb, &volid))) { DumpObjectInfo(guid, dbid, false); if (bRecurse) DumpDatabaseByOid(guid, dbid); } CeCloseHandle(hEnumDb); } std::string guidstring(const CEGUID& guid) { return stringformat("{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", guid.Data1, guid.Data2&0xffff, guid.Data2>>16, guid.Data3&0xff, (guid.Data3>>8)&0xff, (guid.Data3>>16)&0xff, (guid.Data3>>24)&0xff, guid.Data4&0xff, (guid.Data4>>8)&0xff, (guid.Data4>>16)&0xff, (guid.Data4>>24)&0xff); } void EnumVolumes(bool bDoListDatabases, bool bDoRecursiveDump) { CEGUID dbvol; CREATE_INVALIDGUID(&dbvol); int bufferSize= 1024; WCHAR *volumeName= (WCHAR*)malloc(bufferSize*sizeof(WCHAR)); while(true) { if (!CeEnumDBVolumes(&dbvol, volumeName, bufferSize)) { int err= CeGetLastError(); if (err==ERROR_NO_MORE_ITEMS) break; else if (err==ERROR_INSUFFICIENT_BUFFER) { bufferSize *= 2; volumeName= (WCHAR*)realloc(volumeName, bufferSize*sizeof(WCHAR)); } else { error(err, "CeEnumDbVolumes"); break; } } else { printf("volume %s %ls\n", guidstring(dbvol).c_str(), volumeName); if (bDoListDatabases) EnumDatabases(dbvol, bDoRecursiveDump); } } } CEOID FindDatabaseForRecord(const CEGUID& guid, CEOID recid) { CEOIDINFO info; memset(&info, 0, sizeof(info)); if (!CeOidGetInfoEx(const_cast(&guid), recid, &info)) { ceerror("finddb-CeOidGetInfoEx(%08lx)", recid); return 0; } if (info.wObjType==OBJTYPE_DATABASE) return recid; if (info.wObjType!=OBJTYPE_RECORD) { printf("ERROR - expected record object id\n"); return 0; } return info.infRecord.oidParent; } int StrAndBlobSizes(CEPROPVAL *props, WORD nProps); void DumpProperty(CEPROPVAL *property); void DumpRecord(CEPROPVAL *props, WORD nProps); void DumpDBRecord(const CEGUID& guid, CEOID recid) { CEOID dbid= FindDatabaseForRecord(guid, recid); if (dbid==recid) recid=0; //debug("dumprec: open(%hs, %08lx)\n", guidstring(guid).c_str(), dbid); HANDLE h= CeOpenDatabaseEx(const_cast(&guid), &dbid, NULL, 0, 0, 0); if (h==INVALID_HANDLE_VALUE) { ceerror("CeOpenDatabaseEx"); return; } DWORD dwIndex; if (0==CeSeekDatabase(h, CEDB_SEEK_CEOID, recid, &dwIndex)) { ceerror("CeSeekDatabase"); CeCloseHandle(h); return; } CEPROPVAL *props=NULL; DWORD bufsize=0; WORD nProps; if (!CeReadRecordProps(h, CEDB_ALLOWREALLOC, &nProps, NULL, (BYTE**)&props, &bufsize)) { ceerror("CeReadRecordProps"); CeCloseHandle(h); return; } DumpRecord(props, nProps); LocalFree(props); CeCloseHandle(h); } void DumpDatabaseByHandle(HANDLE h); void DumpDatabaseByName(const CEGUID& guid, char *name) { WCHAR *wname= (WCHAR*)malloc((strlen(name)+1)*sizeof(WCHAR)); swprintf(wname, L"%hs", name); CEOID dbid=0; //debug("dumpdb: open(%hs, '%ls')\n", guidstring(guid).c_str(), wname); HANDLE h= CeOpenDatabaseEx(const_cast(&guid), &dbid, wname, 0, CEDB_AUTOINCREMENT, 0); if (h==INVALID_HANDLE_VALUE) { ceerror("CeOpenDatabaseEx"); free(wname); return; } DumpDatabaseByHandle(h); CeCloseHandle(h); free(wname); } BOOL DumpDatabaseByOid(const CEGUID& guid, CEOID oid) { //debug("dumpdb: open(%hs, %08lx)\n", guidstring(guid).c_str(), oid); HANDLE h= CeOpenDatabaseEx(const_cast(&guid), &oid, NULL, 0, CEDB_AUTOINCREMENT, 0); if (h==INVALID_HANDLE_VALUE) { ceerror("CeOpenDatabaseEx"); return FALSE; } DumpDatabaseByHandle(h); CeCloseHandle(h); return TRUE; } void DumpDatabaseByHandle(HANDLE h) { CEPROPVAL *props=NULL; DWORD bufsize=0; CEOID rid; WORD nProps; while (0!=(rid= CeReadRecordProps(h, CEDB_ALLOWREALLOC, &nProps, NULL, (BYTE**)&props, &bufsize))) { printf("%08lx (%5d %2d %5d)\n", rid, bufsize, nProps, bufsize-nProps*sizeof(CEPROPVAL)-StrAndBlobSizes(props, nProps)); DumpRecord(props, nProps); //printf(" "); hexdump((BYTE*)&props[nProps], bufsize-nProps*sizeof(CEPROPVAL)); printf("\n"); } LocalFree(props); } int StrAndBlobSizes(CEPROPVAL *props, WORD nProps) { int totalsize=0; for (int i=0 ; ipropid>>16, p->propid&0xffff, p->wLenData, p->wFlags); switch(p->propid&0xffff) { case CEVT_I2: printf("I2 %d", p->val.iVal); break; case CEVT_UI2: printf("UI2 %u", p->val.uiVal); break; case CEVT_I4: printf("I4 %ld", p->val.lVal); break; case CEVT_UI4: printf("UI4 %lu", p->val.ulVal); break; case CEVT_FILETIME: SYSTEMTIME systime; FileTimeToSystemTime(&p->val.filetime, &systime); printf("FT %04d-%02d-%02d %02d:%02d:%02d.%03d", systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond,systime.wMilliseconds); break; case CEVT_LPWSTR: printf("STR [%08lx]", p->val.lpwstr); if (!IsBadReadPtr(p->val.lpwstr, 1)) printf("(%2d) '%ls'", wcslen(p->val.lpwstr), p->val.lpwstr); else printf(" ..... invalid ptr"); break; case CEVT_BLOB: printf("BIN [%08lx] (%2d): ", p->val.blob.lpb, p->val.blob.dwCount); if (!IsBadReadPtr(p->val.blob.lpb, p->val.blob.dwCount)) debug("%hs\n", hexdump(p->val.blob.lpb, p->val.blob.dwCount).c_str()); else printf(" ..... invalid ptr"); break; case CEVT_BOOL: printf("BOO "); printf("%s", p->val.boolVal ? "TRUE" : "FALSE"); break; case CEVT_R8: printf("DBL "); printf("%lg", p->val.dblVal); break; default: printf("??? %hs\n", hexdump((BYTE*)&p->val, sizeof(p->val)).c_str()); break; } printf("\n"); } void DumpFileInfo(CEOID oid, CEFILEINFO *info); void DumpDirectoryInfo(CEOID oid, CEDIRINFO *info); void DumpDatabaseInfo(CEOID oid, CEDBASEINFO *info); void DumpRecordInfo(CEOID oid, CERECORDINFO *info); BOOL isOid(const CEGUID& guid, CEOID oid) { CEOIDINFO info; return CeOidGetInfoEx(const_cast(&guid), oid, &info); } void DumpObjectInfo(const CEGUID& guid, CEOID oid, bool bRecurse) { CEOIDINFO info; memset(&info, 0, sizeof(info)); if (!CeOidGetInfoEx(const_cast(&guid), oid, &info)) { ceerror("doi-CeOidGetInfoEx(%s, %08lx)", guidstring(guid).c_str(), oid); return; } switch(info.wObjType) { case OBJTYPE_INVALID: printf("oid%08lx is not a valid object\n", oid); break; case OBJTYPE_FILE: DumpFileInfo(oid, &info.infFile); break; case OBJTYPE_DIRECTORY: DumpDirectoryInfo(oid, &info.infDirectory); break; case OBJTYPE_DATABASE: DumpDatabaseInfo(oid, &info.infDatabase); if (bRecurse) { DumpDatabaseByOid(guid, oid); } break; case OBJTYPE_RECORD: DumpRecordInfo(oid, &info.infRecord); if (bRecurse) { DumpDBRecord(guid, oid); } break; default: printf("oid%08lx: unknown obj type %d\n", info.wObjType); } } void DumpFileInfo(CEOID oid, CEFILEINFO *info) { printf("oid%08lx: file A%08lx P%08lx %7d ... '%ls'\n", oid, info->dwAttributes, info->oidParent, info->dwLength, /* info->ftLastChanged */ info->szFileName); } void DumpDirectoryInfo(CEOID oid, CEDIRINFO *info) { printf("oid%08lx: dir A%08lx P%08lx '%ls'\n", oid, info->dwAttributes, info->oidParent, info->szDirName); } void DumpDatabaseInfo(CEOID oid, CEDBASEINFO *info) { printf("oid%08lx: dbase F%08lx T%08lx %4d %6d ... '%ls'\n", oid, info->dwFlags, info->dwDbaseType, info->wNumRecords, info->dwSize, /* ftLastModified, wNumSortOrder, rgSortSpecs */ info->szDbaseName); if (info->wNumSortOrder) { printf(" ORDERING:"); for (int i=0 ; iwNumSortOrder ; i++) { printf(" %08lx:%08lx", info->rgSortSpecs[i].propid, info->rgSortSpecs[i].dwFlags); } printf("\n"); } } void DumpRecordInfo(CEOID oid, CERECORDINFO *info) { printf("oid%08lx: rec P%08lx\n", oid, info->oidParent); } void ValueToWString(WCHAR **pwstr, char *str) { WCHAR *wname= (WCHAR*)malloc((strlen(str)+1)*sizeof(WCHAR)); swprintf(wname, L"%hs", str); *pwstr= wname; } DWORD MakePropVal(CEPROPVAL *pv, DWORD dwFieldId, char *szValue) { pv->propid= dwFieldId; pv->wFlags= 0; pv->wLenData= 0; switch(dwFieldId&0xffff) { case CEVT_I2: pv->val.iVal= (short)strtol(szValue, 0, 0); break; case CEVT_UI2: pv->val.uiVal= (unsigned short)strtoul(szValue, 0, 0); break; case CEVT_I4: pv->val.lVal= strtol(szValue, 0, 0); break; case CEVT_UI4: pv->val.ulVal= strtoul(szValue, 0, 0); break; case CEVT_BOOL: pv->val.boolVal= strtoul(szValue, 0, 0); break; //case CEVT_FILETIME: ValueToFiletime(&pv->val.filetime, szValue); break; case CEVT_LPWSTR: ValueToWString(&pv->val.lpwstr, szValue); break; //case CEVT_BLOB: ValueToBlob(&pv->val.blob, szValue); break; case CEVT_R8: pv->val.dblVal= strtod(szValue, 0); break; default: return 0; } DumpProperty(pv); return (DWORD)pv; } void SearchDatabase(const CEGUID& guid, char *szDatabaseName, DWORD dwOrdering, DWORD dwFieldId, char *seektype, char *szValue) { DWORD dwValue; DWORD dwSeekType; CEPROPVAL pv; bool usePv= false; if (strcmp(seektype, "<")==0) { usePv= true; dwSeekType= CEDB_SEEK_VALUESMALLER; } else if (strcmp(seektype, "=")==0) { usePv= true; dwSeekType=CEDB_SEEK_VALUEFIRSTEQUAL; } else if (strcmp(seektype, "=+")==0) { usePv= true; dwSeekType=CEDB_SEEK_VALUENEXTEQUAL; } else if (strcmp(seektype, ">")==0) { usePv= true; dwSeekType=CEDB_SEEK_VALUEGREATER; } else if (strcmp(seektype, "++")==0) { dwSeekType=CEDB_SEEK_CURRENT; } else if (strcmp(seektype, "--")==0) { dwSeekType=CEDB_SEEK_CURRENT; } else if (strcmp(seektype, "[")==0) { dwSeekType=CEDB_SEEK_BEGINNING; } else if (strcmp(seektype, "]")==0) { dwSeekType=CEDB_SEEK_END; } else { debug("invalid seektype: %hs\n", seektype); return; } if (usePv) { dwValue= MakePropVal(&pv, dwFieldId, szValue); if (dwValue==0) { debug("invalid field type\n"); return; } } else { dwValue= strtoul(szValue, 0, 0); } WCHAR *wname= (WCHAR*)malloc((strlen(szDatabaseName)+1)*sizeof(WCHAR)); swprintf(wname, L"%hs", szDatabaseName); CEOID dbid=0; //debug("searchdb: open(%hs, '%ls')\n", guidstring(guid).c_str(), wname); HANDLE h= CeOpenDatabaseEx(const_cast(&guid), &dbid, wname, dwOrdering, CEDB_AUTOINCREMENT, 0); if (h==INVALID_HANDLE_VALUE) { ceerror("CeOpenDatabaseEx"); return; } DWORD dwIndex; CEOID oid= CeSeekDatabase(h, dwSeekType, dwValue, &dwIndex); debug("CeSeekDatabase(%08lx, %08lx, %08lx) = %08lx i=%08lx\n", h, dwSeekType, dwValue, oid, dwIndex); if (oid==0) { ceerror("CeSeekDatabase"); CeCloseHandle(h); return; } printf("found match:\n"); DumpObjectInfo(guid, oid, true); CeCloseHandle(h); } void SetFieldValue(const CEGUID& guid, CEOID dwObjectId, DWORD dwFieldId, char *szValue) { CEOID dbid= FindDatabaseForRecord(guid, dwObjectId); if (dbid==dwObjectId) dwObjectId=0; CEPROPVAL pv; if (!MakePropVal(&pv, dwFieldId, szValue)) { debug("error making propvalue\n"); return; } //debug("setval: open(%hs, %08lx)\n", guidstring(guid).c_str(), dbid); HANDLE h= CeOpenDatabaseEx(const_cast(&guid), &dbid, NULL, 0, CEDB_AUTOINCREMENT, 0); if (h==INVALID_HANDLE_VALUE) { ceerror("CeOpenDatabaseEx"); return; } CEOID oid= CeWriteRecordProps(h, dwObjectId, 1, &pv); if (oid==0) ceerror("CeWriteRecordProps"); debug("set field %08lx in record %08lx to %s\n", dwFieldId, oid, szValue); CeCloseHandle(h); } void PrintFileInfo(const std::string& szFileName) { CE_FIND_DATA wfd; HANDLE hFind= CeFindFirstFile(ToWString(szFileName).c_str(), &wfd); if (hFind==NULL || hFind==INVALID_HANDLE_VALUE) { debug("could not find %s\n", szFileName.c_str()); return; } CloseHandle(hFind); debug("oid=%08lx\n", wfd.dwOID); }