Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(258)

Side by Side Diff: runtime/bin/directory_android.cc

Issue 1781883002: Fixes some memory leaks in //runtime/bin (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Cleanup Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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_ANDROID) 6 #if defined(TARGET_OS_ANDROID)
7 7
8 #include "bin/directory.h" 8 #include "bin/directory.h"
9 9
10 #include <dirent.h> // NOLINT 10 #include <dirent.h> // NOLINT
11 #include <errno.h> // NOLINT 11 #include <errno.h> // NOLINT
12 #include <string.h> // NOLINT 12 #include <string.h> // NOLINT
13 #include <sys/param.h> // NOLINT 13 #include <sys/param.h> // NOLINT
14 #include <sys/stat.h> // NOLINT 14 #include <sys/stat.h> // NOLINT
15 #include <unistd.h> // NOLINT 15 #include <unistd.h> // NOLINT
16 16
17 #include "bin/dartutils.h"
17 #include "bin/file.h" 18 #include "bin/file.h"
18 #include "bin/platform.h" 19 #include "bin/platform.h"
19
20 #include "platform/signal_blocker.h" 20 #include "platform/signal_blocker.h"
21 21
22
23 namespace dart { 22 namespace dart {
24 namespace bin { 23 namespace bin {
25 24
25 PathBuffer::PathBuffer() : length_(0) {
26 data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT
Ivan Posva 2016/03/13 20:59:19 Please add a comment where this is being free'd.
zra 2016/03/14 18:07:52 Moved the destructor from the header file into the
27 }
26 28
27 PathBuffer::PathBuffer() : length_(0) {
28 data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT
29 }
30 29
31 bool PathBuffer::AddW(const wchar_t* name) { 30 bool PathBuffer::AddW(const wchar_t* name) {
32 UNREACHABLE(); 31 UNREACHABLE();
33 return false; 32 return false;
34 } 33 }
35 34
35
36 char* PathBuffer::AsString() const { 36 char* PathBuffer::AsString() const {
37 return reinterpret_cast<char*>(data_); 37 return reinterpret_cast<char*>(data_);
38 } 38 }
39 39
40
40 wchar_t* PathBuffer::AsStringW() const { 41 wchar_t* PathBuffer::AsStringW() const {
41 UNREACHABLE(); 42 UNREACHABLE();
42 return NULL; 43 return NULL;
43 } 44 }
44 45
46
47 const char* PathBuffer::AsScopedString() const {
48 return DartUtils::ScopedCopyCString(AsString());
49 }
50
51
45 bool PathBuffer::Add(const char* name) { 52 bool PathBuffer::Add(const char* name) {
46 char* data = AsString(); 53 char* data = AsString();
47 int written = snprintf(data + length_, 54 int written = snprintf(data + length_,
48 PATH_MAX - length_, 55 PATH_MAX - length_,
49 "%s", 56 "%s",
50 name); 57 name);
51 data[PATH_MAX] = '\0'; 58 data[PATH_MAX] = '\0';
52 if (written <= PATH_MAX - length_ && 59 if ((written <= PATH_MAX - length_) &&
53 written >= 0 && 60 (written >= 0) &&
54 static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1)) { 61 (static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1))) {
55 length_ += written; 62 length_ += written;
56 return true; 63 return true;
57 } else { 64 } else {
58 errno = ENAMETOOLONG; 65 errno = ENAMETOOLONG;
59 return false; 66 return false;
60 } 67 }
61 } 68 }
62 69
63 void PathBuffer::Reset(int new_length) { 70
71 void PathBuffer::Reset(intptr_t new_length) {
64 length_ = new_length; 72 length_ = new_length;
65 AsString()[length_] = '\0'; 73 AsString()[length_] = '\0';
66 } 74 }
67 75
68 76
69 // A linked list of symbolic links, with their unique file system identifiers. 77 // A linked list of symbolic links, with their unique file system identifiers.
70 // These are scanned to detect loops while doing a recursive directory listing. 78 // These are scanned to detect loops while doing a recursive directory listing.
71 struct LinkList { 79 struct LinkList {
72 dev_t dev; 80 dev_t dev;
73 ino_t ino; 81 ino_t ino;
74 LinkList* next; 82 LinkList* next;
75 }; 83 };
76 84
77 85
78 ListType DirectoryListingEntry::Next(DirectoryListing* listing) { 86 ListType DirectoryListingEntry::Next(DirectoryListing* listing) {
79 if (done_) { 87 if (done_) {
80 return kListDone; 88 return kListDone;
81 } 89 }
82 90
83 if (lister_ == 0) { 91 if (lister_ == 0) {
84 do { 92 do {
85 lister_ = reinterpret_cast<intptr_t>( 93 lister_ = reinterpret_cast<intptr_t>(
86 opendir(listing->path_buffer().AsString())); 94 opendir(listing->path_buffer().AsString()));
87 } while (lister_ == 0 && errno == EINTR); 95 } while ((lister_ == 0) && (errno == EINTR));
88 96
89 if (lister_ == 0) { 97 if (lister_ == 0) {
90 done_ = true; 98 done_ = true;
91 return kListError; 99 return kListError;
92 } 100 }
93 if (parent_ != NULL) { 101 if (parent_ != NULL) {
94 if (!listing->path_buffer().Add(File::PathSeparator())) { 102 if (!listing->path_buffer().Add(File::PathSeparator())) {
95 return kListError; 103 return kListError;
96 } 104 }
97 } 105 }
98 path_length_ = listing->path_buffer().length(); 106 path_length_ = listing->path_buffer().length();
99 } 107 }
100 // Reset. 108 // Reset.
101 listing->path_buffer().Reset(path_length_); 109 listing->path_buffer().Reset(path_length_);
102 ResetLink(); 110 ResetLink();
103 111
104 // Iterate the directory and post the directories and files to the 112 // Iterate the directory and post the directories and files to the
105 // ports. 113 // ports.
106 int status = 0; 114 int status = 0;
107 dirent entry; 115 dirent entry;
108 dirent* result; 116 dirent* result;
109 if ((status = NO_RETRY_EXPECTED(readdir_r(reinterpret_cast<DIR*>(lister_), 117 status = NO_RETRY_EXPECTED(readdir_r(
110 &entry, 118 reinterpret_cast<DIR*>(lister_), &entry, &result));
111 &result))) == 0 && 119 if ((status == 0) && (result != NULL)) {
112 result != NULL) {
113 if (!listing->path_buffer().Add(entry.d_name)) { 120 if (!listing->path_buffer().Add(entry.d_name)) {
114 done_ = true; 121 done_ = true;
115 return kListError; 122 return kListError;
116 } 123 }
117 switch (entry.d_type) { 124 switch (entry.d_type) {
118 case DT_DIR: 125 case DT_DIR:
119 if (strcmp(entry.d_name, ".") == 0) return Next(listing); 126 if ((strcmp(entry.d_name, ".") == 0) ||
120 if (strcmp(entry.d_name, "..") == 0) return Next(listing); 127 (strcmp(entry.d_name, "..") == 0)) {
128 return Next(listing);
129 }
121 return kListDirectory; 130 return kListDirectory;
122 case DT_REG: 131 case DT_REG:
123 return kListFile; 132 return kListFile;
124 case DT_LNK: 133 case DT_LNK:
125 if (!listing->follow_links()) { 134 if (!listing->follow_links()) {
126 return kListLink; 135 return kListLink;
127 } 136 }
128 // Else fall through to next case. 137 // Else fall through to next case.
129 // Fall through. 138 // Fall through.
130 case DT_UNKNOWN: { 139 case DT_UNKNOWN: {
131 // On some file systems the entry type is not determined by 140 // On some file systems the entry type is not determined by
132 // readdir_r. For those and for links we use stat to determine 141 // readdir_r. For those and for links we use stat to determine
133 // the actual entry type. Notice that stat returns the type of 142 // the actual entry type. Notice that stat returns the type of
134 // the file pointed to. 143 // the file pointed to.
135 struct stat entry_info; 144 struct stat entry_info;
136 int stat_success; 145 int stat_success;
137 stat_success = NO_RETRY_EXPECTED( 146 stat_success = NO_RETRY_EXPECTED(
138 lstat(listing->path_buffer().AsString(), &entry_info)); 147 lstat(listing->path_buffer().AsString(), &entry_info));
139 if (stat_success == -1) { 148 if (stat_success == -1) {
140 return kListError; 149 return kListError;
141 } 150 }
142 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) { 151 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) {
143 // Check to see if we are in a loop created by a symbolic link. 152 // Check to see if we are in a loop created by a symbolic link.
144 LinkList current_link = { entry_info.st_dev, 153 LinkList current_link = { entry_info.st_dev,
145 entry_info.st_ino, 154 entry_info.st_ino,
146 link_ }; 155 link_ };
147 LinkList* previous = link_; 156 LinkList* previous = link_;
148 while (previous != NULL) { 157 while (previous != NULL) {
149 if (previous->dev == current_link.dev && 158 if ((previous->dev == current_link.dev) &&
150 previous->ino == current_link.ino) { 159 (previous->ino == current_link.ino)) {
151 // Report the looping link as a link, rather than following it. 160 // Report the looping link as a link, rather than following it.
152 return kListLink; 161 return kListLink;
153 } 162 }
154 previous = previous->next; 163 previous = previous->next;
155 } 164 }
156 stat_success = NO_RETRY_EXPECTED( 165 stat_success = NO_RETRY_EXPECTED(
157 stat(listing->path_buffer().AsString(), &entry_info)); 166 stat(listing->path_buffer().AsString(), &entry_info));
158 if (stat_success == -1) { 167 if (stat_success == -1) {
159 // Report a broken link as a link, even if follow_links is true. 168 // Report a broken link as a link, even if follow_links is true.
160 return kListLink; 169 return kListLink;
161 } 170 }
162 if (S_ISDIR(entry_info.st_mode)) { 171 if (S_ISDIR(entry_info.st_mode)) {
163 // Recurse into the subdirectory with current_link added to the 172 // Recurse into the subdirectory with current_link added to the
164 // linked list of seen file system links. 173 // linked list of seen file system links.
165 link_ = new LinkList(current_link); 174 link_ = new LinkList(current_link);
166 if (strcmp(entry.d_name, ".") == 0) return Next(listing); 175 if ((strcmp(entry.d_name, ".") == 0) ||
167 if (strcmp(entry.d_name, "..") == 0) return Next(listing); 176 (strcmp(entry.d_name, "..") == 0)) {
177 return Next(listing);
178 }
168 return kListDirectory; 179 return kListDirectory;
169 } 180 }
170 } 181 }
171 if (S_ISDIR(entry_info.st_mode)) { 182 if (S_ISDIR(entry_info.st_mode)) {
172 if (strcmp(entry.d_name, ".") == 0) return Next(listing); 183 if ((strcmp(entry.d_name, ".") == 0) ||
173 if (strcmp(entry.d_name, "..") == 0) return Next(listing); 184 (strcmp(entry.d_name, "..") == 0)) {
185 return Next(listing);
186 }
174 return kListDirectory; 187 return kListDirectory;
175 } else if (S_ISREG(entry_info.st_mode)) { 188 } else if (S_ISREG(entry_info.st_mode)) {
176 return kListFile; 189 return kListFile;
177 } else if (S_ISLNK(entry_info.st_mode)) { 190 } else if (S_ISLNK(entry_info.st_mode)) {
178 return kListLink; 191 return kListLink;
179 } 192 }
180 } 193 }
181 194
182 default: 195 default:
183 break; 196 break;
(...skipping 12 matching lines...) Expand all
196 209
197 DirectoryListingEntry::~DirectoryListingEntry() { 210 DirectoryListingEntry::~DirectoryListingEntry() {
198 ResetLink(); 211 ResetLink();
199 if (lister_ != 0) { 212 if (lister_ != 0) {
200 closedir(reinterpret_cast<DIR*>(lister_)); 213 closedir(reinterpret_cast<DIR*>(lister_));
201 } 214 }
202 } 215 }
203 216
204 217
205 void DirectoryListingEntry::ResetLink() { 218 void DirectoryListingEntry::ResetLink() {
206 if (link_ != NULL && (parent_ == NULL || parent_->link_ != link_)) { 219 if ((link_ != NULL) && ((parent_ == NULL) || (parent_->link_ != link_))) {
207 delete link_; 220 delete link_;
208 link_ = NULL; 221 link_ = NULL;
209 } 222 }
210 if (parent_ != NULL) { 223 if (parent_ != NULL) {
211 link_ = parent_->link_; 224 link_ = parent_->link_;
212 } 225 }
213 } 226 }
214 227
215 228
216 static bool DeleteRecursively(PathBuffer* path); 229 static bool DeleteRecursively(PathBuffer* path);
217 230
218 231
219 static bool DeleteFile(char* file_name, 232 static bool DeleteFile(char* file_name,
220 PathBuffer* path) { 233 PathBuffer* path) {
221 return path->Add(file_name) && unlink(path->AsString()) == 0; 234 return path->Add(file_name) && (unlink(path->AsString()) == 0);
222 } 235 }
223 236
224 237
225 static bool DeleteDir(char* dir_name, 238 static bool DeleteDir(char* dir_name,
226 PathBuffer* path) { 239 PathBuffer* path) {
227 if (strcmp(dir_name, ".") == 0) return true; 240 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) {
228 if (strcmp(dir_name, "..") == 0) return true; 241 return true;
242 }
229 return path->Add(dir_name) && DeleteRecursively(path); 243 return path->Add(dir_name) && DeleteRecursively(path);
230 } 244 }
231 245
232 246
233 static bool DeleteRecursively(PathBuffer* path) { 247 static bool DeleteRecursively(PathBuffer* path) {
234 // Do not recurse into links for deletion. Instead delete the link. 248 // Do not recurse into links for deletion. Instead delete the link.
235 // If it's a file, delete it. 249 // If it's a file, delete it.
236 struct stat st; 250 struct stat st;
237 if (NO_RETRY_EXPECTED(lstat(path->AsString(), &st)) == -1) { 251 if (NO_RETRY_EXPECTED(lstat(path->AsString(), &st)) == -1) {
238 return false; 252 return false;
239 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { 253 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
240 return (unlink(path->AsString()) == 0); 254 return (unlink(path->AsString()) == 0);
241 } 255 }
242 256
243 if (!path->Add(File::PathSeparator())) return false; 257 if (!path->Add(File::PathSeparator())) {
258 return false;
259 }
244 260
245 // Not a link. Attempt to open as a directory and recurse into the 261 // Not a link. Attempt to open as a directory and recurse into the
246 // directory. 262 // directory.
247 DIR* dir_pointer; 263 DIR* dir_pointer;
248 do { 264 do {
249 dir_pointer = opendir(path->AsString()); 265 dir_pointer = opendir(path->AsString());
250 } while (dir_pointer == NULL && errno == EINTR); 266 } while ((dir_pointer == NULL) && (errno == EINTR));
251 if (dir_pointer == NULL) { 267 if (dir_pointer == NULL) {
252 return false; 268 return false;
253 } 269 }
254 270
255 // Iterate the directory and delete all files and directories. 271 // Iterate the directory and delete all files and directories.
256 int path_length = path->length(); 272 int path_length = path->length();
257 dirent entry; 273 dirent entry;
258 dirent* result; 274 dirent* result;
259 while (NO_RETRY_EXPECTED(readdir_r(dir_pointer, &entry, &result)) == 0) { 275 while (NO_RETRY_EXPECTED(readdir_r(dir_pointer, &entry, &result)) == 0) {
260 if (result == NULL) { 276 if (result == NULL) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 Directory::ExistsResult Directory::Exists(const char* dir_name) { 332 Directory::ExistsResult Directory::Exists(const char* dir_name) {
317 struct stat entry_info; 333 struct stat entry_info;
318 int success = NO_RETRY_EXPECTED(stat(dir_name, &entry_info)); 334 int success = NO_RETRY_EXPECTED(stat(dir_name, &entry_info));
319 if (success == 0) { 335 if (success == 0) {
320 if (S_ISDIR(entry_info.st_mode)) { 336 if (S_ISDIR(entry_info.st_mode)) {
321 return EXISTS; 337 return EXISTS;
322 } else { 338 } else {
323 return DOES_NOT_EXIST; 339 return DOES_NOT_EXIST;
324 } 340 }
325 } else { 341 } else {
326 if (errno == EACCES || 342 if ((errno == EACCES) ||
327 errno == EBADF || 343 (errno == EBADF) ||
328 errno == EFAULT || 344 (errno == EFAULT) ||
329 errno == ENOMEM || 345 (errno == ENOMEM) ||
330 errno == EOVERFLOW) { 346 (errno == EOVERFLOW)) {
331 // Search permissions denied for one of the directories in the 347 // Search permissions denied for one of the directories in the
332 // path or a low level error occured. We do not know if the 348 // path or a low level error occured. We do not know if the
333 // directory exists. 349 // directory exists.
334 return UNKNOWN; 350 return UNKNOWN;
335 } 351 }
336 ASSERT(errno == ELOOP || 352 ASSERT((errno == ELOOP) ||
337 errno == ENAMETOOLONG || 353 (errno == ENAMETOOLONG) ||
338 errno == ENOENT || 354 (errno == ENOENT) ||
339 errno == ENOTDIR); 355 (errno == ENOTDIR));
340 return DOES_NOT_EXIST; 356 return DOES_NOT_EXIST;
341 } 357 }
342 } 358 }
343 359
344 360
345 char* Directory::Current() { 361 char* Directory::CurrentNoScope() {
346 // Android's getcwd adheres closely to the POSIX standard. It won't 362 // Android's getcwd adheres closely to the POSIX standard. It won't
347 // allocate memory. We need to make our own copy. 363 // allocate memory. We need to make our own copy.
348 364
349 char buffer[PATH_MAX]; 365 char buffer[PATH_MAX];
350 if (NULL == getcwd(buffer, PATH_MAX)) { 366 if (NULL == getcwd(buffer, PATH_MAX)) {
351 return NULL; 367 return NULL;
352 } 368 }
353 369
354 return strdup(buffer); 370 return strdup(buffer);
355 } 371 }
356 372
357 373
374 const char* Directory::Current() {
375 char* result = DartUtils::ScopedCString(PATH_MAX);
376 ASSERT(result != NULL);
377 return getcwd(result, PATH_MAX);
378 }
379
380
358 bool Directory::SetCurrent(const char* path) { 381 bool Directory::SetCurrent(const char* path) {
359 int result = NO_RETRY_EXPECTED(chdir(path)); 382 int result = NO_RETRY_EXPECTED(chdir(path));
360 return result == 0; 383 return result == 0;
361 } 384 }
362 385
363 386
364 bool Directory::Create(const char* dir_name) { 387 bool Directory::Create(const char* dir_name) {
365 // Create the directory with the permissions specified by the 388 // Create the directory with the permissions specified by the
366 // process umask. 389 // process umask.
367 int result = NO_RETRY_EXPECTED(mkdir(dir_name, 0777)); 390 int result = NO_RETRY_EXPECTED(mkdir(dir_name, 0777));
368 // If the directory already exists, treat it as a success. 391 // If the directory already exists, treat it as a success.
369 if (result == -1 && errno == EEXIST) { 392 if ((result == -1) && (errno == EEXIST)) {
370 return (Exists(dir_name) == EXISTS); 393 return (Exists(dir_name) == EXISTS);
371 } 394 }
372 return (result == 0); 395 return (result == 0);
373 } 396 }
374 397
375 398
376 char* Directory::SystemTemp() { 399 const char* Directory::SystemTemp() {
377 // Android does not have a /tmp directory. A partial substitute, 400 // Android does not have a /tmp directory. A partial substitute,
378 // suitable for bring-up work and tests, is to create a tmp 401 // suitable for bring-up work and tests, is to create a tmp
379 // directory in /data/local/tmp. 402 // directory in /data/local/tmp.
380 // 403 //
381 // TODO(4413): In the long run, when running in an application we should 404 // TODO(4413): In the long run, when running in an application we should
382 // probably use the appropriate directory from the Android API, 405 // probably use the appropriate directory from the Android API,
383 // probably what File.createTempFile uses. 406 // probably what File.createTempFile uses.
384 #define ANDROID_TEMP_DIR "/data/local/tmp" 407 #define ANDROID_TEMP_DIR "/data/local/tmp"
385 struct stat st; 408 struct stat st;
386 if (stat(ANDROID_TEMP_DIR, &st) != 0) { 409 if (stat(ANDROID_TEMP_DIR, &st) != 0) {
387 mkdir(ANDROID_TEMP_DIR, 0777); 410 mkdir(ANDROID_TEMP_DIR, 0777);
388 } 411 }
389 return strdup(ANDROID_TEMP_DIR); 412 return ANDROID_TEMP_DIR;
390 } 413 }
391 414
392 415
393 char* Directory::CreateTemp(const char* prefix) { 416 const char* Directory::CreateTemp(const char* prefix) {
394 // Returns a new, unused directory name, adding characters to the end 417 // Returns a new, unused directory name, adding characters to the end
395 // of prefix. Creates the directory with the permissions specified 418 // of prefix. Creates the directory with the permissions specified
396 // by the process umask. 419 // by the process umask.
397 // The return value must be freed by the caller. 420 // The return value is Dart_ScopeAllocated.
398 PathBuffer path; 421 PathBuffer path;
399 path.Add(prefix); 422 if (!path.Add(prefix)) {
423 return NULL;
424 }
400 if (!path.Add("XXXXXX")) { 425 if (!path.Add("XXXXXX")) {
401 // Pattern has overflowed. 426 // Pattern has overflowed.
402 return NULL; 427 return NULL;
403 } 428 }
404 char* result; 429 char* result;
405 do { 430 do {
406 result = mkdtemp(path.AsString()); 431 result = mkdtemp(path.AsString());
407 } while (result == NULL && errno == EINTR); 432 } while ((result == NULL) && (errno == EINTR));
408 if (result == NULL) { 433 if (result == NULL) {
409 return NULL; 434 return NULL;
410 } 435 }
411 return strdup(result); 436 return path.AsScopedString();
412 } 437 }
413 438
414 439
415 bool Directory::Delete(const char* dir_name, bool recursive) { 440 bool Directory::Delete(const char* dir_name, bool recursive) {
416 if (!recursive) { 441 if (!recursive) {
417 if (File::GetType(dir_name, false) == File::kIsLink && 442 if ((File::GetType(dir_name, false) == File::kIsLink) &&
418 File::GetType(dir_name, true) == File::kIsDirectory) { 443 (File::GetType(dir_name, true) == File::kIsDirectory)) {
419 return (NO_RETRY_EXPECTED(unlink(dir_name)) == 0); 444 return (NO_RETRY_EXPECTED(unlink(dir_name)) == 0);
420 } 445 }
421 return (NO_RETRY_EXPECTED(rmdir(dir_name)) == 0); 446 return (NO_RETRY_EXPECTED(rmdir(dir_name)) == 0);
422 } else { 447 } else {
423 PathBuffer path; 448 PathBuffer path;
424 if (!path.Add(dir_name)) { 449 if (!path.Add(dir_name)) {
425 return false; 450 return false;
426 } 451 }
427 return DeleteRecursively(&path); 452 return DeleteRecursively(&path);
428 } 453 }
429 } 454 }
430 455
431 456
432 bool Directory::Rename(const char* path, const char* new_path) { 457 bool Directory::Rename(const char* path, const char* new_path) {
433 ExistsResult exists = Exists(path); 458 ExistsResult exists = Exists(path);
434 if (exists != EXISTS) return false; 459 if (exists != EXISTS) {
460 return false;
461 }
435 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); 462 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0);
436 } 463 }
437 464
438 } // namespace bin 465 } // namespace bin
439 } // namespace dart 466 } // namespace dart
440 467
441 #endif // defined(TARGET_OS_ANDROID) 468 #endif // defined(TARGET_OS_ANDROID)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698