OSDN Git Service

Modify documents.
[ffftp/ffftp.git] / src / updater.c
1 // updater.c\r
2 // Copyright (C) 2014 Suguru Kawamoto\r
3 // ソフトウェア自動更新\r
4 // コードの再利用のため表記はwchar_t型だが実体はchar型でUTF-8\r
5 \r
6 #include <tchar.h>\r
7 #include <ws2tcpip.h>\r
8 #include <windows.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
13 \r
14 #include "updater.h"\r
15 #include "socketwrapper.h"\r
16 #include "protectprocess.h"\r
17 #include "mbswrapper.h"\r
18 #include "apiemulator.h"\r
19 \r
20 typedef struct\r
21 {\r
22         BYTE Signature[64];\r
23         BYTE ListHash[64];\r
24 } UPDATE_HASH;\r
25 \r
26 #define UPDATE_LIST_FILE_FLAG_DIRECTORY 0x00000001\r
27 \r
28 typedef struct\r
29 {\r
30         DWORD Flags;\r
31         CHAR SrcPath[128];\r
32         BYTE SrcHash[64];\r
33         CHAR DstPath[128];\r
34         FILETIME Timestamp;\r
35 } UPDATE_LIST_FILE;\r
36 \r
37 typedef struct\r
38 {\r
39         DWORD Version;\r
40         CHAR VersionString[32];\r
41         CHAR Description[1024];\r
42         DWORD FileCount;\r
43         UPDATE_LIST_FILE File[1];\r
44 } UPDATE_LIST;\r
45 \r
46 #define UPDATE_MAX_LIST_SIZE 1048576\r
47 #define UPDATE_MAX_FILE_SIZE 16777216\r
48 \r
49 BOOL ReadFileViaHTTPW(void* pOut, DWORD Length, DWORD* pLength, LPCWSTR UserAgent, LPCWSTR ServerName, LPCWSTR ObjectName)\r
50 {\r
51         BOOL bResult;\r
52         HINTERNET hSession;\r
53         DWORD Buffer;\r
54         HINTERNET hConnect;\r
55         HINTERNET hRequest;\r
56         WCHAR* Url;\r
57         WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions;\r
58         WINHTTP_PROXY_INFO ProxyInfo;\r
59         WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ProxyConfig;\r
60         bResult = FALSE;\r
61         if(hSession = WinHttpOpen(UserAgent, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0))\r
62         {\r
63                 Buffer = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS;\r
64                 if(WinHttpSetOption(hSession, WINHTTP_OPTION_REDIRECT_POLICY, &Buffer, sizeof(DWORD)))\r
65                 {\r
66                         if(hConnect = WinHttpConnect(hSession, ServerName, INTERNET_DEFAULT_HTTP_PORT, 0))\r
67                         {\r
68                                 if(hRequest = WinHttpOpenRequest(hConnect, L"GET", ObjectName, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0))\r
69                                 {\r
70                                         if(Url = (WCHAR*)malloc(sizeof(WCHAR) * (wcslen(L"http://") + wcslen(ServerName) + wcslen(ObjectName) + 1)))\r
71                                         {\r
72                                                 wcscpy(Url, L"http://");\r
73                                                 wcscat(Url, ServerName);\r
74                                                 wcscat(Url, ObjectName);\r
75                                         }\r
76                                         memset(&AutoProxyOptions, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS));\r
77                                         AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;\r
78                                         AutoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;\r
79                                         AutoProxyOptions.fAutoLogonIfChallenged = TRUE;\r
80                                         memset(&ProxyInfo, 0, sizeof(WINHTTP_PROXY_INFO));\r
81                                         memset(&ProxyConfig, 0, sizeof(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG));\r
82                                         if(WinHttpGetProxyForUrl(hSession, Url, &AutoProxyOptions, &ProxyInfo))\r
83                                         {\r
84                                                 WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY, &ProxyInfo, sizeof(WINHTTP_PROXY_INFO));\r
85                                                 if(ProxyInfo.lpszProxy)\r
86                                                         GlobalFree(ProxyInfo.lpszProxy);\r
87                                                 if(ProxyInfo.lpszProxyBypass)\r
88                                                         GlobalFree(ProxyInfo.lpszProxyBypass);\r
89                                         }\r
90                                         else if(WinHttpGetIEProxyConfigForCurrentUser(&ProxyConfig))\r
91                                         {\r
92                                                 if(ProxyConfig.lpszAutoConfigUrl)\r
93                                                 {\r
94                                                         memset(&AutoProxyOptions, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS));\r
95                                                         AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;\r
96                                                         AutoProxyOptions.lpszAutoConfigUrl = ProxyConfig.lpszAutoConfigUrl;\r
97                                                         AutoProxyOptions.fAutoLogonIfChallenged = TRUE;\r
98                                                         memset(&ProxyInfo, 0, sizeof(WINHTTP_PROXY_INFO));\r
99                                                         if(WinHttpGetProxyForUrl(hSession, Url, &AutoProxyOptions, &ProxyInfo))\r
100                                                         {\r
101                                                                 WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY, &ProxyInfo, sizeof(WINHTTP_PROXY_INFO));\r
102                                                                 if(ProxyInfo.lpszProxy)\r
103                                                                         GlobalFree(ProxyInfo.lpszProxy);\r
104                                                                 if(ProxyInfo.lpszProxyBypass)\r
105                                                                         GlobalFree(ProxyInfo.lpszProxyBypass);\r
106                                                         }\r
107                                                 }\r
108                                                 else if(ProxyConfig.lpszProxy)\r
109                                                 {\r
110                                                         memset(&ProxyInfo, 0, sizeof(WINHTTP_PROXY_INFO));\r
111                                                         ProxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;\r
112                                                         ProxyInfo.lpszProxy = ProxyConfig.lpszProxy;\r
113                                                         ProxyInfo.lpszProxyBypass = ProxyConfig.lpszProxyBypass;\r
114                                                         WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY, &ProxyInfo, sizeof(WINHTTP_PROXY_INFO));\r
115                                                 }\r
116                                                 if(ProxyConfig.lpszAutoConfigUrl)\r
117                                                         GlobalFree(ProxyConfig.lpszAutoConfigUrl);\r
118                                                 if(ProxyConfig.lpszProxy)\r
119                                                         GlobalFree(ProxyConfig.lpszProxy);\r
120                                                 if(ProxyConfig.lpszProxyBypass)\r
121                                                         GlobalFree(ProxyConfig.lpszProxyBypass);\r
122                                         }\r
123                                         if(Url)\r
124                                                 free(Url);\r
125                                         if(WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0))\r
126                                         {\r
127                                                 if(WinHttpReceiveResponse(hRequest, NULL))\r
128                                                 {\r
129                                                         if(WinHttpQueryDataAvailable(hRequest, pLength))\r
130                                                         {\r
131                                                                 if(*pLength <= Length)\r
132                                                                 {\r
133                                                                         if(WinHttpReadData(hRequest, pOut, Length, pLength))\r
134                                                                                 bResult = TRUE;\r
135                                                                 }\r
136                                                         }\r
137                                                 }\r
138                                         }\r
139                                         WinHttpCloseHandle(hRequest);\r
140                                 }\r
141                                 WinHttpCloseHandle(hConnect);\r
142                         }\r
143                 }\r
144                 WinHttpCloseHandle(hSession);\r
145         }\r
146         return bResult;\r
147 }\r
148 \r
149 BOOL ReadFileViaHTTP(void* pOut, DWORD Length, DWORD* pLength, LPCSTR UserAgent, LPCSTR ServerName, LPCSTR ObjectName)\r
150 {\r
151         BOOL r;\r
152         wchar_t* pw0;\r
153         wchar_t* pw1;\r
154         wchar_t* pw2;\r
155         pw0 = DuplicateMtoW(UserAgent, -1);\r
156         pw1 = DuplicateMtoW(ServerName, -1);\r
157         pw2 = DuplicateMtoW(ObjectName, -1);\r
158         r = ReadFileViaHTTPW(pOut, Length, pLength, pw0, pw1, pw2);\r
159         FreeDuplicatedString(pw0);\r
160         FreeDuplicatedString(pw1);\r
161         FreeDuplicatedString(pw2);\r
162         return r;\r
163 }\r
164 \r
165 BOOL SaveMemoryToFileWithTimestamp(LPCTSTR FileName, void* pData, DWORD Size, FILETIME* pTimestamp)\r
166 {\r
167         BOOL bResult;\r
168         HANDLE hFile;\r
169         bResult = FALSE;\r
170         if((hFile = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)\r
171         {\r
172                 if(WriteFile(hFile, pData, Size, &Size, NULL))\r
173                 {\r
174                         if(pTimestamp)\r
175                         {\r
176                                 if(SetFileTime(hFile, NULL, NULL, pTimestamp))\r
177                                         bResult = TRUE;\r
178                         }\r
179                         else\r
180                                 bResult = TRUE;\r
181                 }\r
182                 CloseHandle(hFile);\r
183         }\r
184         return bResult;\r
185 }\r
186 \r
187 BOOL LoadMemoryFromFileWithTimestamp(LPCTSTR FileName, void* pData, DWORD Size, DWORD* pReadSize, FILETIME* pTimestamp)\r
188 {\r
189         BOOL bResult;\r
190         HANDLE hFile;\r
191         LARGE_INTEGER li;\r
192         bResult = FALSE;\r
193         if((hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)\r
194         {\r
195                 if(GetFileSizeEx(hFile, &li))\r
196                 {\r
197                         if(li.QuadPart <= (LONGLONG)Size)\r
198                         {\r
199                                 if(ReadFile(hFile, pData, Size, pReadSize, NULL))\r
200                                 {\r
201                                         if(*pReadSize == li.LowPart)\r
202                                         {\r
203                                                 if(pTimestamp)\r
204                                                 {\r
205                                                         if(GetFileTime(hFile, NULL, NULL, pTimestamp))\r
206                                                                 bResult = TRUE;\r
207                                                 }\r
208                                                 else\r
209                                                         bResult = TRUE;\r
210                                         }\r
211                                 }\r
212                         }\r
213                         CloseHandle(hFile);\r
214                 }\r
215         }\r
216         return bResult;\r
217 }\r
218 \r
219 BOOL CopyAllFilesInDirectory(LPCTSTR From, LPCTSTR To)\r
220 {\r
221         BOOL bResult;\r
222         TCHAR* pFrom;\r
223         TCHAR* pTo;\r
224         SHFILEOPSTRUCT fop;\r
225         bResult = FALSE;\r
226         if(pFrom = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(From) + _tcslen(_T("\\*")) + 2)))\r
227         {\r
228                 _tcscpy(pFrom, From);\r
229                 _tcsncpy(pFrom + _tcslen(pFrom), _T("\\*"), _tcslen(_T("\\*")) + 2);\r
230                 if(pTo = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(To) + 2)))\r
231                 {\r
232                         _tcsncpy(pTo, To, _tcslen(To) + 2);\r
233                         memset(&fop, 0, sizeof(SHFILEOPSTRUCT));\r
234                         fop.wFunc = FO_COPY;\r
235                         fop.pFrom = pFrom;\r
236                         fop.pTo = pTo;\r
237                         fop.fFlags = FOF_NO_UI;\r
238                         if(SHFileOperation(&fop) == 0)\r
239                                 bResult = TRUE;\r
240                         free(pTo);\r
241                 }\r
242                 free(pFrom);\r
243         }\r
244         return bResult;\r
245 }\r
246 \r
247 BOOL DeleteDirectoryAndContents(LPCTSTR Path)\r
248 {\r
249         BOOL bResult;\r
250         TCHAR* pFrom;\r
251         SHFILEOPSTRUCT fop;\r
252         bResult = FALSE;\r
253         if(pFrom = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(Path) + 2)))\r
254         {\r
255                 _tcsncpy(pFrom, Path, _tcslen(Path) + 2);\r
256                 memset(&fop, 0, sizeof(SHFILEOPSTRUCT));\r
257                 fop.wFunc = FO_DELETE;\r
258                 fop.pFrom = pFrom;\r
259                 fop.fFlags = FOF_NO_UI;\r
260                 if(SHFileOperation(&fop) == 0)\r
261                         bResult = TRUE;\r
262                 free(pFrom);\r
263         }\r
264         return bResult;\r
265 }\r
266 \r
267 DWORD ListUpdateFile(UPDATE_LIST* pList, DWORD MaxCount, LPCTSTR ServerPath, LPCTSTR ReferenceDir, LPCTSTR Path)\r
268 {\r
269         DWORD Result;\r
270         TCHAR Temp1[MAX_PATH];\r
271         TCHAR Temp2[MAX_PATH];\r
272         TCHAR Temp3[MAX_PATH];\r
273         HANDLE hFind;\r
274         WIN32_FIND_DATA Find;\r
275         void* pBuf;\r
276         DWORD Length;\r
277         FILETIME Time;\r
278         BYTE Hash[64];\r
279         Result = 0;\r
280         if(!Path)\r
281                 Path = _T("");\r
282         if(_tcslen(ReferenceDir) + _tcslen(Path) + _tcslen(_T("\\*")) < MAX_PATH)\r
283         {\r
284                 _tcscpy(Temp1, ReferenceDir);\r
285                 _tcscat(Temp1, Path);\r
286                 _tcscat(Temp1, _T("\\*"));\r
287                 if((hFind = FindFirstFile(Temp1, &Find)) != INVALID_HANDLE_VALUE)\r
288                 {\r
289                         do\r
290                         {\r
291                                 if(_tcscmp(Find.cFileName, _T(".")) != 0 && _tcscmp(Find.cFileName, _T("..")) != 0)\r
292                                 {\r
293 //                                      if(_tcslen(ServerPath) + _tcslen(_T("/")) + _tcslen(Find.cFileName) < 128 && _tcslen(Path) + _tcslen(_T("\\")) + _tcslen(Find.cFileName) < 128)\r
294                                         if(_tcslen(ServerPath) + _tcslen(Find.cFileName) < 128 && _tcslen(Path) + _tcslen(_T("\\")) + _tcslen(Find.cFileName) < 128)\r
295                                         {\r
296                                                 _tcscpy(Temp1, ServerPath);\r
297 //                                              _tcscat(Temp1, _T("/"));\r
298                                                 _tcscat(Temp1, Find.cFileName);\r
299                                                 _tcscpy(Temp2, Path);\r
300                                                 _tcscat(Temp2, _T("\\"));\r
301                                                 _tcscat(Temp2, Find.cFileName);\r
302                                                 if(_tcslen(ReferenceDir) + _tcslen(Temp2) < MAX_PATH)\r
303                                                 {\r
304                                                         _tcscpy(Temp3, ReferenceDir);\r
305                                                         _tcscat(Temp3, Temp2);\r
306                                                         if((Find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\r
307                                                         {\r
308                                                                 if(!(Find.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))\r
309                                                                 {\r
310                                                                         if(pList)\r
311                                                                         {\r
312                                                                                 memset(&pList->File[pList->FileCount], 0, sizeof(UPDATE_LIST_FILE));\r
313                                                                                 pList->File[pList->FileCount].Flags = UPDATE_LIST_FILE_FLAG_DIRECTORY;\r
314                                                                                 _tcscpy(pList->File[pList->FileCount].DstPath, Temp2);\r
315                                                                                 pList->FileCount++;\r
316                                                                         }\r
317                                                                         Result++;\r
318                                                                         if(Result >= MaxCount)\r
319                                                                                 break;\r
320                                                                         Result += ListUpdateFile(pList, MaxCount, Temp1, ReferenceDir, Temp2);\r
321                                                                 }\r
322                                                         }\r
323                                                         else\r
324                                                         {\r
325                                                                 if(pList)\r
326                                                                 {\r
327                                                                         if(pBuf = malloc(UPDATE_MAX_FILE_SIZE))\r
328                                                                         {\r
329                                                                                 if(LoadMemoryFromFileWithTimestamp(Temp3, pBuf, UPDATE_MAX_FILE_SIZE, &Length, &Time))\r
330                                                                                 {\r
331                                                                                         if(GetHashSHA512(pBuf, Length, &Hash))\r
332                                                                                         {\r
333                                                                                                 memset(&pList->File[pList->FileCount], 0, sizeof(UPDATE_LIST_FILE));\r
334                                                                                                 _tcscpy(pList->File[pList->FileCount].SrcPath, Temp1);\r
335                                                                                                 memcpy(&pList->File[pList->FileCount].SrcHash, &Hash, 64);\r
336                                                                                                 _tcscpy(pList->File[pList->FileCount].DstPath, Temp2);\r
337                                                                                                 pList->File[pList->FileCount].Timestamp = Time;\r
338                                                                                                 pList->FileCount++;\r
339                                                                                         }\r
340                                                                                 }\r
341                                                                                 free(pBuf);\r
342                                                                         }\r
343                                                                 }\r
344                                                                 Result++;\r
345                                                                 if(Result >= MaxCount)\r
346                                                                         break;\r
347                                                         }\r
348                                                 }\r
349                                         }\r
350                                 }\r
351                         }\r
352                         while(FindNextFile(hFind, &Find));\r
353                         FindClose(hFind);\r
354                 }\r
355         }\r
356         return Result;\r
357 }\r
358 \r
359 // FFFTPの更新情報を作成\r
360 BOOL BuildUpdates(LPCTSTR PrivateKeyFile, LPCTSTR Password, LPCTSTR ServerPath, LPCTSTR HashFile, LPCTSTR ListFile, DWORD Version, LPCTSTR VersionString, LPCTSTR Description)\r
361 {\r
362         BOOL bResult;\r
363         char PrivateKey[4096];\r
364         DWORD Length;\r
365         TCHAR Name[MAX_PATH];\r
366         TCHAR* p;\r
367         UPDATE_LIST* pList;\r
368         UPDATE_HASH Hash;\r
369         BYTE Buf[1024];\r
370         bResult = FALSE;\r
371         memset(PrivateKey, 0, sizeof(PrivateKey));\r
372         if(LoadMemoryFromFileWithTimestamp(PrivateKeyFile, &PrivateKey, sizeof(PrivateKey) - sizeof(char), &Length, NULL))\r
373         {\r
374                 if(GetModuleFileName(NULL, Name, MAX_PATH) > 0)\r
375                 {\r
376                         if(p = _tcsrchr(Name, _T('\\')))\r
377                                 *p = _T('\0');\r
378                         if(pList = (UPDATE_LIST*)malloc(UPDATE_MAX_LIST_SIZE))\r
379                         {\r
380                                 memset(pList, 0, UPDATE_MAX_LIST_SIZE);\r
381                                 pList->Version = Version;\r
382                                 _tcscpy(pList->VersionString, VersionString);\r
383                                 _tcscpy(pList->Description, Description);\r
384                                 ListUpdateFile(pList, (UPDATE_MAX_LIST_SIZE - sizeof(UPDATE_LIST)) / sizeof(UPDATE_LIST_FILE) + 1, ServerPath, Name, NULL);\r
385                                 Length = (pList->FileCount - 1) * sizeof(UPDATE_LIST_FILE) + sizeof(UPDATE_LIST);\r
386                                 if(SaveMemoryToFileWithTimestamp(ListFile, pList, Length, NULL))\r
387                                 {\r
388                                         memcpy(&Hash.Signature, UPDATE_SIGNATURE, 64);\r
389                                         if(GetHashSHA512(pList, Length, &Hash.ListHash))\r
390                                         {\r
391                                                 if(EncryptSignature(PrivateKey, Password, &Hash, sizeof(UPDATE_HASH), &Buf, sizeof(Buf), &Length))\r
392                                                 {\r
393                                                         if(SaveMemoryToFileWithTimestamp(HashFile, &Buf, Length, NULL))\r
394                                                                 bResult = TRUE;\r
395                                                 }\r
396                                         }\r
397                                 }\r
398                                 free(pList);\r
399                         }\r
400                 }\r
401         }\r
402         return bResult;\r
403 }\r
404 \r
405 // FFFTPの更新情報を確認\r
406 BOOL CheckForUpdates(BOOL bDownload, LPCTSTR DownloadDir, DWORD* pVersion, LPTSTR pVersionString, LPTSTR pDescription)\r
407 {\r
408         BOOL bResult;\r
409         DWORD Length;\r
410         BYTE Buf1[1024];\r
411         BYTE Buf2[1024];\r
412         void* pBuf;\r
413         UPDATE_HASH UpdateHash;\r
414         BYTE Hash[64];\r
415         UPDATE_LIST* pUpdateList;\r
416         bResult = FALSE;\r
417         if(ReadFileViaHTTP(&Buf1, sizeof(Buf1), &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_HASH_PATH))\r
418         {\r
419                 if(DecryptSignature(UPDATE_RSA_PUBLIC_KEY, NULL, &Buf1, Length, &Buf2, sizeof(Buf2), &Length))\r
420                 {\r
421                         if(Length == sizeof(UPDATE_HASH))\r
422                         {\r
423                                 memcpy(&UpdateHash, &Buf2, sizeof(UPDATE_HASH));\r
424                                 if(memcmp(&UpdateHash.Signature, UPDATE_SIGNATURE, 64) == 0)\r
425                                 {\r
426                                         if(pBuf = malloc(UPDATE_MAX_LIST_SIZE))\r
427                                         {\r
428                                                 if(ReadFileViaHTTP(pBuf, UPDATE_MAX_LIST_SIZE, &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_LIST_PATH))\r
429                                                 {\r
430                                                         if(GetHashSHA512(pBuf, Length, &Hash))\r
431                                                         {\r
432                                                                 if(memcmp(&Hash, &UpdateHash.ListHash, 64) == 0)\r
433                                                                 {\r
434                                                                         if(Length >= sizeof(UPDATE_LIST))\r
435                                                                         {\r
436                                                                                 bResult = TRUE;\r
437                                                                                 pUpdateList = (UPDATE_LIST*)pBuf;\r
438                                                                                 if(pUpdateList->Version > *pVersion)\r
439                                                                                 {\r
440                                                                                         *pVersion = pUpdateList->Version;\r
441                                                                                         _tcscpy(pVersionString, pUpdateList->VersionString);\r
442                                                                                         _tcscpy(pDescription, pUpdateList->Description);\r
443                                                                                 }\r
444                                                                                 if(bDownload)\r
445                                                                                         bResult = PrepareUpdates(pBuf, Length, DownloadDir);\r
446                                                                         }\r
447                                                                 }\r
448                                                         }\r
449                                                 }\r
450                                                 free(pBuf);\r
451                                         }\r
452                                 }\r
453                         }\r
454                 }\r
455         }\r
456         return bResult;\r
457 }\r
458 \r
459 // 更新するファイルをダウンロード\r
460 BOOL PrepareUpdates(void* pList, DWORD ListLength, LPCTSTR DownloadDir)\r
461 {\r
462         BOOL bResult;\r
463         UPDATE_LIST* pUpdateList;\r
464         void* pBuf;\r
465         TCHAR LocalDir[MAX_PATH];\r
466         TCHAR* p;\r
467         DWORD i;\r
468         BOOL b;\r
469         TCHAR Path[MAX_PATH];\r
470         DWORD Length;\r
471         BYTE Hash[64];\r
472         bResult = FALSE;\r
473         if(ListLength >= sizeof(UPDATE_LIST))\r
474         {\r
475                 pUpdateList = (UPDATE_LIST*)pList;\r
476                 if((pUpdateList->FileCount - 1) * sizeof(UPDATE_LIST_FILE) + sizeof(UPDATE_LIST) >= ListLength)\r
477                 {\r
478                         bResult = TRUE;\r
479                         DeleteDirectoryAndContents(DownloadDir);\r
480                         CreateDirectory(DownloadDir, NULL);\r
481                         if(pBuf = malloc(UPDATE_MAX_FILE_SIZE))\r
482                         {\r
483                                 if(GetModuleFileName(NULL, LocalDir, MAX_PATH) > 0)\r
484                                 {\r
485                                         if(p = _tcsrchr(LocalDir, _T('\\')))\r
486                                                 *p = _T('\0');\r
487                                 }\r
488                                 else\r
489                                         _tcscpy(LocalDir, _T("."));\r
490                                 for(i = 0; i < pUpdateList->FileCount; i++)\r
491                                 {\r
492                                         b = FALSE;\r
493                                         if(pUpdateList->File[i].Flags & UPDATE_LIST_FILE_FLAG_DIRECTORY)\r
494                                         {\r
495                                                 _tcscpy(Path, DownloadDir);\r
496                                                 _tcscat(Path, pUpdateList->File[i].DstPath);\r
497                                                 if(CreateDirectory(Path, NULL))\r
498                                                         b = TRUE;\r
499                                         }\r
500                                         if(strlen(pUpdateList->File[i].SrcPath) > 0)\r
501                                         {\r
502                                                 _tcscpy(Path, LocalDir);\r
503                                                 _tcscat(Path, pUpdateList->File[i].DstPath);\r
504                                                 if(LoadMemoryFromFileWithTimestamp(Path, pBuf, UPDATE_MAX_FILE_SIZE, &Length, NULL))\r
505                                                 {\r
506                                                         if(GetHashSHA512(pBuf, Length, &Hash))\r
507                                                         {\r
508                                                                 if(memcmp(&Hash, &pUpdateList->File[i].SrcHash, 64) == 0)\r
509                                                                         b = TRUE;\r
510                                                         }\r
511                                                 }\r
512                                                 if(!b)\r
513                                                 {\r
514                                                         if(ReadFileViaHTTP(pBuf, UPDATE_MAX_FILE_SIZE, &Length, HTTP_USER_AGENT, UPDATE_SERVER, pUpdateList->File[i].SrcPath))\r
515                                                         {\r
516                                                                 if(GetHashSHA512(pBuf, Length, &Hash))\r
517                                                                 {\r
518                                                                         if(memcmp(&Hash, &pUpdateList->File[i].SrcHash, 64) == 0)\r
519                                                                         {\r
520                                                                                 _tcscpy(Path, DownloadDir);\r
521                                                                                 _tcscat(Path, pUpdateList->File[i].DstPath);\r
522                                                                                 if(SaveMemoryToFileWithTimestamp(Path, pBuf, Length, &pUpdateList->File[i].Timestamp))\r
523                                                                                         b = TRUE;\r
524                                                                         }\r
525                                                                 }\r
526                                                         }\r
527                                                 }\r
528                                         }\r
529                                         if(!b)\r
530                                         {\r
531                                                 bResult = FALSE;\r
532                                                 break;\r
533                                         }\r
534                                 }\r
535                                 free(pBuf);\r
536                         }\r
537                 }\r
538         }\r
539         return bResult;\r
540 }\r
541 \r
542 // FFFTPを更新\r
543 BOOL ApplyUpdates(LPCTSTR DestinationDir, LPCTSTR BackupDirName)\r
544 {\r
545         BOOL bResult;\r
546         TCHAR Source[MAX_PATH];\r
547         TCHAR Backup[MAX_PATH];\r
548         TCHAR DestinationBackup[MAX_PATH];\r
549         TCHAR* p;\r
550         bResult = FALSE;\r
551         if(GetModuleFileName(NULL, Source, MAX_PATH) > 0)\r
552         {\r
553                 if(p = _tcsrchr(Source, _T('\\')))\r
554                         *p = _T('\0');\r
555                 _tcscpy(Backup, Source);\r
556                 _tcscat(Backup, _T("\\"));\r
557                 _tcscat(Backup, BackupDirName);\r
558                 DeleteDirectoryAndContents(Backup);\r
559                 if(CreateDirectory(Backup, NULL))\r
560                 {\r
561                         if(CopyAllFilesInDirectory(DestinationDir, Backup))\r
562                         {\r
563                                 _tcscpy(DestinationBackup, DestinationDir);\r
564                                 _tcscat(DestinationBackup, _T("\\"));\r
565                                 _tcscat(DestinationBackup, BackupDirName);\r
566                                 if(CopyAllFilesInDirectory(Source, DestinationDir))\r
567                                 {\r
568                                         DeleteDirectoryAndContents(DestinationBackup);\r
569                                         bResult = TRUE;\r
570                                 }\r
571                                 else\r
572                                 {\r
573                                         DeleteDirectoryAndContents(DestinationBackup);\r
574                                         CopyAllFilesInDirectory(Backup, DestinationDir);\r
575                                 }\r
576                         }\r
577                 }\r
578         }\r
579         return bResult;\r
580 }\r
581 \r
582 // 更新するファイルをダウンロード\r
583 BOOL CleanupUpdates(LPCTSTR DownloadDir)\r
584 {\r
585         BOOL bResult;\r
586         bResult = FALSE;\r
587         if(DeleteDirectoryAndContents(DownloadDir))\r
588                 bResult = TRUE;\r
589         return bResult;\r
590 }\r
591 \r
592 // 更新用のプロセスを起動\r
593 BOOL StartUpdateProcess(LPCTSTR DownloadDir, LPCTSTR CommandLine)\r
594 {\r
595         BOOL bResult;\r
596         TCHAR Name[MAX_PATH];\r
597         TCHAR* p;\r
598         TCHAR Path[MAX_PATH];\r
599         bResult = FALSE;\r
600         if(GetModuleFileName(NULL, Name, MAX_PATH) > 0)\r
601         {\r
602                 if(p = _tcsrchr(Name, _T('\\')))\r
603                         p++;\r
604                 else\r
605                         p = Name;\r
606                 _tcscpy(Path, DownloadDir);\r
607                 _tcscat(Path, _T("\\"));\r
608                 _tcscat(Path, p);\r
609                 if(ShellExecute(NULL, _T("open"), Path, CommandLine, NULL, SW_SHOW) > (HINSTANCE)32)\r
610                         bResult = TRUE;\r
611         }\r
612         return bResult;\r
613 }\r
614 \r
615 // 更新用のプロセスを管理者権限で起動\r
616 // Windows XP以前など起動できない場合は現在のプロセスで処理を続行\r
617 BOOL RestartUpdateProcessAsAdministrator(LPCTSTR CommandLine, LPCTSTR Keyword)\r
618 {\r
619         BOOL bResult;\r
620         TCHAR* NewCommandLine;\r
621         TCHAR Path[MAX_PATH];\r
622         SHELLEXECUTEINFO Info;\r
623         bResult = FALSE;\r
624         if(_tcslen(CommandLine) < _tcslen(Keyword) || _tcscmp(CommandLine + _tcslen(CommandLine) - _tcslen(Keyword), Keyword) != 0)\r
625         {\r
626                 if(NewCommandLine = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(CommandLine) + _tcslen(Keyword) + 1)))\r
627                 {\r
628                         _tcscpy(NewCommandLine, CommandLine);\r
629                         _tcscat(NewCommandLine, Keyword);\r
630                         if(GetModuleFileName(NULL, Path, MAX_PATH) > 0)\r
631                         {\r
632                                 memset(&Info, 0, sizeof(SHELLEXECUTEINFO));\r
633                                 Info.cbSize = sizeof(SHELLEXECUTEINFO);\r
634                                 Info.fMask = SEE_MASK_NOCLOSEPROCESS;\r
635                                 if(IsUserAnAdmin())\r
636                                         Info.lpVerb = _T("open");\r
637                                 else\r
638                                         Info.lpVerb = _T("runas");\r
639                                 Info.lpFile = Path;\r
640                                 Info.lpParameters = NewCommandLine;\r
641                                 Info.nShow = SW_SHOW;\r
642                                 if(ShellExecuteEx(&Info))\r
643                                 {\r
644                                         WaitForSingleObject(Info.hProcess, INFINITE);\r
645                                         CloseHandle(Info.hProcess);\r
646                                         bResult = TRUE;\r
647                                 }\r
648                         }\r
649                         free(NewCommandLine);\r
650                 }\r
651         }\r
652         return bResult;\r
653 }\r
654 \r