| 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 "platform/globals.h" | 5 #include "platform/globals.h" |
| 6 #if defined(TARGET_OS_WINDOWS) | 6 #if defined(TARGET_OS_WINDOWS) |
| 7 | 7 |
| 8 #include "bin/directory.h" | 8 #include "bin/directory.h" |
| 9 #include "bin/file.h" | 9 #include "bin/file.h" |
| 10 #include "bin/utils.h" | 10 #include "bin/utils.h" |
| 11 | 11 |
| 12 #include <errno.h> // NOLINT | 12 #include <errno.h> // NOLINT |
| 13 #include <sys/stat.h> // NOLINT | 13 #include <sys/stat.h> // NOLINT |
| 14 | 14 |
| 15 #include "bin/log.h" | 15 #include "bin/log.h" |
| 16 | 16 |
| 17 #undef DeleteFile | 17 #undef DeleteFile |
| 18 | 18 |
| 19 namespace dart { | 19 namespace dart { |
| 20 namespace bin { | 20 namespace bin { |
| 21 | 21 |
| 22 class PathBuffer { | 22 PathBuffer::PathBuffer() : length_(0) { |
| 23 public: | 23 data_ = new wchar_t[MAX_PATH + 1]; |
| 24 PathBuffer() : length(0) { | 24 } |
| 25 data = new wchar_t[MAX_PATH + 1]; | 25 |
| 26 char* PathBuffer::AsString() const { |
| 27 return StringUtils::WideToUtf8(AsStringW()); |
| 28 } |
| 29 |
| 30 wchar_t* PathBuffer::AsStringW() const { |
| 31 return reinterpret_cast<wchar_t*>(data_); |
| 32 } |
| 33 |
| 34 bool PathBuffer::Add(const char* name) { |
| 35 const wchar_t* wide_name = StringUtils::Utf8ToWide(name); |
| 36 bool success = AddW(wide_name); |
| 37 free(const_cast<wchar_t*>(wide_name)); |
| 38 return success; |
| 39 } |
| 40 |
| 41 bool PathBuffer::AddW(const wchar_t* name) { |
| 42 wchar_t* data = AsStringW(); |
| 43 int written = _snwprintf(data + length_, |
| 44 MAX_PATH - length_, |
| 45 L"%s", |
| 46 name); |
| 47 data[MAX_PATH] = L'\0'; |
| 48 if (written <= MAX_PATH - length_ && |
| 49 written >= 0 && |
| 50 static_cast<size_t>(written) == wcsnlen(name, MAX_PATH + 1)) { |
| 51 length_ += written; |
| 52 return true; |
| 53 } else { |
| 54 SetLastError(ERROR_BUFFER_OVERFLOW); |
| 55 return false; |
| 26 } | 56 } |
| 57 } |
| 27 | 58 |
| 28 ~PathBuffer() { | 59 void PathBuffer::Reset(int new_length) { |
| 29 delete[] data; | 60 length_ = new_length; |
| 30 } | 61 AsStringW()[length_] = L'\0'; |
| 31 | 62 } |
| 32 wchar_t* data; | |
| 33 int length; | |
| 34 | |
| 35 bool Add(const wchar_t* name) { | |
| 36 int written = _snwprintf(data + length, | |
| 37 MAX_PATH - length, | |
| 38 L"%s", | |
| 39 name); | |
| 40 data[MAX_PATH] = L'\0'; | |
| 41 if (written <= MAX_PATH - length && | |
| 42 written >= 0 && | |
| 43 static_cast<size_t>(written) == wcsnlen(name, MAX_PATH + 1)) { | |
| 44 length += written; | |
| 45 return true; | |
| 46 } else { | |
| 47 SetLastError(ERROR_BUFFER_OVERFLOW); | |
| 48 return false; | |
| 49 } | |
| 50 } | |
| 51 | |
| 52 void Reset(int new_length) { | |
| 53 length = new_length; | |
| 54 data[length] = L'\0'; | |
| 55 } | |
| 56 }; | |
| 57 | 63 |
| 58 // If link_name points to a link, IsBrokenLink will return true if link_name | 64 // If link_name points to a link, IsBrokenLink will return true if link_name |
| 59 // points to an invalid target. | 65 // points to an invalid target. |
| 60 static bool IsBrokenLink(const wchar_t* link_name) { | 66 static bool IsBrokenLink(const wchar_t* link_name) { |
| 61 HANDLE handle = CreateFileW( | 67 HANDLE handle = CreateFileW( |
| 62 link_name, | 68 link_name, |
| 63 0, | 69 0, |
| 64 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | 70 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 65 NULL, | 71 NULL, |
| 66 OPEN_EXISTING, | 72 OPEN_EXISTING, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 77 // A linked list structure holding a link target's unique file system ID. | 83 // A linked list structure holding a link target's unique file system ID. |
| 78 // Used to detect loops in the file system when listing recursively. | 84 // Used to detect loops in the file system when listing recursively. |
| 79 struct LinkList { | 85 struct LinkList { |
| 80 DWORD volume; | 86 DWORD volume; |
| 81 DWORD id_low; | 87 DWORD id_low; |
| 82 DWORD id_high; | 88 DWORD id_high; |
| 83 LinkList* next; | 89 LinkList* next; |
| 84 }; | 90 }; |
| 85 | 91 |
| 86 // Forward declarations. | 92 // Forward declarations. |
| 87 static bool ListRecursively(PathBuffer* path, | |
| 88 bool recursive, | |
| 89 bool follow_links, | |
| 90 LinkList* seen, | |
| 91 DirectoryListing* listing); | |
| 92 static bool DeleteRecursively(PathBuffer* path); | 93 static bool DeleteRecursively(PathBuffer* path); |
| 93 | 94 |
| 94 | 95 |
| 95 static void PostError(DirectoryListing* listing, | 96 static ListType HandleFindFile(DirectoryListing* listing, |
| 96 const wchar_t* dir_name) { | 97 DirectoryListingEntry* entry, |
| 97 const char* utf8_path = StringUtils::WideToUtf8(dir_name); | 98 WIN32_FIND_DATAW& find_file_data) { |
| 98 listing->HandleError(utf8_path); | 99 if (!listing->path_buffer().AddW(find_file_data.cFileName)) { |
| 99 free(const_cast<char*>(utf8_path)); | 100 return kListError; |
| 100 } | |
| 101 | |
| 102 | |
| 103 static bool HandleDir(wchar_t* dir_name, | |
| 104 PathBuffer* path, | |
| 105 bool recursive, | |
| 106 bool follow_links, | |
| 107 LinkList* seen, | |
| 108 DirectoryListing* listing) { | |
| 109 if (wcscmp(dir_name, L".") == 0) return true; | |
| 110 if (wcscmp(dir_name, L"..") == 0) return true; | |
| 111 if (!path->Add(dir_name)) { | |
| 112 PostError(listing, path->data); | |
| 113 return false; | |
| 114 } | 101 } |
| 115 char* utf8_path = StringUtils::WideToUtf8(path->data); | 102 DWORD attributes = find_file_data.dwFileAttributes; |
| 116 bool ok = listing->HandleDirectory(utf8_path); | |
| 117 free(utf8_path); | |
| 118 return ok && | |
| 119 (!recursive || | |
| 120 ListRecursively(path, recursive, follow_links, seen, listing)); | |
| 121 } | |
| 122 | |
| 123 | |
| 124 static bool HandleFile(wchar_t* file_name, | |
| 125 PathBuffer* path, | |
| 126 DirectoryListing* listing) { | |
| 127 if (!path->Add(file_name)) { | |
| 128 PostError(listing, path->data); | |
| 129 return false; | |
| 130 } | |
| 131 char* utf8_path = StringUtils::WideToUtf8(path->data); | |
| 132 bool ok = listing->HandleFile(utf8_path); | |
| 133 free(utf8_path); | |
| 134 return ok; | |
| 135 } | |
| 136 | |
| 137 | |
| 138 static bool HandleLink(wchar_t* link_name, | |
| 139 PathBuffer* path, | |
| 140 DirectoryListing* listing) { | |
| 141 if (!path->Add(link_name)) { | |
| 142 PostError(listing, path->data); | |
| 143 return false; | |
| 144 } | |
| 145 char* utf8_path = StringUtils::WideToUtf8(path->data); | |
| 146 bool ok = listing->HandleLink(utf8_path); | |
| 147 free(utf8_path); | |
| 148 return ok; | |
| 149 } | |
| 150 | |
| 151 | |
| 152 static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data, | |
| 153 PathBuffer* path, | |
| 154 bool recursive, | |
| 155 bool follow_links, | |
| 156 LinkList* seen, | |
| 157 DirectoryListing* listing) { | |
| 158 DWORD attributes = find_file_data->dwFileAttributes; | |
| 159 if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { | 103 if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { |
| 160 if (!follow_links) { | 104 if (!listing->follow_links()) { |
| 161 return HandleLink(find_file_data->cFileName, path, listing); | 105 return kListLink; |
| 162 } | 106 } |
| 163 int path_length = path->length; | |
| 164 if (!path->Add(find_file_data->cFileName)) return false; | |
| 165 HANDLE handle = CreateFileW( | 107 HANDLE handle = CreateFileW( |
| 166 path->data, | 108 listing->path_buffer().AsStringW(), |
| 167 0, | 109 0, |
| 168 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | 110 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 169 NULL, | 111 NULL, |
| 170 OPEN_EXISTING, | 112 OPEN_EXISTING, |
| 171 FILE_FLAG_BACKUP_SEMANTICS, | 113 FILE_FLAG_BACKUP_SEMANTICS, |
| 172 NULL); | 114 NULL); |
| 173 path->Reset(path_length); | |
| 174 if (handle == INVALID_HANDLE_VALUE) { | 115 if (handle == INVALID_HANDLE_VALUE) { |
| 175 // Report as (broken) link. | 116 // Report as (broken) link. |
| 176 return HandleLink(find_file_data->cFileName, path, listing); | 117 return kListLink; |
| 177 } | 118 } |
| 178 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { | 119 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 179 // Check the seen link targets to see if we are in a file system loop. | 120 // Check the seen link targets to see if we are in a file system loop. |
| 180 LinkList current_link; | 121 LinkList current_link; |
| 181 BY_HANDLE_FILE_INFORMATION info; | 122 BY_HANDLE_FILE_INFORMATION info; |
| 182 // Get info | 123 // Get info |
| 183 if (!GetFileInformationByHandle(handle, &info)) { | 124 if (!GetFileInformationByHandle(handle, &info)) { |
| 184 DWORD error = GetLastError(); | 125 DWORD error = GetLastError(); |
| 185 CloseHandle(handle); | 126 CloseHandle(handle); |
| 186 SetLastError(error); | 127 SetLastError(error); |
| 187 PostError(listing, path->data); | 128 return kListError; |
| 188 return false; | |
| 189 } | 129 } |
| 190 CloseHandle(handle); | 130 CloseHandle(handle); |
| 191 current_link.volume = info.dwVolumeSerialNumber; | 131 current_link.volume = info.dwVolumeSerialNumber; |
| 192 current_link.id_low = info.nFileIndexLow; | 132 current_link.id_low = info.nFileIndexLow; |
| 193 current_link.id_high = info.nFileIndexHigh; | 133 current_link.id_high = info.nFileIndexHigh; |
| 194 current_link.next = seen; | 134 current_link.next = entry->link(); |
| 195 LinkList* previous = seen; | 135 LinkList* previous = entry->link(); |
| 196 while (previous != NULL) { | 136 while (previous != NULL) { |
| 197 if (previous->volume == current_link.volume && | 137 if (previous->volume == current_link.volume && |
| 198 previous->id_low == current_link.id_low && | 138 previous->id_low == current_link.id_low && |
| 199 previous->id_high == current_link.id_high) { | 139 previous->id_high == current_link.id_high) { |
| 200 // Report the looping link as a link, rather than following it. | 140 // Report the looping link as a link, rather than following it. |
| 201 return HandleLink(find_file_data->cFileName, path, listing); | 141 return kListLink; |
| 202 } | 142 } |
| 203 previous = previous->next; | 143 previous = previous->next; |
| 204 } | 144 } |
| 205 // Recurse into the directory, adding current link to the seen links list. | 145 // Recurse into the directory, adding current link to the seen links list. |
| 206 return HandleDir(find_file_data->cFileName, | 146 if (wcscmp(find_file_data.cFileName, L".") == 0 || |
| 207 path, | 147 wcscmp(find_file_data.cFileName, L"..") == 0) { |
| 208 recursive, | 148 return entry->Next(listing); |
| 209 follow_links, | 149 } |
| 210 ¤t_link, | 150 entry->set_link(new LinkList(current_link)); |
| 211 listing); | 151 return kListDirectory; |
| 212 } | 152 } |
| 213 } | 153 } |
| 214 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { | 154 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 215 return HandleDir(find_file_data->cFileName, | 155 if (wcscmp(find_file_data.cFileName, L".") == 0 || |
| 216 path, | 156 wcscmp(find_file_data.cFileName, L"..") == 0) { |
| 217 recursive, | 157 return entry->Next(listing); |
| 218 follow_links, | 158 } |
| 219 seen, | 159 return kListDirectory; |
| 220 listing); | |
| 221 } else { | 160 } else { |
| 222 return HandleFile(find_file_data->cFileName, path, listing); | 161 return kListFile; |
| 223 } | 162 } |
| 224 } | 163 } |
| 225 | 164 |
| 226 | 165 ListType DirectoryListingEntry::Next(DirectoryListing* listing) { |
| 227 static bool ListRecursively(PathBuffer* path, | 166 if (done_) { |
| 228 bool recursive, | 167 return kListDone; |
| 229 bool follow_links, | |
| 230 LinkList* seen, | |
| 231 DirectoryListing* listing) { | |
| 232 if (!path->Add(L"\\*")) { | |
| 233 PostError(listing, path->data); | |
| 234 return false; | |
| 235 } | 168 } |
| 236 | 169 |
| 237 WIN32_FIND_DATAW find_file_data; | 170 WIN32_FIND_DATAW find_file_data; |
| 238 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); | |
| 239 | 171 |
| 240 // Adjust the path by removing the '*' used for the search. | 172 if (lister_ == 0) { |
| 241 path->Reset(path->length - 1); | 173 if (!listing->path_buffer().AddW(L"\\*")) { |
| 174 done_ = true; |
| 175 return kListError; |
| 176 } |
| 242 | 177 |
| 243 if (find_handle == INVALID_HANDLE_VALUE) { | 178 path_length_ = listing->path_buffer().length() - 1; |
| 244 PostError(listing, path->data); | 179 |
| 245 return false; | 180 HANDLE find_handle = FindFirstFileW(listing->path_buffer().AsStringW(), |
| 181 &find_file_data); |
| 182 |
| 183 if (find_handle == INVALID_HANDLE_VALUE) { |
| 184 done_ = true; |
| 185 return kListError; |
| 186 } |
| 187 |
| 188 lister_ = reinterpret_cast<intptr_t>(find_handle); |
| 189 |
| 190 listing->path_buffer().Reset(path_length_); |
| 191 |
| 192 return HandleFindFile(listing, this, find_file_data); |
| 246 } | 193 } |
| 247 | 194 |
| 248 int path_length = path->length; | 195 // Reset. |
| 249 bool success = HandleEntry(&find_file_data, | 196 listing->path_buffer().Reset(path_length_); |
| 250 path, | 197 ResetLink(); |
| 251 recursive, | |
| 252 follow_links, | |
| 253 seen, | |
| 254 listing); | |
| 255 | 198 |
| 256 while ((FindNextFileW(find_handle, &find_file_data) != 0)) { | 199 if (FindNextFileW(reinterpret_cast<HANDLE>(lister_), &find_file_data) != 0) { |
| 257 path->Reset(path_length); // HandleEntry adds the entry name to path. | 200 return HandleFindFile(listing, this, find_file_data); |
| 258 success = HandleEntry(&find_file_data, | |
| 259 path, | |
| 260 recursive, | |
| 261 follow_links, | |
| 262 seen, | |
| 263 listing) && success; | |
| 264 } | 201 } |
| 265 | 202 |
| 203 done_ = true; |
| 204 |
| 266 if (GetLastError() != ERROR_NO_MORE_FILES) { | 205 if (GetLastError() != ERROR_NO_MORE_FILES) { |
| 267 success = false; | 206 return kListError; |
| 268 PostError(listing, path->data); | |
| 269 } | 207 } |
| 270 | 208 |
| 271 if (FindClose(find_handle) == 0) { | 209 if (FindClose(reinterpret_cast<HANDLE>(lister_)) == 0) { |
| 272 success = false; | 210 return kListError; |
| 273 PostError(listing, path->data); | |
| 274 } | 211 } |
| 275 | 212 |
| 276 return success; | 213 return kListDone; |
| 277 } | 214 } |
| 278 | 215 |
| 279 | 216 |
| 280 static bool DeleteFile(wchar_t* file_name, PathBuffer* path) { | 217 static bool DeleteFile(wchar_t* file_name, PathBuffer* path) { |
| 281 if (!path->Add(file_name)) return false; | 218 if (!path->AddW(file_name)) return false; |
| 282 | 219 |
| 283 if (DeleteFileW(path->data) != 0) { | 220 if (DeleteFileW(path->AsStringW()) != 0) { |
| 284 return true; | 221 return true; |
| 285 } | 222 } |
| 286 | 223 |
| 287 // If we failed because the file is read-only, make it writeable and try | 224 // If we failed because the file is read-only, make it writeable and try |
| 288 // again. This mirrors Linux/Mac where a directory containing read-only files | 225 // again. This mirrors Linux/Mac where a directory containing read-only files |
| 289 // can still be recursively deleted. | 226 // can still be recursively deleted. |
| 290 if (GetLastError() == ERROR_ACCESS_DENIED) { | 227 if (GetLastError() == ERROR_ACCESS_DENIED) { |
| 291 DWORD attributes = GetFileAttributesW(path->data); | 228 DWORD attributes = GetFileAttributesW(path->AsStringW()); |
| 292 if (attributes == INVALID_FILE_ATTRIBUTES) { | 229 if (attributes == INVALID_FILE_ATTRIBUTES) { |
| 293 return false; | 230 return false; |
| 294 } | 231 } |
| 295 | 232 |
| 296 if ((attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) { | 233 if ((attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) { |
| 297 attributes &= ~FILE_ATTRIBUTE_READONLY; | 234 attributes &= ~FILE_ATTRIBUTE_READONLY; |
| 298 | 235 |
| 299 if (SetFileAttributesW(path->data, attributes) == 0) { | 236 if (SetFileAttributesW(path->AsStringW(), attributes) == 0) { |
| 300 return false; | 237 return false; |
| 301 } | 238 } |
| 302 | 239 |
| 303 return DeleteFileW(path->data) != 0; | 240 return DeleteFileW(path->AsStringW()) != 0; |
| 304 } | 241 } |
| 305 } | 242 } |
| 306 | 243 |
| 307 return false; | 244 return false; |
| 308 } | 245 } |
| 309 | 246 |
| 310 | 247 |
| 311 static bool DeleteDir(wchar_t* dir_name, PathBuffer* path) { | 248 static bool DeleteDir(wchar_t* dir_name, PathBuffer* path) { |
| 312 if (wcscmp(dir_name, L".") == 0) return true; | 249 if (wcscmp(dir_name, L".") == 0) return true; |
| 313 if (wcscmp(dir_name, L"..") == 0) return true; | 250 if (wcscmp(dir_name, L"..") == 0) return true; |
| 314 return path->Add(dir_name) && DeleteRecursively(path); | 251 return path->AddW(dir_name) && DeleteRecursively(path); |
| 315 } | 252 } |
| 316 | 253 |
| 317 | 254 |
| 318 static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data, PathBuffer* path) { | 255 static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data, PathBuffer* path) { |
| 319 DWORD attributes = find_file_data->dwFileAttributes; | 256 DWORD attributes = find_file_data->dwFileAttributes; |
| 320 | 257 |
| 321 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { | 258 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 322 return DeleteDir(find_file_data->cFileName, path); | 259 return DeleteDir(find_file_data->cFileName, path); |
| 323 } else { | 260 } else { |
| 324 return DeleteFile(find_file_data->cFileName, path); | 261 return DeleteFile(find_file_data->cFileName, path); |
| 325 } | 262 } |
| 326 } | 263 } |
| 327 | 264 |
| 328 | 265 |
| 329 static bool DeleteRecursively(PathBuffer* path) { | 266 static bool DeleteRecursively(PathBuffer* path) { |
| 330 DWORD attributes = GetFileAttributesW(path->data); | 267 DWORD attributes = GetFileAttributesW(path->AsStringW()); |
| 331 if ((attributes == INVALID_FILE_ATTRIBUTES)) { | 268 if ((attributes == INVALID_FILE_ATTRIBUTES)) { |
| 332 return false; | 269 return false; |
| 333 } | 270 } |
| 334 // If the directory is a junction, it's pointing to some other place in the | 271 // If the directory is a junction, it's pointing to some other place in the |
| 335 // filesystem that we do not want to recurse into. | 272 // filesystem that we do not want to recurse into. |
| 336 if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { | 273 if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { |
| 337 // Just delete the junction itself. | 274 // Just delete the junction itself. |
| 338 return RemoveDirectoryW(path->data) != 0; | 275 return RemoveDirectoryW(path->AsStringW()) != 0; |
| 339 } | 276 } |
| 340 // If it's a file, remove it directly. | 277 // If it's a file, remove it directly. |
| 341 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { | 278 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { |
| 342 return DeleteFile(L"", path); | 279 return DeleteFile(L"", path); |
| 343 } | 280 } |
| 344 | 281 |
| 345 if (!path->Add(L"\\*")) return false; | 282 if (!path->AddW(L"\\*")) return false; |
| 346 | 283 |
| 347 WIN32_FIND_DATAW find_file_data; | 284 WIN32_FIND_DATAW find_file_data; |
| 348 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); | 285 HANDLE find_handle = FindFirstFileW(path->AsStringW(), &find_file_data); |
| 349 | 286 |
| 350 // Adjust the path by removing the '*' used for the search. | 287 // Adjust the path by removing the '*' used for the search. |
| 351 int path_length = path->length - 1; | 288 int path_length = path->length() - 1; |
| 352 path->Reset(path_length); | 289 path->Reset(path_length); |
| 353 | 290 |
| 354 if (find_handle == INVALID_HANDLE_VALUE) { | 291 if (find_handle == INVALID_HANDLE_VALUE) { |
| 355 return false; | 292 return false; |
| 356 } | 293 } |
| 357 | 294 |
| 358 bool success = DeleteEntry(&find_file_data, path); | 295 bool success = DeleteEntry(&find_file_data, path); |
| 359 | 296 |
| 360 while ((FindNextFileW(find_handle, &find_file_data) != 0) && success) { | 297 while ((FindNextFileW(find_handle, &find_file_data) != 0) && success) { |
| 361 path->Reset(path_length); // DeleteEntry adds to the path. | 298 path->Reset(path_length); // DeleteEntry adds to the path. |
| 362 success = success && DeleteEntry(&find_file_data, path); | 299 success = success && DeleteEntry(&find_file_data, path); |
| 363 } | 300 } |
| 364 | 301 |
| 365 path->Reset(path_length - 1); // Drop the "\" from the end of the path. | 302 path->Reset(path_length - 1); // Drop the "\" from the end of the path. |
| 366 if ((GetLastError() != ERROR_NO_MORE_FILES) || | 303 if ((GetLastError() != ERROR_NO_MORE_FILES) || |
| 367 (FindClose(find_handle) == 0) || | 304 (FindClose(find_handle) == 0) || |
| 368 (RemoveDirectoryW(path->data) == 0)) { | 305 (RemoveDirectoryW(path->AsStringW()) == 0)) { |
| 369 return false; | 306 return false; |
| 370 } | 307 } |
| 371 | 308 |
| 372 return success; | 309 return success; |
| 373 } | 310 } |
| 374 | 311 |
| 375 | 312 |
| 376 bool Directory::List(const char* dir_name, | |
| 377 bool recursive, | |
| 378 bool follow_links, | |
| 379 DirectoryListing* listing) { | |
| 380 const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name); | |
| 381 PathBuffer path; | |
| 382 if (!path.Add(system_name)) { | |
| 383 PostError(listing, system_name); | |
| 384 return false; | |
| 385 } | |
| 386 free(const_cast<wchar_t*>(system_name)); | |
| 387 return ListRecursively(&path, recursive, follow_links, NULL, listing); | |
| 388 } | |
| 389 | |
| 390 | |
| 391 static Directory::ExistsResult ExistsHelper(const wchar_t* dir_name) { | 313 static Directory::ExistsResult ExistsHelper(const wchar_t* dir_name) { |
| 392 DWORD attributes = GetFileAttributesW(dir_name); | 314 DWORD attributes = GetFileAttributesW(dir_name); |
| 393 if (attributes == INVALID_FILE_ATTRIBUTES) { | 315 if (attributes == INVALID_FILE_ATTRIBUTES) { |
| 394 DWORD last_error = GetLastError(); | 316 DWORD last_error = GetLastError(); |
| 395 if (last_error == ERROR_FILE_NOT_FOUND || | 317 if (last_error == ERROR_FILE_NOT_FOUND || |
| 396 last_error == ERROR_PATH_NOT_FOUND) { | 318 last_error == ERROR_PATH_NOT_FOUND) { |
| 397 return Directory::DOES_NOT_EXIST; | 319 return Directory::DOES_NOT_EXIST; |
| 398 } else { | 320 } else { |
| 399 // We might not be able to get the file attributes for other | 321 // We might not be able to get the file attributes for other |
| 400 // reasons such as lack of permissions. In that case we do | 322 // reasons such as lack of permissions. In that case we do |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 } | 371 } |
| 450 | 372 |
| 451 | 373 |
| 452 char* Directory::CreateTemp(const char* const_template) { | 374 char* Directory::CreateTemp(const char* const_template) { |
| 453 // Returns a new, unused directory name, modifying the contents of | 375 // Returns a new, unused directory name, modifying the contents of |
| 454 // dir_template. Creates this directory, with a default security | 376 // dir_template. Creates this directory, with a default security |
| 455 // descriptor inherited from its parent directory. | 377 // descriptor inherited from its parent directory. |
| 456 // The return value must be freed by the caller. | 378 // The return value must be freed by the caller. |
| 457 PathBuffer path; | 379 PathBuffer path; |
| 458 if (0 == strncmp(const_template, "", 1)) { | 380 if (0 == strncmp(const_template, "", 1)) { |
| 459 path.length = GetTempPathW(MAX_PATH, path.data); | 381 path.Reset(GetTempPathW(MAX_PATH, path.AsStringW())); |
| 460 if (path.length == 0) { | 382 if (path.length() == 0) { |
| 461 return NULL; | 383 return NULL; |
| 462 } | 384 } |
| 463 } else { | 385 } else { |
| 464 const wchar_t* system_template = StringUtils::Utf8ToWide(const_template); | 386 const wchar_t* system_template = StringUtils::Utf8ToWide(const_template); |
| 465 path.Add(system_template); | 387 path.AddW(system_template); |
| 466 free(const_cast<wchar_t*>(system_template)); | 388 free(const_cast<wchar_t*>(system_template)); |
| 467 } | 389 } |
| 468 // Length of tempdir-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 44. | 390 // Length of tempdir-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 44. |
| 469 if (path.length > MAX_PATH - 44) { | 391 if (path.length() > MAX_PATH - 44) { |
| 470 return NULL; | 392 return NULL; |
| 471 } | 393 } |
| 472 if ((path.data)[path.length - 1] == L'\\') { | 394 if ((path.AsStringW())[path.length() - 1] == L'\\') { |
| 473 // No base name for the directory - use "tempdir". | 395 // No base name for the directory - use "tempdir". |
| 474 path.Add(L"tempdir"); | 396 path.AddW(L"tempdir"); |
| 475 } | 397 } |
| 476 | 398 |
| 477 UUID uuid; | 399 UUID uuid; |
| 478 RPC_STATUS status = UuidCreateSequential(&uuid); | 400 RPC_STATUS status = UuidCreateSequential(&uuid); |
| 479 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) { | 401 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) { |
| 480 return NULL; | 402 return NULL; |
| 481 } | 403 } |
| 482 RPC_WSTR uuid_string; | 404 RPC_WSTR uuid_string; |
| 483 status = UuidToStringW(&uuid, &uuid_string); | 405 status = UuidToStringW(&uuid, &uuid_string); |
| 484 if (status != RPC_S_OK) { | 406 if (status != RPC_S_OK) { |
| 485 return NULL; | 407 return NULL; |
| 486 } | 408 } |
| 487 | 409 |
| 488 path.Add(L"-"); | 410 path.AddW(L"-"); |
| 489 // RPC_WSTR is an unsigned short*, so we cast to wchar_t*. | 411 // RPC_WSTR is an unsigned short*, so we cast to wchar_t*. |
| 490 path.Add(reinterpret_cast<wchar_t*>(uuid_string)); | 412 path.AddW(reinterpret_cast<wchar_t*>(uuid_string)); |
| 491 RpcStringFreeW(&uuid_string); | 413 RpcStringFreeW(&uuid_string); |
| 492 if (!CreateDirectoryW(path.data, NULL)) { | 414 if (!CreateDirectoryW(path.AsStringW(), NULL)) { |
| 493 return NULL; | 415 return NULL; |
| 494 } | 416 } |
| 495 char* result = StringUtils::WideToUtf8(path.data); | 417 char* result = path.AsString(); |
| 496 return result; | 418 return result; |
| 497 } | 419 } |
| 498 | 420 |
| 499 | 421 |
| 500 bool Directory::Delete(const char* dir_name, bool recursive) { | 422 bool Directory::Delete(const char* dir_name, bool recursive) { |
| 501 bool result = false; | 423 bool result = false; |
| 502 const wchar_t* system_dir_name = StringUtils::Utf8ToWide(dir_name); | 424 const wchar_t* system_dir_name = StringUtils::Utf8ToWide(dir_name); |
| 503 if (!recursive) { | 425 if (!recursive) { |
| 504 if (File::GetType(dir_name, true) == File::kIsDirectory) { | 426 if (File::GetType(dir_name, true) == File::kIsDirectory) { |
| 505 result = (RemoveDirectoryW(system_dir_name) != 0); | 427 result = (RemoveDirectoryW(system_dir_name) != 0); |
| 506 } else { | 428 } else { |
| 507 SetLastError(ERROR_FILE_NOT_FOUND); | 429 SetLastError(ERROR_FILE_NOT_FOUND); |
| 508 } | 430 } |
| 509 } else { | 431 } else { |
| 510 PathBuffer path; | 432 PathBuffer path; |
| 511 if (path.Add(system_dir_name)) { | 433 if (path.AddW(system_dir_name)) { |
| 512 result = DeleteRecursively(&path); | 434 result = DeleteRecursively(&path); |
| 513 } | 435 } |
| 514 } | 436 } |
| 515 free(const_cast<wchar_t*>(system_dir_name)); | 437 free(const_cast<wchar_t*>(system_dir_name)); |
| 516 return result; | 438 return result; |
| 517 } | 439 } |
| 518 | 440 |
| 519 | 441 |
| 520 bool Directory::Rename(const char* path, const char* new_path) { | 442 bool Directory::Rename(const char* path, const char* new_path) { |
| 521 const wchar_t* system_path = StringUtils::Utf8ToWide(path); | 443 const wchar_t* system_path = StringUtils::Utf8ToWide(path); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 535 MoveFileExW(system_path, system_new_path, flags); | 457 MoveFileExW(system_path, system_new_path, flags); |
| 536 free(const_cast<wchar_t*>(system_path)); | 458 free(const_cast<wchar_t*>(system_path)); |
| 537 free(const_cast<wchar_t*>(system_new_path)); | 459 free(const_cast<wchar_t*>(system_new_path)); |
| 538 return (move_status != 0); | 460 return (move_status != 0); |
| 539 } | 461 } |
| 540 | 462 |
| 541 } // namespace bin | 463 } // namespace bin |
| 542 } // namespace dart | 464 } // namespace dart |
| 543 | 465 |
| 544 #endif // defined(TARGET_OS_WINDOWS) | 466 #endif // defined(TARGET_OS_WINDOWS) |
| OLD | NEW |