diff options
Diffstat (limited to 'toolkit/mozapps/update/common/updateutils_win.cpp')
-rw-r--r-- | toolkit/mozapps/update/common/updateutils_win.cpp | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/toolkit/mozapps/update/common/updateutils_win.cpp b/toolkit/mozapps/update/common/updateutils_win.cpp new file mode 100644 index 0000000000..fc2554e569 --- /dev/null +++ b/toolkit/mozapps/update/common/updateutils_win.cpp @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "updateutils_win.h" +#include <errno.h> +#include <shlwapi.h> +#include <string.h> + +/** + * Note: The reason that these functions are separated from those in + * updatehelper.h/updatehelper.cpp is that those functions are strictly + * used within the updater, whereas changing functions in updateutils_win + * will have effects reaching beyond application update. + */ + +// This section implements the minimum set of dirent APIs used by updater.cpp on +// Windows. If updater.cpp is modified to use more of this API, we need to +// implement those parts here too. +static dirent gDirEnt; + +DIR::DIR(const WCHAR* path) : findHandle(INVALID_HANDLE_VALUE) { + memset(name, 0, sizeof(name)); + wcsncpy(name, path, sizeof(name) / sizeof(name[0])); + wcsncat(name, L"\\*", sizeof(name) / sizeof(name[0]) - wcslen(name) - 1); +} + +DIR::~DIR() { + if (findHandle != INVALID_HANDLE_VALUE) { + FindClose(findHandle); + } +} + +dirent::dirent() { d_name[0] = L'\0'; } + +DIR* opendir(const WCHAR* path) { return new DIR(path); } + +int closedir(DIR* dir) { + delete dir; + return 0; +} + +dirent* readdir(DIR* dir) { + WIN32_FIND_DATAW data; + if (dir->findHandle != INVALID_HANDLE_VALUE) { + BOOL result = FindNextFileW(dir->findHandle, &data); + if (!result) { + if (GetLastError() != ERROR_NO_MORE_FILES) { + errno = ENOENT; + } + return 0; + } + } else { + // Reading the first directory entry + dir->findHandle = FindFirstFileW(dir->name, &data); + if (dir->findHandle == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_FILE_NOT_FOUND) { + errno = ENOENT; + } else { + errno = EBADF; + } + return 0; + } + } + size_t direntBufferLength = + sizeof(gDirEnt.d_name) / sizeof(gDirEnt.d_name[0]); + wcsncpy(gDirEnt.d_name, data.cFileName, direntBufferLength); + // wcsncpy does not guarantee a null-terminated string if the source string is + // too long. + gDirEnt.d_name[direntBufferLength - 1] = '\0'; + return &gDirEnt; +} + +/** + * Joins a base directory path with a filename. + * + * @param base The base directory path of size MAX_PATH + 1 + * @param extra The filename to append + * @return TRUE if the file name was successful appended to base + */ +BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra) { + if (wcslen(base) + wcslen(extra) >= MAX_PATH) { + return FALSE; + } + + return PathAppendW(base, extra); +} + +/** + * Obtains a uuid as a wide string. + * + * @param outBuf + * A buffer of size MAX_PATH + 1 to store the result. + * @return TRUE if successful + */ +BOOL GetUUIDString(LPWSTR outBuf) { + UUID uuid; + RPC_WSTR uuidString = nullptr; + + // Note: the return value of UuidCreate should always be RPC_S_OK on systems + // after Win2K / Win2003 due to the network hardware address no longer being + // used to create the UUID. + if (UuidCreate(&uuid) != RPC_S_OK) { + return FALSE; + } + if (UuidToStringW(&uuid, &uuidString) != RPC_S_OK) { + return FALSE; + } + if (!uuidString) { + return FALSE; + } + + if (wcslen(reinterpret_cast<LPCWSTR>(uuidString)) > MAX_PATH) { + return FALSE; + } + wcsncpy(outBuf, reinterpret_cast<LPCWSTR>(uuidString), MAX_PATH + 1); + RpcStringFreeW(&uuidString); + + return TRUE; +} + +/** + * Build a temporary file path whose name component is a UUID. + * + * @param basePath The base directory path for the temp file + * @param prefix Optional prefix for the beginning of the file name + * @param tmpPath Output full path, with the base directory and the file + * name. Must already have been allocated with size >= MAX_PATH. + * @return TRUE if tmpPath was successfully filled in, FALSE on errors + */ +BOOL GetUUIDTempFilePath(LPCWSTR basePath, LPCWSTR prefix, LPWSTR tmpPath) { + WCHAR filename[MAX_PATH + 1] = {L"\0"}; + if (prefix) { + if (wcslen(prefix) > MAX_PATH) { + return FALSE; + } + wcsncpy(filename, prefix, MAX_PATH + 1); + } + + WCHAR tmpFileNameString[MAX_PATH + 1] = {L"\0"}; + if (!GetUUIDString(tmpFileNameString)) { + return FALSE; + } + + size_t tmpFileNameStringLen = wcslen(tmpFileNameString); + if (wcslen(filename) + tmpFileNameStringLen > MAX_PATH) { + return FALSE; + } + wcsncat(filename, tmpFileNameString, tmpFileNameStringLen); + + size_t basePathLen = wcslen(basePath); + if (basePathLen > MAX_PATH) { + return FALSE; + } + // Use basePathLen + 1 so wcsncpy will add null termination and if a caller + // doesn't allocate MAX_PATH + 1 for tmpPath this won't fail when there is + // actually enough space allocated. + wcsncpy(tmpPath, basePath, basePathLen + 1); + if (!PathAppendSafe(tmpPath, filename)) { + return FALSE; + } + + return TRUE; +} |