Path.inc revision 77e31bca0321c6b470a844e3d5468fd998eef44e
1//===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the Unix specific implementation of the Path API. 11// 12//===----------------------------------------------------------------------===// 13 14//===----------------------------------------------------------------------===// 15//=== WARNING: Implementation here must contain only generic UNIX code that 16//=== is guaranteed to work on *all* UNIX variants. 17//===----------------------------------------------------------------------===// 18 19#include "Unix.h" 20#include "llvm/Support/Process.h" 21#if HAVE_SYS_STAT_H 22#include <sys/stat.h> 23#endif 24#if HAVE_FCNTL_H 25#include <fcntl.h> 26#endif 27#ifdef HAVE_SYS_MMAN_H 28#include <sys/mman.h> 29#endif 30#if HAVE_DIRENT_H 31# include <dirent.h> 32# define NAMLEN(dirent) strlen((dirent)->d_name) 33#else 34# define dirent direct 35# define NAMLEN(dirent) (dirent)->d_namlen 36# if HAVE_SYS_NDIR_H 37# include <sys/ndir.h> 38# endif 39# if HAVE_SYS_DIR_H 40# include <sys/dir.h> 41# endif 42# if HAVE_NDIR_H 43# include <ndir.h> 44# endif 45#endif 46#if HAVE_STDIO_H 47#include <stdio.h> 48#endif 49#if HAVE_LIMITS_H 50#include <limits.h> 51#endif 52 53#ifdef __APPLE__ 54#include <mach-o/dyld.h> 55#endif 56 57// Both stdio.h and cstdio are included via different pathes and 58// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros 59// either. 60#undef ferror 61#undef feof 62 63// For GNU Hurd 64#if defined(__GNU__) && !defined(PATH_MAX) 65# define PATH_MAX 4096 66#endif 67 68using namespace llvm; 69 70namespace { 71 /// This class automatically closes the given file descriptor when it goes out 72 /// of scope. You can take back explicit ownership of the file descriptor by 73 /// calling take(). The destructor does not verify that close was successful. 74 /// Therefore, never allow this class to call close on a file descriptor that 75 /// has been read from or written to. 76 struct AutoFD { 77 int FileDescriptor; 78 79 AutoFD(int fd) : FileDescriptor(fd) {} 80 ~AutoFD() { 81 if (FileDescriptor >= 0) 82 ::close(FileDescriptor); 83 } 84 85 int take() { 86 int ret = FileDescriptor; 87 FileDescriptor = -1; 88 return ret; 89 } 90 91 operator int() const {return FileDescriptor;} 92 }; 93 94 error_code TempDir(SmallVectorImpl<char> &result) { 95 // FIXME: Don't use TMPDIR if program is SUID or SGID enabled. 96 const char *dir = 0; 97 (dir = std::getenv("TMPDIR" )) || 98 (dir = std::getenv("TMP" )) || 99 (dir = std::getenv("TEMP" )) || 100 (dir = std::getenv("TEMPDIR")) || 101#ifdef P_tmpdir 102 (dir = P_tmpdir) || 103#endif 104 (dir = "/tmp"); 105 106 result.clear(); 107 StringRef d(dir); 108 result.append(d.begin(), d.end()); 109 return error_code::success(); 110 } 111} 112 113static error_code createUniqueEntity(const Twine &Model, int &ResultFD, 114 SmallVectorImpl<char> &ResultPath, 115 bool MakeAbsolute, unsigned Mode, 116 FSEntity Type) { 117 SmallString<128> ModelStorage; 118 Model.toVector(ModelStorage); 119 120 if (MakeAbsolute) { 121 // Make model absolute by prepending a temp directory if it's not already. 122 bool absolute = sys::path::is_absolute(Twine(ModelStorage)); 123 if (!absolute) { 124 SmallString<128> TDir; 125 if (error_code ec = TempDir(TDir)) return ec; 126 sys::path::append(TDir, Twine(ModelStorage)); 127 ModelStorage.swap(TDir); 128 } 129 } 130 131 // From here on, DO NOT modify model. It may be needed if the randomly chosen 132 // path already exists. 133 ResultPath = ModelStorage; 134 // Null terminate. 135 ResultPath.push_back(0); 136 ResultPath.pop_back(); 137 138retry_random_path: 139 // Replace '%' with random chars. 140 for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) { 141 if (ModelStorage[i] == '%') 142 ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; 143 } 144 145 // Try to open + create the file. 146 switch (Type) { 147 case FS_File: { 148 int RandomFD = ::open(ResultPath.begin(), O_RDWR | O_CREAT | O_EXCL, Mode); 149 if (RandomFD == -1) { 150 int SavedErrno = errno; 151 // If the file existed, try again, otherwise, error. 152 if (SavedErrno == errc::file_exists) 153 goto retry_random_path; 154 return error_code(SavedErrno, system_category()); 155 } 156 157 ResultFD = RandomFD; 158 return error_code::success(); 159 } 160 161 case FS_Name: { 162 bool Exists; 163 error_code EC = sys::fs::exists(ResultPath.begin(), Exists); 164 if (EC) 165 return EC; 166 if (Exists) 167 goto retry_random_path; 168 return error_code::success(); 169 } 170 171 case FS_Dir: { 172 bool Existed; 173 error_code EC = sys::fs::create_directory(ResultPath.begin(), Existed); 174 if (EC) 175 return EC; 176 if (Existed) 177 goto retry_random_path; 178 return error_code::success(); 179 } 180 } 181 llvm_unreachable("Invalid Type"); 182} 183 184namespace llvm { 185namespace sys { 186namespace fs { 187#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ 188 defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \ 189 defined(__linux__) || defined(__CYGWIN__) 190static int 191test_dir(char buf[PATH_MAX], char ret[PATH_MAX], 192 const char *dir, const char *bin) 193{ 194 struct stat sb; 195 196 snprintf(buf, PATH_MAX, "%s/%s", dir, bin); 197 if (realpath(buf, ret) == NULL) 198 return (1); 199 if (stat(buf, &sb) != 0) 200 return (1); 201 202 return (0); 203} 204 205static char * 206getprogpath(char ret[PATH_MAX], const char *bin) 207{ 208 char *pv, *s, *t, buf[PATH_MAX]; 209 210 /* First approach: absolute path. */ 211 if (bin[0] == '/') { 212 if (test_dir(buf, ret, "/", bin) == 0) 213 return (ret); 214 return (NULL); 215 } 216 217 /* Second approach: relative path. */ 218 if (strchr(bin, '/') != NULL) { 219 if (getcwd(buf, PATH_MAX) == NULL) 220 return (NULL); 221 if (test_dir(buf, ret, buf, bin) == 0) 222 return (ret); 223 return (NULL); 224 } 225 226 /* Third approach: $PATH */ 227 if ((pv = getenv("PATH")) == NULL) 228 return (NULL); 229 s = pv = strdup(pv); 230 if (pv == NULL) 231 return (NULL); 232 while ((t = strsep(&s, ":")) != NULL) { 233 if (test_dir(buf, ret, t, bin) == 0) { 234 free(pv); 235 return (ret); 236 } 237 } 238 free(pv); 239 return (NULL); 240} 241#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__ 242 243/// GetMainExecutable - Return the path to the main executable, given the 244/// value of argv[0] from program startup. 245std::string getMainExecutable(const char *argv0, void *MainAddr) { 246#if defined(__APPLE__) 247 // On OS X the executable path is saved to the stack by dyld. Reading it 248 // from there is much faster than calling dladdr, especially for large 249 // binaries with symbols. 250 char exe_path[MAXPATHLEN]; 251 uint32_t size = sizeof(exe_path); 252 if (_NSGetExecutablePath(exe_path, &size) == 0) { 253 char link_path[MAXPATHLEN]; 254 if (realpath(exe_path, link_path)) 255 return link_path; 256 } 257#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ 258 defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) 259 char exe_path[PATH_MAX]; 260 261 if (getprogpath(exe_path, argv0) != NULL) 262 return exe_path; 263#elif defined(__linux__) || defined(__CYGWIN__) 264 char exe_path[MAXPATHLEN]; 265 StringRef aPath("/proc/self/exe"); 266 if (sys::fs::exists(aPath)) { 267 // /proc is not always mounted under Linux (chroot for example). 268 ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path)); 269 if (len >= 0) 270 return StringRef(exe_path, len); 271 } else { 272 // Fall back to the classical detection. 273 if (getprogpath(exe_path, argv0) != NULL) 274 return exe_path; 275 } 276#elif defined(HAVE_DLFCN_H) 277 // Use dladdr to get executable path if available. 278 Dl_info DLInfo; 279 int err = dladdr(MainAddr, &DLInfo); 280 if (err == 0) 281 return ""; 282 283 // If the filename is a symlink, we need to resolve and return the location of 284 // the actual executable. 285 char link_path[MAXPATHLEN]; 286 if (realpath(DLInfo.dli_fname, link_path)) 287 return link_path; 288#else 289#error GetMainExecutable is not implemented on this host yet. 290#endif 291 return ""; 292} 293 294TimeValue file_status::getLastModificationTime() const { 295 TimeValue Ret; 296 Ret.fromEpochTime(fs_st_mtime); 297 return Ret; 298} 299 300error_code current_path(SmallVectorImpl<char> &result) { 301#ifdef MAXPATHLEN 302 result.reserve(MAXPATHLEN); 303#else 304// For GNU Hurd 305 result.reserve(1024); 306#endif 307 308 while (true) { 309 if (::getcwd(result.data(), result.capacity()) == 0) { 310 // See if there was a real error. 311 if (errno != errc::not_enough_memory) 312 return error_code(errno, system_category()); 313 // Otherwise there just wasn't enough space. 314 result.reserve(result.capacity() * 2); 315 } else 316 break; 317 } 318 319 result.set_size(strlen(result.data())); 320 return error_code::success(); 321} 322 323error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { 324 // Get arguments. 325 SmallString<128> from_storage; 326 SmallString<128> to_storage; 327 StringRef f = from.toNullTerminatedStringRef(from_storage); 328 StringRef t = to.toNullTerminatedStringRef(to_storage); 329 330 const size_t buf_sz = 32768; 331 char buffer[buf_sz]; 332 int from_file = -1, to_file = -1; 333 334 // Open from. 335 if ((from_file = ::open(f.begin(), O_RDONLY)) < 0) 336 return error_code(errno, system_category()); 337 AutoFD from_fd(from_file); 338 339 // Stat from. 340 struct stat from_stat; 341 if (::stat(f.begin(), &from_stat) != 0) 342 return error_code(errno, system_category()); 343 344 // Setup to flags. 345 int to_flags = O_CREAT | O_WRONLY; 346 if (copt == copy_option::fail_if_exists) 347 to_flags |= O_EXCL; 348 349 // Open to. 350 if ((to_file = ::open(t.begin(), to_flags, from_stat.st_mode)) < 0) 351 return error_code(errno, system_category()); 352 AutoFD to_fd(to_file); 353 354 // Copy! 355 ssize_t sz, sz_read = 1, sz_write; 356 while (sz_read > 0 && 357 (sz_read = ::read(from_fd, buffer, buf_sz)) > 0) { 358 // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), 359 // Marc Rochkind, Addison-Wesley, 2004, page 94 360 sz_write = 0; 361 do { 362 if ((sz = ::write(to_fd, buffer + sz_write, sz_read - sz_write)) < 0) { 363 sz_read = sz; // cause read loop termination. 364 break; // error. 365 } 366 sz_write += sz; 367 } while (sz_write < sz_read); 368 } 369 370 // After all the file operations above the return value of close actually 371 // matters. 372 if (::close(from_fd.take()) < 0) sz_read = -1; 373 if (::close(to_fd.take()) < 0) sz_read = -1; 374 375 // Check for errors. 376 if (sz_read < 0) 377 return error_code(errno, system_category()); 378 379 return error_code::success(); 380} 381 382error_code create_directory(const Twine &path, bool &existed) { 383 SmallString<128> path_storage; 384 StringRef p = path.toNullTerminatedStringRef(path_storage); 385 386 if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { 387 if (errno != errc::file_exists) 388 return error_code(errno, system_category()); 389 existed = true; 390 } else 391 existed = false; 392 393 return error_code::success(); 394} 395 396error_code create_hard_link(const Twine &to, const Twine &from) { 397 // Get arguments. 398 SmallString<128> from_storage; 399 SmallString<128> to_storage; 400 StringRef f = from.toNullTerminatedStringRef(from_storage); 401 StringRef t = to.toNullTerminatedStringRef(to_storage); 402 403 if (::link(t.begin(), f.begin()) == -1) 404 return error_code(errno, system_category()); 405 406 return error_code::success(); 407} 408 409error_code create_symlink(const Twine &to, const Twine &from) { 410 // Get arguments. 411 SmallString<128> from_storage; 412 SmallString<128> to_storage; 413 StringRef f = from.toNullTerminatedStringRef(from_storage); 414 StringRef t = to.toNullTerminatedStringRef(to_storage); 415 416 if (::symlink(t.begin(), f.begin()) == -1) 417 return error_code(errno, system_category()); 418 419 return error_code::success(); 420} 421 422error_code remove(const Twine &path, bool &existed) { 423 SmallString<128> path_storage; 424 StringRef p = path.toNullTerminatedStringRef(path_storage); 425 426 struct stat buf; 427 if (stat(p.begin(), &buf) != 0) { 428 if (errno != errc::no_such_file_or_directory) 429 return error_code(errno, system_category()); 430 existed = false; 431 return error_code::success(); 432 } 433 434 // Note: this check catches strange situations. In all cases, LLVM should 435 // only be involved in the creation and deletion of regular files. This 436 // check ensures that what we're trying to erase is a regular file. It 437 // effectively prevents LLVM from erasing things like /dev/null, any block 438 // special file, or other things that aren't "regular" files. 439 if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) 440 return make_error_code(errc::operation_not_permitted); 441 442 if (::remove(p.begin()) == -1) { 443 if (errno != errc::no_such_file_or_directory) 444 return error_code(errno, system_category()); 445 existed = false; 446 } else 447 existed = true; 448 449 return error_code::success(); 450} 451 452error_code rename(const Twine &from, const Twine &to) { 453 // Get arguments. 454 SmallString<128> from_storage; 455 SmallString<128> to_storage; 456 StringRef f = from.toNullTerminatedStringRef(from_storage); 457 StringRef t = to.toNullTerminatedStringRef(to_storage); 458 459 if (::rename(f.begin(), t.begin()) == -1) { 460 // If it's a cross device link, copy then delete, otherwise return the error 461 if (errno == EXDEV) { 462 if (error_code ec = copy_file(from, to, copy_option::overwrite_if_exists)) 463 return ec; 464 bool Existed; 465 if (error_code ec = remove(from, Existed)) 466 return ec; 467 } else 468 return error_code(errno, system_category()); 469 } 470 471 return error_code::success(); 472} 473 474error_code resize_file(const Twine &path, uint64_t size) { 475 SmallString<128> path_storage; 476 StringRef p = path.toNullTerminatedStringRef(path_storage); 477 478 if (::truncate(p.begin(), size) == -1) 479 return error_code(errno, system_category()); 480 481 return error_code::success(); 482} 483 484error_code exists(const Twine &path, bool &result) { 485 SmallString<128> path_storage; 486 StringRef p = path.toNullTerminatedStringRef(path_storage); 487 488 if (::access(p.begin(), F_OK) == -1) { 489 if (errno != errc::no_such_file_or_directory) 490 return error_code(errno, system_category()); 491 result = false; 492 } else 493 result = true; 494 495 return error_code::success(); 496} 497 498bool can_write(const Twine &Path) { 499 SmallString<128> PathStorage; 500 StringRef P = Path.toNullTerminatedStringRef(PathStorage); 501 return 0 == access(P.begin(), W_OK); 502} 503 504bool can_execute(const Twine &Path) { 505 SmallString<128> PathStorage; 506 StringRef P = Path.toNullTerminatedStringRef(PathStorage); 507 508 if (0 != access(P.begin(), R_OK | X_OK)) 509 return false; 510 struct stat buf; 511 if (0 != stat(P.begin(), &buf)) 512 return false; 513 if (!S_ISREG(buf.st_mode)) 514 return false; 515 return true; 516} 517 518bool equivalent(file_status A, file_status B) { 519 assert(status_known(A) && status_known(B)); 520 return A.fs_st_dev == B.fs_st_dev && 521 A.fs_st_ino == B.fs_st_ino; 522} 523 524error_code equivalent(const Twine &A, const Twine &B, bool &result) { 525 file_status fsA, fsB; 526 if (error_code ec = status(A, fsA)) return ec; 527 if (error_code ec = status(B, fsB)) return ec; 528 result = equivalent(fsA, fsB); 529 return error_code::success(); 530} 531 532error_code getUniqueID(const Twine Path, uint64_t &Result) { 533 SmallString<128> Storage; 534 StringRef P = Path.toNullTerminatedStringRef(Storage); 535 536 struct stat Status; 537 if (::stat(P.begin(), &Status) != 0) 538 return error_code(errno, system_category()); 539 540 Result = Status.st_ino; 541 return error_code::success(); 542} 543 544error_code status(const Twine &path, file_status &result) { 545 SmallString<128> path_storage; 546 StringRef p = path.toNullTerminatedStringRef(path_storage); 547 548 struct stat status; 549 if (::stat(p.begin(), &status) != 0) { 550 error_code ec(errno, system_category()); 551 if (ec == errc::no_such_file_or_directory) 552 result = file_status(file_type::file_not_found); 553 else 554 result = file_status(file_type::status_error); 555 return ec; 556 } 557 558 perms prms = static_cast<perms>(status.st_mode); 559 file_type Type = file_type::type_unknown; 560 561 if (S_ISDIR(status.st_mode)) 562 Type = file_type::directory_file; 563 else if (S_ISREG(status.st_mode)) 564 Type = file_type::regular_file; 565 else if (S_ISBLK(status.st_mode)) 566 Type = file_type::block_file; 567 else if (S_ISCHR(status.st_mode)) 568 Type = file_type::character_file; 569 else if (S_ISFIFO(status.st_mode)) 570 Type = file_type::fifo_file; 571 else if (S_ISSOCK(status.st_mode)) 572 Type = file_type::socket_file; 573 574 result = 575 file_status(Type, prms, status.st_dev, status.st_ino, status.st_mtime, 576 status.st_uid, status.st_gid, status.st_size); 577 578 return error_code::success(); 579} 580 581error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { 582#if defined(HAVE_FUTIMENS) 583 timespec Times[2]; 584 Times[0].tv_sec = Time.toPosixTime(); 585 Times[0].tv_nsec = 0; 586 Times[1] = Times[0]; 587 if (::futimens(FD, Times)) 588#elif defined(HAVE_FUTIMES) 589 timeval Times[2]; 590 Times[0].tv_sec = Time.toPosixTime(); 591 Times[0].tv_usec = 0; 592 Times[1] = Times[0]; 593 if (::futimes(FD, Times)) 594#else 595#error Missing futimes() and futimens() 596#endif 597 return error_code(errno, system_category()); 598 return error_code::success(); 599} 600 601error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { 602 AutoFD ScopedFD(FD); 603 if (!CloseFD) 604 ScopedFD.take(); 605 606 // Figure out how large the file is. 607 struct stat FileInfo; 608 if (fstat(FD, &FileInfo) == -1) 609 return error_code(errno, system_category()); 610 uint64_t FileSize = FileInfo.st_size; 611 612 if (Size == 0) 613 Size = FileSize; 614 else if (FileSize < Size) { 615 // We need to grow the file. 616 if (ftruncate(FD, Size) == -1) 617 return error_code(errno, system_category()); 618 } 619 620 int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; 621 int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); 622#ifdef MAP_FILE 623 flags |= MAP_FILE; 624#endif 625 Mapping = ::mmap(0, Size, prot, flags, FD, Offset); 626 if (Mapping == MAP_FAILED) 627 return error_code(errno, system_category()); 628 return error_code::success(); 629} 630 631mapped_file_region::mapped_file_region(const Twine &path, 632 mapmode mode, 633 uint64_t length, 634 uint64_t offset, 635 error_code &ec) 636 : Mode(mode) 637 , Size(length) 638 , Mapping() { 639 // Make sure that the requested size fits within SIZE_T. 640 if (length > std::numeric_limits<size_t>::max()) { 641 ec = make_error_code(errc::invalid_argument); 642 return; 643 } 644 645 SmallString<128> path_storage; 646 StringRef name = path.toNullTerminatedStringRef(path_storage); 647 int oflags = (mode == readonly) ? O_RDONLY : O_RDWR; 648 int ofd = ::open(name.begin(), oflags); 649 if (ofd == -1) { 650 ec = error_code(errno, system_category()); 651 return; 652 } 653 654 ec = init(ofd, true, offset); 655 if (ec) 656 Mapping = 0; 657} 658 659mapped_file_region::mapped_file_region(int fd, 660 bool closefd, 661 mapmode mode, 662 uint64_t length, 663 uint64_t offset, 664 error_code &ec) 665 : Mode(mode) 666 , Size(length) 667 , Mapping() { 668 // Make sure that the requested size fits within SIZE_T. 669 if (length > std::numeric_limits<size_t>::max()) { 670 ec = make_error_code(errc::invalid_argument); 671 return; 672 } 673 674 ec = init(fd, closefd, offset); 675 if (ec) 676 Mapping = 0; 677} 678 679mapped_file_region::~mapped_file_region() { 680 if (Mapping) 681 ::munmap(Mapping, Size); 682} 683 684#if LLVM_HAS_RVALUE_REFERENCES 685mapped_file_region::mapped_file_region(mapped_file_region &&other) 686 : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { 687 other.Mapping = 0; 688} 689#endif 690 691mapped_file_region::mapmode mapped_file_region::flags() const { 692 assert(Mapping && "Mapping failed but used anyway!"); 693 return Mode; 694} 695 696uint64_t mapped_file_region::size() const { 697 assert(Mapping && "Mapping failed but used anyway!"); 698 return Size; 699} 700 701char *mapped_file_region::data() const { 702 assert(Mapping && "Mapping failed but used anyway!"); 703 assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); 704 return reinterpret_cast<char*>(Mapping); 705} 706 707const char *mapped_file_region::const_data() const { 708 assert(Mapping && "Mapping failed but used anyway!"); 709 return reinterpret_cast<const char*>(Mapping); 710} 711 712int mapped_file_region::alignment() { 713 return process::get_self()->page_size(); 714} 715 716error_code detail::directory_iterator_construct(detail::DirIterState &it, 717 StringRef path){ 718 SmallString<128> path_null(path); 719 DIR *directory = ::opendir(path_null.c_str()); 720 if (directory == 0) 721 return error_code(errno, system_category()); 722 723 it.IterationHandle = reinterpret_cast<intptr_t>(directory); 724 // Add something for replace_filename to replace. 725 path::append(path_null, "."); 726 it.CurrentEntry = directory_entry(path_null.str()); 727 return directory_iterator_increment(it); 728} 729 730error_code detail::directory_iterator_destruct(detail::DirIterState &it) { 731 if (it.IterationHandle) 732 ::closedir(reinterpret_cast<DIR *>(it.IterationHandle)); 733 it.IterationHandle = 0; 734 it.CurrentEntry = directory_entry(); 735 return error_code::success(); 736} 737 738error_code detail::directory_iterator_increment(detail::DirIterState &it) { 739 errno = 0; 740 dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle)); 741 if (cur_dir == 0 && errno != 0) { 742 return error_code(errno, system_category()); 743 } else if (cur_dir != 0) { 744 StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); 745 if ((name.size() == 1 && name[0] == '.') || 746 (name.size() == 2 && name[0] == '.' && name[1] == '.')) 747 return directory_iterator_increment(it); 748 it.CurrentEntry.replace_filename(name); 749 } else 750 return directory_iterator_destruct(it); 751 752 return error_code::success(); 753} 754 755error_code get_magic(const Twine &path, uint32_t len, 756 SmallVectorImpl<char> &result) { 757 SmallString<128> PathStorage; 758 StringRef Path = path.toNullTerminatedStringRef(PathStorage); 759 result.set_size(0); 760 761 // Open path. 762 std::FILE *file = std::fopen(Path.data(), "rb"); 763 if (file == 0) 764 return error_code(errno, system_category()); 765 766 // Reserve storage. 767 result.reserve(len); 768 769 // Read magic! 770 size_t size = std::fread(result.data(), 1, len, file); 771 if (std::ferror(file) != 0) { 772 std::fclose(file); 773 return error_code(errno, system_category()); 774 } else if (size != len) { 775 if (std::feof(file) != 0) { 776 std::fclose(file); 777 result.set_size(size); 778 return make_error_code(errc::value_too_large); 779 } 780 } 781 std::fclose(file); 782 result.set_size(size); 783 return error_code::success(); 784} 785 786error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, 787 bool map_writable, void *&result) { 788 SmallString<128> path_storage; 789 StringRef name = path.toNullTerminatedStringRef(path_storage); 790 int oflags = map_writable ? O_RDWR : O_RDONLY; 791 int ofd = ::open(name.begin(), oflags); 792 if ( ofd == -1 ) 793 return error_code(errno, system_category()); 794 AutoFD fd(ofd); 795 int flags = map_writable ? MAP_SHARED : MAP_PRIVATE; 796 int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ; 797#ifdef MAP_FILE 798 flags |= MAP_FILE; 799#endif 800 result = ::mmap(0, size, prot, flags, fd, file_offset); 801 if (result == MAP_FAILED) { 802 return error_code(errno, system_category()); 803 } 804 805 return error_code::success(); 806} 807 808error_code unmap_file_pages(void *base, size_t size) { 809 if ( ::munmap(base, size) == -1 ) 810 return error_code(errno, system_category()); 811 812 return error_code::success(); 813} 814 815 816} // end namespace fs 817} // end namespace sys 818} // end namespace llvm 819