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