| 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 class PathBuffer { | 12 class PathBuffer { |
| 13 public: | 13 public: |
| 14 PathBuffer() : length(0) { } | 14 PathBuffer() : length(0) { |
| 15 data = new wchar_t[MAX_PATH + 1]; |
| 16 } |
| 15 | 17 |
| 16 wchar_t data[MAX_PATH + 1]; | 18 ~PathBuffer() { |
| 19 delete[] data; |
| 20 } |
| 21 |
| 22 wchar_t* data; |
| 17 int length; | 23 int length; |
| 18 | 24 |
| 19 bool Add(const wchar_t* name) { | 25 bool Add(const wchar_t* name) { |
| 20 size_t written = _snwprintf(data + length, | 26 size_t written = _snwprintf(data + length, |
| 21 MAX_PATH - length, | 27 MAX_PATH - length, |
| 22 L"%s", | 28 L"%s", |
| 23 name); | 29 name); |
| 24 data[MAX_PATH] = L'\0'; | 30 data[MAX_PATH] = L'\0'; |
| 25 if (written == wcsnlen(name, MAX_PATH + 1)) { | 31 if (written == wcsnlen(name, MAX_PATH + 1)) { |
| 26 length += written; | 32 length += written; |
| 27 return true; | 33 return true; |
| 28 } else { | 34 } else { |
| 29 SetLastError(ERROR_BUFFER_OVERFLOW); | 35 SetLastError(ERROR_BUFFER_OVERFLOW); |
| 30 return false; | 36 return false; |
| 31 } | 37 } |
| 32 } | 38 } |
| 33 | 39 |
| 34 void Reset(int new_length) { | 40 void Reset(int new_length) { |
| 35 length = new_length; | 41 length = new_length; |
| 36 data[length] = L'\0'; | 42 data[length] = L'\0'; |
| 37 } | 43 } |
| 38 }; | 44 }; |
| 39 | 45 |
| 40 | 46 |
| 41 // Forward declarations. | 47 // Forward declarations. |
| 42 static bool ListRecursively(const wchar_t* dir_name, | 48 static bool ListRecursively(PathBuffer* path, |
| 43 bool recursive, | 49 bool recursive, |
| 44 DirectoryListing* listing); | 50 DirectoryListing* listing); |
| 45 static bool DeleteRecursively(const wchar_t* dir_name); | 51 static bool DeleteRecursively(PathBuffer* path); |
| 46 | 52 |
| 47 | 53 |
| 48 static void PostError(DirectoryListing* listing, | 54 static void PostError(DirectoryListing* listing, |
| 49 const wchar_t* dir_name) { | 55 const wchar_t* dir_name) { |
| 50 const char* utf8_path = StringUtils::WideToUtf8(dir_name); | 56 const char* utf8_path = StringUtils::WideToUtf8(dir_name); |
| 51 listing->HandleError(utf8_path); | 57 listing->HandleError(utf8_path); |
| 52 free(const_cast<char*>(utf8_path)); | 58 free(const_cast<char*>(utf8_path)); |
| 53 } | 59 } |
| 54 | 60 |
| 55 | 61 |
| 56 static bool HandleDir(wchar_t* dir_name, | 62 static bool HandleDir(wchar_t* dir_name, |
| 57 PathBuffer* path, | 63 PathBuffer* path, |
| 58 bool recursive, | 64 bool recursive, |
| 59 DirectoryListing* listing) { | 65 DirectoryListing* listing) { |
| 60 if (wcscmp(dir_name, L".") == 0) return true; | 66 if (wcscmp(dir_name, L".") == 0) return true; |
| 61 if (wcscmp(dir_name, L"..") == 0) return true; | 67 if (wcscmp(dir_name, L"..") == 0) return true; |
| 62 if (!path->Add(dir_name)) { | 68 if (!path->Add(dir_name)) { |
| 63 PostError(listing, path->data); | 69 PostError(listing, path->data); |
| 64 return false; | 70 return false; |
| 65 } | 71 } |
| 66 char* utf8_path = StringUtils::WideToUtf8(path->data); | 72 char* utf8_path = StringUtils::WideToUtf8(path->data); |
| 67 bool ok = listing->HandleDirectory(utf8_path); | 73 bool ok = listing->HandleDirectory(utf8_path); |
| 68 free(utf8_path); | 74 free(utf8_path); |
| 69 return ok && (!recursive || ListRecursively(path->data, recursive, listing)); | 75 return ok && (!recursive || ListRecursively(path, recursive, listing)); |
| 70 } | 76 } |
| 71 | 77 |
| 72 | 78 |
| 73 static bool HandleFile(wchar_t* file_name, | 79 static bool HandleFile(wchar_t* file_name, |
| 74 PathBuffer* path, | 80 PathBuffer* path, |
| 75 DirectoryListing* listing) { | 81 DirectoryListing* listing) { |
| 76 if (!path->Add(file_name)) { | 82 if (!path->Add(file_name)) { |
| 77 PostError(listing, path->data); | 83 PostError(listing, path->data); |
| 78 return false; | 84 return false; |
| 79 } | 85 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 93 return HandleDir(find_file_data->cFileName, | 99 return HandleDir(find_file_data->cFileName, |
| 94 path, | 100 path, |
| 95 recursive, | 101 recursive, |
| 96 listing); | 102 listing); |
| 97 } else { | 103 } else { |
| 98 return HandleFile(find_file_data->cFileName, path, listing); | 104 return HandleFile(find_file_data->cFileName, path, listing); |
| 99 } | 105 } |
| 100 } | 106 } |
| 101 | 107 |
| 102 | 108 |
| 103 static PathBuffer* ComputeFullSearchPath(const wchar_t* dir_name) { | 109 static bool ListRecursively(PathBuffer* path, |
| 104 // GetFullPathName only works in a multi-threaded environment if | |
| 105 // SetCurrentDirectory is not used. We currently have no plan for | |
| 106 // exposing SetCurrentDirectory. | |
| 107 PathBuffer* path = new PathBuffer(); | |
| 108 | |
| 109 size_t written = GetFullPathNameW(dir_name, MAX_PATH + 1, path->data, NULL); | |
| 110 // GetFullPathName only accepts input strings of size less than | |
| 111 // MAX_PATH and returns 0 to indicate failure for paths longer than | |
| 112 // that. Therefore the path buffer is always big enough. | |
| 113 if (written == 0 || written > MAX_PATH) { | |
| 114 delete path; | |
| 115 return NULL; | |
| 116 } | |
| 117 path->length = written; | |
| 118 if (path->Add(L"\\*")) { | |
| 119 return path; | |
| 120 } else { | |
| 121 delete path; | |
| 122 return NULL; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 | |
| 127 static bool ListRecursively(const wchar_t* dir_name, | |
| 128 bool recursive, | 110 bool recursive, |
| 129 DirectoryListing* listing) { | 111 DirectoryListing* listing) { |
| 130 // Compute full path for the directory currently being listed. The | 112 if (!path->Add(L"\\*")) { |
| 131 // path buffer will be used to construct the current path in the | 113 PostError(listing, path->data); |
| 132 // recursive traversal. path_length does not always equal | |
| 133 // strlen(path) but indicates the current prefix of path that is the | |
| 134 // path of the current directory in the traversal. | |
| 135 PathBuffer* path = ComputeFullSearchPath(dir_name); | |
| 136 if (path == NULL) { | |
| 137 PostError(listing, dir_name); | |
| 138 delete path; | |
| 139 return false; | 114 return false; |
| 140 } | 115 } |
| 141 | 116 |
| 142 WIN32_FIND_DATAW find_file_data; | 117 WIN32_FIND_DATAW find_file_data; |
| 143 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); | 118 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); |
| 144 | 119 |
| 145 // Adjust the path by removing the '*' used for the search. | 120 // Adjust the path by removing the '*' used for the search. |
| 146 path->Reset(path->length - 1); | 121 path->Reset(path->length - 1); |
| 147 | 122 |
| 148 if (find_handle == INVALID_HANDLE_VALUE) { | 123 if (find_handle == INVALID_HANDLE_VALUE) { |
| 149 PostError(listing, path->data); | 124 PostError(listing, path->data); |
| 150 delete path; | |
| 151 return false; | 125 return false; |
| 152 } | 126 } |
| 153 | 127 |
| 154 int path_length = path->length; | 128 int path_length = path->length; |
| 155 bool success = HandleEntry(&find_file_data, | 129 bool success = HandleEntry(&find_file_data, |
| 156 path, | 130 path, |
| 157 recursive, | 131 recursive, |
| 158 listing); | 132 listing); |
| 159 | 133 |
| 160 while ((FindNextFileW(find_handle, &find_file_data) != 0)) { | 134 while ((FindNextFileW(find_handle, &find_file_data) != 0)) { |
| 161 path->Reset(path_length); // HandleEntry adds the entry name to path. | 135 path->Reset(path_length); // HandleEntry adds the entry name to path. |
| 162 success = HandleEntry(&find_file_data, | 136 success = HandleEntry(&find_file_data, |
| 163 path, | 137 path, |
| 164 recursive, | 138 recursive, |
| 165 listing) && success; | 139 listing) && success; |
| 166 } | 140 } |
| 167 | 141 |
| 168 if (GetLastError() != ERROR_NO_MORE_FILES) { | 142 if (GetLastError() != ERROR_NO_MORE_FILES) { |
| 169 success = false; | 143 success = false; |
| 170 PostError(listing, dir_name); | 144 PostError(listing, path->data); |
| 171 } | 145 } |
| 172 | 146 |
| 173 if (FindClose(find_handle) == 0) { | 147 if (FindClose(find_handle) == 0) { |
| 174 success = false; | 148 success = false; |
| 175 PostError(listing, dir_name); | 149 PostError(listing, path->data); |
| 176 } | 150 } |
| 177 delete path; | |
| 178 | 151 |
| 179 return success; | 152 return success; |
| 180 } | 153 } |
| 181 | 154 |
| 182 | 155 |
| 183 static bool DeleteFile(wchar_t* file_name, PathBuffer* path) { | 156 static bool DeleteFile(wchar_t* file_name, PathBuffer* path) { |
| 184 if (!path->Add(file_name)) return false; | 157 if (!path->Add(file_name)) return false; |
| 185 | 158 |
| 186 if (DeleteFileW(path->data) != 0) { | 159 if (DeleteFileW(path->data) != 0) { |
| 187 return true; | 160 return true; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 207 } | 180 } |
| 208 } | 181 } |
| 209 | 182 |
| 210 return false; | 183 return false; |
| 211 } | 184 } |
| 212 | 185 |
| 213 | 186 |
| 214 static bool DeleteDir(wchar_t* dir_name, PathBuffer* path) { | 187 static bool DeleteDir(wchar_t* dir_name, PathBuffer* path) { |
| 215 if (wcscmp(dir_name, L".") == 0) return true; | 188 if (wcscmp(dir_name, L".") == 0) return true; |
| 216 if (wcscmp(dir_name, L"..") == 0) return true; | 189 if (wcscmp(dir_name, L"..") == 0) return true; |
| 217 return path->Add(dir_name) && DeleteRecursively(path->data); | 190 return path->Add(dir_name) && DeleteRecursively(path); |
| 218 } | 191 } |
| 219 | 192 |
| 220 | 193 |
| 221 static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data, PathBuffer* path) { | 194 static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data, PathBuffer* path) { |
| 222 DWORD attributes = find_file_data->dwFileAttributes; | 195 DWORD attributes = find_file_data->dwFileAttributes; |
| 223 | 196 |
| 224 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { | 197 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 225 return DeleteDir(find_file_data->cFileName, path); | 198 return DeleteDir(find_file_data->cFileName, path); |
| 226 } else { | 199 } else { |
| 227 return DeleteFile(find_file_data->cFileName, path); | 200 return DeleteFile(find_file_data->cFileName, path); |
| 228 } | 201 } |
| 229 } | 202 } |
| 230 | 203 |
| 231 | 204 |
| 232 static bool DeleteRecursively(const wchar_t* dir_name) { | 205 static bool DeleteRecursively(PathBuffer* path) { |
| 233 // If the directory is a junction, it's pointing to some other place in the | 206 // If the directory is a junction, it's pointing to some other place in the |
| 234 // filesystem that we do not want to recurse into. | 207 // filesystem that we do not want to recurse into. |
| 235 DWORD attributes = GetFileAttributesW(dir_name); | 208 DWORD attributes = GetFileAttributesW(path->data); |
| 236 if ((attributes != INVALID_FILE_ATTRIBUTES) && | 209 if ((attributes != INVALID_FILE_ATTRIBUTES) && |
| 237 (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { | 210 (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { |
| 238 // Just delete the junction itself. | 211 // Just delete the junction itself. |
| 239 return RemoveDirectoryW(dir_name) != 0; | 212 return RemoveDirectoryW(path->data) != 0; |
| 240 } | 213 } |
| 241 | 214 |
| 242 // Compute full path for the directory currently being deleted. The | 215 if (!path->Add(L"\\*")) return false; |
| 243 // path buffer will be used to construct the current path in the | |
| 244 // recursive traversal. path_length does not always equal | |
| 245 // strlen(path) but indicates the current prefix of path that is the | |
| 246 // path of the current directory in the traversal. | |
| 247 PathBuffer* path = ComputeFullSearchPath(dir_name); | |
| 248 if (path == NULL) return false; | |
| 249 | 216 |
| 250 WIN32_FIND_DATAW find_file_data; | 217 WIN32_FIND_DATAW find_file_data; |
| 251 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); | 218 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); |
| 252 | 219 |
| 253 // Adjust the path by removing the '*' used for the search. | 220 // Adjust the path by removing the '*' used for the search. |
| 254 int path_length = path->length - 1; | 221 int path_length = path->length - 1; |
| 255 path->Reset(path_length); | 222 path->Reset(path_length); |
| 256 | 223 |
| 257 if (find_handle == INVALID_HANDLE_VALUE) { | 224 if (find_handle == INVALID_HANDLE_VALUE) { |
| 258 delete path; | |
| 259 return false; | 225 return false; |
| 260 } | 226 } |
| 261 | 227 |
| 262 bool success = DeleteEntry(&find_file_data, path); | 228 bool success = DeleteEntry(&find_file_data, path); |
| 263 | 229 |
| 264 while ((FindNextFileW(find_handle, &find_file_data) != 0) && success) { | 230 while ((FindNextFileW(find_handle, &find_file_data) != 0) && success) { |
| 265 path->Reset(path_length); // DeleteEntry adds to the path. | 231 path->Reset(path_length); // DeleteEntry adds to the path. |
| 266 success = success && DeleteEntry(&find_file_data, path); | 232 success = success && DeleteEntry(&find_file_data, path); |
| 267 } | 233 } |
| 268 | 234 |
| 269 delete path; | 235 path->Reset(path_length - 1); // Drop the "\" from the end of the path. |
| 270 | |
| 271 if ((GetLastError() != ERROR_NO_MORE_FILES) || | 236 if ((GetLastError() != ERROR_NO_MORE_FILES) || |
| 272 (FindClose(find_handle) == 0) || | 237 (FindClose(find_handle) == 0) || |
| 273 (RemoveDirectoryW(dir_name) == 0)) { | 238 (RemoveDirectoryW(path->data) == 0)) { |
| 274 return false; | 239 return false; |
| 275 } | 240 } |
| 276 | 241 |
| 277 return success; | 242 return success; |
| 278 } | 243 } |
| 279 | 244 |
| 280 | 245 |
| 281 bool Directory::List(const char* dir_name, | 246 bool Directory::List(const char* dir_name, |
| 282 bool recursive, | 247 bool recursive, |
| 283 DirectoryListing* listing) { | 248 DirectoryListing* listing) { |
| 284 const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name); | 249 const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name); |
| 285 bool completed = ListRecursively(system_name, recursive, listing); | 250 PathBuffer path; |
| 251 if (!path.Add(system_name)) { |
| 252 PostError(listing, system_name); |
| 253 return false; |
| 254 } |
| 286 free(const_cast<wchar_t*>(system_name)); | 255 free(const_cast<wchar_t*>(system_name)); |
| 287 return completed; | 256 return ListRecursively(&path, recursive, listing); |
| 288 } | 257 } |
| 289 | 258 |
| 290 | 259 |
| 291 static Directory::ExistsResult ExistsHelper(const wchar_t* dir_name) { | 260 static Directory::ExistsResult ExistsHelper(const wchar_t* dir_name) { |
| 292 DWORD attributes = GetFileAttributesW(dir_name); | 261 DWORD attributes = GetFileAttributesW(dir_name); |
| 293 if (attributes == INVALID_FILE_ATTRIBUTES) { | 262 if (attributes == INVALID_FILE_ATTRIBUTES) { |
| 294 DWORD last_error = GetLastError(); | 263 DWORD last_error = GetLastError(); |
| 295 if (last_error == ERROR_FILE_NOT_FOUND || | 264 if (last_error == ERROR_FILE_NOT_FOUND || |
| 296 last_error == ERROR_PATH_NOT_FOUND) { | 265 last_error == ERROR_PATH_NOT_FOUND) { |
| 297 return Directory::DOES_NOT_EXIST; | 266 return Directory::DOES_NOT_EXIST; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 free(const_cast<wchar_t*>(system_name)); | 307 free(const_cast<wchar_t*>(system_name)); |
| 339 return (create_status != 0); | 308 return (create_status != 0); |
| 340 } | 309 } |
| 341 | 310 |
| 342 | 311 |
| 343 char* Directory::CreateTemp(const char* const_template) { | 312 char* Directory::CreateTemp(const char* const_template) { |
| 344 // Returns a new, unused directory name, modifying the contents of | 313 // Returns a new, unused directory name, modifying the contents of |
| 345 // dir_template. Creates this directory, with a default security | 314 // dir_template. Creates this directory, with a default security |
| 346 // descriptor inherited from its parent directory. | 315 // descriptor inherited from its parent directory. |
| 347 // The return value must be freed by the caller. | 316 // The return value must be freed by the caller. |
| 348 PathBuffer* path = new PathBuffer(); | 317 PathBuffer path; |
| 349 if (0 == strncmp(const_template, "", 1)) { | 318 if (0 == strncmp(const_template, "", 1)) { |
| 350 path->length = GetTempPathW(MAX_PATH, path->data); | 319 path.length = GetTempPathW(MAX_PATH, path.data); |
| 351 if (path->length == 0) { | 320 if (path.length == 0) { |
| 352 delete path; | |
| 353 return NULL; | 321 return NULL; |
| 354 } | 322 } |
| 355 } else { | 323 } else { |
| 356 const wchar_t* system_template = StringUtils::Utf8ToWide(const_template); | 324 const wchar_t* system_template = StringUtils::Utf8ToWide(const_template); |
| 357 path->Add(system_template); | 325 path.Add(system_template); |
| 358 free(const_cast<wchar_t*>(system_template)); | 326 free(const_cast<wchar_t*>(system_template)); |
| 359 } | 327 } |
| 360 // Length of tempdir-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 44. | 328 // Length of tempdir-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 44. |
| 361 if (path->length > MAX_PATH - 44) { | 329 if (path.length > MAX_PATH - 44) { |
| 362 delete path; | |
| 363 return NULL; | 330 return NULL; |
| 364 } | 331 } |
| 365 if ((path->data)[path->length - 1] == L'\\') { | 332 if ((path.data)[path.length - 1] == L'\\') { |
| 366 // No base name for the directory - use "tempdir". | 333 // No base name for the directory - use "tempdir". |
| 367 path->Add(L"tempdir"); | 334 path.Add(L"tempdir"); |
| 368 } | 335 } |
| 369 | 336 |
| 370 UUID uuid; | 337 UUID uuid; |
| 371 RPC_STATUS status = UuidCreateSequential(&uuid); | 338 RPC_STATUS status = UuidCreateSequential(&uuid); |
| 372 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) { | 339 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) { |
| 373 delete path; | |
| 374 return NULL; | 340 return NULL; |
| 375 } | 341 } |
| 376 RPC_WSTR uuid_string; | 342 RPC_WSTR uuid_string; |
| 377 status = UuidToStringW(&uuid, &uuid_string); | 343 status = UuidToStringW(&uuid, &uuid_string); |
| 378 if (status != RPC_S_OK) { | 344 if (status != RPC_S_OK) { |
| 379 delete path; | |
| 380 return NULL; | 345 return NULL; |
| 381 } | 346 } |
| 382 | 347 |
| 383 path->Add(L"-"); | 348 path.Add(L"-"); |
| 384 // RPC_WSTR is an unsigned short*, so we cast to wchar_t*. | 349 // RPC_WSTR is an unsigned short*, so we cast to wchar_t*. |
| 385 path->Add(reinterpret_cast<wchar_t*>(uuid_string)); | 350 path.Add(reinterpret_cast<wchar_t*>(uuid_string)); |
| 386 RpcStringFreeW(&uuid_string); | 351 RpcStringFreeW(&uuid_string); |
| 387 if (!CreateDirectoryW(path->data, NULL)) { | 352 if (!CreateDirectoryW(path.data, NULL)) { |
| 388 delete path; | |
| 389 return NULL; | 353 return NULL; |
| 390 } | 354 } |
| 391 char* result = StringUtils::WideToUtf8(path->data); | 355 char* result = StringUtils::WideToUtf8(path.data); |
| 392 delete path; | |
| 393 return result; | 356 return result; |
| 394 } | 357 } |
| 395 | 358 |
| 396 | 359 |
| 397 bool Directory::Delete(const char* dir_name, bool recursive) { | 360 bool Directory::Delete(const char* dir_name, bool recursive) { |
| 398 bool result = false; | 361 bool result = false; |
| 399 const wchar_t* system_dir_name = StringUtils::Utf8ToWide(dir_name); | 362 const wchar_t* system_dir_name = StringUtils::Utf8ToWide(dir_name); |
| 400 if (!recursive) { | 363 if (!recursive) { |
| 401 result = (RemoveDirectoryW(system_dir_name) != 0); | 364 result = (RemoveDirectoryW(system_dir_name) != 0); |
| 402 } else { | 365 } else { |
| 403 result = DeleteRecursively(system_dir_name); | 366 PathBuffer path; |
| 367 if (!path.Add(system_dir_name)) { |
| 368 return false; |
| 369 } |
| 370 result = DeleteRecursively(&path); |
| 404 } | 371 } |
| 405 free(const_cast<wchar_t*>(system_dir_name)); | 372 free(const_cast<wchar_t*>(system_dir_name)); |
| 406 return result; | 373 return result; |
| 407 } | 374 } |
| 408 | 375 |
| 409 | 376 |
| 410 bool Directory::Rename(const char* path, const char* new_path) { | 377 bool Directory::Rename(const char* path, const char* new_path) { |
| 411 const wchar_t* system_path = StringUtils::Utf8ToWide(path); | 378 const wchar_t* system_path = StringUtils::Utf8ToWide(path); |
| 412 const wchar_t* system_new_path = StringUtils::Utf8ToWide(new_path); | 379 const wchar_t* system_new_path = StringUtils::Utf8ToWide(new_path); |
| 413 ExistsResult exists = ExistsHelper(system_path); | 380 ExistsResult exists = ExistsHelper(system_path); |
| 414 if (exists != EXISTS) return false; | 381 if (exists != EXISTS) return false; |
| 415 ExistsResult new_exists = ExistsHelper(system_new_path); | 382 ExistsResult new_exists = ExistsHelper(system_new_path); |
| 416 // MoveFile does not allow replacing exising directories. Therefore, | 383 // MoveFile does not allow replacing exising directories. Therefore, |
| 417 // if the new_path is currently a directory we need to delete it | 384 // if the new_path is currently a directory we need to delete it |
| 418 // first. | 385 // first. |
| 419 if (new_exists == EXISTS) { | 386 if (new_exists == EXISTS) { |
| 420 bool success = DeleteRecursively(system_new_path); | 387 bool success = Delete(new_path, true); |
| 421 if (!success) return false; | 388 if (!success) return false; |
| 422 } | 389 } |
| 423 DWORD flags = MOVEFILE_WRITE_THROUGH; | 390 DWORD flags = MOVEFILE_WRITE_THROUGH; |
| 424 int move_status = | 391 int move_status = |
| 425 MoveFileExW(system_path, system_new_path, flags); | 392 MoveFileExW(system_path, system_new_path, flags); |
| 426 free(const_cast<wchar_t*>(system_path)); | 393 free(const_cast<wchar_t*>(system_path)); |
| 427 free(const_cast<wchar_t*>(system_new_path)); | 394 free(const_cast<wchar_t*>(system_new_path)); |
| 428 return (move_status != 0); | 395 return (move_status != 0); |
| 429 } | 396 } |
| OLD | NEW |