• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

FFFTPのソースコードです。


Commit MetaInfo

Revision4fe3b8c6631b7c5862b657c7425af7696a6487b7 (tree)
Time2014-06-15 19:04:33
Authors_kawamoto <s_kawamoto@user...>
Commiters_kawamoto

Log Message

Add routines for creating files for software update.

Change Summary

Incremental Difference

Binary files a/FFFTP_Eng_Release/FFFTP.exe and b/FFFTP_Eng_Release/FFFTP.exe differ
Binary files a/Release/FFFTP.exe and b/Release/FFFTP.exe differ
--- a/main.c
+++ b/main.c
@@ -305,98 +305,85 @@ int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLi
305305 MSG Msg;
306306 int Ret;
307307 BOOL Sts;
308+ // プロセス保護
309+ char* pCommand;
310+ DWORD ProtectLevel;
311+ char Option[FMAX_PATH+1];
308312 // ソフトウェア自動更新
313+ int ImmediateExit;
314+ char PrivateKeyFile[FMAX_PATH+1];
315+ char Password[FMAX_PATH+1];
316+ char ServerPath[FMAX_PATH+1];
317+ char HashFile[FMAX_PATH+1];
318+ char ListFile[FMAX_PATH+1];
319+ char Description[FMAX_PATH+1];
309320 char UpdateDir[FMAX_PATH+1];
310321 char Path[FMAX_PATH+1];
311322 char Command[FMAX_PATH+1];
312323 char* p;
313324
314- // プロセス保護
315325 #ifdef ENABLE_PROCESS_PROTECTION
326+ ProtectLevel = PROCESS_PROTECTION_NONE;
327+ pCommand = lpszCmdLine;
328+ while(pCommand = GetToken(pCommand, Option))
316329 {
317- DWORD ProtectLevel;
318- char* pCommand;
319- char Option[FMAX_PATH+1];
320- ProtectLevel = PROCESS_PROTECTION_NONE;
321- pCommand = lpszCmdLine;
322- while(pCommand = GetToken(pCommand, Option))
330+ if(Option[0] == '-')
323331 {
324- if(Option[0] == '-')
332+ if(strcmp(&Option[1], "-protect") == 0)
325333 {
326- if(strcmp(&Option[1], "-protect") == 0)
327- {
328- ProtectLevel = PROCESS_PROTECTION_DEFAULT;
329- break;
330- }
331- else if(strcmp(&Option[1], "-protect-high") == 0)
332- {
333- ProtectLevel = PROCESS_PROTECTION_HIGH;
334- break;
335- }
336- else if(strcmp(&Option[1], "-protect-medium") == 0)
337- {
338- ProtectLevel = PROCESS_PROTECTION_MEDIUM;
339- break;
340- }
341- else if(strcmp(&Option[1], "-protect-low") == 0)
342- {
343- ProtectLevel = PROCESS_PROTECTION_LOW;
344- break;
345- }
334+ ProtectLevel = PROCESS_PROTECTION_DEFAULT;
335+ break;
346336 }
347- }
348- if(ProtectLevel != PROCESS_PROTECTION_NONE)
349- {
350- SetProcessProtectionLevel(ProtectLevel);
351- if(!InitializeLoadLibraryHook())
337+ else if(strcmp(&Option[1], "-protect-high") == 0)
352338 {
353- MessageBox(NULL, MSGJPN321, "FFFTP", MB_OK | MB_ICONERROR);
354- return 0;
339+ ProtectLevel = PROCESS_PROTECTION_HIGH;
340+ break;
355341 }
356-#ifndef _DEBUG
357- if(IsDebuggerPresent())
342+ else if(strcmp(&Option[1], "-protect-medium") == 0)
358343 {
359- MessageBox(NULL, MSGJPN322, "FFFTP", MB_OK | MB_ICONERROR);
360- return 0;
344+ ProtectLevel = PROCESS_PROTECTION_MEDIUM;
345+ break;
361346 }
362-#endif
363- if(!UnloadUntrustedModule())
347+ else if(strcmp(&Option[1], "-protect-low") == 0)
364348 {
365- MessageBox(NULL, MSGJPN323, "FFFTP", MB_OK | MB_ICONERROR);
366- return 0;
349+ ProtectLevel = PROCESS_PROTECTION_LOW;
350+ break;
367351 }
352+ }
353+ }
354+ if(ProtectLevel != PROCESS_PROTECTION_NONE)
355+ {
356+ SetProcessProtectionLevel(ProtectLevel);
357+ if(!InitializeLoadLibraryHook())
358+ {
359+ MessageBox(NULL, MSGJPN321, "FFFTP", MB_OK | MB_ICONERROR);
360+ return 0;
361+ }
368362 #ifndef _DEBUG
369- if(RestartProtectedProcess(" --restart"))
370- return 0;
363+ if(IsDebuggerPresent())
364+ {
365+ MessageBox(NULL, MSGJPN322, "FFFTP", MB_OK | MB_ICONERROR);
366+ return 0;
367+ }
371368 #endif
372- if(!EnableLoadLibraryHook(TRUE))
373- {
374- MessageBox(NULL, MSGJPN324, "FFFTP", MB_OK | MB_ICONERROR);
375- return 0;
376- }
369+ if(!UnloadUntrustedModule())
370+ {
371+ MessageBox(NULL, MSGJPN323, "FFFTP", MB_OK | MB_ICONERROR);
372+ return 0;
377373 }
378- else
379- InitializeLoadLibraryHook();
380- }
374+#ifndef _DEBUG
375+ if(RestartProtectedProcess(" --restart"))
376+ return 0;
381377 #endif
382-
383- // ソフトウェア自動更新
384- if(GetTokenAfterOption(lpszCmdLine, UpdateDir, "-software-update", "-software-update"))
385- {
386- if(!RestartUpdateProcessAsAdministrator(lpszCmdLine, " --restart"))
378+ if(!EnableLoadLibraryHook(TRUE))
387379 {
388- Sleep(1000);
389- if(ApplyUpdates(UpdateDir, "updatebackup"))
390- MessageBox(NULL, MSGJPN359, "FFFTP", MB_OK);
391- else
392- MessageBox(NULL, MSGJPN360, "FFFTP", MB_OK | MB_ICONERROR);
380+ MessageBox(NULL, MSGJPN324, "FFFTP", MB_OK | MB_ICONERROR);
381+ return 0;
393382 }
394- return 0;
395- }
396- else if(GetTokenAfterOption(lpszCmdLine, UpdateDir, "-software-cleanup", "-software-cleanup"))
397- {
398- CleanupUpdates(UpdateDir);
399383 }
384+ else
385+ InitializeLoadLibraryHook();
386+#endif
400387
401388 // マルチコアCPUの特定環境下でファイル通信中にクラッシュするバグ対策
402389 #ifdef DISABLE_MULTI_CPUS
@@ -429,10 +416,66 @@ int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLi
429416 // SFTP対応
430417 LoadPuTTY();
431418
419+ // ソフトウェア自動更新
420+ ImmediateExit = NO;
421+ pCommand = lpszCmdLine;
422+ while(pCommand = GetToken(pCommand, Option))
423+ {
424+ if(Option[0] == '-')
425+ {
426+ if(strcmp(&Option[1], "-build-software-update") == 0)
427+ {
428+ if(pCommand = GetToken(pCommand, PrivateKeyFile))
429+ {
430+ if(pCommand = GetToken(pCommand, Password))
431+ {
432+ if(pCommand = GetToken(pCommand, ServerPath))
433+ {
434+ if(pCommand = GetToken(pCommand, HashFile))
435+ {
436+ if(pCommand = GetToken(pCommand, ListFile))
437+ {
438+ if(pCommand = GetToken(pCommand, Description))
439+ BuildUpdates(PrivateKeyFile, Password, ServerPath, HashFile, ListFile, RELEASE_VERSION_NUM, VER_STR, Description);
440+ }
441+ }
442+ }
443+ }
444+ }
445+ ImmediateExit = YES;
446+ break;
447+ }
448+ else if(strcmp(&Option[1], "-software-update") == 0)
449+ {
450+ if(pCommand = GetToken(pCommand, UpdateDir))
451+ {
452+ if(!RestartUpdateProcessAsAdministrator(lpszCmdLine, " --restart"))
453+ {
454+ Sleep(1000);
455+ if(ApplyUpdates(UpdateDir, "updatebackup"))
456+ MessageBox(NULL, MSGJPN359, "FFFTP", MB_OK);
457+ else
458+ MessageBox(NULL, MSGJPN360, "FFFTP", MB_OK | MB_ICONERROR);
459+ }
460+ }
461+ ImmediateExit = YES;
462+ break;
463+ }
464+ else if(strcmp(&Option[1], "-software-cleanup") == 0)
465+ {
466+ if(pCommand = GetToken(pCommand, UpdateDir))
467+ CleanupUpdates(UpdateDir);
468+ break;
469+ }
470+ }
471+ }
472+
432473 Ret = FALSE;
433474 hWndFtp = NULL;
434475 hInstFtp = hInstance;
435- if(InitApp(lpszCmdLine, cmdShow) == FFFTP_SUCCESS)
476+ // ソフトウェア自動更新
477+// if(InitApp(lpszCmdLine, cmdShow) == FFFTP_SUCCESS)
478+ if(ImmediateExit == NO && InitApp(lpszCmdLine, cmdShow) == FFFTP_SUCCESS)
436479 {
437480 for(;;)
438481 {
@@ -2166,6 +2209,8 @@ static int AnalyzeComLine(char *Str, int *AutoConnect, int *CmdOption, char *unc
21662209 {
21672210 int Ret;
21682211 char Tmp[FMAX_PATH+1];
2212+ // ソフトウェア自動更新
2213+ int i;
21692214
21702215 *AutoConnect = -1;
21712216 *CmdOption = 0;
@@ -2292,6 +2337,17 @@ static int AnalyzeComLine(char *Str, int *AutoConnect, int *CmdOption, char *unc
22922337 else if((strcmp(&Tmp[1], "u8n") == 0) || (strcmp(&Tmp[1], "-utf8name") == 0))
22932338 *CmdOption |= OPT_UTF8N_NAME;
22942339 // ソフトウェア自動更新
2340+ else if(strcmp(&Tmp[1], "-build-software-update") == 0)
2341+ {
2342+ for(i = 0; i < 6; i++)
2343+ {
2344+ if((Str = GetToken(Str, Tmp)) == NULL)
2345+ {
2346+ Ret = -1;
2347+ break;
2348+ }
2349+ }
2350+ }
22952351 else if(strcmp(&Tmp[1], "-software-update") == 0)
22962352 {
22972353 if((Str = GetToken(Str, Tmp)) == NULL)
@@ -3650,7 +3706,8 @@ void UpdateSoftware(int Async, int NoError, int NoConfirm)
36503706 UPDATESOFTWAREDATA* pData;
36513707 DWORD Version;
36523708 char VersionString[32];
3653- char Tmp[FMAX_PATH+1];
3709+ char Description[1024];
3710+ char Tmp[2048];
36543711 if(Async == YES)
36553712 {
36563713 if(pData = malloc(sizeof(UPDATESOFTWAREDATA)))
@@ -3667,18 +3724,18 @@ void UpdateSoftware(int Async, int NoError, int NoConfirm)
36673724 {
36683725 Version = RELEASE_VERSION_NUM;
36693726 LastAutoCheckForUpdates = time(NULL);
3670- if(CheckForUpdates(FALSE, NULL, &Version, VersionString))
3727+ if(CheckForUpdates(FALSE, NULL, &Version, VersionString, Description))
36713728 {
36723729 if(Version > RELEASE_VERSION_NUM)
36733730 {
3674- sprintf(Tmp, MSGJPN362, VER_STR, VersionString);
3731+ sprintf(Tmp, MSGJPN362, VER_STR, VersionString, Description);
36753732 if(NoConfirm == YES || MessageBox(GetMainHwnd(), Tmp, "FFFTP", MB_YESNO) == IDYES)
36763733 {
36773734 strcpy(Tmp, TmpPath);
36783735 SetYenTail(Tmp);
36793736 strcat(Tmp, "update");
36803737 _mkdir(Tmp);
3681- if(CheckForUpdates(TRUE, Tmp, &Version, VersionString))
3738+ if(CheckForUpdates(TRUE, Tmp, &Version, VersionString, Description))
36823739 {
36833740 MessageBox(GetMainHwnd(), MSGJPN365, "FFFTP", MB_OK);
36843741 ApplyUpdatesOnExit = YES;
--- a/mesg-eng.h
+++ b/mesg-eng.h
@@ -360,7 +360,7 @@
360360 #define MSGJPN359 _Tu8("Software update has been completed.", "Software update has been completed.")
361361 #define MSGJPN360 _Tu8("Failed to update the software.\nPlease get the latest version from our web site and update it manually.", "Failed to update the software.\nPlease get the latest version from our web site and update it manually.")
362362 #define MSGJPN361 _Tu8("Updates", "Updates")
363-#define MSGJPN362 _Tu8("There is a new version.\n\nCurrent version: %s\nNew version: %s\n\nIt takes a few minutes to download the updates.\nDo you want to update now?\n", "There is a new version.\n\nCurrent version: %s\nNew version: %s\n\nIt takes a few minutes to download the updates.\nDo you want to update now?\n")
363+#define MSGJPN362 _Tu8("There is a new version.\n\nCurrent version: %s\nNew version: %s\n%s\n\nIt takes a few minutes to download the updates.\nDo you want to update now?\n", "There is a new version.\n\nCurrent version: %s\nNew version: %s\n%s\n\nIt takes a few minutes to download the updates.\nDo you want to update now?\n")
364364 #define MSGJPN363 _Tu8("Failed to update the software.\nCannot connect to the server or the data is corrupted.", "Failed to update the software.\nCannot connect to the server or the data is corrupted.")
365365 #define MSGJPN364 _Tu8("Your version is already up-to-date.", "Your version is already up-to-date.")
366366 #define MSGJPN365 _Tu8("Preparing for the software update has been completed.\nIt will be applied on exit.", "Preparing for the software update has been completed.\nIt will be applied on exit.")
--- a/mesg-jpn.h
+++ b/mesg-jpn.h
@@ -360,7 +360,7 @@
360360 #define MSGJPN359 _Tu8("ソフトウェアの更新が完了しました.", "\xE3\x82\xBD\xE3\x83\x95\xE3\x83\x88\xE3\x82\xA6\xE3\x82\xA7\xE3\x82\xA2\xE3\x81\xAE\xE6\x9B\xB4\xE6\x96\xB0\xE3\x81\x8C\xE5\xAE\x8C\xE4\xBA\x86\xE3\x81\x97\xE3\x81\xBE\xE3\x81\x97\xE3\x81\x9F.")
361361 #define MSGJPN360 _Tu8("ソフトウェアの更新に失敗しました.\nWebサイトから最新版を入手して手動で更新してください.", "\xE3\x82\xBD\xE3\x83\x95\xE3\x83\x88\xE3\x82\xA6\xE3\x82\xA7\xE3\x82\xA2\xE3\x81\xAE\xE6\x9B\xB4\xE6\x96\xB0\xE3\x81\xAB\xE5\xA4\xB1\xE6\x95\x97\xE3\x81\x97\xE3\x81\xBE\xE3\x81\x97\xE3\x81\x9F.\nWeb\xE3\x82\xB5\xE3\x82\xA4\xE3\x83\x88\xE3\x81\x8B\xE3\x82\x89\xE6\x9C\x80\xE6\x96\xB0\xE7\x89\x88\xE3\x82\x92\xE5\x85\xA5\xE6\x89\x8B\xE3\x81\x97\xE3\x81\xA6\xE6\x89\x8B\xE5\x8B\x95\xE3\x81\xA7\xE6\x9B\xB4\xE6\x96\xB0\xE3\x81\x97\xE3\x81\xA6\xE3\x81\x8F\xE3\x81\xA0\xE3\x81\x95\xE3\x81\x84.")
362362 #define MSGJPN361 _Tu8("更新", "\xE6\x9B\xB4\xE6\x96\xB0")
363-#define MSGJPN362 _Tu8("新しいバージョンがあります.\n\n現在のバージョン: %s\n新しいバージョン: %s\n\n更新のダウンロードには数分間かかります.\n今すぐ更新しますか.", "\xE6\x96\xB0\xE3\x81\x97\xE3\x81\x84\xE3\x83\x90\xE3\x83\xBC\xE3\x82\xB8\xE3\x83\xA7\xE3\x83\xB3\xE3\x81\x8C\xE3\x81\x82\xE3\x82\x8A\xE3\x81\xBE\xE3\x81\x99.\n\n\xE7\x8F\xBE\xE5\x9C\xA8\xE3\x81\xAE\xE3\x83\x90\xE3\x83\xBC\xE3\x82\xB8\xE3\x83\xA7\xE3\x83\xB3: %s\n\xE6\x96\xB0\xE3\x81\x97\xE3\x81\x84\xE3\x83\x90\xE3\x83\xBC\xE3\x82\xB8\xE3\x83\xA7\xE3\x83\xB3: %s\n\n\xE6\x9B\xB4\xE6\x96\xB0\xE3\x81\xAE\xE3\x83\x80\xE3\x82\xA6\xE3\x83\xB3\xE3\x83\xAD\xE3\x83\xBC\xE3\x83\x89\xE3\x81\xAB\xE3\x81\xAF\xE6\x95\xB0\xE5\x88\x86\xE9\x96\x93\xE3\x81\x8B\xE3\x81\x8B\xE3\x82\x8A\xE3\x81\xBE\xE3\x81\x99.\n\xE4\xBB\x8A\xE3\x81\x99\xE3\x81\x90\xE6\x9B\xB4\xE6\x96\xB0\xE3\x81\x97\xE3\x81\xBE\xE3\x81\x99\xE3\x81\x8B.")
363+#define MSGJPN362 _Tu8("新しいバージョンがあります.\n\n現在のバージョン: %s\n新しいバージョン: %s\n%s\n\n更新のダウンロードには数分間かかります.\n今すぐ更新しますか.", "\xE6\x96\xB0\xE3\x81\x97\xE3\x81\x84\xE3\x83\x90\xE3\x83\xBC\xE3\x82\xB8\xE3\x83\xA7\xE3\x83\xB3\xE3\x81\x8C\xE3\x81\x82\xE3\x82\x8A\xE3\x81\xBE\xE3\x81\x99.\n\n\xE7\x8F\xBE\xE5\x9C\xA8\xE3\x81\xAE\xE3\x83\x90\xE3\x83\xBC\xE3\x82\xB8\xE3\x83\xA7\xE3\x83\xB3: %s\n\xE6\x96\xB0\xE3\x81\x97\xE3\x81\x84\xE3\x83\x90\xE3\x83\xBC\xE3\x82\xB8\xE3\x83\xA7\xE3\x83\xB3: %s\n%s\n\n\xE6\x9B\xB4\xE6\x96\xB0\xE3\x81\xAE\xE3\x83\x80\xE3\x82\xA6\xE3\x83\xB3\xE3\x83\xAD\xE3\x83\xBC\xE3\x83\x89\xE3\x81\xAB\xE3\x81\xAF\xE6\x95\xB0\xE5\x88\x86\xE9\x96\x93\xE3\x81\x8B\xE3\x81\x8B\xE3\x82\x8A\xE3\x81\xBE\xE3\x81\x99.\n\xE4\xBB\x8A\xE3\x81\x99\xE3\x81\x90\xE6\x9B\xB4\xE6\x96\xB0\xE3\x81\x97\xE3\x81\xBE\xE3\x81\x99\xE3\x81\x8B.")
364364 #define MSGJPN363 _Tu8("ソフトウェアの更新に失敗しました.\nサーバーに接続できないかデータが破損しています.", "\xE3\x82\xBD\xE3\x83\x95\xE3\x83\x88\xE3\x82\xA6\xE3\x82\xA7\xE3\x82\xA2\xE3\x81\xAE\xE6\x9B\xB4\xE6\x96\xB0\xE3\x81\xAB\xE5\xA4\xB1\xE6\x95\x97\xE3\x81\x97\xE3\x81\xBE\xE3\x81\x97\xE3\x81\x9F.\n\xE3\x82\xB5\xE3\x83\xBC\xE3\x83\x90\xE3\x83\xBC\xE3\x81\xAB\xE6\x8E\xA5\xE7\xB6\x9A\xE3\x81\xA7\xE3\x81\x8D\xE3\x81\xAA\xE3\x81\x84\xE3\x81\x8B\xE3\x83\x87\xE3\x83\xBC\xE3\x82\xBF\xE3\x81\x8C\xE7\xA0\xB4\xE6\x90\x8D\xE3\x81\x97\xE3\x81\xA6\xE3\x81\x84\xE3\x81\xBE\xE3\x81\x99.")
365365 #define MSGJPN364 _Tu8("お使いのバージョンはすでに最新です.", "\xE3\x81\x8A\xE4\xBD\xBF\xE3\x81\x84\xE3\x81\xAE\xE3\x83\x90\xE3\x83\xBC\xE3\x82\xB8\xE3\x83\xA7\xE3\x83\xB3\xE3\x81\xAF\xE3\x81\x99\xE3\x81\xA7\xE3\x81\xAB\xE6\x9C\x80\xE6\x96\xB0\xE3\x81\xA7\xE3\x81\x99.")
366366 #define MSGJPN365 _Tu8("ソフトウェアの更新の準備が完了しました.\nFFFTPの終了時に更新が適用されます.", "\xE3\x82\xBD\xE3\x83\x95\xE3\x83\x88\xE3\x82\xA6\xE3\x82\xA7\xE3\x82\xA2\xE3\x81\xAE\xE6\x9B\xB4\xE6\x96\xB0\xE3\x81\xAE\xE6\xBA\x96\xE5\x82\x99\xE3\x81\x8C\xE5\xAE\x8C\xE4\xBA\x86\xE3\x81\x97\xE3\x81\xBE\xE3\x81\x97\xE3\x81\x9F.\nFFFTP\xE3\x81\xAE\xE7\xB5\x82\xE4\xBA\x86\xE6\x99\x82\xE3\x81\xAB\xE6\x9B\xB4\xE6\x96\xB0\xE3\x81\x8C\xE9\x81\xA9\xE7\x94\xA8\xE3\x81\x95\xE3\x82\x8C\xE3\x81\xBE\xE3\x81\x99.")
--- a/socketwrapper.c
+++ b/socketwrapper.c
@@ -52,6 +52,7 @@ typedef int (__cdecl* _X509_print_ex)(BIO*, X509*, unsigned long, unsigned long)
5252 typedef X509_NAME* (__cdecl* _X509_get_subject_name)(X509*);
5353 typedef int (__cdecl* _X509_NAME_print_ex)(BIO*, X509_NAME*, int, unsigned long);
5454 typedef void (__cdecl* _X509_CRL_free)(X509_CRL*);
55+typedef EVP_PKEY* (__cdecl* _PEM_read_bio_PrivateKey)(BIO*, EVP_PKEY**, pem_password_cb*, void*);
5556 typedef EVP_PKEY* (__cdecl* _PEM_read_bio_PUBKEY)(BIO*, EVP_PKEY**, pem_password_cb*, void*);
5657 typedef X509* (__cdecl* _PEM_read_bio_X509)(BIO*, X509**, pem_password_cb*, void*);
5758 typedef X509_CRL* (__cdecl* _PEM_read_bio_X509_CRL)(BIO*, X509_CRL**, pem_password_cb*, void*);
@@ -61,6 +62,7 @@ typedef void (__cdecl* _EVP_PKEY_free)(EVP_PKEY*);
6162 typedef RSA* (__cdecl* _EVP_PKEY_get1_RSA)(EVP_PKEY*);
6263 typedef void (__cdecl* _RSA_free)(RSA*);
6364 typedef int (__cdecl* _RSA_size)(const RSA*);
65+typedef int (__cdecl* _RSA_private_encrypt)(int, const unsigned char*, unsigned char*, RSA*, int);
6466 typedef int (__cdecl* _RSA_public_decrypt)(int, const unsigned char*, unsigned char*, RSA*, int);
6567 typedef unsigned char* (__cdecl* _SHA1)(const unsigned char*, size_t, unsigned char*);
6668 typedef unsigned char* (__cdecl* _SHA224)(const unsigned char*, size_t, unsigned char*);
@@ -102,6 +104,7 @@ _X509_print_ex p_X509_print_ex;
102104 _X509_get_subject_name p_X509_get_subject_name;
103105 _X509_NAME_print_ex p_X509_NAME_print_ex;
104106 _X509_CRL_free p_X509_CRL_free;
107+_PEM_read_bio_PrivateKey p_PEM_read_bio_PrivateKey;
105108 _PEM_read_bio_PUBKEY p_PEM_read_bio_PUBKEY;
106109 _PEM_read_bio_X509 p_PEM_read_bio_X509;
107110 _PEM_read_bio_X509_CRL p_PEM_read_bio_X509_CRL;
@@ -111,6 +114,7 @@ _EVP_PKEY_free p_EVP_PKEY_free;
111114 _EVP_PKEY_get1_RSA p_EVP_PKEY_get1_RSA;
112115 _RSA_free p_RSA_free;
113116 _RSA_size p_RSA_size;
117+_RSA_private_encrypt p_RSA_private_encrypt;
114118 _RSA_public_decrypt p_RSA_public_decrypt;
115119 _SHA1 p_SHA1;
116120 _SHA224 p_SHA224;
@@ -207,6 +211,7 @@ BOOL LoadOpenSSL()
207211 || !(p_X509_get_subject_name = (_X509_get_subject_name)GetProcAddress(g_hOpenSSLCommon, "X509_get_subject_name"))
208212 || !(p_X509_NAME_print_ex = (_X509_NAME_print_ex)GetProcAddress(g_hOpenSSLCommon, "X509_NAME_print_ex"))
209213 || !(p_X509_CRL_free = (_X509_CRL_free)GetProcAddress(g_hOpenSSLCommon, "X509_CRL_free"))
214+ || !(p_PEM_read_bio_PrivateKey = (_PEM_read_bio_PrivateKey)GetProcAddress(g_hOpenSSLCommon, "PEM_read_bio_PrivateKey"))
210215 || !(p_PEM_read_bio_PUBKEY = (_PEM_read_bio_PUBKEY)GetProcAddress(g_hOpenSSLCommon, "PEM_read_bio_PUBKEY"))
211216 || !(p_PEM_read_bio_X509 = (_PEM_read_bio_X509)GetProcAddress(g_hOpenSSLCommon, "PEM_read_bio_X509"))
212217 || !(p_PEM_read_bio_X509_CRL = (_PEM_read_bio_X509_CRL)GetProcAddress(g_hOpenSSLCommon, "PEM_read_bio_X509_CRL"))
@@ -216,6 +221,7 @@ BOOL LoadOpenSSL()
216221 || !(p_EVP_PKEY_get1_RSA = (_EVP_PKEY_get1_RSA)GetProcAddress(g_hOpenSSLCommon, "EVP_PKEY_get1_RSA"))
217222 || !(p_RSA_free = (_RSA_free)GetProcAddress(g_hOpenSSLCommon, "RSA_free"))
218223 || !(p_RSA_size = (_RSA_size)GetProcAddress(g_hOpenSSLCommon, "RSA_size"))
224+ || !(p_RSA_private_encrypt = (_RSA_private_encrypt)GetProcAddress(g_hOpenSSLCommon, "RSA_private_encrypt"))
219225 || !(p_RSA_public_decrypt = (_RSA_public_decrypt)GetProcAddress(g_hOpenSSLCommon, "RSA_public_decrypt"))
220226 || !(p_SHA1 = (_SHA1)GetProcAddress(g_hOpenSSLCommon, "SHA1"))
221227 || !(p_SHA224 = (_SHA224)GetProcAddress(g_hOpenSSLCommon, "SHA224"))
@@ -536,9 +542,47 @@ BOOL IsHostNameMatched(LPCSTR HostName, LPCSTR CommonName)
536542 return bResult;
537543 }
538544
545+#pragma warning(push)
546+#pragma warning(disable:4090)
547+
548+// RSA暗号化
549+BOOL EncryptSignature(const char* PrivateKey, const char* Password, const void* pIn, DWORD InLength, void* pOut, DWORD OutLength, DWORD* pOutLength)
550+{
551+ BOOL bResult;
552+ BIO* pBIO;
553+ EVP_PKEY* pPKEY;
554+ RSA* pRSA;
555+ int i;
556+ if(!g_bOpenSSLLoaded)
557+ return FALSE;
558+ bResult = FALSE;
559+ if(pBIO = p_BIO_new_mem_buf((void*)PrivateKey, sizeof(char) * strlen(PrivateKey)))
560+ {
561+ if(pPKEY = p_PEM_read_bio_PrivateKey(pBIO, NULL, NULL, (void*)Password))
562+ {
563+ if(pRSA = p_EVP_PKEY_get1_RSA(pPKEY))
564+ {
565+ if(p_RSA_size(pRSA) <= (int)OutLength)
566+ {
567+ i = p_RSA_private_encrypt((int)InLength, (const unsigned char*)pIn, (unsigned char*)pOut, pRSA, RSA_PKCS1_PADDING);
568+ if(i >= 0)
569+ {
570+ *pOutLength = (DWORD)i;
571+ bResult = TRUE;
572+ }
573+ }
574+ p_RSA_free(pRSA);
575+ }
576+ p_EVP_PKEY_free(pPKEY);
577+ }
578+ p_BIO_free(pBIO);
579+ }
580+ return bResult;
581+}
582+
539583 // RSA復号化
540584 // 主に自動更新ファイルのハッシュの改竄確認
541-BOOL DecryptSignature(const char* PublicKey, const void* pIn, DWORD InLength, void* pOut, DWORD OutLength, DWORD* pOutLength)
585+BOOL DecryptSignature(const char* PublicKey, const char* Password, const void* pIn, DWORD InLength, void* pOut, DWORD OutLength, DWORD* pOutLength)
542586 {
543587 BOOL bResult;
544588 BIO* pBIO;
@@ -550,7 +594,7 @@ BOOL DecryptSignature(const char* PublicKey, const void* pIn, DWORD InLength, vo
550594 bResult = FALSE;
551595 if(pBIO = p_BIO_new_mem_buf((void*)PublicKey, sizeof(char) * strlen(PublicKey)))
552596 {
553- if(pPKEY = p_PEM_read_bio_PUBKEY(pBIO, NULL, NULL, NULL))
597+ if(pPKEY = p_PEM_read_bio_PUBKEY(pBIO, NULL, NULL, Password))
554598 {
555599 if(pRSA = p_EVP_PKEY_get1_RSA(pPKEY))
556600 {
@@ -572,6 +616,8 @@ BOOL DecryptSignature(const char* PublicKey, const void* pIn, DWORD InLength, vo
572616 return bResult;
573617 }
574618
619+#pragma warning(pop)
620+
575621 // ハッシュ計算
576622 // 他にも同等の関数はあるが主にマルウェア対策のための冗長化
577623 BOOL GetHashSHA1(const void* pData, DWORD Size, void* pHash)
--- a/socketwrapper.h
+++ b/socketwrapper.h
@@ -20,7 +20,8 @@ void SetSSLTimeoutCallback(DWORD Timeout, LPSSLTIMEOUTCALLBACK pCallback);
2020 void SetSSLConfirmCallback(LPSSLCONFIRMCALLBACK pCallback);
2121 BOOL SetSSLRootCertificate(const void* pData, DWORD Length);
2222 BOOL IsHostNameMatched(LPCSTR HostName, LPCSTR CommonName);
23-BOOL DecryptSignature(const char* PublicKey, const void* pIn, DWORD InLength, void* pOut, DWORD OutLength, DWORD* pOutLength);
23+BOOL EncryptSignature(const char* PrivateKey, const char* Password, const void* pIn, DWORD InLength, void* pOut, DWORD OutLength, DWORD* pOutLength);
24+BOOL DecryptSignature(const char* PublicKey, const char* Password, const void* pIn, DWORD InLength, void* pOut, DWORD OutLength, DWORD* pOutLength);
2425 BOOL GetHashSHA1(const void* pData, DWORD Size, void* pHash);
2526 BOOL GetHashSHA224(const void* pData, DWORD Size, void* pHash);
2627 BOOL GetHashSHA256(const void* pData, DWORD Size, void* pHash);
--- a/updater.c
+++ b/updater.c
@@ -37,6 +37,7 @@ typedef struct
3737 {
3838 DWORD Version;
3939 CHAR VersionString[32];
40+ CHAR Description[1024];
4041 DWORD FileCount;
4142 UPDATE_LIST_FILE File[1];
4243 } UPDATE_LIST;
@@ -102,7 +103,12 @@ BOOL SaveMemoryToFileWithTimestamp(LPCTSTR FileName, void* pData, DWORD Size, FI
102103 {
103104 if(WriteFile(hFile, pData, Size, &Size, NULL))
104105 {
105- if(SetFileTime(hFile, NULL, NULL, pTimestamp))
106+ if(pTimestamp)
107+ {
108+ if(SetFileTime(hFile, NULL, NULL, pTimestamp))
109+ bResult = TRUE;
110+ }
111+ else
106112 bResult = TRUE;
107113 }
108114 CloseHandle(hFile);
@@ -110,6 +116,38 @@ BOOL SaveMemoryToFileWithTimestamp(LPCTSTR FileName, void* pData, DWORD Size, FI
110116 return bResult;
111117 }
112118
119+BOOL LoadMemoryFromFileWithTimestamp(LPCTSTR FileName, void* pData, DWORD Size, DWORD* pReadSize, FILETIME* pTimestamp)
120+{
121+ BOOL bResult;
122+ HANDLE hFile;
123+ LARGE_INTEGER li;
124+ bResult = FALSE;
125+ if((hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
126+ {
127+ if(GetFileSizeEx(hFile, &li))
128+ {
129+ if(li.QuadPart <= (LONGLONG)Size)
130+ {
131+ if(ReadFile(hFile, pData, Size, pReadSize, NULL))
132+ {
133+ if(*pReadSize == li.LowPart)
134+ {
135+ if(pTimestamp)
136+ {
137+ if(GetFileTime(hFile, NULL, NULL, pTimestamp))
138+ bResult = TRUE;
139+ }
140+ else
141+ bResult = TRUE;
142+ }
143+ }
144+ }
145+ CloseHandle(hFile);
146+ }
147+ }
148+ return bResult;
149+}
150+
113151 BOOL CopyAllFilesInDirectory(LPCTSTR From, LPCTSTR To)
114152 {
115153 BOOL bResult;
@@ -158,46 +196,189 @@ BOOL DeleteDirectoryAndContents(LPCTSTR Path)
158196 return bResult;
159197 }
160198
199+DWORD ListUpdateFile(UPDATE_LIST* pList, DWORD MaxCount, LPCTSTR ServerPath, LPCTSTR ReferenceDir, LPCTSTR Path)
200+{
201+ DWORD Result;
202+ TCHAR Temp1[MAX_PATH];
203+ TCHAR Temp2[MAX_PATH];
204+ TCHAR Temp3[MAX_PATH];
205+ HANDLE hFind;
206+ WIN32_FIND_DATA Find;
207+ void* pBuf;
208+ DWORD Length;
209+ FILETIME Time;
210+ BYTE Hash[64];
211+ Result = 0;
212+ if(!Path)
213+ Path = _T("");
214+ if(_tcslen(ReferenceDir) + _tcslen(Path) + _tcslen(_T("\\*")) < MAX_PATH)
215+ {
216+ _tcscpy(Temp1, ReferenceDir);
217+ _tcscat(Temp1, Path);
218+ _tcscat(Temp1, _T("\\*"));
219+ if((hFind = FindFirstFile(Temp1, &Find)) != INVALID_HANDLE_VALUE)
220+ {
221+ do
222+ {
223+ if(_tcscmp(Find.cFileName, _T(".")) != 0 && _tcscmp(Find.cFileName, _T("..")) != 0)
224+ {
225+ if(_tcslen(ServerPath) + _tcslen(_T("/")) + _tcslen(Find.cFileName) < 128 && _tcslen(Path) + _tcslen(_T("\\")) + _tcslen(Find.cFileName) < 128)
226+ {
227+ _tcscpy(Temp1, ServerPath);
228+ _tcscat(Temp1, _T("/"));
229+ _tcscat(Temp1, Find.cFileName);
230+ _tcscpy(Temp2, Path);
231+ _tcscat(Temp2, _T("\\"));
232+ _tcscat(Temp2, Find.cFileName);
233+ if(_tcslen(ReferenceDir) + _tcslen(Temp2) < MAX_PATH)
234+ {
235+ _tcscpy(Temp3, ReferenceDir);
236+ _tcscat(Temp3, Temp2);
237+ if((Find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
238+ {
239+ if(!(Find.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
240+ {
241+ if(pList)
242+ {
243+ memset(&pList->File[pList->FileCount], 0, sizeof(UPDATE_LIST_FILE));
244+ pList->File[pList->FileCount].Flags = UPDATE_LIST_FILE_FLAG_DIRECTORY;
245+ _tcscpy(pList->File[pList->FileCount].DstPath, Temp2);
246+ pList->FileCount++;
247+ }
248+ Result++;
249+ if(Result >= MaxCount)
250+ break;
251+ Result += ListUpdateFile(pList, MaxCount, Temp1, ReferenceDir, Temp2);
252+ }
253+ }
254+ else
255+ {
256+ if(pList)
257+ {
258+ if(pBuf = malloc(16777216))
259+ {
260+ if(LoadMemoryFromFileWithTimestamp(Temp3, pBuf, 16777216, &Length, &Time))
261+ {
262+ if(GetHashSHA512(pBuf, Length, &Hash))
263+ {
264+ memset(&pList->File[pList->FileCount], 0, sizeof(UPDATE_LIST_FILE));
265+ _tcscpy(pList->File[pList->FileCount].SrcPath, Temp1);
266+ memcpy(&pList->File[pList->FileCount].SrcHash, &Hash, 64);
267+ _tcscpy(pList->File[pList->FileCount].DstPath, Temp2);
268+ pList->File[pList->FileCount].Timestamp = Time;
269+ pList->FileCount++;
270+ }
271+ }
272+ free(pBuf);
273+ }
274+ }
275+ Result++;
276+ if(Result >= MaxCount)
277+ break;
278+ }
279+ }
280+ }
281+ }
282+ }
283+ while(FindNextFile(hFind, &Find));
284+ FindClose(hFind);
285+ }
286+ }
287+ return Result;
288+}
289+
290+// FFFTPの更新情報を作成
291+BOOL BuildUpdates(LPCTSTR PrivateKeyFile, LPCTSTR Password, LPCTSTR ServerPath, LPCTSTR HashFile, LPCTSTR ListFile, DWORD Version, LPCTSTR VersionString, LPCTSTR Description)
292+{
293+ BOOL bResult;
294+ char PrivateKey[4096];
295+ DWORD Length;
296+ TCHAR Name[MAX_PATH];
297+ TCHAR* p;
298+ UPDATE_LIST* pList;
299+ UPDATE_HASH Hash;
300+ BYTE Buf[1024];
301+ bResult = FALSE;
302+ memset(PrivateKey, 0, sizeof(PrivateKey));
303+ if(LoadMemoryFromFileWithTimestamp(PrivateKeyFile, &PrivateKey, sizeof(PrivateKey) - sizeof(char), &Length, NULL))
304+ {
305+ if(GetModuleFileName(NULL, Name, MAX_PATH) > 0)
306+ {
307+ if(p = _tcsrchr(Name, _T('\\')))
308+ *p = _T('\0');
309+ if(pList = (UPDATE_LIST*)malloc(1048576))
310+ {
311+ memset(pList, 0, 1048576);
312+ pList->Version = Version;
313+ _tcscpy(pList->VersionString, VersionString);
314+ _tcscpy(pList->Description, Description);
315+ ListUpdateFile(pList, (1048576 - sizeof(UPDATE_LIST)) / sizeof(UPDATE_LIST_FILE) + 1, ServerPath, Name, NULL);
316+ Length = (pList->FileCount - 1) * sizeof(UPDATE_LIST_FILE) + sizeof(UPDATE_LIST);
317+ if(SaveMemoryToFileWithTimestamp(ListFile, pList, Length, NULL))
318+ {
319+ memcpy(&Hash.Signature, UPDATE_SIGNATURE, 64);
320+ if(GetHashSHA512(pList, Length, &Hash.ListHash))
321+ {
322+ if(EncryptSignature(PrivateKey, Password, &Hash, sizeof(UPDATE_HASH), &Buf, sizeof(Buf), &Length))
323+ {
324+ if(SaveMemoryToFileWithTimestamp(HashFile, &Buf, Length, NULL))
325+ bResult = TRUE;
326+ }
327+ }
328+ }
329+ free(pList);
330+ }
331+ }
332+ }
333+ return bResult;
334+}
335+
161336 // FFFTPの更新情報を確認
162-BOOL CheckForUpdates(BOOL bDownload, LPCTSTR DownloadDir, DWORD* pVersion, LPTSTR pVersionString)
337+BOOL CheckForUpdates(BOOL bDownload, LPCTSTR DownloadDir, DWORD* pVersion, LPTSTR pVersionString, LPTSTR pDescription)
163338 {
164339 BOOL bResult;
165340 DWORD Length;
166- BYTE Buf1[65536];
341+ BYTE Buf1[1024];
167342 BYTE Buf2[1024];
343+ void* pBuf;
168344 UPDATE_HASH UpdateHash;
169345 BYTE Hash[64];
170346 UPDATE_LIST* pUpdateList;
171347 bResult = FALSE;
172348 if(ReadFileViaHTTP(&Buf1, sizeof(Buf1), &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_HASH_PATH))
173349 {
174- if(DecryptSignature(UPDATE_RSA_PUBLIC_KEY, &Buf1, Length, &Buf2, sizeof(Buf2), &Length))
350+ if(DecryptSignature(UPDATE_RSA_PUBLIC_KEY, NULL, &Buf1, Length, &Buf2, sizeof(Buf2), &Length))
175351 {
176352 if(Length == sizeof(UPDATE_HASH))
177353 {
178354 memcpy(&UpdateHash, &Buf2, sizeof(UPDATE_HASH));
179355 if(memcmp(&UpdateHash.Signature, UPDATE_SIGNATURE, 64) == 0)
180356 {
181- if(ReadFileViaHTTP(&Buf1, sizeof(Buf1), &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_LIST_PATH))
357+ if(pBuf = malloc(1048576))
182358 {
183- if(GetHashSHA512(&Buf1, Length, &Hash))
359+ if(ReadFileViaHTTP(pBuf, 1048576, &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_LIST_PATH))
184360 {
185- if(memcmp(&Hash, &UpdateHash.ListHash, 64) == 0)
361+ if(GetHashSHA512(pBuf, Length, &Hash))
186362 {
187- if(Length >= sizeof(UPDATE_LIST))
363+ if(memcmp(&Hash, &UpdateHash.ListHash, 64) == 0)
188364 {
189- bResult = TRUE;
190- pUpdateList = (UPDATE_LIST*)&Buf1;
191- if(pUpdateList->Version > *pVersion)
365+ if(Length >= sizeof(UPDATE_LIST))
192366 {
193- *pVersion = pUpdateList->Version;
194- _tcscpy(pVersionString, pUpdateList->VersionString);
367+ bResult = TRUE;
368+ pUpdateList = (UPDATE_LIST*)pBuf;
369+ if(pUpdateList->Version > *pVersion)
370+ {
371+ *pVersion = pUpdateList->Version;
372+ _tcscpy(pVersionString, pUpdateList->VersionString);
373+ _tcscpy(pDescription, pUpdateList->Description);
374+ }
375+ if(bDownload)
376+ bResult = PrepareUpdates(pBuf, Length, DownloadDir);
195377 }
196- if(bDownload)
197- bResult = PrepareUpdates(&Buf1, Length, DownloadDir);
198378 }
199379 }
200380 }
381+ free(pBuf);
201382 }
202383 }
203384 }
@@ -226,42 +407,42 @@ BOOL PrepareUpdates(void* pList, DWORD ListLength, LPCTSTR DownloadDir)
226407 bResult = TRUE;
227408 DeleteDirectoryAndContents(DownloadDir);
228409 CreateDirectory(DownloadDir, NULL);
229- pBuf = malloc(16777216);
230- for(i = 0; i < pUpdateList->FileCount; i++)
410+ if(pBuf = malloc(16777216))
231411 {
232- b = FALSE;
233- if(pUpdateList->File[i].Flags & UPDATE_LIST_FILE_FLAG_DIRECTORY)
412+ for(i = 0; i < pUpdateList->FileCount; i++)
234413 {
235- _tcscpy(Path, DownloadDir);
236- _tcscat(Path, _T("\\"));
237- _tcscat(Path, pUpdateList->File[i].DstPath);
238- if(CreateDirectory(Path, NULL))
239- b = TRUE;
240- }
241- if(strlen(pUpdateList->File[i].SrcPath) > 0)
242- {
243- if(ReadFileViaHTTP(pBuf, 16777216, &Length, HTTP_USER_AGENT, UPDATE_SERVER, pUpdateList->File[i].SrcPath))
414+ b = FALSE;
415+ if(pUpdateList->File[i].Flags & UPDATE_LIST_FILE_FLAG_DIRECTORY)
244416 {
245- if(GetHashSHA512(pBuf, Length, &Hash))
417+ _tcscpy(Path, DownloadDir);
418+ _tcscat(Path, pUpdateList->File[i].DstPath);
419+ if(CreateDirectory(Path, NULL))
420+ b = TRUE;
421+ }
422+ if(strlen(pUpdateList->File[i].SrcPath) > 0)
423+ {
424+ if(ReadFileViaHTTP(pBuf, 16777216, &Length, HTTP_USER_AGENT, UPDATE_SERVER, pUpdateList->File[i].SrcPath))
246425 {
247- if(memcmp(&Hash, &pUpdateList->File[i].SrcHash, 64) == 0)
426+ if(GetHashSHA512(pBuf, Length, &Hash))
248427 {
249- _tcscpy(Path, DownloadDir);
250- _tcscat(Path, _T("\\"));
251- _tcscat(Path, pUpdateList->File[i].DstPath);
252- if(SaveMemoryToFileWithTimestamp(Path, pBuf, Length, &pUpdateList->File[i].Timestamp))
253- b = TRUE;
428+ if(memcmp(&Hash, &pUpdateList->File[i].SrcHash, 64) == 0)
429+ {
430+ _tcscpy(Path, DownloadDir);
431+ _tcscat(Path, pUpdateList->File[i].DstPath);
432+ if(SaveMemoryToFileWithTimestamp(Path, pBuf, Length, &pUpdateList->File[i].Timestamp))
433+ b = TRUE;
434+ }
254435 }
255436 }
256437 }
438+ if(!b)
439+ {
440+ bResult = FALSE;
441+ break;
442+ }
257443 }
258- if(!b)
259- {
260- bResult = FALSE;
261- break;
262- }
444+ free(pBuf);
263445 }
264- free(pBuf);
265446 }
266447 }
267448 return bResult;
--- a/updater.h
+++ b/updater.h
@@ -33,7 +33,8 @@
3333 "-----END PUBLIC KEY-----\n"
3434 #define UPDATE_SIGNATURE "\x4C\x2A\x8E\x57\xAB\x75\x0C\xB5\xDA\x5F\xFE\xB9\x57\x9A\x1B\xA2\x7A\x61\x32\xF8\xFA\x4B\x61\xE2\xBA\x20\x9C\x37\xD5\x0A\xDC\x94\x10\x4D\x02\x30\x9B\xCD\x01\x9B\xB8\x73\x1E\xDB\xFD\xD7\x45\xCA\xE0\x8E\xF9\xB0\x1F\xB4\x0D\xD8\xFB\xE8\x41\x48\xE7\xF5\xE8\x64"
3535
36-BOOL CheckForUpdates(BOOL bDownload, LPCTSTR DownloadDir, DWORD* pVersion, LPTSTR pVersionString);
36+BOOL BuildUpdates(LPCTSTR PrivateKeyFile, LPCTSTR Password, LPCTSTR ServerPath, LPCTSTR HashFile, LPCTSTR ListFile, DWORD Version, LPCTSTR VersionString, LPCTSTR Description);
37+BOOL CheckForUpdates(BOOL bDownload, LPCTSTR DownloadDir, DWORD* pVersion, LPTSTR pVersionString, LPTSTR pDescription);
3738 BOOL PrepareUpdates(void* pList, DWORD ListLength, LPCTSTR DownloadDir);
3839 BOOL ApplyUpdates(LPCTSTR DestinationDir, LPCTSTR BackupDirName);
3940 BOOL CleanupUpdates(LPCTSTR DownloadDir);