OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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_FUCHSIA) | 6 #if defined(TARGET_OS_FUCHSIA) |
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 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 FDUtils::SaveErrorAndClose(fd); | 241 FDUtils::SaveErrorAndClose(fd); |
242 return is_file; | 242 return is_file; |
243 } | 243 } |
244 | 244 |
245 | 245 |
246 bool File::CreateLink(const char* name, const char* target) { | 246 bool File::CreateLink(const char* name, const char* target) { |
247 return NO_RETRY_EXPECTED(symlink(target, name)) == 0; | 247 return NO_RETRY_EXPECTED(symlink(target, name)) == 0; |
248 } | 248 } |
249 | 249 |
250 | 250 |
251 bool File::Delete(const char* name) { | 251 File::Type File::GetType(const char* pathname, bool follow_links) { |
252 File::Type type = File::GetType(name, true); | 252 struct stat entry_info; |
253 if (type == kIsFile) { | 253 int stat_success; |
254 return NO_RETRY_EXPECTED(unlink(name)) == 0; | 254 if (follow_links) { |
255 } else if (type == kIsDirectory) { | 255 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info)); |
256 errno = EISDIR; | |
257 } else { | 256 } else { |
258 errno = ENOENT; | 257 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info)); |
| 258 } |
| 259 if (stat_success == -1) { |
| 260 return File::kDoesNotExist; |
| 261 } |
| 262 if (S_ISDIR(entry_info.st_mode)) { |
| 263 return File::kIsDirectory; |
| 264 } |
| 265 if (S_ISREG(entry_info.st_mode)) { |
| 266 return File::kIsFile; |
| 267 } |
| 268 if (S_ISLNK(entry_info.st_mode)) { |
| 269 return File::kIsLink; |
| 270 } |
| 271 return File::kDoesNotExist; |
| 272 } |
| 273 |
| 274 |
| 275 static bool CheckTypeAndSetErrno(const char* name, |
| 276 File::Type expected, |
| 277 bool follow_links) { |
| 278 File::Type actual = File::GetType(name, follow_links); |
| 279 if (actual == expected) { |
| 280 return true; |
| 281 } |
| 282 switch (actual) { |
| 283 case File::kIsDirectory: |
| 284 errno = EISDIR; |
| 285 break; |
| 286 case File::kDoesNotExist: |
| 287 errno = ENOENT; |
| 288 break; |
| 289 default: |
| 290 errno = EINVAL; |
| 291 break; |
259 } | 292 } |
260 return false; | 293 return false; |
261 } | 294 } |
262 | 295 |
263 | 296 |
| 297 bool File::Delete(const char* name) { |
| 298 return CheckTypeAndSetErrno(name, kIsFile, true) && |
| 299 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
| 300 } |
| 301 |
| 302 |
264 bool File::DeleteLink(const char* name) { | 303 bool File::DeleteLink(const char* name) { |
265 File::Type type = File::GetType(name, false); | 304 return CheckTypeAndSetErrno(name, kIsLink, false) && |
266 if (type == kIsLink) { | 305 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
267 return NO_RETRY_EXPECTED(unlink(name)) == 0; | |
268 } | |
269 errno = EINVAL; | |
270 return false; | |
271 } | 306 } |
272 | 307 |
273 | 308 |
274 bool File::Rename(const char* old_path, const char* new_path) { | 309 bool File::Rename(const char* old_path, const char* new_path) { |
275 File::Type type = File::GetType(old_path, true); | 310 return CheckTypeAndSetErrno(old_path, kIsFile, true) && |
276 if (type == kIsFile) { | 311 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
277 return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0; | |
278 } else if (type == kIsDirectory) { | |
279 errno = EISDIR; | |
280 } else { | |
281 errno = ENOENT; | |
282 } | |
283 return false; | |
284 } | 312 } |
285 | 313 |
286 | 314 |
287 bool File::RenameLink(const char* old_path, const char* new_path) { | 315 bool File::RenameLink(const char* old_path, const char* new_path) { |
288 File::Type type = File::GetType(old_path, false); | 316 return CheckTypeAndSetErrno(old_path, kIsLink, false) && |
289 if (type == kIsLink) { | 317 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
290 return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0; | |
291 } else if (type == kIsDirectory) { | |
292 errno = EISDIR; | |
293 } else { | |
294 errno = EINVAL; | |
295 } | |
296 return false; | |
297 } | 318 } |
298 | 319 |
299 | 320 |
300 bool File::Copy(const char* old_path, const char* new_path) { | 321 bool File::Copy(const char* old_path, const char* new_path) { |
301 File::Type type = File::GetType(old_path, true); | 322 if (!CheckTypeAndSetErrno(old_path, kIsFile, true)) { |
302 if (type == kIsFile) { | 323 return false; |
303 struct stat64 st; | 324 } |
304 if (NO_RETRY_EXPECTED(stat64(old_path, &st)) != 0) { | 325 struct stat64 st; |
305 return false; | 326 if (NO_RETRY_EXPECTED(stat64(old_path, &st)) != 0) { |
| 327 return false; |
| 328 } |
| 329 int old_fd = NO_RETRY_EXPECTED(open64(old_path, O_RDONLY | O_CLOEXEC)); |
| 330 if (old_fd < 0) { |
| 331 return false; |
| 332 } |
| 333 int new_fd = NO_RETRY_EXPECTED( |
| 334 open64(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode)); |
| 335 if (new_fd < 0) { |
| 336 VOID_TEMP_FAILURE_RETRY(close(old_fd)); |
| 337 return false; |
| 338 } |
| 339 // TODO(MG-429): Use sendfile/copyfile or equivalent when there is one. |
| 340 intptr_t result; |
| 341 const intptr_t kBufferSize = 8 * KB; |
| 342 uint8_t buffer[kBufferSize]; |
| 343 while ((result = NO_RETRY_EXPECTED(read(old_fd, buffer, kBufferSize))) > 0) { |
| 344 int wrote = NO_RETRY_EXPECTED(write(new_fd, buffer, result)); |
| 345 if (wrote != result) { |
| 346 result = -1; |
| 347 break; |
306 } | 348 } |
307 int old_fd = NO_RETRY_EXPECTED(open64(old_path, O_RDONLY | O_CLOEXEC)); | |
308 if (old_fd < 0) { | |
309 return false; | |
310 } | |
311 int new_fd = NO_RETRY_EXPECTED( | |
312 open64(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode)); | |
313 if (new_fd < 0) { | |
314 VOID_TEMP_FAILURE_RETRY(close(old_fd)); | |
315 return false; | |
316 } | |
317 // TODO(MG-429): Use sendfile/copyfile or equivalent when there is one. | |
318 intptr_t result; | |
319 const intptr_t kBufferSize = 8 * KB; | |
320 uint8_t buffer[kBufferSize]; | |
321 while ((result = NO_RETRY_EXPECTED(read(old_fd, buffer, kBufferSize))) > | |
322 0) { | |
323 int wrote = NO_RETRY_EXPECTED(write(new_fd, buffer, result)); | |
324 if (wrote != result) { | |
325 result = -1; | |
326 break; | |
327 } | |
328 } | |
329 FDUtils::SaveErrorAndClose(old_fd); | |
330 FDUtils::SaveErrorAndClose(new_fd); | |
331 if (result < 0) { | |
332 int e = errno; | |
333 VOID_NO_RETRY_EXPECTED(unlink(new_path)); | |
334 errno = e; | |
335 return false; | |
336 } | |
337 return true; | |
338 } else if (type == kIsDirectory) { | |
339 errno = EISDIR; | |
340 } else { | |
341 errno = ENOENT; | |
342 } | 349 } |
343 return false; | 350 FDUtils::SaveErrorAndClose(old_fd); |
| 351 FDUtils::SaveErrorAndClose(new_fd); |
| 352 if (result < 0) { |
| 353 int e = errno; |
| 354 VOID_NO_RETRY_EXPECTED(unlink(new_path)); |
| 355 errno = e; |
| 356 return false; |
| 357 } |
| 358 return true; |
344 } | 359 } |
345 | 360 |
346 | 361 |
347 int64_t File::LengthFromPath(const char* name) { | 362 int64_t File::LengthFromPath(const char* name) { |
348 struct stat st; | 363 struct stat st; |
349 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { | 364 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { |
350 // Signal an error if it's a directory. | 365 // Signal an error if it's a directory. |
351 if (S_ISDIR(st.st_mode)) { | 366 if (S_ISDIR(st.st_mode)) { |
352 errno = EISDIR; | 367 errno = EISDIR; |
353 return -1; | 368 return -1; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
472 if (S_ISSOCK(buf.st_mode)) { | 487 if (S_ISSOCK(buf.st_mode)) { |
473 return kSocket; | 488 return kSocket; |
474 } | 489 } |
475 if (S_ISREG(buf.st_mode)) { | 490 if (S_ISREG(buf.st_mode)) { |
476 return kFile; | 491 return kFile; |
477 } | 492 } |
478 return kOther; | 493 return kOther; |
479 } | 494 } |
480 | 495 |
481 | 496 |
482 File::Type File::GetType(const char* pathname, bool follow_links) { | |
483 struct stat entry_info; | |
484 int stat_success; | |
485 if (follow_links) { | |
486 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info)); | |
487 } else { | |
488 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info)); | |
489 } | |
490 if (stat_success == -1) { | |
491 return File::kDoesNotExist; | |
492 } | |
493 if (S_ISDIR(entry_info.st_mode)) { | |
494 return File::kIsDirectory; | |
495 } | |
496 if (S_ISREG(entry_info.st_mode)) { | |
497 return File::kIsFile; | |
498 } | |
499 if (S_ISLNK(entry_info.st_mode)) { | |
500 return File::kIsLink; | |
501 } | |
502 return File::kDoesNotExist; | |
503 } | |
504 | |
505 | |
506 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { | 497 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { |
507 struct stat file_1_info; | 498 struct stat file_1_info; |
508 struct stat file_2_info; | 499 struct stat file_2_info; |
509 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) || | 500 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) || |
510 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) { | 501 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) { |
511 return File::kError; | 502 return File::kError; |
512 } | 503 } |
513 return ((file_1_info.st_ino == file_2_info.st_ino) && | 504 return ((file_1_info.st_ino == file_2_info.st_ino) && |
514 (file_1_info.st_dev == file_2_info.st_dev)) | 505 (file_1_info.st_dev == file_2_info.st_dev)) |
515 ? File::kIdentical | 506 ? File::kIdentical |
516 : File::kDifferent; | 507 : File::kDifferent; |
517 } | 508 } |
518 | 509 |
519 } // namespace bin | 510 } // namespace bin |
520 } // namespace dart | 511 } // namespace dart |
521 | 512 |
522 #endif // defined(TARGET_OS_FUCHSIA) | 513 #endif // defined(TARGET_OS_FUCHSIA) |
OLD | NEW |