iecache
IEのキャッシュ情報をテキスト形式で取得して抽出/定型処理したいなーと思いコマンドラインツールを作ってみる。
調べたら、WindowsAPIで、以下の様に使用できるらしい。
1. まずFindFirstUrlCacheEntryA()をコール。
2. FindNextUrlCacheEntryA()を呼び続けることで次々にキュッシュ情報をゲット。
3. 最後にFindCloseUrlCache()をコール。
ゲットできるキャッシュ情報は以下の様な構造体。
c:/cygwin/usr/include/w32api/wininet.h:648:
typedef struct _INTERNET_CACHE_ENTRY_INFOA { DWORD dwStructSize; LPSTR lpszSourceUrlName; LPSTR lpszLocalFileName; DWORD CacheEntryType; DWORD dwUseCount; DWORD dwHitRate; DWORD dwSizeLow; DWORD dwSizeHigh; FILETIME LastModifiedTime; FILETIME ExpireTime; FILETIME LastAccessTime; FILETIME LastSyncTime; PBYTE lpHeaderInfo; DWORD dwHeaderInfoSize; LPSTR lpszFileExtension; DWORD dwReserved; } INTERNET_CACHE_ENTRY_INFOA,*LPINTERNET_CACHE_ENTRY_INFOA;
↑この情報をテキストでゲットして、5/26 0:00 〜 5/27 0:00 のアクセス履歴をgrepできる様にしたい。以下の様な感じで。
~/$ iecache -f 05260000 -t 05270000 | grep twitter
以下の様にしてクッキー情報を抽出するとか。
~/$ iecache -f 05260000 -t 05270000 | grep ^Cookie
…
で、大体以下の様な感じで、とりあえず動作するのを確認。
~/s/c/iecache/iecache.c:0:
/* $ gcc -mwindows iecache.c -lwininet -o iecache */ #include "wininet.h" #include <stdio.h> #include <unistd.h> /* getopt用 */ /* winerror.h:190:#define ERROR_NO_MORE_ITEMS 259L */ UINT64 ftime2u64(FILETIME * pFt) { UINT64 u64 = pFt->dwHighDateTime; return (u64<<32) + pFt->dwLowDateTime; } UINT64 str2u64(char * s) {/* hhmmss で渡された文字列を元に FILETIME と同等の uint64 を生成する */ SYSTEMTIME st; int len = strlen(s); int hhmm = atoi(s); UINT64 u64; FILETIME ft; GetLocalTime(&st); if (hhmm < 0) { SystemTimeToFileTime(&st, &ft); u64 = ftime2u64(&ft); /* FileTime は100ナノ秒単位の64bit値 */ /* "-100" と指定された時、100分前と解釈すべきなのか 1:00 前(一時間前)と解釈すべきなのか 悩ましいところだが、とりあえずは 100分前と解釈するものとする。 */ u64 = u64 / 600000000UL - (-hhmm); u64 *= 600000000UL; } else { st.wSecond = st.wMilliseconds = 0; /* 大小比較時にややこしくなるのでゼロに初期化しておく */ /* 例えば現在が 12:34 で 1.23 と指定された場合は 12:01.23 と解釈 */ if (len > 3 && s[len-3] == '.') { st.wSecond = atoi(s+len-2); len -= 3; /* 末尾の ".XX" の分をマイナスする */ } if (len > 8) { /* MMDDhhmm で8桁。20億を越えると 32bit桁溢れするので2回に分けて処理する */ if (len == 10 || len == 12) { /* yyYYMMDDhhmm */ char yy[5]; hhmm = atoi(s + len - 8); /* MMDDhhmm */ strncpy(yy, s, len - 8); /* yyYY */ st.wYear = atoi(yy); if (len == 10) st.wYear += 2000; } else { fprintf(stderr, "Strange date : %s\n", s); exit(0); } } st.wMinute = hhmm%100; hhmm /= 100; if (hhmm < 100) { if (hhmm != 0) st.wHour = hhmm;/* hourの桁がゼロの時は、現在時刻の wHourをそのまま使用(ってどうなんだろ。わかりにくい?? */ } else { /* 上位桁に DD が付いてる */ st.wHour = hhmm%100; hhmm /= 100; if (hhmm < 100) { st.wDay = hhmm; } else { /* 上位桁に MM(月) が付いてる */ st.wDay = hhmm%100; hhmm /= 100; if (hhmm < 100) { st.wMonth = hhmm; } else { /* 上位桁に YY が付いてる */ st.wMonth = hhmm%100; hhmm /= 100; if (hhmm < 100) hhmm += 2000; st.wYear = hhmm; } } } SystemTimeToFileTime(&st, &ft); u64 = ftime2u64(&ft); } return u64; } int main(int ac, char ** av) { HANDLE hFind; DWORD dwLen; DWORD dwLen_pre = MAX_CACHE_ENTRY_INFO_SIZE; INTERNET_CACHE_ENTRY_INFO* psInfo; SYSTEMTIME st; FILETIME ft; long er = 0; int ch; UINT64 u64; UINT64 from = 0; UINT64 to = 0; BOOL ret; char def_wildcard[] = "*.*"; char * wildcard = def_wildcard; extern char *optarg; extern int optind, opterr; while ((ch = getopt(ac, av, "f:t:")) != -1){ switch (ch){ /* FromTime から ToTime までの間のIEキャッシュのみ取り出す。 引数の指定方式としては touch と大体同じ形式を採用。 つまり、 [[CC]YY]MMDDhhmm[.ss] という感じ。 ただし、ちょっと拡張して、hhmmのみ/mmのみの指定も許す。 [[[[CC]YY]MMDD]hh]mm[.ss] という感じ。 あと、負数指定も許し、「-5」で「5分前」と指定できる様にしてみる。 */ case 'f': // FromTime from = str2u64(optarg); break; case 't': // ToTime to = str2u64(optarg); break; default: ; } } ac -= optind; av += optind; /* これ以降は,av[0]〜av[ac-1]にオプションを除いた引数が入る */ if (ac == 1) wildcard = av[0]; dwLen = dwLen_pre; psInfo = (INTERNET_CACHE_ENTRY_INFO*) malloc(dwLen_pre); /* hFind = FindFirstUrlCacheEntryA("visited:", psInfo, &dwLen); //例えば "cookie:" とか "visited:" とかが指定可能 */ hFind = FindFirstUrlCacheEntryA(wildcard, psInfo, &dwLen); if (dwLen == 0 || hFind == 0) { if (hFind) FindCloseUrlCache(hFind); return 0; } if (dwLen > dwLen_pre) { psInfo = realloc(psInfo, dwLen); if (psInfo == NULL) { FindCloseUrlCache(hFind); return 0; } dwLen_pre = dwLen; hFind = FindFirstUrlCacheEntryA(wildcard, psInfo, &dwLen); } FileTimeToLocalFileTime(&psInfo->LastAccessTime, &ft); FileTimeToSystemTime(&ft, &st); while (1) { ret = 1; u64 = ftime2u64(&ft); if (from && u64 < from) ret = 0; if (to && u64 > to) ret = 0; if (ret == 1) { char * s = psInfo->lpszLocalFileName; printf("%s\r%04d/%02d/%02d %02d:%02d:%02d\r%s\n", psInfo->lpszSourceUrlName, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, s?s:"" ); } ret = FindNextUrlCacheEntryA(hFind, psInfo, &dwLen); if (dwLen == 0) break; if (dwLen > dwLen_pre) { psInfo = realloc(psInfo, dwLen); if (psInfo == NULL) { FindCloseUrlCache(hFind); return 0; } dwLen_pre = dwLen; ret = FindNextUrlCacheEntryA(hFind, psInfo, &dwLen); } if (ret == 0) { er = GetLastError(); if (er == ERROR_NO_MORE_ITEMS) { break; } } FileTimeToLocalFileTime(&psInfo->LastAccessTime, &ft); FileTimeToSystemTime(&ft, &st); } FindCloseUrlCache(hFind); return 0; }