| Index: runtime/bin/directory_win.cc
|
| diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
|
| index 9d8f6f31935d30691c4344acc8354d300dfef835..24d98f70eaf18e54b5caec609cf54ef518a28570 100644
|
| --- a/runtime/bin/directory_win.cc
|
| +++ b/runtime/bin/directory_win.cc
|
| @@ -9,51 +9,78 @@
|
|
|
| #include "bin/log.h"
|
|
|
| -// Forward declaration.
|
| +class PathBuffer {
|
| + public:
|
| + PathBuffer() : length(0) { }
|
| +
|
| + wchar_t data[MAX_PATH + 1];
|
| + int length;
|
| +
|
| + bool Add(const wchar_t* name) {
|
| + size_t written = _snwprintf(data + length,
|
| + MAX_PATH - length,
|
| + L"%s",
|
| + name);
|
| + data[MAX_PATH] = L'\0';
|
| + if (written == wcsnlen(name, MAX_PATH + 1)) {
|
| + length += written;
|
| + return true;
|
| + } else {
|
| + SetLastError(ERROR_BUFFER_OVERFLOW);
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + void Reset(int new_length) {
|
| + length = new_length;
|
| + data[length] = L'\0';
|
| + }
|
| +};
|
| +
|
| +
|
| +// Forward declarations.
|
| static bool ListRecursively(const wchar_t* dir_name,
|
| bool recursive,
|
| DirectoryListing* listing);
|
| static bool DeleteRecursively(const wchar_t* dir_name);
|
|
|
|
|
| +static void PostError(DirectoryListing* listing,
|
| + const wchar_t* dir_name) {
|
| + const char* utf8_path = StringUtils::WideToUtf8(dir_name);
|
| + listing->HandleError(utf8_path);
|
| + free(const_cast<char*>(utf8_path));
|
| +}
|
| +
|
| +
|
| static bool HandleDir(wchar_t* dir_name,
|
| - wchar_t* path,
|
| - int path_length,
|
| + PathBuffer* path,
|
| bool recursive,
|
| DirectoryListing* listing) {
|
| - if (wcscmp(dir_name, L".") != 0 &&
|
| - wcscmp(dir_name, L"..") != 0) {
|
| - size_t written = _snwprintf(path + path_length,
|
| - MAX_PATH - path_length,
|
| - L"%s",
|
| - dir_name);
|
| - if (written != wcslen(dir_name)) {
|
| - return false;
|
| - }
|
| - char* utf8_path = StringUtils::WideToUtf8(path);
|
| - bool ok = listing->HandleDirectory(utf8_path);
|
| - free(utf8_path);
|
| - if (!ok) return ok;
|
| - if (recursive) {
|
| - return ListRecursively(path, recursive, listing);
|
| - }
|
| + if (wcscmp(dir_name, L".") == 0) return true;
|
| + if (wcscmp(dir_name, L"..") == 0) return true;
|
| + if (!path->Add(dir_name)) {
|
| + PostError(listing, path->data);
|
| + return false;
|
| + }
|
| + char* utf8_path = StringUtils::WideToUtf8(path->data);
|
| + bool ok = listing->HandleDirectory(utf8_path);
|
| + free(utf8_path);
|
| + if (!ok) return ok;
|
| + if (recursive) {
|
| + return ListRecursively(path->data, recursive, listing);
|
| }
|
| - return true;
|
| }
|
|
|
|
|
| static bool HandleFile(wchar_t* file_name,
|
| - wchar_t* path,
|
| - int path_length,
|
| + PathBuffer* path,
|
| DirectoryListing* listing) {
|
| - size_t written = _snwprintf(path + path_length,
|
| - MAX_PATH - path_length,
|
| - L"%s",
|
| - file_name);
|
| - if (written != wcslen(file_name)) {
|
| + if (!path->Add(file_name)) {
|
| + PostError(listing, path->data);
|
| return false;
|
| - };
|
| - char* utf8_path = StringUtils::WideToUtf8(path);
|
| + }
|
| + char* utf8_path = StringUtils::WideToUtf8(path->data);
|
| bool ok = listing->HandleFile(utf8_path);
|
| free(utf8_path);
|
| return ok;
|
| @@ -61,55 +88,42 @@ static bool HandleFile(wchar_t* file_name,
|
|
|
|
|
| static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data,
|
| - wchar_t* path,
|
| - int path_length,
|
| + PathBuffer* path,
|
| bool recursive,
|
| DirectoryListing* listing) {
|
| DWORD attributes = find_file_data->dwFileAttributes;
|
| if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
|
| return HandleDir(find_file_data->cFileName,
|
| path,
|
| - path_length,
|
| recursive,
|
| listing);
|
| } else {
|
| - return HandleFile(find_file_data->cFileName, path, path_length, listing);
|
| + return HandleFile(find_file_data->cFileName, path, listing);
|
| }
|
| }
|
|
|
|
|
| -// ComputeFullSearchPath must be called with a path array of size at
|
| -// least MAX_PATH.
|
| -static bool ComputeFullSearchPath(const wchar_t* dir_name,
|
| - wchar_t* path,
|
| - int* path_length) {
|
| +static PathBuffer* ComputeFullSearchPath(const wchar_t* dir_name) {
|
| // GetFullPathName only works in a multi-threaded environment if
|
| // SetCurrentDirectory is not used. We currently have no plan for
|
| // exposing SetCurrentDirectory.
|
| - size_t written = GetFullPathNameW(dir_name, MAX_PATH, path, NULL);
|
| + PathBuffer* path = new PathBuffer();
|
| +
|
| + size_t written = GetFullPathNameW(dir_name, MAX_PATH + 1, path->data, NULL);
|
| // GetFullPathName only accepts input strings of size less than
|
| // MAX_PATH and returns 0 to indicate failure for paths longer than
|
| // that. Therefore the path buffer is always big enough.
|
| if (written == 0 || written > MAX_PATH) {
|
| - return false;
|
| + delete path;
|
| + return NULL;
|
| }
|
| - *path_length = written;
|
| - written = _snwprintf(path + *path_length,
|
| - MAX_PATH - *path_length,
|
| - L"%s",
|
| - L"\\*");
|
| - if (written != 2) {
|
| - return false;
|
| + path->length = written;
|
| + if (path->Add(L"\\*")) {
|
| + return path;
|
| + } else {
|
| + delete path;
|
| + return NULL;
|
| }
|
| - *path_length += written;
|
| - return true;
|
| -}
|
| -
|
| -static void PostError(DirectoryListing* listing,
|
| - const wchar_t* dir_name) {
|
| - const char* utf8_path = StringUtils::WideToUtf8(dir_name);
|
| - listing->HandleError(utf8_path);
|
| - free(const_cast<char*>(utf8_path));
|
| }
|
|
|
|
|
| @@ -121,38 +135,35 @@ static bool ListRecursively(const wchar_t* dir_name,
|
| // recursive traversal. path_length does not always equal
|
| // strlen(path) but indicates the current prefix of path that is the
|
| // path of the current directory in the traversal.
|
| - wchar_t* path = static_cast<wchar_t*>(malloc(MAX_PATH * sizeof(wchar_t)));
|
| - int path_length = 0;
|
| - bool valid = ComputeFullSearchPath(dir_name, path, &path_length);
|
| - if (!valid) {
|
| + PathBuffer* path = ComputeFullSearchPath(dir_name);
|
| + if (path == NULL) {
|
| PostError(listing, dir_name);
|
| - free(path);
|
| + delete path;
|
| return false;
|
| }
|
|
|
| WIN32_FIND_DATAW find_file_data;
|
| - HANDLE find_handle = FindFirstFileW(path, &find_file_data);
|
| + HANDLE find_handle = FindFirstFileW(path->data, &find_file_data);
|
|
|
| // Adjust the path by removing the '*' used for the search.
|
| - path_length -= 1;
|
| - path[path_length] = '\0';
|
| + path->Reset(path->length - 1);
|
|
|
| if (find_handle == INVALID_HANDLE_VALUE) {
|
| - PostError(listing, path);
|
| - free(path);
|
| + PostError(listing, path->data);
|
| + delete path;
|
| return false;
|
| }
|
|
|
| + int path_length = path->length;
|
| bool success = HandleEntry(&find_file_data,
|
| path,
|
| - path_length,
|
| recursive,
|
| listing);
|
|
|
| while ((FindNextFileW(find_handle, &find_file_data) != 0)) {
|
| + path->Reset(path_length); // HandleEntry adds the entry name to path.
|
| success = HandleEntry(&find_file_data,
|
| path,
|
| - path_length,
|
| recursive,
|
| listing) && success;
|
| }
|
| @@ -166,24 +177,16 @@ static bool ListRecursively(const wchar_t* dir_name,
|
| success = false;
|
| PostError(listing, dir_name);
|
| }
|
| - free(path);
|
| + delete path;
|
|
|
| return success;
|
| }
|
|
|
|
|
| -static bool DeleteFile(wchar_t* file_name,
|
| - wchar_t* path,
|
| - int path_length) {
|
| - size_t written = _snwprintf(path + path_length,
|
| - MAX_PATH - path_length,
|
| - L"%s",
|
| - file_name);
|
| - if (written != wcslen(file_name)) {
|
| - return false;
|
| - }
|
| +static bool DeleteFile(wchar_t* file_name, PathBuffer* path) {
|
| + if (!path->Add(file_name)) return false;
|
|
|
| - if (DeleteFileW(path) != 0) {
|
| + if (DeleteFileW(path->data) != 0) {
|
| return true;
|
| }
|
|
|
| @@ -191,7 +194,7 @@ static bool DeleteFile(wchar_t* file_name,
|
| // again. This mirrors Linux/Mac where a directory containing read-only files
|
| // can still be recursively deleted.
|
| if (GetLastError() == ERROR_ACCESS_DENIED) {
|
| - DWORD attributes = GetFileAttributesW(path);
|
| + DWORD attributes = GetFileAttributesW(path->data);
|
| if (attributes == INVALID_FILE_ATTRIBUTES) {
|
| return false;
|
| }
|
| @@ -199,11 +202,11 @@ static bool DeleteFile(wchar_t* file_name,
|
| if ((attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) {
|
| attributes &= ~FILE_ATTRIBUTE_READONLY;
|
|
|
| - if (SetFileAttributesW(path, attributes) == 0) {
|
| + if (SetFileAttributesW(path->data, attributes) == 0) {
|
| return false;
|
| }
|
|
|
| - return DeleteFileW(path) != 0;
|
| + return DeleteFileW(path->data) != 0;
|
| }
|
| }
|
|
|
| @@ -211,33 +214,20 @@ static bool DeleteFile(wchar_t* file_name,
|
| }
|
|
|
|
|
| -static bool DeleteDir(wchar_t* dir_name,
|
| - wchar_t* path,
|
| - int path_length) {
|
| - if (wcscmp(dir_name, L".") != 0 &&
|
| - wcscmp(dir_name, L"..") != 0) {
|
| - size_t written = _snwprintf(path + path_length,
|
| - MAX_PATH - path_length,
|
| - L"%s",
|
| - dir_name);
|
| - if (written != wcslen(dir_name)) {
|
| - return false;
|
| - }
|
| - return DeleteRecursively(path);
|
| - }
|
| - return true;
|
| +static bool DeleteDir(wchar_t* dir_name, PathBuffer* path) {
|
| + if (wcscmp(dir_name, L".") == 0) return true;
|
| + if (wcscmp(dir_name, L"..") == 0) return true;
|
| + return path->Add(dir_name) && DeleteRecursively(path->data);
|
| }
|
|
|
|
|
| -static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data,
|
| - wchar_t* path,
|
| - int path_length) {
|
| +static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data, PathBuffer* path) {
|
| DWORD attributes = find_file_data->dwFileAttributes;
|
|
|
| if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
|
| - return DeleteDir(find_file_data->cFileName, path, path_length);
|
| + return DeleteDir(find_file_data->cFileName, path);
|
| } else {
|
| - return DeleteFile(find_file_data->cFileName, path, path_length);
|
| + return DeleteFile(find_file_data->cFileName, path);
|
| }
|
| }
|
|
|
| @@ -257,33 +247,29 @@ static bool DeleteRecursively(const wchar_t* dir_name) {
|
| // recursive traversal. path_length does not always equal
|
| // strlen(path) but indicates the current prefix of path that is the
|
| // path of the current directory in the traversal.
|
| - wchar_t* path = static_cast<wchar_t*>(malloc(MAX_PATH * sizeof(wchar_t)));
|
| - int path_length = 0;
|
| - bool valid = ComputeFullSearchPath(dir_name, path, &path_length);
|
| - if (!valid) {
|
| - free(path);
|
| - return false;
|
| - }
|
| + PathBuffer* path = ComputeFullSearchPath(dir_name);
|
| + if (path == NULL) return false;
|
|
|
| WIN32_FIND_DATAW find_file_data;
|
| - HANDLE find_handle = FindFirstFileW(path, &find_file_data);
|
| + HANDLE find_handle = FindFirstFileW(path->data, &find_file_data);
|
|
|
| // Adjust the path by removing the '*' used for the search.
|
| - path_length -= 1;
|
| - path[path_length] = '\0';
|
| + int path_length = path->length - 1;
|
| + path->Reset(path_length);
|
|
|
| if (find_handle == INVALID_HANDLE_VALUE) {
|
| - free(path);
|
| + delete path;
|
| return false;
|
| }
|
|
|
| - bool success = DeleteEntry(&find_file_data, path, path_length);
|
| + bool success = DeleteEntry(&find_file_data, path);
|
|
|
| while ((FindNextFileW(find_handle, &find_file_data) != 0) && success) {
|
| - success = success && DeleteEntry(&find_file_data, path, path_length);
|
| + path->Reset(path_length); // DeleteEntry adds to the path.
|
| + success = success && DeleteEntry(&find_file_data, path);
|
| }
|
|
|
| - free(path);
|
| + delete path;
|
|
|
| if ((GetLastError() != ERROR_NO_MORE_FILES) ||
|
| (FindClose(find_handle) == 0) ||
|
| @@ -362,52 +348,51 @@ char* Directory::CreateTemp(const char* const_template) {
|
| // dir_template. Creates this directory, with a default security
|
| // descriptor inherited from its parent directory.
|
| // The return value must be freed by the caller.
|
| - wchar_t* path = static_cast<wchar_t*>(malloc(MAX_PATH * sizeof(wchar_t)));
|
| - int path_length;
|
| + PathBuffer* path = new PathBuffer();
|
| if (0 == strncmp(const_template, "", 1)) {
|
| - path_length = GetTempPathW(MAX_PATH, path);
|
| - if (path_length == 0) {
|
| - free(path);
|
| + path->length = GetTempPathW(MAX_PATH, path->data);
|
| + if (path->length == 0) {
|
| + delete path;
|
| return NULL;
|
| }
|
| } else {
|
| const wchar_t* system_template = StringUtils::Utf8ToWide(const_template);
|
| - _snwprintf(path, MAX_PATH, L"%s", system_template);
|
| + path->Add(system_template);
|
| free(const_cast<wchar_t*>(system_template));
|
| - path_length = wcslen(path);
|
| }
|
| // Length of tempdir-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 44.
|
| - if (path_length > MAX_PATH - 44) {
|
| - free(path);
|
| + if (path->length > MAX_PATH - 44) {
|
| + delete path;
|
| return NULL;
|
| }
|
| - if ((path)[path_length - 1] == L'\\') {
|
| + if ((path->data)[path->length - 1] == L'\\') {
|
| // No base name for the directory - use "tempdir".
|
| - _snwprintf(path + path_length, MAX_PATH - path_length, L"tempdir");
|
| - path_length = wcslen(path);
|
| + path->Add(L"tempdir");
|
| }
|
|
|
| UUID uuid;
|
| RPC_STATUS status = UuidCreateSequential(&uuid);
|
| if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
|
| - free(path);
|
| + delete path;
|
| return NULL;
|
| }
|
| RPC_WSTR uuid_string;
|
| status = UuidToStringW(&uuid, &uuid_string);
|
| if (status != RPC_S_OK) {
|
| - free(path);
|
| + delete path;
|
| return NULL;
|
| }
|
|
|
| - _snwprintf(path + path_length, MAX_PATH - path_length, L"-%s", uuid_string);
|
| + path->Add(L"-");
|
| + // RPC_WSTR is an unsigned short*, so we cast to wchar_t*.
|
| + path->Add(reinterpret_cast<wchar_t*>(uuid_string));
|
| RpcStringFreeW(&uuid_string);
|
| - if (!CreateDirectoryW(path, NULL)) {
|
| - free(path);
|
| + if (!CreateDirectoryW(path->data, NULL)) {
|
| + delete path;
|
| return NULL;
|
| }
|
| - char* result = StringUtils::WideToUtf8(path);
|
| - free(path);
|
| + char* result = StringUtils::WideToUtf8(path->data);
|
| + delete path;
|
| return result;
|
| }
|
|
|
|
|