| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "bin/directory.h" | 5 #include "bin/directory.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <sys/stat.h> | 8 #include <sys/stat.h> |
| 9 | 9 |
| 10 #include "bin/log.h" | 10 #include "bin/log.h" |
| 11 | 11 |
| 12 // Forward declaration. | 12 class PathBuffer { |
| 13 public: |
| 14 PathBuffer() : length(0) { } |
| 15 |
| 16 wchar_t data[MAX_PATH + 1]; |
| 17 int length; |
| 18 |
| 19 bool Add(const wchar_t* name) { |
| 20 size_t written = _snprintf(data + length, |
| 21 MAX_PATH - length, |
| 22 L"%s", |
| 23 name); |
| 24 data[MAX_PATH] = L'\0'; |
| 25 if (written == wcsnlen(name, MAX_PATH + 1)) { |
| 26 length += written; |
| 27 return true; |
| 28 } else { |
| 29 return false; |
| 30 } |
| 31 } |
| 32 |
| 33 void Reset(int new_length) { |
| 34 length = new_length; |
| 35 data[length] = L'\0'; |
| 36 } |
| 37 }; |
| 38 |
| 39 |
| 40 // Forward declarations. |
| 13 static bool ListRecursively(const wchar_t* dir_name, | 41 static bool ListRecursively(const wchar_t* dir_name, |
| 14 bool recursive, | 42 bool recursive, |
| 15 DirectoryListing* listing); | 43 DirectoryListing* listing); |
| 16 static bool DeleteRecursively(const wchar_t* dir_name); | 44 static bool DeleteRecursively(const wchar_t* dir_name); |
| 17 | 45 |
| 18 | 46 |
| 19 static bool HandleDir(wchar_t* dir_name, | 47 static bool HandleDir(wchar_t* dir_name, |
| 20 wchar_t* path, | 48 PathBuffer* path, |
| 21 int path_length, | |
| 22 bool recursive, | 49 bool recursive, |
| 23 DirectoryListing* listing) { | 50 DirectoryListing* listing) { |
| 24 if (wcscmp(dir_name, L".") != 0 && | 51 if (wcscmp(dir_name, L".") == 0) return true; |
| 25 wcscmp(dir_name, L"..") != 0) { | 52 if (wcscmp(dir_name, L"..") == 0) return true; |
| 26 size_t written = _snwprintf(path + path_length, | 53 if (!path->Add(dir_name)) return false; |
| 27 MAX_PATH - path_length, | 54 char* utf8_path = StringUtils::WideToUtf8(path->data); |
| 28 L"%s", | 55 bool ok = listing->HandleDirectory(utf8_path); |
| 29 dir_name); | 56 free(utf8_path); |
| 30 if (written != wcslen(dir_name)) { | 57 if (!ok) return ok; |
| 31 return false; | 58 if (recursive) { |
| 32 } | 59 return ListRecursively(path->data, recursive, listing); |
| 33 char* utf8_path = StringUtils::WideToUtf8(path); | |
| 34 bool ok = listing->HandleDirectory(utf8_path); | |
| 35 free(utf8_path); | |
| 36 if (!ok) return ok; | |
| 37 if (recursive) { | |
| 38 return ListRecursively(path, recursive, listing); | |
| 39 } | |
| 40 } | 60 } |
| 41 return true; | |
| 42 } | 61 } |
| 43 | 62 |
| 44 | 63 |
| 45 static bool HandleFile(wchar_t* file_name, | 64 static bool HandleFile(wchar_t* file_name, |
| 46 wchar_t* path, | 65 PathBuffer* path, |
| 47 int path_length, | |
| 48 DirectoryListing* listing) { | 66 DirectoryListing* listing) { |
| 49 size_t written = _snwprintf(path + path_length, | 67 if (!path->Add(file_name)) { |
| 50 MAX_PATH - path_length, | |
| 51 L"%s", | |
| 52 file_name); | |
| 53 if (written != wcslen(file_name)) { | |
| 54 return false; | 68 return false; |
| 55 }; | 69 } |
| 56 char* utf8_path = StringUtils::WideToUtf8(path); | 70 char* utf8_path = StringUtils::WideToUtf8(path->data); |
| 57 bool ok = listing->HandleFile(utf8_path); | 71 bool ok = listing->HandleFile(utf8_path); |
| 58 free(utf8_path); | 72 free(utf8_path); |
| 59 return ok; | 73 return ok; |
| 60 } | 74 } |
| 61 | 75 |
| 62 | 76 |
| 63 static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data, | 77 static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data, |
| 64 wchar_t* path, | 78 PathBuffer* path, |
| 65 int path_length, | |
| 66 bool recursive, | 79 bool recursive, |
| 67 DirectoryListing* listing) { | 80 DirectoryListing* listing) { |
| 68 DWORD attributes = find_file_data->dwFileAttributes; | 81 DWORD attributes = find_file_data->dwFileAttributes; |
| 69 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { | 82 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 70 return HandleDir(find_file_data->cFileName, | 83 return HandleDir(find_file_data->cFileName, |
| 71 path, | 84 path, |
| 72 path_length, | |
| 73 recursive, | 85 recursive, |
| 74 listing); | 86 listing); |
| 75 } else { | 87 } else { |
| 76 return HandleFile(find_file_data->cFileName, path, path_length, listing); | 88 return HandleFile(find_file_data->cFileName, path, listing); |
| 77 } | 89 } |
| 78 } | 90 } |
| 79 | 91 |
| 80 | 92 |
| 81 // ComputeFullSearchPath must be called with a path array of size at | 93 static PathBuffer* ComputeFullSearchPath(const wchar_t* dir_name) { |
| 82 // least MAX_PATH. | |
| 83 static bool ComputeFullSearchPath(const wchar_t* dir_name, | |
| 84 wchar_t* path, | |
| 85 int* path_length) { | |
| 86 // GetFullPathName only works in a multi-threaded environment if | 94 // GetFullPathName only works in a multi-threaded environment if |
| 87 // SetCurrentDirectory is not used. We currently have no plan for | 95 // SetCurrentDirectory is not used. We currently have no plan for |
| 88 // exposing SetCurrentDirectory. | 96 // exposing SetCurrentDirectory. |
| 89 size_t written = GetFullPathNameW(dir_name, MAX_PATH, path, NULL); | 97 PathBuffer* path = new PathBuffer(); |
| 98 |
| 99 size_t written = GetFullPathNameW(dir_name, MAX_PATH + 1, path->data, NULL); |
| 90 // GetFullPathName only accepts input strings of size less than | 100 // GetFullPathName only accepts input strings of size less than |
| 91 // MAX_PATH and returns 0 to indicate failure for paths longer than | 101 // MAX_PATH and returns 0 to indicate failure for paths longer than |
| 92 // that. Therefore the path buffer is always big enough. | 102 // that. Therefore the path buffer is always big enough. |
| 93 if (written == 0 || written > MAX_PATH) { | 103 if (written == 0 || written > MAX_PATH) { |
| 94 return false; | 104 delete path; |
| 105 return NULL; |
| 95 } | 106 } |
| 96 *path_length = written; | 107 path->length = written; |
| 97 written = _snwprintf(path + *path_length, | 108 if (path->Add(L"\\*")) { |
| 98 MAX_PATH - *path_length, | 109 return path; |
| 99 L"%s", | 110 } else { |
| 100 L"\\*"); | 111 delete path; |
| 101 if (written != 2) { | 112 return NULL; |
| 102 return false; | |
| 103 } | 113 } |
| 104 *path_length += written; | |
| 105 return true; | |
| 106 } | 114 } |
| 107 | 115 |
| 108 static void PostError(DirectoryListing* listing, | 116 static void PostError(DirectoryListing* listing, |
| 109 const wchar_t* dir_name) { | 117 const wchar_t* dir_name) { |
| 110 const char* utf8_path = StringUtils::WideToUtf8(dir_name); | 118 const char* utf8_path = StringUtils::WideToUtf8(dir_name); |
| 111 listing->HandleError(utf8_path); | 119 listing->HandleError(utf8_path); |
| 112 free(const_cast<char*>(utf8_path)); | 120 free(const_cast<char*>(utf8_path)); |
| 113 } | 121 } |
| 114 | 122 |
| 115 | 123 |
| 116 static bool ListRecursively(const wchar_t* dir_name, | 124 static bool ListRecursively(const wchar_t* dir_name, |
| 117 bool recursive, | 125 bool recursive, |
| 118 DirectoryListing* listing) { | 126 DirectoryListing* listing) { |
| 119 // Compute full path for the directory currently being listed. The | 127 // Compute full path for the directory currently being listed. The |
| 120 // path buffer will be used to construct the current path in the | 128 // path buffer will be used to construct the current path in the |
| 121 // recursive traversal. path_length does not always equal | 129 // recursive traversal. path_length does not always equal |
| 122 // strlen(path) but indicates the current prefix of path that is the | 130 // strlen(path) but indicates the current prefix of path that is the |
| 123 // path of the current directory in the traversal. | 131 // path of the current directory in the traversal. |
| 124 wchar_t* path = static_cast<wchar_t*>(malloc(MAX_PATH * sizeof(wchar_t))); | 132 PathBuffer* path = ComputeFullSearchPath(dir_name, path, &path_length); |
| 125 int path_length = 0; | 133 if (path == NULL) { |
| 126 bool valid = ComputeFullSearchPath(dir_name, path, &path_length); | |
| 127 if (!valid) { | |
| 128 PostError(listing, dir_name); | 134 PostError(listing, dir_name); |
| 129 free(path); | 135 delete path; |
| 130 return false; | 136 return false; |
| 131 } | 137 } |
| 132 | 138 |
| 133 WIN32_FIND_DATAW find_file_data; | 139 WIN32_FIND_DATAW find_file_data; |
| 134 HANDLE find_handle = FindFirstFileW(path, &find_file_data); | 140 HANDLE find_handle = FindFirstFileW(path, &find_file_data); |
| 135 | 141 |
| 136 // Adjust the path by removing the '*' used for the search. | 142 // Adjust the path by removing the '*' used for the search. |
| 137 path_length -= 1; | 143 path->Reset(path->length - 1); |
| 138 path[path_length] = '\0'; | |
| 139 | 144 |
| 140 if (find_handle == INVALID_HANDLE_VALUE) { | 145 if (find_handle == INVALID_HANDLE_VALUE) { |
| 141 PostError(listing, path); | 146 PostError(listing, path); |
| 142 free(path); | 147 delete path; |
| 143 return false; | 148 return false; |
| 144 } | 149 } |
| 145 | 150 |
| 151 int path_length = path->length; |
| 146 bool success = HandleEntry(&find_file_data, | 152 bool success = HandleEntry(&find_file_data, |
| 147 path, | 153 path, |
| 148 path_length, | |
| 149 recursive, | 154 recursive, |
| 150 listing); | 155 listing); |
| 151 | 156 |
| 152 while ((FindNextFileW(find_handle, &find_file_data) != 0)) { | 157 while ((FindNextFileW(find_handle, &find_file_data) != 0)) { |
| 158 path->Reset(path_length); // HandleEntry adds the entry name to path. |
| 153 success = HandleEntry(&find_file_data, | 159 success = HandleEntry(&find_file_data, |
| 154 path, | 160 path, |
| 155 path_length, | |
| 156 recursive, | 161 recursive, |
| 157 listing) && success; | 162 listing) && success; |
| 158 } | 163 } |
| 159 | 164 |
| 160 if (GetLastError() != ERROR_NO_MORE_FILES) { | 165 if (GetLastError() != ERROR_NO_MORE_FILES) { |
| 161 success = false; | 166 success = false; |
| 162 PostError(listing, dir_name); | 167 PostError(listing, dir_name); |
| 163 } | 168 } |
| 164 | 169 |
| 165 if (FindClose(find_handle) == 0) { | 170 if (FindClose(find_handle) == 0) { |
| 166 success = false; | 171 success = false; |
| 167 PostError(listing, dir_name); | 172 PostError(listing, dir_name); |
| 168 } | 173 } |
| 169 free(path); | 174 delete path; |
| 170 | 175 |
| 171 return success; | 176 return success; |
| 172 } | 177 } |
| 173 | 178 |
| 174 | 179 // TODO(whesse): Finish adding PathBuffer, starting here. |
| 175 static bool DeleteFile(wchar_t* file_name, | 180 static bool DeleteFile(wchar_t* file_name, |
| 176 wchar_t* path, | 181 wchar_t* path, |
| 177 int path_length) { | 182 int path_length) { |
| 178 size_t written = _snwprintf(path + path_length, | 183 size_t written = _snwprintf(path + path_length, |
| 179 MAX_PATH - path_length, | 184 MAX_PATH - path_length, |
| 180 L"%s", | 185 L"%s", |
| 181 file_name); | 186 file_name); |
| 182 if (written != wcslen(file_name)) { | 187 if (written != wcslen(file_name)) { |
| 183 return false; | 188 return false; |
| 184 } | 189 } |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 bool success = DeleteRecursively(system_new_path); | 443 bool success = DeleteRecursively(system_new_path); |
| 439 if (!success) return false; | 444 if (!success) return false; |
| 440 } | 445 } |
| 441 DWORD flags = MOVEFILE_WRITE_THROUGH; | 446 DWORD flags = MOVEFILE_WRITE_THROUGH; |
| 442 int move_status = | 447 int move_status = |
| 443 MoveFileExW(system_path, system_new_path, flags); | 448 MoveFileExW(system_path, system_new_path, flags); |
| 444 free(const_cast<wchar_t*>(system_path)); | 449 free(const_cast<wchar_t*>(system_path)); |
| 445 free(const_cast<wchar_t*>(system_new_path)); | 450 free(const_cast<wchar_t*>(system_new_path)); |
| 446 return (move_status != 0); | 451 return (move_status != 0); |
| 447 } | 452 } |
| OLD | NEW |