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_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/dartutils.h" |
18 #include "bin/file.h" | 18 #include "bin/file.h" |
19 #include "bin/platform.h" | 19 #include "bin/platform.h" |
20 #include "platform/signal_blocker.h" | 20 #include "platform/signal_blocker.h" |
21 | 21 |
22 namespace dart { | 22 namespace dart { |
23 namespace bin { | 23 namespace bin { |
24 | 24 |
25 PathBuffer::PathBuffer() : length_(0) { | 25 PathBuffer::PathBuffer() : length_(0) { |
(...skipping 23 matching lines...) Expand all Loading... |
49 } | 49 } |
50 | 50 |
51 | 51 |
52 const char* PathBuffer::AsScopedString() const { | 52 const char* PathBuffer::AsScopedString() const { |
53 return DartUtils::ScopedCopyCString(AsString()); | 53 return DartUtils::ScopedCopyCString(AsString()); |
54 } | 54 } |
55 | 55 |
56 | 56 |
57 bool PathBuffer::Add(const char* name) { | 57 bool PathBuffer::Add(const char* name) { |
58 char* data = AsString(); | 58 char* data = AsString(); |
59 int written = snprintf(data + length_, | 59 int written = snprintf(data + length_, PATH_MAX - length_, "%s", name); |
60 PATH_MAX - length_, | |
61 "%s", | |
62 name); | |
63 data[PATH_MAX] = '\0'; | 60 data[PATH_MAX] = '\0'; |
64 if ((written <= PATH_MAX - length_) && | 61 if ((written <= PATH_MAX - length_) && (written >= 0) && |
65 (written >= 0) && | |
66 (static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1))) { | 62 (static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1))) { |
67 length_ += written; | 63 length_ += written; |
68 return true; | 64 return true; |
69 } else { | 65 } else { |
70 errno = ENAMETOOLONG; | 66 errno = ENAMETOOLONG; |
71 return false; | 67 return false; |
72 } | 68 } |
73 } | 69 } |
74 | 70 |
75 | 71 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 } | 108 } |
113 // Reset. | 109 // Reset. |
114 listing->path_buffer().Reset(path_length_); | 110 listing->path_buffer().Reset(path_length_); |
115 ResetLink(); | 111 ResetLink(); |
116 | 112 |
117 // Iterate the directory and post the directories and files to the | 113 // Iterate the directory and post the directories and files to the |
118 // ports. | 114 // ports. |
119 int status = 0; | 115 int status = 0; |
120 dirent entry; | 116 dirent entry; |
121 dirent* result; | 117 dirent* result; |
122 status = NO_RETRY_EXPECTED(readdir_r( | 118 status = NO_RETRY_EXPECTED( |
123 reinterpret_cast<DIR*>(lister_), &entry, &result)); | 119 readdir_r(reinterpret_cast<DIR*>(lister_), &entry, &result)); |
124 if ((status == 0) && (result != NULL)) { | 120 if ((status == 0) && (result != NULL)) { |
125 if (!listing->path_buffer().Add(entry.d_name)) { | 121 if (!listing->path_buffer().Add(entry.d_name)) { |
126 done_ = true; | 122 done_ = true; |
127 return kListError; | 123 return kListError; |
128 } | 124 } |
129 switch (entry.d_type) { | 125 switch (entry.d_type) { |
130 case DT_DIR: | 126 case DT_DIR: |
131 if ((strcmp(entry.d_name, ".") == 0) || | 127 if ((strcmp(entry.d_name, ".") == 0) || |
132 (strcmp(entry.d_name, "..") == 0)) { | 128 (strcmp(entry.d_name, "..") == 0)) { |
133 return Next(listing); | 129 return Next(listing); |
134 } | 130 } |
135 return kListDirectory; | 131 return kListDirectory; |
136 case DT_REG: | 132 case DT_REG: |
137 return kListFile; | 133 return kListFile; |
138 case DT_LNK: | 134 case DT_LNK: |
139 if (!listing->follow_links()) { | 135 if (!listing->follow_links()) { |
140 return kListLink; | 136 return kListLink; |
141 } | 137 } |
142 // Else fall through to next case. | 138 // Else fall through to next case. |
143 // Fall through. | 139 // Fall through. |
144 case DT_UNKNOWN: { | 140 case DT_UNKNOWN: { |
145 // On some file systems the entry type is not determined by | 141 // On some file systems the entry type is not determined by |
146 // readdir_r. For those and for links we use stat to determine | 142 // readdir_r. For those and for links we use stat to determine |
147 // the actual entry type. Notice that stat returns the type of | 143 // the actual entry type. Notice that stat returns the type of |
148 // the file pointed to. | 144 // the file pointed to. |
149 struct stat entry_info; | 145 struct stat entry_info; |
150 int stat_success; | 146 int stat_success; |
151 stat_success = NO_RETRY_EXPECTED( | 147 stat_success = NO_RETRY_EXPECTED( |
152 lstat(listing->path_buffer().AsString(), &entry_info)); | 148 lstat(listing->path_buffer().AsString(), &entry_info)); |
153 if (stat_success == -1) { | 149 if (stat_success == -1) { |
154 return kListError; | 150 return kListError; |
155 } | 151 } |
156 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) { | 152 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) { |
157 // Check to see if we are in a loop created by a symbolic link. | 153 // Check to see if we are in a loop created by a symbolic link. |
158 LinkList current_link = { entry_info.st_dev, | 154 LinkList current_link = {entry_info.st_dev, entry_info.st_ino, link_}; |
159 entry_info.st_ino, | |
160 link_ }; | |
161 LinkList* previous = link_; | 155 LinkList* previous = link_; |
162 while (previous != NULL) { | 156 while (previous != NULL) { |
163 if ((previous->dev == current_link.dev) && | 157 if ((previous->dev == current_link.dev) && |
164 (previous->ino == current_link.ino)) { | 158 (previous->ino == current_link.ino)) { |
165 // Report the looping link as a link, rather than following it. | 159 // Report the looping link as a link, rather than following it. |
166 return kListLink; | 160 return kListLink; |
167 } | 161 } |
168 previous = previous->next; | 162 previous = previous->next; |
169 } | 163 } |
170 stat_success = NO_RETRY_EXPECTED( | 164 stat_success = NO_RETRY_EXPECTED( |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 } | 221 } |
228 if (parent_ != NULL) { | 222 if (parent_ != NULL) { |
229 link_ = parent_->link_; | 223 link_ = parent_->link_; |
230 } | 224 } |
231 } | 225 } |
232 | 226 |
233 | 227 |
234 static bool DeleteRecursively(PathBuffer* path); | 228 static bool DeleteRecursively(PathBuffer* path); |
235 | 229 |
236 | 230 |
237 static bool DeleteFile(char* file_name, | 231 static bool DeleteFile(char* file_name, PathBuffer* path) { |
238 PathBuffer* path) { | |
239 return path->Add(file_name) && (unlink(path->AsString()) == 0); | 232 return path->Add(file_name) && (unlink(path->AsString()) == 0); |
240 } | 233 } |
241 | 234 |
242 | 235 |
243 static bool DeleteDir(char* dir_name, | 236 static bool DeleteDir(char* dir_name, PathBuffer* path) { |
244 PathBuffer* path) { | |
245 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { | 237 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { |
246 return true; | 238 return true; |
247 } | 239 } |
248 return path->Add(dir_name) && DeleteRecursively(path); | 240 return path->Add(dir_name) && DeleteRecursively(path); |
249 } | 241 } |
250 | 242 |
251 | 243 |
252 static bool DeleteRecursively(PathBuffer* path) { | 244 static bool DeleteRecursively(PathBuffer* path) { |
253 // Do not recurse into links for deletion. Instead delete the link. | 245 // Do not recurse into links for deletion. Instead delete the link. |
254 // If it's a file, delete it. | 246 // If it's a file, delete it. |
(...skipping 19 matching lines...) Expand all Loading... |
274 } | 266 } |
275 | 267 |
276 // Iterate the directory and delete all files and directories. | 268 // Iterate the directory and delete all files and directories. |
277 int path_length = path->length(); | 269 int path_length = path->length(); |
278 dirent entry; | 270 dirent entry; |
279 dirent* result; | 271 dirent* result; |
280 while (NO_RETRY_EXPECTED(readdir_r(dir_pointer, &entry, &result)) == 0) { | 272 while (NO_RETRY_EXPECTED(readdir_r(dir_pointer, &entry, &result)) == 0) { |
281 if (result == NULL) { | 273 if (result == NULL) { |
282 // End of directory. | 274 // End of directory. |
283 return NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0 && | 275 return NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0 && |
284 NO_RETRY_EXPECTED(remove(path->AsString())) == 0; | 276 NO_RETRY_EXPECTED(remove(path->AsString())) == 0; |
285 } | 277 } |
286 bool ok = false; | 278 bool ok = false; |
287 switch (entry.d_type) { | 279 switch (entry.d_type) { |
288 case DT_DIR: | 280 case DT_DIR: |
289 ok = DeleteDir(entry.d_name, path); | 281 ok = DeleteDir(entry.d_name, path); |
290 break; | 282 break; |
291 case DT_REG: | 283 case DT_REG: |
292 case DT_LNK: | 284 case DT_LNK: |
293 // Treat all links as files. This will delete the link which | 285 // Treat all links as files. This will delete the link which |
294 // is what we want no matter if the link target is a file or a | 286 // is what we want no matter if the link target is a file or a |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 Directory::ExistsResult Directory::Exists(const char* dir_name) { | 329 Directory::ExistsResult Directory::Exists(const char* dir_name) { |
338 struct stat entry_info; | 330 struct stat entry_info; |
339 int success = NO_RETRY_EXPECTED(stat(dir_name, &entry_info)); | 331 int success = NO_RETRY_EXPECTED(stat(dir_name, &entry_info)); |
340 if (success == 0) { | 332 if (success == 0) { |
341 if (S_ISDIR(entry_info.st_mode)) { | 333 if (S_ISDIR(entry_info.st_mode)) { |
342 return EXISTS; | 334 return EXISTS; |
343 } else { | 335 } else { |
344 return DOES_NOT_EXIST; | 336 return DOES_NOT_EXIST; |
345 } | 337 } |
346 } else { | 338 } else { |
347 if ((errno == EACCES) || | 339 if ((errno == EACCES) || (errno == EBADF) || (errno == EFAULT) || |
348 (errno == EBADF) || | 340 (errno == ENOMEM) || (errno == EOVERFLOW)) { |
349 (errno == EFAULT) || | |
350 (errno == ENOMEM) || | |
351 (errno == EOVERFLOW)) { | |
352 // Search permissions denied for one of the directories in the | 341 // Search permissions denied for one of the directories in the |
353 // path or a low level error occured. We do not know if the | 342 // path or a low level error occured. We do not know if the |
354 // directory exists. | 343 // directory exists. |
355 return UNKNOWN; | 344 return UNKNOWN; |
356 } | 345 } |
357 ASSERT((errno == ELOOP) || | 346 ASSERT((errno == ELOOP) || (errno == ENAMETOOLONG) || (errno == ENOENT) || |
358 (errno == ENAMETOOLONG) || | |
359 (errno == ENOENT) || | |
360 (errno == ENOTDIR)); | 347 (errno == ENOTDIR)); |
361 return DOES_NOT_EXIST; | 348 return DOES_NOT_EXIST; |
362 } | 349 } |
363 } | 350 } |
364 | 351 |
365 | 352 |
366 char* Directory::CurrentNoScope() { | 353 char* Directory::CurrentNoScope() { |
367 // Android's getcwd adheres closely to the POSIX standard. It won't | 354 // Android's getcwd adheres closely to the POSIX standard. It won't |
368 // allocate memory. We need to make our own copy. | 355 // allocate memory. We need to make our own copy. |
369 char buffer[PATH_MAX]; | 356 char buffer[PATH_MAX]; |
(...skipping 29 matching lines...) Expand all Loading... |
399 return (Exists(dir_name) == EXISTS); | 386 return (Exists(dir_name) == EXISTS); |
400 } | 387 } |
401 return (result == 0); | 388 return (result == 0); |
402 } | 389 } |
403 | 390 |
404 | 391 |
405 const char* Directory::SystemTemp() { | 392 const char* Directory::SystemTemp() { |
406 if (Directory::system_temp_path_override_ != NULL) { | 393 if (Directory::system_temp_path_override_ != NULL) { |
407 return DartUtils::ScopedCopyCString(Directory::system_temp_path_override_); | 394 return DartUtils::ScopedCopyCString(Directory::system_temp_path_override_); |
408 } | 395 } |
409 // Android does not have a /tmp directory. A partial substitute, | 396 // Android does not have a /tmp directory. A partial substitute, |
410 // suitable for bring-up work and tests, is to create a tmp | 397 // suitable for bring-up work and tests, is to create a tmp |
411 // directory in /data/local/tmp. | 398 // directory in /data/local/tmp. |
412 // | 399 // |
413 // TODO(4413): In the long run, when running in an application we should | 400 // TODO(4413): In the long run, when running in an application we should |
414 // probably use the appropriate directory from the Android API, | 401 // probably use the appropriate directory from the Android API, |
415 // probably what File.createTempFile uses. | 402 // probably what File.createTempFile uses. |
416 #define ANDROID_TEMP_DIR "/data/local/tmp" | 403 #define ANDROID_TEMP_DIR "/data/local/tmp" |
417 struct stat st; | 404 struct stat st; |
418 if (stat(ANDROID_TEMP_DIR, &st) != 0) { | 405 if (stat(ANDROID_TEMP_DIR, &st) != 0) { |
419 mkdir(ANDROID_TEMP_DIR, 0777); | 406 mkdir(ANDROID_TEMP_DIR, 0777); |
420 } | 407 } |
421 return ANDROID_TEMP_DIR; | 408 return ANDROID_TEMP_DIR; |
422 } | 409 } |
423 | 410 |
424 | 411 |
425 const char* Directory::CreateTemp(const char* prefix) { | 412 const char* Directory::CreateTemp(const char* prefix) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 if (exists != EXISTS) { | 455 if (exists != EXISTS) { |
469 return false; | 456 return false; |
470 } | 457 } |
471 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); | 458 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); |
472 } | 459 } |
473 | 460 |
474 } // namespace bin | 461 } // namespace bin |
475 } // namespace dart | 462 } // namespace dart |
476 | 463 |
477 #endif // defined(TARGET_OS_ANDROID) | 464 #endif // defined(TARGET_OS_ANDROID) |
OLD | NEW |