OSDN Git Service

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