Index: runtime/bin/directory_win.cc |
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc |
index 8f97f0ee51bdf77e9f77142c8de83cb8696dc825..9e3cf306abae0c888fb046f31c5c8c28281e239f 100644 |
--- a/runtime/bin/directory_win.cc |
+++ b/runtime/bin/directory_win.cc |
@@ -19,41 +19,47 @@ |
namespace dart { |
namespace bin { |
-class PathBuffer { |
- public: |
- PathBuffer() : length(0) { |
- data = new wchar_t[MAX_PATH + 1]; |
- } |
+PathBuffer::PathBuffer() : length_(0) { |
+ data_ = new wchar_t[MAX_PATH + 1]; |
+} |
- ~PathBuffer() { |
- delete[] data; |
- } |
+char* PathBuffer::AsString() const { |
+ return StringUtils::WideToUtf8(AsStringW()); |
+} |
- wchar_t* data; |
- int length; |
- |
- bool Add(const wchar_t* name) { |
- int written = _snwprintf(data + length, |
- MAX_PATH - length, |
- L"%s", |
- name); |
- data[MAX_PATH] = L'\0'; |
- if (written <= MAX_PATH - length && |
- written >= 0 && |
- static_cast<size_t>(written) == wcsnlen(name, MAX_PATH + 1)) { |
- length += written; |
- return true; |
- } else { |
- SetLastError(ERROR_BUFFER_OVERFLOW); |
- return false; |
- } |
- } |
+wchar_t* PathBuffer::AsStringW() const { |
+ return reinterpret_cast<wchar_t*>(data_); |
+} |
- void Reset(int new_length) { |
- length = new_length; |
- data[length] = L'\0'; |
+bool PathBuffer::Add(const char* name) { |
+ const wchar_t* wide_name = StringUtils::Utf8ToWide(name); |
+ bool success = AddW(wide_name); |
+ free(const_cast<wchar_t*>(wide_name)); |
+ return success; |
+} |
+ |
+bool PathBuffer::AddW(const wchar_t* name) { |
+ wchar_t* data = AsStringW(); |
+ int written = _snwprintf(data + length_, |
+ MAX_PATH - length_, |
+ L"%s", |
+ name); |
+ data[MAX_PATH] = L'\0'; |
+ if (written <= MAX_PATH - length_ && |
+ written >= 0 && |
+ static_cast<size_t>(written) == wcsnlen(name, MAX_PATH + 1)) { |
+ length_ += written; |
+ return true; |
+ } else { |
+ SetLastError(ERROR_BUFFER_OVERFLOW); |
+ return false; |
} |
-}; |
+} |
+ |
+void PathBuffer::Reset(int new_length) { |
+ length_ = new_length; |
+ AsStringW()[length_] = L'\0'; |
+} |
// If link_name points to a link, IsBrokenLink will return true if link_name |
// points to an invalid target. |
@@ -84,96 +90,31 @@ struct LinkList { |
}; |
// Forward declarations. |
-static bool ListRecursively(PathBuffer* path, |
- bool recursive, |
- bool follow_links, |
- LinkList* seen, |
- DirectoryListing* listing); |
static bool DeleteRecursively(PathBuffer* path); |
-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, |
- PathBuffer* path, |
- bool recursive, |
- bool follow_links, |
- LinkList* seen, |
- DirectoryListing* 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); |
- return ok && |
- (!recursive || |
- ListRecursively(path, recursive, follow_links, seen, listing)); |
-} |
- |
- |
-static bool HandleFile(wchar_t* file_name, |
- PathBuffer* path, |
- DirectoryListing* listing) { |
- if (!path->Add(file_name)) { |
- PostError(listing, path->data); |
- return false; |
+static ListType HandleFindFile(DirectoryListing* listing, |
+ DirectoryListingEntry* entry, |
+ WIN32_FIND_DATAW& find_file_data) { |
+ if (!listing->path_buffer().AddW(find_file_data.cFileName)) { |
+ return kListError; |
} |
- char* utf8_path = StringUtils::WideToUtf8(path->data); |
- bool ok = listing->HandleFile(utf8_path); |
- free(utf8_path); |
- return ok; |
-} |
- |
- |
-static bool HandleLink(wchar_t* link_name, |
- PathBuffer* path, |
- DirectoryListing* listing) { |
- if (!path->Add(link_name)) { |
- PostError(listing, path->data); |
- return false; |
- } |
- char* utf8_path = StringUtils::WideToUtf8(path->data); |
- bool ok = listing->HandleLink(utf8_path); |
- free(utf8_path); |
- return ok; |
-} |
- |
- |
-static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data, |
- PathBuffer* path, |
- bool recursive, |
- bool follow_links, |
- LinkList* seen, |
- DirectoryListing* listing) { |
- DWORD attributes = find_file_data->dwFileAttributes; |
+ DWORD attributes = find_file_data.dwFileAttributes; |
if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { |
- if (!follow_links) { |
- return HandleLink(find_file_data->cFileName, path, listing); |
+ if (!listing->follow_links()) { |
+ return kListLink; |
} |
- int path_length = path->length; |
- if (!path->Add(find_file_data->cFileName)) return false; |
HANDLE handle = CreateFileW( |
- path->data, |
+ listing->path_buffer().AsStringW(), |
0, |
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
NULL, |
OPEN_EXISTING, |
FILE_FLAG_BACKUP_SEMANTICS, |
NULL); |
- path->Reset(path_length); |
if (handle == INVALID_HANDLE_VALUE) { |
// Report as (broken) link. |
- return HandleLink(find_file_data->cFileName, path, listing); |
+ return kListLink; |
} |
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
// Check the seen link targets to see if we are in a file system loop. |
@@ -184,103 +125,99 @@ static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data, |
DWORD error = GetLastError(); |
CloseHandle(handle); |
SetLastError(error); |
- PostError(listing, path->data); |
- return false; |
+ return kListError; |
} |
CloseHandle(handle); |
current_link.volume = info.dwVolumeSerialNumber; |
current_link.id_low = info.nFileIndexLow; |
current_link.id_high = info.nFileIndexHigh; |
- current_link.next = seen; |
- LinkList* previous = seen; |
+ current_link.next = entry->link(); |
+ LinkList* previous = entry->link(); |
while (previous != NULL) { |
if (previous->volume == current_link.volume && |
previous->id_low == current_link.id_low && |
previous->id_high == current_link.id_high) { |
// Report the looping link as a link, rather than following it. |
- return HandleLink(find_file_data->cFileName, path, listing); |
+ return kListLink; |
} |
previous = previous->next; |
} |
// Recurse into the directory, adding current link to the seen links list. |
- return HandleDir(find_file_data->cFileName, |
- path, |
- recursive, |
- follow_links, |
- ¤t_link, |
- listing); |
+ if (wcscmp(find_file_data.cFileName, L".") == 0 || |
+ wcscmp(find_file_data.cFileName, L"..") == 0) { |
+ return entry->Next(listing); |
+ } |
+ entry->set_link(new LinkList(current_link)); |
+ return kListDirectory; |
} |
} |
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
- return HandleDir(find_file_data->cFileName, |
- path, |
- recursive, |
- follow_links, |
- seen, |
- listing); |
+ if (wcscmp(find_file_data.cFileName, L".") == 0 || |
+ wcscmp(find_file_data.cFileName, L"..") == 0) { |
+ return entry->Next(listing); |
+ } |
+ return kListDirectory; |
} else { |
- return HandleFile(find_file_data->cFileName, path, listing); |
+ return kListFile; |
} |
} |
- |
-static bool ListRecursively(PathBuffer* path, |
- bool recursive, |
- bool follow_links, |
- LinkList* seen, |
- DirectoryListing* listing) { |
- if (!path->Add(L"\\*")) { |
- PostError(listing, path->data); |
- return false; |
+ListType DirectoryListingEntry::Next(DirectoryListing* listing) { |
+ if (done_) { |
+ return kListDone; |
} |
WIN32_FIND_DATAW find_file_data; |
- HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); |
- // Adjust the path by removing the '*' used for the search. |
- path->Reset(path->length - 1); |
+ if (lister_ == 0) { |
+ if (!listing->path_buffer().AddW(L"\\*")) { |
+ done_ = true; |
+ return kListError; |
+ } |
- if (find_handle == INVALID_HANDLE_VALUE) { |
- PostError(listing, path->data); |
- return false; |
+ path_length_ = listing->path_buffer().length() - 1; |
+ |
+ HANDLE find_handle = FindFirstFileW(listing->path_buffer().AsStringW(), |
+ &find_file_data); |
+ |
+ if (find_handle == INVALID_HANDLE_VALUE) { |
+ done_ = true; |
+ return kListError; |
+ } |
+ |
+ lister_ = reinterpret_cast<intptr_t>(find_handle); |
+ |
+ listing->path_buffer().Reset(path_length_); |
+ |
+ return HandleFindFile(listing, this, find_file_data); |
} |
- int path_length = path->length; |
- bool success = HandleEntry(&find_file_data, |
- path, |
- recursive, |
- follow_links, |
- seen, |
- 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, |
- recursive, |
- follow_links, |
- seen, |
- listing) && success; |
+ // Reset. |
+ listing->path_buffer().Reset(path_length_); |
+ ResetLink(); |
+ |
+ if (FindNextFileW(reinterpret_cast<HANDLE>(lister_), &find_file_data) != 0) { |
+ return HandleFindFile(listing, this, find_file_data); |
} |
+ done_ = true; |
+ |
if (GetLastError() != ERROR_NO_MORE_FILES) { |
- success = false; |
- PostError(listing, path->data); |
+ return kListError; |
} |
- if (FindClose(find_handle) == 0) { |
- success = false; |
- PostError(listing, path->data); |
+ if (FindClose(reinterpret_cast<HANDLE>(lister_)) == 0) { |
+ return kListError; |
} |
- return success; |
+ return kListDone; |
} |
static bool DeleteFile(wchar_t* file_name, PathBuffer* path) { |
- if (!path->Add(file_name)) return false; |
+ if (!path->AddW(file_name)) return false; |
- if (DeleteFileW(path->data) != 0) { |
+ if (DeleteFileW(path->AsStringW()) != 0) { |
return true; |
} |
@@ -288,7 +225,7 @@ static bool DeleteFile(wchar_t* file_name, PathBuffer* path) { |
// 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->data); |
+ DWORD attributes = GetFileAttributesW(path->AsStringW()); |
if (attributes == INVALID_FILE_ATTRIBUTES) { |
return false; |
} |
@@ -296,11 +233,11 @@ static bool DeleteFile(wchar_t* file_name, PathBuffer* path) { |
if ((attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) { |
attributes &= ~FILE_ATTRIBUTE_READONLY; |
- if (SetFileAttributesW(path->data, attributes) == 0) { |
+ if (SetFileAttributesW(path->AsStringW(), attributes) == 0) { |
return false; |
} |
- return DeleteFileW(path->data) != 0; |
+ return DeleteFileW(path->AsStringW()) != 0; |
} |
} |
@@ -311,7 +248,7 @@ static bool DeleteFile(wchar_t* file_name, PathBuffer* path) { |
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); |
+ return path->AddW(dir_name) && DeleteRecursively(path); |
} |
@@ -327,7 +264,7 @@ static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data, PathBuffer* path) { |
static bool DeleteRecursively(PathBuffer* path) { |
- DWORD attributes = GetFileAttributesW(path->data); |
+ DWORD attributes = GetFileAttributesW(path->AsStringW()); |
if ((attributes == INVALID_FILE_ATTRIBUTES)) { |
return false; |
} |
@@ -335,20 +272,20 @@ static bool DeleteRecursively(PathBuffer* path) { |
// filesystem that we do not want to recurse into. |
if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { |
// Just delete the junction itself. |
- return RemoveDirectoryW(path->data) != 0; |
+ return RemoveDirectoryW(path->AsStringW()) != 0; |
} |
// If it's a file, remove it directly. |
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { |
return DeleteFile(L"", path); |
} |
- if (!path->Add(L"\\*")) return false; |
+ if (!path->AddW(L"\\*")) return false; |
WIN32_FIND_DATAW find_file_data; |
- HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); |
+ HANDLE find_handle = FindFirstFileW(path->AsStringW(), &find_file_data); |
// Adjust the path by removing the '*' used for the search. |
- int path_length = path->length - 1; |
+ int path_length = path->length() - 1; |
path->Reset(path_length); |
if (find_handle == INVALID_HANDLE_VALUE) { |
@@ -365,7 +302,7 @@ static bool DeleteRecursively(PathBuffer* path) { |
path->Reset(path_length - 1); // Drop the "\" from the end of the path. |
if ((GetLastError() != ERROR_NO_MORE_FILES) || |
(FindClose(find_handle) == 0) || |
- (RemoveDirectoryW(path->data) == 0)) { |
+ (RemoveDirectoryW(path->AsStringW()) == 0)) { |
return false; |
} |
@@ -373,21 +310,6 @@ static bool DeleteRecursively(PathBuffer* path) { |
} |
-bool Directory::List(const char* dir_name, |
- bool recursive, |
- bool follow_links, |
- DirectoryListing* listing) { |
- const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name); |
- PathBuffer path; |
- if (!path.Add(system_name)) { |
- PostError(listing, system_name); |
- return false; |
- } |
- free(const_cast<wchar_t*>(system_name)); |
- return ListRecursively(&path, recursive, follow_links, NULL, listing); |
-} |
- |
- |
static Directory::ExistsResult ExistsHelper(const wchar_t* dir_name) { |
DWORD attributes = GetFileAttributesW(dir_name); |
if (attributes == INVALID_FILE_ATTRIBUTES) { |
@@ -456,22 +378,22 @@ char* Directory::CreateTemp(const char* const_template) { |
// The return value must be freed by the caller. |
PathBuffer path; |
if (0 == strncmp(const_template, "", 1)) { |
- path.length = GetTempPathW(MAX_PATH, path.data); |
- if (path.length == 0) { |
+ path.Reset(GetTempPathW(MAX_PATH, path.AsStringW())); |
+ if (path.length() == 0) { |
return NULL; |
} |
} else { |
const wchar_t* system_template = StringUtils::Utf8ToWide(const_template); |
- path.Add(system_template); |
+ path.AddW(system_template); |
free(const_cast<wchar_t*>(system_template)); |
} |
// Length of tempdir-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 44. |
- if (path.length > MAX_PATH - 44) { |
+ if (path.length() > MAX_PATH - 44) { |
return NULL; |
} |
- if ((path.data)[path.length - 1] == L'\\') { |
+ if ((path.AsStringW())[path.length() - 1] == L'\\') { |
// No base name for the directory - use "tempdir". |
- path.Add(L"tempdir"); |
+ path.AddW(L"tempdir"); |
} |
UUID uuid; |
@@ -485,14 +407,14 @@ char* Directory::CreateTemp(const char* const_template) { |
return NULL; |
} |
- path.Add(L"-"); |
+ path.AddW(L"-"); |
// RPC_WSTR is an unsigned short*, so we cast to wchar_t*. |
- path.Add(reinterpret_cast<wchar_t*>(uuid_string)); |
+ path.AddW(reinterpret_cast<wchar_t*>(uuid_string)); |
RpcStringFreeW(&uuid_string); |
- if (!CreateDirectoryW(path.data, NULL)) { |
+ if (!CreateDirectoryW(path.AsStringW(), NULL)) { |
return NULL; |
} |
- char* result = StringUtils::WideToUtf8(path.data); |
+ char* result = path.AsString(); |
return result; |
} |
@@ -508,7 +430,7 @@ bool Directory::Delete(const char* dir_name, bool recursive) { |
} |
} else { |
PathBuffer path; |
- if (path.Add(system_dir_name)) { |
+ if (path.AddW(system_dir_name)) { |
result = DeleteRecursively(&path); |
} |
} |