2 // Copyright (C) 2014 Suguru Kawamoto
\r
4 // コードの再利用のため表記はwchar_t型だが実体はchar型でUTF-8
\r
7 #include <ws2tcpip.h>
\r
9 #include <mmsystem.h>
\r
10 typedef SOCKADDR_STORAGE_XP SOCKADDR_STORAGE;
\r
11 typedef SOCKADDR_STORAGE *PSOCKADDR_STORAGE, FAR *LPSOCKADDR_STORAGE;
\r
12 #include <winhttp.h>
\r
14 #include "updater.h"
\r
15 #include "socketwrapper.h"
\r
16 #include "protectprocess.h"
\r
17 #include "mbswrapper.h"
\r
25 #define UPDATE_LIST_FILE_FLAG_DIRECTORY 0x00000001
\r
39 CHAR VersionString[32];
\r
41 UPDATE_LIST_FILE File[1];
\r
44 BOOL ReadFileViaHTTPW(void* pOut, DWORD Length, DWORD* pLength, LPCWSTR UserAgent, LPCWSTR ServerName, LPCWSTR ObjectName)
\r
51 if(hSession = WinHttpOpen(UserAgent, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0))
\r
53 if(hConnect = WinHttpConnect(hSession, ServerName, INTERNET_DEFAULT_HTTP_PORT, 0))
\r
55 if(hRequest = WinHttpOpenRequest(hConnect, L"GET", ObjectName, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0))
\r
57 if(WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0))
\r
59 if(WinHttpReceiveResponse(hRequest, NULL))
\r
61 if(WinHttpQueryDataAvailable(hRequest, pLength))
\r
63 if(*pLength <= Length)
\r
65 if(WinHttpReadData(hRequest, pOut, Length, pLength))
\r
71 WinHttpCloseHandle(hRequest);
\r
73 WinHttpCloseHandle(hConnect);
\r
75 WinHttpCloseHandle(hSession);
\r
80 BOOL ReadFileViaHTTP(void* pOut, DWORD Length, DWORD* pLength, LPCSTR UserAgent, LPCSTR ServerName, LPCSTR ObjectName)
\r
86 pw0 = DuplicateMtoW(UserAgent, -1);
\r
87 pw1 = DuplicateMtoW(ServerName, -1);
\r
88 pw2 = DuplicateMtoW(ObjectName, -1);
\r
89 r = ReadFileViaHTTPW(pOut, Length, pLength, pw0, pw1, pw2);
\r
90 FreeDuplicatedString(pw0);
\r
91 FreeDuplicatedString(pw1);
\r
92 FreeDuplicatedString(pw2);
\r
96 BOOL SaveMemoryToFileWithTimestamp(LPCTSTR FileName, void* pData, DWORD Size, FILETIME* pTimestamp)
\r
101 if((hFile = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
\r
103 if(WriteFile(hFile, pData, Size, &Size, NULL))
\r
105 if(SetFileTime(hFile, NULL, NULL, pTimestamp))
\r
108 CloseHandle(hFile);
\r
113 BOOL CopyAllFilesInDirectory(LPCTSTR From, LPCTSTR To)
\r
118 SHFILEOPSTRUCT fop;
\r
120 if(pFrom = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(From) + _tcslen(_T("\\*")) + 2)))
\r
122 _tcscpy(pFrom, From);
\r
123 _tcsncpy(pFrom + _tcslen(pFrom), _T("\\*"), _tcslen(_T("\\*")) + 2);
\r
124 if(pTo = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(To) + 2)))
\r
126 _tcsncpy(pTo, To, _tcslen(To) + 2);
\r
127 memset(&fop, 0, sizeof(SHFILEOPSTRUCT));
\r
128 fop.wFunc = FO_COPY;
\r
131 fop.fFlags = FOF_NO_UI;
\r
132 if(SHFileOperation(&fop) == 0)
\r
141 BOOL DeleteDirectoryAndContents(LPCTSTR Path)
\r
145 SHFILEOPSTRUCT fop;
\r
147 if(pFrom = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(Path) + 2)))
\r
149 _tcsncpy(pFrom, Path, _tcslen(Path) + 2);
\r
150 memset(&fop, 0, sizeof(SHFILEOPSTRUCT));
\r
151 fop.wFunc = FO_DELETE;
\r
153 fop.fFlags = FOF_NO_UI;
\r
154 if(SHFileOperation(&fop) == 0)
\r
162 BOOL CheckForUpdates(BOOL bDownload, LPCTSTR DownloadDir, DWORD* pVersion, LPTSTR pVersionString)
\r
168 UPDATE_HASH UpdateHash;
\r
170 UPDATE_LIST* pUpdateList;
\r
172 if(ReadFileViaHTTP(&Buf1, sizeof(Buf1), &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_HASH_PATH))
\r
174 if(DecryptSignature(UPDATE_RSA_PUBLIC_KEY, &Buf1, Length, &Buf2, sizeof(Buf2), &Length))
\r
176 if(Length == sizeof(UPDATE_HASH))
\r
178 memcpy(&UpdateHash, &Buf2, sizeof(UPDATE_HASH));
\r
179 if(memcmp(&UpdateHash.Signature, UPDATE_SIGNATURE, 64) == 0)
\r
181 if(ReadFileViaHTTP(&Buf1, sizeof(Buf1), &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_LIST_PATH))
\r
183 if(GetHashSHA512(&Buf1, Length, &Hash))
\r
185 if(memcmp(&Hash, &UpdateHash.ListHash, 64) == 0)
\r
187 if(Length >= sizeof(UPDATE_LIST))
\r
190 pUpdateList = (UPDATE_LIST*)&Buf1;
\r
191 if(pUpdateList->Version > *pVersion)
\r
193 *pVersion = pUpdateList->Version;
\r
194 _tcscpy(pVersionString, pUpdateList->VersionString);
\r
197 bResult = PrepareUpdates(&Buf1, Length, DownloadDir);
\r
210 BOOL PrepareUpdates(void* pList, DWORD ListLength, LPCTSTR DownloadDir)
\r
213 UPDATE_LIST* pUpdateList;
\r
219 TCHAR Path[MAX_PATH];
\r
221 if(ListLength >= sizeof(UPDATE_LIST))
\r
223 pUpdateList = (UPDATE_LIST*)pList;
\r
224 if((pUpdateList->FileCount - 1) * sizeof(UPDATE_LIST_FILE) + sizeof(UPDATE_LIST) >= ListLength)
\r
227 DeleteDirectoryAndContents(DownloadDir);
\r
228 CreateDirectory(DownloadDir, NULL);
\r
229 pBuf = malloc(16777216);
\r
230 for(i = 0; i < pUpdateList->FileCount; i++)
\r
233 if(pUpdateList->File[i].Flags & UPDATE_LIST_FILE_FLAG_DIRECTORY)
\r
235 _tcscpy(Path, DownloadDir);
\r
236 _tcscat(Path, _T("\\"));
\r
237 _tcscat(Path, pUpdateList->File[i].DstPath);
\r
238 if(CreateDirectory(Path, NULL))
\r
241 if(strlen(pUpdateList->File[i].SrcPath) > 0)
\r
243 if(ReadFileViaHTTP(pBuf, 16777216, &Length, HTTP_USER_AGENT, UPDATE_SERVER, pUpdateList->File[i].SrcPath))
\r
245 if(GetHashSHA512(pBuf, Length, &Hash))
\r
247 if(memcmp(&Hash, &pUpdateList->File[i].SrcHash, 64) == 0)
\r
249 _tcscpy(Path, DownloadDir);
\r
250 _tcscat(Path, _T("\\"));
\r
251 _tcscat(Path, pUpdateList->File[i].DstPath);
\r
252 if(SaveMemoryToFileWithTimestamp(Path, pBuf, Length, &pUpdateList->File[i].Timestamp))
\r
271 BOOL ApplyUpdates(LPCTSTR DestinationDir, LPCTSTR BackupDirName)
\r
274 TCHAR Source[MAX_PATH];
\r
275 TCHAR Backup[MAX_PATH];
\r
276 TCHAR DestinationBackup[MAX_PATH];
\r
279 if(GetModuleFileName(NULL, Source, MAX_PATH) > 0)
\r
281 if(p = _tcsrchr(Source, _T('\\')))
\r
283 _tcscpy(Backup, Source);
\r
284 _tcscat(Backup, _T("\\"));
\r
285 _tcscat(Backup, BackupDirName);
\r
286 DeleteDirectoryAndContents(Backup);
\r
287 if(CopyAllFilesInDirectory(DestinationDir, Backup))
\r
289 _tcscpy(DestinationBackup, DestinationDir);
\r
290 _tcscat(DestinationBackup, _T("\\"));
\r
291 _tcscat(DestinationBackup, BackupDirName);
\r
292 if(CopyAllFilesInDirectory(Source, DestinationDir))
\r
294 DeleteDirectoryAndContents(DestinationBackup);
\r
299 DeleteDirectoryAndContents(DestinationBackup);
\r
300 CopyAllFilesInDirectory(Backup, DestinationDir);
\r
308 BOOL CleanupUpdates(LPCTSTR DownloadDir)
\r
312 if(DeleteDirectoryAndContents(DownloadDir))
\r
318 BOOL StartUpdateProcess(LPCTSTR DownloadDir, LPCTSTR CommandLine)
\r
321 TCHAR Name[MAX_PATH];
\r
323 TCHAR Path[MAX_PATH];
\r
325 if(GetModuleFileName(NULL, Name, MAX_PATH) > 0)
\r
327 if(p = _tcsrchr(Name, _T('\\')))
\r
331 _tcscpy(Path, DownloadDir);
\r
332 _tcscat(Path, _T("\\"));
\r
334 if(ShellExecute(NULL, _T("open"), Path, CommandLine, NULL, SW_SHOW) > (HINSTANCE)32)
\r
340 // 更新用のプロセスを管理者権限で起動
\r
341 // Windows XP以前など起動できない場合は現在のプロセスで処理を続行
\r
342 BOOL RestartUpdateProcessAsAdministrator(LPCTSTR CommandLine, LPCTSTR Keyword)
\r
345 TCHAR* NewCommandLine;
\r
346 TCHAR Path[MAX_PATH];
\r
347 SHELLEXECUTEINFO Info;
\r
349 if(_tcslen(CommandLine) < _tcslen(Keyword) || _tcscmp(CommandLine + _tcslen(CommandLine) - _tcslen(Keyword), Keyword) != 0)
\r
351 if(NewCommandLine = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(CommandLine) + _tcslen(Keyword) + 1)))
\r
353 _tcscpy(NewCommandLine, CommandLine);
\r
354 _tcscat(NewCommandLine, Keyword);
\r
355 if(GetModuleFileName(NULL, Path, MAX_PATH) > 0)
\r
357 memset(&Info, 0, sizeof(SHELLEXECUTEINFO));
\r
358 Info.cbSize = sizeof(SHELLEXECUTEINFO);
\r
359 Info.fMask = SEE_MASK_NOCLOSEPROCESS;
\r
360 Info.lpVerb = _T("runas");
\r
361 Info.lpFile = Path;
\r
362 Info.lpParameters = NewCommandLine;
\r
363 Info.nShow = SW_SHOW;
\r
364 if(ShellExecuteEx(&Info))
\r
366 WaitForSingleObject(Info.hProcess, INFINITE);
\r
367 CloseHandle(Info.hProcess);
\r
371 free(NewCommandLine);
\r