OSDN Git Service

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