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/file.h" | 8 #include "bin/file.h" |
9 | 9 |
10 #include <errno.h> // NOLINT | 10 #include <errno.h> // NOLINT |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 return is_file; | 258 return is_file; |
259 } | 259 } |
260 | 260 |
261 | 261 |
262 bool File::CreateLink(const char* name, const char* target) { | 262 bool File::CreateLink(const char* name, const char* target) { |
263 int status = NO_RETRY_EXPECTED(symlink(target, name)); | 263 int status = NO_RETRY_EXPECTED(symlink(target, name)); |
264 return (status == 0); | 264 return (status == 0); |
265 } | 265 } |
266 | 266 |
267 | 267 |
268 bool File::Delete(const char* name) { | 268 File::Type File::GetType(const char* pathname, bool follow_links) { |
269 File::Type type = File::GetType(name, true); | 269 struct stat entry_info; |
270 if (type == kIsFile) { | 270 int stat_success; |
271 return NO_RETRY_EXPECTED(unlink(name)) == 0; | 271 if (follow_links) { |
272 } else if (type == kIsDirectory) { | 272 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info)); |
273 errno = EISDIR; | |
274 } else { | 273 } else { |
275 errno = ENOENT; | 274 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info)); |
| 275 } |
| 276 if (stat_success == -1) { |
| 277 return File::kDoesNotExist; |
| 278 } |
| 279 if (S_ISDIR(entry_info.st_mode)) { |
| 280 return File::kIsDirectory; |
| 281 } |
| 282 if (S_ISREG(entry_info.st_mode)) { |
| 283 return File::kIsFile; |
| 284 } |
| 285 if (S_ISLNK(entry_info.st_mode)) { |
| 286 return File::kIsLink; |
| 287 } |
| 288 return File::kDoesNotExist; |
| 289 } |
| 290 |
| 291 |
| 292 static bool CheckTypeAndSetErrno(const char* name, |
| 293 File::Type expected, |
| 294 bool follow_links) { |
| 295 File::Type actual = File::GetType(name, follow_links); |
| 296 if (actual == expected) { |
| 297 return true; |
| 298 } |
| 299 switch (actual) { |
| 300 case File::kIsDirectory: |
| 301 errno = EISDIR; |
| 302 break; |
| 303 case File::kDoesNotExist: |
| 304 errno = ENOENT; |
| 305 break; |
| 306 default: |
| 307 errno = EINVAL; |
| 308 break; |
276 } | 309 } |
277 return false; | 310 return false; |
278 } | 311 } |
279 | 312 |
280 | 313 |
| 314 bool File::Delete(const char* name) { |
| 315 return CheckTypeAndSetErrno(name, kIsFile, true) && |
| 316 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
| 317 } |
| 318 |
| 319 |
281 bool File::DeleteLink(const char* name) { | 320 bool File::DeleteLink(const char* name) { |
282 File::Type type = File::GetType(name, false); | 321 return CheckTypeAndSetErrno(name, kIsLink, false) && |
283 if (type == kIsLink) { | 322 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
284 return NO_RETRY_EXPECTED(unlink(name)) == 0; | |
285 } | |
286 errno = EINVAL; | |
287 return false; | |
288 } | 323 } |
289 | 324 |
290 | 325 |
291 bool File::Rename(const char* old_path, const char* new_path) { | 326 bool File::Rename(const char* old_path, const char* new_path) { |
292 File::Type type = File::GetType(old_path, true); | 327 return CheckTypeAndSetErrno(old_path, kIsFile, true) && |
293 if (type == kIsFile) { | 328 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
294 return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0; | |
295 } else if (type == kIsDirectory) { | |
296 errno = EISDIR; | |
297 } else { | |
298 errno = ENOENT; | |
299 } | |
300 return false; | |
301 } | 329 } |
302 | 330 |
303 | 331 |
304 bool File::RenameLink(const char* old_path, const char* new_path) { | 332 bool File::RenameLink(const char* old_path, const char* new_path) { |
305 File::Type type = File::GetType(old_path, false); | 333 return CheckTypeAndSetErrno(old_path, kIsLink, false) && |
306 if (type == kIsLink) { | 334 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
307 return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0; | |
308 } else if (type == kIsDirectory) { | |
309 errno = EISDIR; | |
310 } else { | |
311 errno = EINVAL; | |
312 } | |
313 return false; | |
314 } | 335 } |
315 | 336 |
316 | 337 |
317 bool File::Copy(const char* old_path, const char* new_path) { | 338 bool File::Copy(const char* old_path, const char* new_path) { |
318 File::Type type = File::GetType(old_path, true); | 339 if (!CheckTypeAndSetErrno(old_path, kIsFile, true)) { |
319 if (type == kIsFile) { | 340 return false; |
320 struct stat st; | 341 } |
321 if (NO_RETRY_EXPECTED(stat(old_path, &st)) != 0) { | 342 struct stat st; |
322 return false; | 343 if (NO_RETRY_EXPECTED(stat(old_path, &st)) != 0) { |
323 } | 344 return false; |
324 int old_fd = TEMP_FAILURE_RETRY(open(old_path, O_RDONLY | O_CLOEXEC)); | 345 } |
325 if (old_fd < 0) { | 346 int old_fd = TEMP_FAILURE_RETRY(open(old_path, O_RDONLY | O_CLOEXEC)); |
326 return false; | 347 if (old_fd < 0) { |
327 } | 348 return false; |
328 int new_fd = TEMP_FAILURE_RETRY( | 349 } |
329 open(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode)); | 350 int new_fd = TEMP_FAILURE_RETRY( |
330 if (new_fd < 0) { | 351 open(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode)); |
331 VOID_TEMP_FAILURE_RETRY(close(old_fd)); | 352 if (new_fd < 0) { |
332 return false; | 353 VOID_TEMP_FAILURE_RETRY(close(old_fd)); |
333 } | 354 return false; |
334 off_t offset = 0; | 355 } |
335 int result = 1; | 356 off_t offset = 0; |
336 while (result > 0) { | 357 int result = 1; |
337 // Loop to ensure we copy everything, and not only up to 2GB. | 358 while (result > 0) { |
338 result = NO_RETRY_EXPECTED(sendfile(new_fd, old_fd, &offset, kMaxUint32)); | 359 // Loop to ensure we copy everything, and not only up to 2GB. |
339 } | 360 result = NO_RETRY_EXPECTED(sendfile(new_fd, old_fd, &offset, kMaxUint32)); |
340 // From sendfile man pages: | 361 } |
341 // Applications may wish to fall back to read(2)/write(2) in the case | 362 // From sendfile man pages: |
342 // where sendfile() fails with EINVAL or ENOSYS. | 363 // Applications may wish to fall back to read(2)/write(2) in the case |
343 if ((result < 0) && ((errno == EINVAL) || (errno == ENOSYS))) { | 364 // where sendfile() fails with EINVAL or ENOSYS. |
344 const intptr_t kBufferSize = 8 * KB; | 365 if ((result < 0) && ((errno == EINVAL) || (errno == ENOSYS))) { |
345 uint8_t buffer[kBufferSize]; | 366 const intptr_t kBufferSize = 8 * KB; |
346 while ((result = TEMP_FAILURE_RETRY(read(old_fd, buffer, kBufferSize))) > | 367 uint8_t buffer[kBufferSize]; |
347 0) { | 368 while ((result = TEMP_FAILURE_RETRY(read(old_fd, buffer, kBufferSize))) > |
348 int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result)); | 369 0) { |
349 if (wrote != result) { | 370 int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result)); |
350 result = -1; | 371 if (wrote != result) { |
351 break; | 372 result = -1; |
352 } | 373 break; |
353 } | 374 } |
354 } | 375 } |
355 int e = errno; | |
356 VOID_TEMP_FAILURE_RETRY(close(old_fd)); | |
357 VOID_TEMP_FAILURE_RETRY(close(new_fd)); | |
358 if (result < 0) { | |
359 VOID_NO_RETRY_EXPECTED(unlink(new_path)); | |
360 errno = e; | |
361 return false; | |
362 } | |
363 return true; | |
364 } else if (type == kIsDirectory) { | |
365 errno = EISDIR; | |
366 } else { | |
367 errno = ENOENT; | |
368 } | 376 } |
369 return false; | 377 int e = errno; |
| 378 VOID_TEMP_FAILURE_RETRY(close(old_fd)); |
| 379 VOID_TEMP_FAILURE_RETRY(close(new_fd)); |
| 380 if (result < 0) { |
| 381 VOID_NO_RETRY_EXPECTED(unlink(new_path)); |
| 382 errno = e; |
| 383 return false; |
| 384 } |
| 385 return true; |
370 } | 386 } |
371 | 387 |
372 | 388 |
373 int64_t File::LengthFromPath(const char* name) { | 389 int64_t File::LengthFromPath(const char* name) { |
374 struct stat st; | 390 struct stat st; |
375 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { | 391 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { |
376 // Signal an error if it's a directory. | 392 // Signal an error if it's a directory. |
377 if (S_ISDIR(st.st_mode)) { | 393 if (S_ISDIR(st.st_mode)) { |
378 errno = EISDIR; | 394 errno = EISDIR; |
379 return -1; | 395 return -1; |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 if (S_ISSOCK(buf.st_mode)) { | 509 if (S_ISSOCK(buf.st_mode)) { |
494 return kSocket; | 510 return kSocket; |
495 } | 511 } |
496 if (S_ISREG(buf.st_mode)) { | 512 if (S_ISREG(buf.st_mode)) { |
497 return kFile; | 513 return kFile; |
498 } | 514 } |
499 return kOther; | 515 return kOther; |
500 } | 516 } |
501 | 517 |
502 | 518 |
503 File::Type File::GetType(const char* pathname, bool follow_links) { | |
504 struct stat entry_info; | |
505 int stat_success; | |
506 if (follow_links) { | |
507 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info)); | |
508 } else { | |
509 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info)); | |
510 } | |
511 if (stat_success == -1) { | |
512 return File::kDoesNotExist; | |
513 } | |
514 if (S_ISDIR(entry_info.st_mode)) { | |
515 return File::kIsDirectory; | |
516 } | |
517 if (S_ISREG(entry_info.st_mode)) { | |
518 return File::kIsFile; | |
519 } | |
520 if (S_ISLNK(entry_info.st_mode)) { | |
521 return File::kIsLink; | |
522 } | |
523 return File::kDoesNotExist; | |
524 } | |
525 | |
526 | |
527 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { | 519 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { |
528 struct stat file_1_info; | 520 struct stat file_1_info; |
529 struct stat file_2_info; | 521 struct stat file_2_info; |
530 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) || | 522 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) || |
531 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) { | 523 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) { |
532 return File::kError; | 524 return File::kError; |
533 } | 525 } |
534 return ((file_1_info.st_ino == file_2_info.st_ino) && | 526 return ((file_1_info.st_ino == file_2_info.st_ino) && |
535 (file_1_info.st_dev == file_2_info.st_dev)) | 527 (file_1_info.st_dev == file_2_info.st_dev)) |
536 ? File::kIdentical | 528 ? File::kIdentical |
537 : File::kDifferent; | 529 : File::kDifferent; |
538 } | 530 } |
539 | 531 |
540 } // namespace bin | 532 } // namespace bin |
541 } // namespace dart | 533 } // namespace dart |
542 | 534 |
543 #endif // defined(TARGET_OS_ANDROID) | 535 #endif // defined(TARGET_OS_ANDROID) |
OLD | NEW |