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__) 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(__FreeBSD_kernel__) 255 char exe_path[PATH_MAX]; 256 257 if (getprogpath(exe_path, argv0) != NULL) 258 return exe_path; 259#elif defined(__linux__) || defined(__CYGWIN__) 260 char exe_path[MAXPATHLEN]; 261 StringRef aPath("/proc/self/exe"); 262 if (sys::fs::exists(aPath)) { 263 // /proc is not always mounted under Linux (chroot for example). 264 ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path)); 265 if (len >= 0) 266 return StringRef(exe_path, len); 267 } else { 268 // Fall back to the classical detection. 269 if (getprogpath(exe_path, argv0) != NULL) 270 return exe_path; 271 } 272#elif defined(HAVE_DLFCN_H) 273 // Use dladdr to get executable path if available. 274 Dl_info DLInfo; 275 int err = dladdr(MainAddr, &DLInfo); 276 if (err == 0) 277 return ""; 278 279 // If the filename is a symlink, we need to resolve and return the location of 280 // the actual executable. 281 char link_path[MAXPATHLEN]; 282 if (realpath(DLInfo.dli_fname, link_path)) 283 return link_path; 284#else 285#error GetMainExecutable is not implemented on this host yet. 286#endif 287 return ""; 288} 289 290TimeValue file_status::getLastModificationTime() const { 291 TimeValue Ret; 292 Ret.fromEpochTime(fs_st_mtime); 293 return Ret; 294} 295 296UniqueID file_status::getUniqueID() const { 297 return UniqueID(fs_st_dev, fs_st_ino); 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 create_directory(const Twine &path, bool &existed) { 324 SmallString<128> path_storage; 325 StringRef p = path.toNullTerminatedStringRef(path_storage); 326 327 if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { 328 if (errno != errc::file_exists) 329 return error_code(errno, system_category()); 330 existed = true; 331 } else 332 existed = false; 333 334 return error_code::success(); 335} 336 337error_code create_hard_link(const Twine &to, const Twine &from) { 338 // Get arguments. 339 SmallString<128> from_storage; 340 SmallString<128> to_storage; 341 StringRef f = from.toNullTerminatedStringRef(from_storage); 342 StringRef t = to.toNullTerminatedStringRef(to_storage); 343 344 if (::link(t.begin(), f.begin()) == -1) 345 return error_code(errno, system_category()); 346 347 return error_code::success(); 348} 349 350error_code create_symlink(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 (::symlink(t.begin(), f.begin()) == -1) 358 return error_code(errno, system_category()); 359 360 return error_code::success(); 361} 362 363error_code remove(const Twine &path, bool &existed) { 364 SmallString<128> path_storage; 365 StringRef p = path.toNullTerminatedStringRef(path_storage); 366 367 struct stat buf; 368 if (stat(p.begin(), &buf) != 0) { 369 if (errno != errc::no_such_file_or_directory) 370 return error_code(errno, system_category()); 371 existed = false; 372 return error_code::success(); 373 } 374 375 // Note: this check catches strange situations. In all cases, LLVM should 376 // only be involved in the creation and deletion of regular files. This 377 // check ensures that what we're trying to erase is a regular file. It 378 // effectively prevents LLVM from erasing things like /dev/null, any block 379 // special file, or other things that aren't "regular" files. 380 if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) 381 return make_error_code(errc::operation_not_permitted); 382 383 if (::remove(p.begin()) == -1) { 384 if (errno != errc::no_such_file_or_directory) 385 return error_code(errno, system_category()); 386 existed = false; 387 } else 388 existed = true; 389 390 return error_code::success(); 391} 392 393error_code rename(const Twine &from, const Twine &to) { 394 // Get arguments. 395 SmallString<128> from_storage; 396 SmallString<128> to_storage; 397 StringRef f = from.toNullTerminatedStringRef(from_storage); 398 StringRef t = to.toNullTerminatedStringRef(to_storage); 399 400 if (::rename(f.begin(), t.begin()) == -1) 401 return error_code(errno, system_category()); 402 403 return error_code::success(); 404} 405 406error_code resize_file(const Twine &path, uint64_t size) { 407 SmallString<128> path_storage; 408 StringRef p = path.toNullTerminatedStringRef(path_storage); 409 410 if (::truncate(p.begin(), size) == -1) 411 return error_code(errno, system_category()); 412 413 return error_code::success(); 414} 415 416error_code exists(const Twine &path, bool &result) { 417 SmallString<128> path_storage; 418 StringRef p = path.toNullTerminatedStringRef(path_storage); 419 420 if (::access(p.begin(), F_OK) == -1) { 421 if (errno != errc::no_such_file_or_directory) 422 return error_code(errno, system_category()); 423 result = false; 424 } else 425 result = true; 426 427 return error_code::success(); 428} 429 430bool can_write(const Twine &Path) { 431 SmallString<128> PathStorage; 432 StringRef P = Path.toNullTerminatedStringRef(PathStorage); 433 return 0 == access(P.begin(), W_OK); 434} 435 436bool can_execute(const Twine &Path) { 437 SmallString<128> PathStorage; 438 StringRef P = Path.toNullTerminatedStringRef(PathStorage); 439 440 if (0 != access(P.begin(), R_OK | X_OK)) 441 return false; 442 struct stat buf; 443 if (0 != stat(P.begin(), &buf)) 444 return false; 445 if (!S_ISREG(buf.st_mode)) 446 return false; 447 return true; 448} 449 450bool equivalent(file_status A, file_status B) { 451 assert(status_known(A) && status_known(B)); 452 return A.fs_st_dev == B.fs_st_dev && 453 A.fs_st_ino == B.fs_st_ino; 454} 455 456error_code equivalent(const Twine &A, const Twine &B, bool &result) { 457 file_status fsA, fsB; 458 if (error_code ec = status(A, fsA)) return ec; 459 if (error_code ec = status(B, fsB)) return ec; 460 result = equivalent(fsA, fsB); 461 return error_code::success(); 462} 463 464static error_code fillStatus(int StatRet, const struct stat &Status, 465 file_status &Result) { 466 if (StatRet != 0) { 467 error_code ec(errno, system_category()); 468 if (ec == errc::no_such_file_or_directory) 469 Result = file_status(file_type::file_not_found); 470 else 471 Result = file_status(file_type::status_error); 472 return ec; 473 } 474 475 file_type Type = file_type::type_unknown; 476 477 if (S_ISDIR(Status.st_mode)) 478 Type = file_type::directory_file; 479 else if (S_ISREG(Status.st_mode)) 480 Type = file_type::regular_file; 481 else if (S_ISBLK(Status.st_mode)) 482 Type = file_type::block_file; 483 else if (S_ISCHR(Status.st_mode)) 484 Type = file_type::character_file; 485 else if (S_ISFIFO(Status.st_mode)) 486 Type = file_type::fifo_file; 487 else if (S_ISSOCK(Status.st_mode)) 488 Type = file_type::socket_file; 489 490 perms Perms = static_cast<perms>(Status.st_mode); 491 Result = 492 file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_mtime, 493 Status.st_uid, Status.st_gid, Status.st_size); 494 495 return error_code::success(); 496} 497 498error_code status(const Twine &Path, file_status &Result) { 499 SmallString<128> PathStorage; 500 StringRef P = Path.toNullTerminatedStringRef(PathStorage); 501 502 struct stat Status; 503 int StatRet = ::stat(P.begin(), &Status); 504 return fillStatus(StatRet, Status, Result); 505} 506 507error_code status(int FD, file_status &Result) { 508 struct stat Status; 509 int StatRet = ::fstat(FD, &Status); 510 return fillStatus(StatRet, Status, Result); 511} 512 513error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { 514#if defined(HAVE_FUTIMENS) 515 timespec Times[2]; 516 Times[0].tv_sec = Time.toPosixTime(); 517 Times[0].tv_nsec = 0; 518 Times[1] = Times[0]; 519 if (::futimens(FD, Times)) 520#elif defined(HAVE_FUTIMES) 521 timeval Times[2]; 522 Times[0].tv_sec = Time.toPosixTime(); 523 Times[0].tv_usec = 0; 524 Times[1] = Times[0]; 525 if (::futimes(FD, Times)) 526#else 527#error Missing futimes() and futimens() 528#endif 529 return error_code(errno, system_category()); 530 return error_code::success(); 531} 532 533error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { 534 AutoFD ScopedFD(FD); 535 if (!CloseFD) 536 ScopedFD.take(); 537 538 // Figure out how large the file is. 539 struct stat FileInfo; 540 if (fstat(FD, &FileInfo) == -1) 541 return error_code(errno, system_category()); 542 uint64_t FileSize = FileInfo.st_size; 543 544 if (Size == 0) 545 Size = FileSize; 546 else if (FileSize < Size) { 547 // We need to grow the file. 548 if (ftruncate(FD, Size) == -1) 549 return error_code(errno, system_category()); 550 } 551 552 int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; 553 int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); 554#ifdef MAP_FILE 555 flags |= MAP_FILE; 556#endif 557 Mapping = ::mmap(0, Size, prot, flags, FD, Offset); 558 if (Mapping == MAP_FAILED) 559 return error_code(errno, system_category()); 560 return error_code::success(); 561} 562 563mapped_file_region::mapped_file_region(const Twine &path, 564 mapmode mode, 565 uint64_t length, 566 uint64_t offset, 567 error_code &ec) 568 : Mode(mode) 569 , Size(length) 570 , Mapping() { 571 // Make sure that the requested size fits within SIZE_T. 572 if (length > std::numeric_limits<size_t>::max()) { 573 ec = make_error_code(errc::invalid_argument); 574 return; 575 } 576 577 SmallString<128> path_storage; 578 StringRef name = path.toNullTerminatedStringRef(path_storage); 579 int oflags = (mode == readonly) ? O_RDONLY : O_RDWR; 580 int ofd = ::open(name.begin(), oflags); 581 if (ofd == -1) { 582 ec = error_code(errno, system_category()); 583 return; 584 } 585 586 ec = init(ofd, true, offset); 587 if (ec) 588 Mapping = 0; 589} 590 591mapped_file_region::mapped_file_region(int fd, 592 bool closefd, 593 mapmode mode, 594 uint64_t length, 595 uint64_t offset, 596 error_code &ec) 597 : Mode(mode) 598 , Size(length) 599 , Mapping() { 600 // Make sure that the requested size fits within SIZE_T. 601 if (length > std::numeric_limits<size_t>::max()) { 602 ec = make_error_code(errc::invalid_argument); 603 return; 604 } 605 606 ec = init(fd, closefd, offset); 607 if (ec) 608 Mapping = 0; 609} 610 611mapped_file_region::~mapped_file_region() { 612 if (Mapping) 613 ::munmap(Mapping, Size); 614} 615 616#if LLVM_HAS_RVALUE_REFERENCES 617mapped_file_region::mapped_file_region(mapped_file_region &&other) 618 : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { 619 other.Mapping = 0; 620} 621#endif 622 623mapped_file_region::mapmode mapped_file_region::flags() const { 624 assert(Mapping && "Mapping failed but used anyway!"); 625 return Mode; 626} 627 628uint64_t mapped_file_region::size() const { 629 assert(Mapping && "Mapping failed but used anyway!"); 630 return Size; 631} 632 633char *mapped_file_region::data() const { 634 assert(Mapping && "Mapping failed but used anyway!"); 635 assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); 636 return reinterpret_cast<char*>(Mapping); 637} 638 639const char *mapped_file_region::const_data() const { 640 assert(Mapping && "Mapping failed but used anyway!"); 641 return reinterpret_cast<const char*>(Mapping); 642} 643 644int mapped_file_region::alignment() { 645 return process::get_self()->page_size(); 646} 647 648error_code detail::directory_iterator_construct(detail::DirIterState &it, 649 StringRef path){ 650 SmallString<128> path_null(path); 651 DIR *directory = ::opendir(path_null.c_str()); 652 if (directory == 0) 653 return error_code(errno, system_category()); 654 655 it.IterationHandle = reinterpret_cast<intptr_t>(directory); 656 // Add something for replace_filename to replace. 657 path::append(path_null, "."); 658 it.CurrentEntry = directory_entry(path_null.str()); 659 return directory_iterator_increment(it); 660} 661 662error_code detail::directory_iterator_destruct(detail::DirIterState &it) { 663 if (it.IterationHandle) 664 ::closedir(reinterpret_cast<DIR *>(it.IterationHandle)); 665 it.IterationHandle = 0; 666 it.CurrentEntry = directory_entry(); 667 return error_code::success(); 668} 669 670error_code detail::directory_iterator_increment(detail::DirIterState &it) { 671 errno = 0; 672 dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle)); 673 if (cur_dir == 0 && errno != 0) { 674 return error_code(errno, system_category()); 675 } else if (cur_dir != 0) { 676 StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); 677 if ((name.size() == 1 && name[0] == '.') || 678 (name.size() == 2 && name[0] == '.' && name[1] == '.')) 679 return directory_iterator_increment(it); 680 it.CurrentEntry.replace_filename(name); 681 } else 682 return directory_iterator_destruct(it); 683 684 return error_code::success(); 685} 686 687error_code get_magic(const Twine &path, uint32_t len, 688 SmallVectorImpl<char> &result) { 689 SmallString<128> PathStorage; 690 StringRef Path = path.toNullTerminatedStringRef(PathStorage); 691 result.set_size(0); 692 693 // Open path. 694 std::FILE *file = std::fopen(Path.data(), "rb"); 695 if (file == 0) 696 return error_code(errno, system_category()); 697 698 // Reserve storage. 699 result.reserve(len); 700 701 // Read magic! 702 size_t size = std::fread(result.data(), 1, len, file); 703 if (std::ferror(file) != 0) { 704 std::fclose(file); 705 return error_code(errno, system_category()); 706 } else if (size != len) { 707 if (std::feof(file) != 0) { 708 std::fclose(file); 709 result.set_size(size); 710 return make_error_code(errc::value_too_large); 711 } 712 } 713 std::fclose(file); 714 result.set_size(size); 715 return error_code::success(); 716} 717 718error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, 719 bool map_writable, void *&result) { 720 SmallString<128> path_storage; 721 StringRef name = path.toNullTerminatedStringRef(path_storage); 722 int oflags = map_writable ? O_RDWR : O_RDONLY; 723 int ofd = ::open(name.begin(), oflags); 724 if ( ofd == -1 ) 725 return error_code(errno, system_category()); 726 AutoFD fd(ofd); 727 int flags = map_writable ? MAP_SHARED : MAP_PRIVATE; 728 int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ; 729#ifdef MAP_FILE 730 flags |= MAP_FILE; 731#endif 732 result = ::mmap(0, size, prot, flags, fd, file_offset); 733 if (result == MAP_FAILED) { 734 return error_code(errno, system_category()); 735 } 736 737 return error_code::success(); 738} 739 740error_code unmap_file_pages(void *base, size_t size) { 741 if ( ::munmap(base, size) == -1 ) 742 return error_code(errno, system_category()); 743 744 return error_code::success(); 745} 746 747error_code openFileForRead(const Twine &Name, int &ResultFD) { 748 SmallString<128> Storage; 749 StringRef P = Name.toNullTerminatedStringRef(Storage); 750 while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) { 751 if (errno != EINTR) 752 return error_code(errno, system_category()); 753 } 754 return error_code::success(); 755} 756 757error_code openFileForWrite(const Twine &Name, int &ResultFD, 758 sys::fs::OpenFlags Flags, unsigned Mode) { 759 // Verify that we don't have both "append" and "excl". 760 assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && 761 "Cannot specify both 'excl' and 'append' file creation flags!"); 762 763 int OpenFlags = O_WRONLY | O_CREAT; 764 765 if (Flags & F_Append) 766 OpenFlags |= O_APPEND; 767 else 768 OpenFlags |= O_TRUNC; 769 770 if (Flags & F_Excl) 771 OpenFlags |= O_EXCL; 772 773 SmallString<128> Storage; 774 StringRef P = Name.toNullTerminatedStringRef(Storage); 775 while ((ResultFD = open(P.begin(), OpenFlags, Mode)) < 0) { 776 if (errno != EINTR) 777 return error_code(errno, system_category()); 778 } 779 return error_code::success(); 780} 781 782} // end namespace fs 783} // end namespace sys 784} // end namespace llvm 785