OSDN Git Service

Fix bugs of UPnP port mapping control.
[ffftp/ffftp.git] / updater.c
index 815996b..d60464d 100644 (file)
--- a/updater.c
+++ b/updater.c
@@ -1,6 +1,7 @@
 // updater.c\r
 // Copyright (C) 2014 Suguru Kawamoto\r
 // ソフトウェア自動更新\r
+// コードの再利用のため表記はwchar_t型だが実体はchar型でUTF-8\r
 \r
 #include <tchar.h>\r
 #include <ws2tcpip.h>\r
@@ -14,6 +15,7 @@ typedef SOCKADDR_STORAGE *PSOCKADDR_STORAGE, FAR *LPSOCKADDR_STORAGE;
 #include "socketwrapper.h"\r
 #include "protectprocess.h"\r
 #include "mbswrapper.h"\r
+#include "apiemulator.h"\r
 \r
 typedef struct\r
 {\r
@@ -21,7 +23,30 @@ typedef struct
        BYTE ListHash[64];\r
 } UPDATE_HASH;\r
 \r
-BOOL DownloadFileViaHTTP(void* pOut, DWORD Length, DWORD* pLength, LPCWSTR UserAgent, LPCWSTR ServerName, LPCWSTR ObjectName)\r
+#define UPDATE_LIST_FILE_FLAG_DIRECTORY 0x00000001\r
+\r
+typedef struct\r
+{\r
+       DWORD Flags;\r
+       CHAR SrcPath[128];\r
+       BYTE SrcHash[64];\r
+       CHAR DstPath[128];\r
+       FILETIME Timestamp;\r
+} UPDATE_LIST_FILE;\r
+\r
+typedef struct\r
+{\r
+       DWORD Version;\r
+       CHAR VersionString[32];\r
+       CHAR Description[1024];\r
+       DWORD FileCount;\r
+       UPDATE_LIST_FILE File[1];\r
+} UPDATE_LIST;\r
+\r
+#define UPDATE_MAX_LIST_SIZE 1048576\r
+#define UPDATE_MAX_FILE_SIZE 16777216\r
+\r
+BOOL ReadFileViaHTTPW(void* pOut, DWORD Length, DWORD* pLength, LPCWSTR UserAgent, LPCWSTR ServerName, LPCWSTR ObjectName)\r
 {\r
        BOOL bResult;\r
        HINTERNET hSession;\r
@@ -57,35 +82,307 @@ BOOL DownloadFileViaHTTP(void* pOut, DWORD Length, DWORD* pLength, LPCWSTR UserA
        return bResult;\r
 }\r
 \r
+BOOL ReadFileViaHTTP(void* pOut, DWORD Length, DWORD* pLength, LPCSTR UserAgent, LPCSTR ServerName, LPCSTR ObjectName)\r
+{\r
+       BOOL r;\r
+       wchar_t* pw0;\r
+       wchar_t* pw1;\r
+       wchar_t* pw2;\r
+       pw0 = DuplicateMtoW(UserAgent, -1);\r
+       pw1 = DuplicateMtoW(ServerName, -1);\r
+       pw2 = DuplicateMtoW(ObjectName, -1);\r
+       r = ReadFileViaHTTPW(pOut, Length, pLength, pw0, pw1, pw2);\r
+       FreeDuplicatedString(pw0);\r
+       FreeDuplicatedString(pw1);\r
+       FreeDuplicatedString(pw2);\r
+       return r;\r
+}\r
+\r
+BOOL SaveMemoryToFileWithTimestamp(LPCTSTR FileName, void* pData, DWORD Size, FILETIME* pTimestamp)\r
+{\r
+       BOOL bResult;\r
+       HANDLE hFile;\r
+       bResult = FALSE;\r
+       if((hFile = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)\r
+       {\r
+               if(WriteFile(hFile, pData, Size, &Size, NULL))\r
+               {\r
+                       if(pTimestamp)\r
+                       {\r
+                               if(SetFileTime(hFile, NULL, NULL, pTimestamp))\r
+                                       bResult = TRUE;\r
+                       }\r
+                       else\r
+                               bResult = TRUE;\r
+               }\r
+               CloseHandle(hFile);\r
+       }\r
+       return bResult;\r
+}\r
+\r
+BOOL LoadMemoryFromFileWithTimestamp(LPCTSTR FileName, void* pData, DWORD Size, DWORD* pReadSize, FILETIME* pTimestamp)\r
+{\r
+       BOOL bResult;\r
+       HANDLE hFile;\r
+       LARGE_INTEGER li;\r
+       bResult = FALSE;\r
+       if((hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)\r
+       {\r
+               if(GetFileSizeEx(hFile, &li))\r
+               {\r
+                       if(li.QuadPart <= (LONGLONG)Size)\r
+                       {\r
+                               if(ReadFile(hFile, pData, Size, pReadSize, NULL))\r
+                               {\r
+                                       if(*pReadSize == li.LowPart)\r
+                                       {\r
+                                               if(pTimestamp)\r
+                                               {\r
+                                                       if(GetFileTime(hFile, NULL, NULL, pTimestamp))\r
+                                                               bResult = TRUE;\r
+                                               }\r
+                                               else\r
+                                                       bResult = TRUE;\r
+                                       }\r
+                               }\r
+                       }\r
+                       CloseHandle(hFile);\r
+               }\r
+       }\r
+       return bResult;\r
+}\r
+\r
+BOOL CopyAllFilesInDirectory(LPCTSTR From, LPCTSTR To)\r
+{\r
+       BOOL bResult;\r
+       TCHAR* pFrom;\r
+       TCHAR* pTo;\r
+       SHFILEOPSTRUCT fop;\r
+       bResult = FALSE;\r
+       if(pFrom = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(From) + _tcslen(_T("\\*")) + 2)))\r
+       {\r
+               _tcscpy(pFrom, From);\r
+               _tcsncpy(pFrom + _tcslen(pFrom), _T("\\*"), _tcslen(_T("\\*")) + 2);\r
+               if(pTo = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(To) + 2)))\r
+               {\r
+                       _tcsncpy(pTo, To, _tcslen(To) + 2);\r
+                       memset(&fop, 0, sizeof(SHFILEOPSTRUCT));\r
+                       fop.wFunc = FO_COPY;\r
+                       fop.pFrom = pFrom;\r
+                       fop.pTo = pTo;\r
+                       fop.fFlags = FOF_NO_UI;\r
+                       if(SHFileOperation(&fop) == 0)\r
+                               bResult = TRUE;\r
+                       free(pTo);\r
+               }\r
+               free(pFrom);\r
+       }\r
+       return bResult;\r
+}\r
+\r
+BOOL DeleteDirectoryAndContents(LPCTSTR Path)\r
+{\r
+       BOOL bResult;\r
+       TCHAR* pFrom;\r
+       SHFILEOPSTRUCT fop;\r
+       bResult = FALSE;\r
+       if(pFrom = (TCHAR*)malloc(sizeof(TCHAR) * (_tcslen(Path) + 2)))\r
+       {\r
+               _tcsncpy(pFrom, Path, _tcslen(Path) + 2);\r
+               memset(&fop, 0, sizeof(SHFILEOPSTRUCT));\r
+               fop.wFunc = FO_DELETE;\r
+               fop.pFrom = pFrom;\r
+               fop.fFlags = FOF_NO_UI;\r
+               if(SHFileOperation(&fop) == 0)\r
+                       bResult = TRUE;\r
+               free(pFrom);\r
+       }\r
+       return bResult;\r
+}\r
+\r
+DWORD ListUpdateFile(UPDATE_LIST* pList, DWORD MaxCount, LPCTSTR ServerPath, LPCTSTR ReferenceDir, LPCTSTR Path)\r
+{\r
+       DWORD Result;\r
+       TCHAR Temp1[MAX_PATH];\r
+       TCHAR Temp2[MAX_PATH];\r
+       TCHAR Temp3[MAX_PATH];\r
+       HANDLE hFind;\r
+       WIN32_FIND_DATA Find;\r
+       void* pBuf;\r
+       DWORD Length;\r
+       FILETIME Time;\r
+       BYTE Hash[64];\r
+       Result = 0;\r
+       if(!Path)\r
+               Path = _T("");\r
+       if(_tcslen(ReferenceDir) + _tcslen(Path) + _tcslen(_T("\\*")) < MAX_PATH)\r
+       {\r
+               _tcscpy(Temp1, ReferenceDir);\r
+               _tcscat(Temp1, Path);\r
+               _tcscat(Temp1, _T("\\*"));\r
+               if((hFind = FindFirstFile(Temp1, &Find)) != INVALID_HANDLE_VALUE)\r
+               {\r
+                       do\r
+                       {\r
+                               if(_tcscmp(Find.cFileName, _T(".")) != 0 && _tcscmp(Find.cFileName, _T("..")) != 0)\r
+                               {\r
+                                       if(_tcslen(ServerPath) + _tcslen(_T("/")) + _tcslen(Find.cFileName) < 128 && _tcslen(Path) + _tcslen(_T("\\")) + _tcslen(Find.cFileName) < 128)\r
+                                       {\r
+                                               _tcscpy(Temp1, ServerPath);\r
+                                               _tcscat(Temp1, _T("/"));\r
+                                               _tcscat(Temp1, Find.cFileName);\r
+                                               _tcscpy(Temp2, Path);\r
+                                               _tcscat(Temp2, _T("\\"));\r
+                                               _tcscat(Temp2, Find.cFileName);\r
+                                               if(_tcslen(ReferenceDir) + _tcslen(Temp2) < MAX_PATH)\r
+                                               {\r
+                                                       _tcscpy(Temp3, ReferenceDir);\r
+                                                       _tcscat(Temp3, Temp2);\r
+                                                       if((Find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\r
+                                                       {\r
+                                                               if(!(Find.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))\r
+                                                               {\r
+                                                                       if(pList)\r
+                                                                       {\r
+                                                                               memset(&pList->File[pList->FileCount], 0, sizeof(UPDATE_LIST_FILE));\r
+                                                                               pList->File[pList->FileCount].Flags = UPDATE_LIST_FILE_FLAG_DIRECTORY;\r
+                                                                               _tcscpy(pList->File[pList->FileCount].DstPath, Temp2);\r
+                                                                               pList->FileCount++;\r
+                                                                       }\r
+                                                                       Result++;\r
+                                                                       if(Result >= MaxCount)\r
+                                                                               break;\r
+                                                                       Result += ListUpdateFile(pList, MaxCount, Temp1, ReferenceDir, Temp2);\r
+                                                               }\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               if(pList)\r
+                                                               {\r
+                                                                       if(pBuf = malloc(UPDATE_MAX_FILE_SIZE))\r
+                                                                       {\r
+                                                                               if(LoadMemoryFromFileWithTimestamp(Temp3, pBuf, UPDATE_MAX_FILE_SIZE, &Length, &Time))\r
+                                                                               {\r
+                                                                                       if(GetHashSHA512(pBuf, Length, &Hash))\r
+                                                                                       {\r
+                                                                                               memset(&pList->File[pList->FileCount], 0, sizeof(UPDATE_LIST_FILE));\r
+                                                                                               _tcscpy(pList->File[pList->FileCount].SrcPath, Temp1);\r
+                                                                                               memcpy(&pList->File[pList->FileCount].SrcHash, &Hash, 64);\r
+                                                                                               _tcscpy(pList->File[pList->FileCount].DstPath, Temp2);\r
+                                                                                               pList->File[pList->FileCount].Timestamp = Time;\r
+                                                                                               pList->FileCount++;\r
+                                                                                       }\r
+                                                                               }\r
+                                                                               free(pBuf);\r
+                                                                       }\r
+                                                               }\r
+                                                               Result++;\r
+                                                               if(Result >= MaxCount)\r
+                                                                       break;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       while(FindNextFile(hFind, &Find));\r
+                       FindClose(hFind);\r
+               }\r
+       }\r
+       return Result;\r
+}\r
+\r
+// FFFTPの更新情報を作成\r
+BOOL BuildUpdates(LPCTSTR PrivateKeyFile, LPCTSTR Password, LPCTSTR ServerPath, LPCTSTR HashFile, LPCTSTR ListFile, DWORD Version, LPCTSTR VersionString, LPCTSTR Description)\r
+{\r
+       BOOL bResult;\r
+       char PrivateKey[4096];\r
+       DWORD Length;\r
+       TCHAR Name[MAX_PATH];\r
+       TCHAR* p;\r
+       UPDATE_LIST* pList;\r
+       UPDATE_HASH Hash;\r
+       BYTE Buf[1024];\r
+       bResult = FALSE;\r
+       memset(PrivateKey, 0, sizeof(PrivateKey));\r
+       if(LoadMemoryFromFileWithTimestamp(PrivateKeyFile, &PrivateKey, sizeof(PrivateKey) - sizeof(char), &Length, NULL))\r
+       {\r
+               if(GetModuleFileName(NULL, Name, MAX_PATH) > 0)\r
+               {\r
+                       if(p = _tcsrchr(Name, _T('\\')))\r
+                               *p = _T('\0');\r
+                       if(pList = (UPDATE_LIST*)malloc(UPDATE_MAX_LIST_SIZE))\r
+                       {\r
+                               memset(pList, 0, UPDATE_MAX_LIST_SIZE);\r
+                               pList->Version = Version;\r
+                               _tcscpy(pList->VersionString, VersionString);\r
+                               _tcscpy(pList->Description, Description);\r
+                               ListUpdateFile(pList, (UPDATE_MAX_LIST_SIZE - sizeof(UPDATE_LIST)) / sizeof(UPDATE_LIST_FILE) + 1, ServerPath, Name, NULL);\r
+                               Length = (pList->FileCount - 1) * sizeof(UPDATE_LIST_FILE) + sizeof(UPDATE_LIST);\r
+                               if(SaveMemoryToFileWithTimestamp(ListFile, pList, Length, NULL))\r
+                               {\r
+                                       memcpy(&Hash.Signature, UPDATE_SIGNATURE, 64);\r
+                                       if(GetHashSHA512(pList, Length, &Hash.ListHash))\r
+                                       {\r
+                                               if(EncryptSignature(PrivateKey, Password, &Hash, sizeof(UPDATE_HASH), &Buf, sizeof(Buf), &Length))\r
+                                               {\r
+                                                       if(SaveMemoryToFileWithTimestamp(HashFile, &Buf, Length, NULL))\r
+                                                               bResult = TRUE;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               free(pList);\r
+                       }\r
+               }\r
+       }\r
+       return bResult;\r
+}\r
+\r
 // FFFTPの更新情報を確認\r
-BOOL CheckForUpdates(BOOL bDownload, LPCTSTR DownloadDir)\r
+BOOL CheckForUpdates(BOOL bDownload, LPCTSTR DownloadDir, DWORD* pVersion, LPTSTR pVersionString, LPTSTR pDescription)\r
 {\r
        BOOL bResult;\r
        DWORD Length;\r
-       BYTE Buf1[4096];\r
+       BYTE Buf1[1024];\r
        BYTE Buf2[1024];\r
+       void* pBuf;\r
        UPDATE_HASH UpdateHash;\r
        BYTE Hash[64];\r
+       UPDATE_LIST* pUpdateList;\r
        bResult = FALSE;\r
-       if(DownloadFileViaHTTP(&Buf1, sizeof(Buf1), &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_HASH_PATH))\r
+       if(ReadFileViaHTTP(&Buf1, sizeof(Buf1), &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_HASH_PATH))\r
        {\r
-               if(DecryptSignature(UPDATE_RSA_PUBLIC_KEY, &Buf1, Length, &Buf2, sizeof(Buf2), &Length))\r
+               if(DecryptSignature(UPDATE_RSA_PUBLIC_KEY, NULL, &Buf1, Length, &Buf2, sizeof(Buf2), &Length))\r
                {\r
                        if(Length == sizeof(UPDATE_HASH))\r
                        {\r
                                memcpy(&UpdateHash, &Buf2, sizeof(UPDATE_HASH));\r
                                if(memcmp(&UpdateHash.Signature, UPDATE_SIGNATURE, 64) == 0)\r
                                {\r
-                                       if(DownloadFileViaHTTP(&Buf1, sizeof(Buf1), &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_LIST_PATH))\r
+                                       if(pBuf = malloc(UPDATE_MAX_LIST_SIZE))\r
                                        {\r
-                                               GetHashSHA512(&Buf1, Length, &Hash);\r
-                                               if(memcmp(&Hash, &UpdateHash.ListHash, 64) == 0)\r
+                                               if(ReadFileViaHTTP(pBuf, UPDATE_MAX_LIST_SIZE, &Length, HTTP_USER_AGENT, UPDATE_SERVER, UPDATE_LIST_PATH))\r
                                                {\r
-                                                       // TODO: 更新情報を解析\r
-                                                       bResult = TRUE;\r
-                                                       if(bDownload)\r
-                                                               bResult = PrepareUpdates(&Buf1, Length, DownloadDir);\r
+                                                       if(GetHashSHA512(pBuf, Length, &Hash))\r
+                                                       {\r
+                                                               if(memcmp(&Hash, &UpdateHash.ListHash, 64) == 0)\r
+                                                               {\r
+                                                                       if(Length >= sizeof(UPDATE_LIST))\r
+                                                                       {\r
+                                                                               bResult = TRUE;\r
+                                                                               pUpdateList = (UPDATE_LIST*)pBuf;\r
+                                                                               if(pUpdateList->Version > *pVersion)\r
+                                                                               {\r
+                                                                                       *pVersion = pUpdateList->Version;\r
+                                                                                       _tcscpy(pVersionString, pUpdateList->VersionString);\r
+                                                                                       _tcscpy(pDescription, pUpdateList->Description);\r
+                                                                               }\r
+                                                                               if(bDownload)\r
+                                                                                       bResult = PrepareUpdates(pBuf, Length, DownloadDir);\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
                                                }\r
+                                               free(pBuf);\r
                                        }\r
                                }\r
                        }\r
@@ -98,34 +395,161 @@ BOOL CheckForUpdates(BOOL bDownload, LPCTSTR DownloadDir)
 BOOL PrepareUpdates(void* pList, DWORD ListLength, LPCTSTR DownloadDir)\r
 {\r
        BOOL bResult;\r
+       UPDATE_LIST* pUpdateList;\r
+       void* pBuf;\r
+       TCHAR LocalDir[MAX_PATH];\r
+       TCHAR* p;\r
+       DWORD i;\r
+       BOOL b;\r
+       TCHAR Path[MAX_PATH];\r
+       DWORD Length;\r
+       BYTE Hash[64];\r
        bResult = FALSE;\r
-       // TODO: 更新情報を解析\r
-       // TODO: 更新するファイルをダウンロード\r
+       if(ListLength >= sizeof(UPDATE_LIST))\r
+       {\r
+               pUpdateList = (UPDATE_LIST*)pList;\r
+               if((pUpdateList->FileCount - 1) * sizeof(UPDATE_LIST_FILE) + sizeof(UPDATE_LIST) >= ListLength)\r
+               {\r
+                       bResult = TRUE;\r
+                       DeleteDirectoryAndContents(DownloadDir);\r
+                       CreateDirectory(DownloadDir, NULL);\r
+                       if(pBuf = malloc(UPDATE_MAX_FILE_SIZE))\r
+                       {\r
+                               if(GetModuleFileName(NULL, LocalDir, MAX_PATH) > 0)\r
+                               {\r
+                                       if(p = _tcsrchr(LocalDir, _T('\\')))\r
+                                               *p = _T('\0');\r
+                               }\r
+                               else\r
+                                       _tcscpy(LocalDir, _T("."));\r
+                               for(i = 0; i < pUpdateList->FileCount; i++)\r
+                               {\r
+                                       b = FALSE;\r
+                                       if(pUpdateList->File[i].Flags & UPDATE_LIST_FILE_FLAG_DIRECTORY)\r
+                                       {\r
+                                               _tcscpy(Path, DownloadDir);\r
+                                               _tcscat(Path, pUpdateList->File[i].DstPath);\r
+                                               if(CreateDirectory(Path, NULL))\r
+                                                       b = TRUE;\r
+                                       }\r
+                                       if(strlen(pUpdateList->File[i].SrcPath) > 0)\r
+                                       {\r
+                                               _tcscpy(Path, LocalDir);\r
+                                               _tcscat(Path, pUpdateList->File[i].DstPath);\r
+                                               if(LoadMemoryFromFileWithTimestamp(Path, pBuf, UPDATE_MAX_FILE_SIZE, &Length, NULL))\r
+                                               {\r
+                                                       if(GetHashSHA512(pBuf, Length, &Hash))\r
+                                                       {\r
+                                                               if(memcmp(&Hash, &pUpdateList->File[i].SrcHash, 64) == 0)\r
+                                                                       b = TRUE;\r
+                                                       }\r
+                                               }\r
+                                               if(!b)\r
+                                               {\r
+                                                       if(ReadFileViaHTTP(pBuf, UPDATE_MAX_FILE_SIZE, &Length, HTTP_USER_AGENT, UPDATE_SERVER, pUpdateList->File[i].SrcPath))\r
+                                                       {\r
+                                                               if(GetHashSHA512(pBuf, Length, &Hash))\r
+                                                               {\r
+                                                                       if(memcmp(&Hash, &pUpdateList->File[i].SrcHash, 64) == 0)\r
+                                                                       {\r
+                                                                               _tcscpy(Path, DownloadDir);\r
+                                                                               _tcscat(Path, pUpdateList->File[i].DstPath);\r
+                                                                               if(SaveMemoryToFileWithTimestamp(Path, pBuf, Length, &pUpdateList->File[i].Timestamp))\r
+                                                                                       b = TRUE;\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       if(!b)\r
+                                       {\r
+                                               bResult = FALSE;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               free(pBuf);\r
+                       }\r
+               }\r
+       }\r
        return bResult;\r
 }\r
 \r
 // FFFTPを更新\r
-BOOL ApplyUpdates(LPCTSTR DestinationDir)\r
+BOOL ApplyUpdates(LPCTSTR DestinationDir, LPCTSTR BackupDirName)\r
 {\r
        BOOL bResult;\r
+       TCHAR Source[MAX_PATH];\r
+       TCHAR Backup[MAX_PATH];\r
+       TCHAR DestinationBackup[MAX_PATH];\r
+       TCHAR* p;\r
        bResult = FALSE;\r
-       // TODO:\r
+       if(GetModuleFileName(NULL, Source, MAX_PATH) > 0)\r
+       {\r
+               if(p = _tcsrchr(Source, _T('\\')))\r
+                       *p = _T('\0');\r
+               _tcscpy(Backup, Source);\r
+               _tcscat(Backup, _T("\\"));\r
+               _tcscat(Backup, BackupDirName);\r
+               DeleteDirectoryAndContents(Backup);\r
+               if(CreateDirectory(Backup, NULL))\r
+               {\r
+                       if(CopyAllFilesInDirectory(DestinationDir, Backup))\r
+                       {\r
+                               _tcscpy(DestinationBackup, DestinationDir);\r
+                               _tcscat(DestinationBackup, _T("\\"));\r
+                               _tcscat(DestinationBackup, BackupDirName);\r
+                               if(CopyAllFilesInDirectory(Source, DestinationDir))\r
+                               {\r
+                                       DeleteDirectoryAndContents(DestinationBackup);\r
+                                       bResult = TRUE;\r
+                               }\r
+                               else\r
+                               {\r
+                                       DeleteDirectoryAndContents(DestinationBackup);\r
+                                       CopyAllFilesInDirectory(Backup, DestinationDir);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
        return bResult;\r
 }\r
 \r
-// 更新用のプロセスを起動\r
-BOOL StartUpdateProcess(LPCTSTR Path, LPCTSTR CommandLine)\r
+// 更新するファイルをダウンロード\r
+BOOL CleanupUpdates(LPCTSTR DownloadDir)\r
 {\r
        BOOL bResult;\r
        bResult = FALSE;\r
-       if(ShellExecute(NULL, "open", Path, CommandLine, NULL, SW_SHOW) > (HINSTANCE)32)\r
+       if(DeleteDirectoryAndContents(DownloadDir))\r
                bResult = TRUE;\r
        return bResult;\r
 }\r
 \r
+// 更新用のプロセスを起動\r
+BOOL StartUpdateProcess(LPCTSTR DownloadDir, LPCTSTR CommandLine)\r
+{\r
+       BOOL bResult;\r
+       TCHAR Name[MAX_PATH];\r
+       TCHAR* p;\r
+       TCHAR Path[MAX_PATH];\r
+       bResult = FALSE;\r
+       if(GetModuleFileName(NULL, Name, MAX_PATH) > 0)\r
+       {\r
+               if(p = _tcsrchr(Name, _T('\\')))\r
+                       p++;\r
+               else\r
+                       p = Name;\r
+               _tcscpy(Path, DownloadDir);\r
+               _tcscat(Path, _T("\\"));\r
+               _tcscat(Path, p);\r
+               if(ShellExecute(NULL, _T("open"), Path, CommandLine, NULL, SW_SHOW) > (HINSTANCE)32)\r
+                       bResult = TRUE;\r
+       }\r
+       return bResult;\r
+}\r
+\r
 // 更新用のプロセスを管理者権限で起動\r
 // Windows XP以前など起動できない場合は現在のプロセスで処理を続行\r
-BOOL StartUpdateProcessAsAdministrator(LPCTSTR CommandLine, LPCTSTR Keyword)\r
+BOOL RestartUpdateProcessAsAdministrator(LPCTSTR CommandLine, LPCTSTR Keyword)\r
 {\r
        BOOL bResult;\r
        TCHAR* NewCommandLine;\r
@@ -138,19 +562,24 @@ BOOL StartUpdateProcessAsAdministrator(LPCTSTR CommandLine, LPCTSTR Keyword)
                {\r
                        _tcscpy(NewCommandLine, CommandLine);\r
                        _tcscat(NewCommandLine, Keyword);\r
-                       GetModuleFileName(NULL, Path, MAX_PATH);\r
-                       memset(&Info, 0, sizeof(SHELLEXECUTEINFO));\r
-                       Info.cbSize = sizeof(SHELLEXECUTEINFO);\r
-                       Info.fMask = SEE_MASK_NOCLOSEPROCESS;\r
-                       Info.lpVerb = "runas";\r
-                       Info.lpFile = Path;\r
-                       Info.lpParameters = NewCommandLine;\r
-                       Info.nShow = SW_SHOW;\r
-                       if(ShellExecuteEx(&Info))\r
+                       if(GetModuleFileName(NULL, Path, MAX_PATH) > 0)\r
                        {\r
-                               WaitForSingleObject(Info.hProcess, INFINITE);\r
-                               CloseHandle(Info.hProcess);\r
-                               bResult = TRUE;\r
+                               memset(&Info, 0, sizeof(SHELLEXECUTEINFO));\r
+                               Info.cbSize = sizeof(SHELLEXECUTEINFO);\r
+                               Info.fMask = SEE_MASK_NOCLOSEPROCESS;\r
+                               if(IsUserAnAdmin())\r
+                                       Info.lpVerb = _T("open");\r
+                               else\r
+                                       Info.lpVerb = _T("runas");\r
+                               Info.lpFile = Path;\r
+                               Info.lpParameters = NewCommandLine;\r
+                               Info.nShow = SW_SHOW;\r
+                               if(ShellExecuteEx(&Info))\r
+                               {\r
+                                       WaitForSingleObject(Info.hProcess, INFINITE);\r
+                                       CloseHandle(Info.hProcess);\r
+                                       bResult = TRUE;\r
+                               }\r
                        }\r
                        free(NewCommandLine);\r
                }\r