1//===-- FileSpec.cpp --------------------------------------------*- 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 11#include "lldb/Host/File.h" 12 13#include <errno.h> 14#include <fcntl.h> 15#include <limits.h> 16#include <stdarg.h> 17#include <sys/stat.h> 18 19#include "lldb/Core/DataBufferHeap.h" 20#include "lldb/Core/Error.h" 21#include "lldb/Host/Config.h" 22#include "lldb/Host/FileSpec.h" 23 24using namespace lldb; 25using namespace lldb_private; 26 27static const char * 28GetStreamOpenModeFromOptions (uint32_t options) 29{ 30 if (options & File::eOpenOptionAppend) 31 { 32 if (options & File::eOpenOptionRead) 33 { 34 if (options & File::eOpenOptionCanCreateNewOnly) 35 return "a+x"; 36 else 37 return "a+"; 38 } 39 else if (options & File::eOpenOptionWrite) 40 { 41 if (options & File::eOpenOptionCanCreateNewOnly) 42 return "ax"; 43 else 44 return "a"; 45 } 46 } 47 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite) 48 { 49 if (options & File::eOpenOptionCanCreate) 50 { 51 if (options & File::eOpenOptionCanCreateNewOnly) 52 return "w+x"; 53 else 54 return "w+"; 55 } 56 else 57 return "r+"; 58 } 59 else if (options & File::eOpenOptionRead) 60 { 61 return "r"; 62 } 63 else if (options & File::eOpenOptionWrite) 64 { 65 return "w"; 66 } 67 return NULL; 68} 69 70int File::kInvalidDescriptor = -1; 71FILE * File::kInvalidStream = NULL; 72 73File::File(const char *path, uint32_t options, uint32_t permissions) : 74 m_descriptor (kInvalidDescriptor), 75 m_stream (kInvalidStream), 76 m_options (0), 77 m_owned (false) 78{ 79 Open (path, options, permissions); 80} 81 82File::File (const File &rhs) : 83 m_descriptor (kInvalidDescriptor), 84 m_stream (kInvalidStream), 85 m_options (0), 86 m_owned (false) 87{ 88 Duplicate (rhs); 89} 90 91 92File & 93File::operator = (const File &rhs) 94{ 95 if (this != &rhs) 96 Duplicate (rhs); 97 return *this; 98} 99 100File::~File() 101{ 102 Close (); 103} 104 105 106int 107File::GetDescriptor() const 108{ 109 if (DescriptorIsValid()) 110 return m_descriptor; 111 112 // Don't open the file descriptor if we don't need to, just get it from the 113 // stream if we have one. 114 if (StreamIsValid()) 115 return fileno (m_stream); 116 117 // Invalid descriptor and invalid stream, return invalid descriptor. 118 return kInvalidDescriptor; 119} 120 121void 122File::SetDescriptor (int fd, bool transfer_ownership) 123{ 124 if (IsValid()) 125 Close(); 126 m_descriptor = fd; 127 m_owned = transfer_ownership; 128} 129 130 131FILE * 132File::GetStream () 133{ 134 if (!StreamIsValid()) 135 { 136 if (DescriptorIsValid()) 137 { 138 const char *mode = GetStreamOpenModeFromOptions (m_options); 139 if (mode) 140 { 141 do 142 { 143 m_stream = ::fdopen (m_descriptor, mode); 144 } while (m_stream == NULL && errno == EINTR); 145 } 146 } 147 } 148 return m_stream; 149} 150 151 152void 153File::SetStream (FILE *fh, bool transfer_ownership) 154{ 155 if (IsValid()) 156 Close(); 157 m_stream = fh; 158 m_owned = transfer_ownership; 159} 160 161Error 162File::Duplicate (const File &rhs) 163{ 164 Error error; 165 if (IsValid ()) 166 Close(); 167 168 if (rhs.DescriptorIsValid()) 169 { 170 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD); 171 if (!DescriptorIsValid()) 172 error.SetErrorToErrno(); 173 else 174 { 175 m_options = rhs.m_options; 176 m_owned = true; 177 } 178 } 179 else 180 { 181 error.SetErrorString ("invalid file to duplicate"); 182 } 183 return error; 184} 185 186Error 187File::Open (const char *path, uint32_t options, uint32_t permissions) 188{ 189 Error error; 190 if (IsValid()) 191 Close (); 192 193 int oflag = 0; 194 const bool read = options & eOpenOptionRead; 195 const bool write = options & eOpenOptionWrite; 196 if (write) 197 { 198 if (read) 199 oflag |= O_RDWR; 200 else 201 oflag |= O_WRONLY; 202 203 if (options & eOpenOptionAppend) 204 oflag |= O_APPEND; 205 206 if (options & eOpenOptionTruncate) 207 oflag |= O_TRUNC; 208 209 if (options & eOpenOptionCanCreate) 210 oflag |= O_CREAT; 211 212 if (options & eOpenOptionCanCreateNewOnly) 213 oflag |= O_CREAT | O_EXCL; 214 } 215 else if (read) 216 { 217 oflag |= O_RDONLY; 218 } 219 220 if (options & eOpenOptionNonBlocking) 221 oflag |= O_NONBLOCK; 222 223 mode_t mode = 0; 224 if (oflag & O_CREAT) 225 { 226 if (permissions & ePermissionsUserRead) mode |= S_IRUSR; 227 if (permissions & ePermissionsUserWrite) mode |= S_IWUSR; 228 if (permissions & ePermissionsUserExecute) mode |= S_IXUSR; 229 if (permissions & ePermissionsGroupRead) mode |= S_IRGRP; 230 if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP; 231 if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP; 232 if (permissions & ePermissionsWorldRead) mode |= S_IROTH; 233 if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH; 234 if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH; 235 } 236 237 do 238 { 239 m_descriptor = ::open(path, oflag, mode); 240 } while (m_descriptor < 0 && errno == EINTR); 241 242 if (!DescriptorIsValid()) 243 error.SetErrorToErrno(); 244 else 245 m_owned = true; 246 247 return error; 248} 249 250Error 251File::Close () 252{ 253 Error error; 254 if (IsValid ()) 255 { 256 if (m_owned) 257 { 258 if (StreamIsValid()) 259 { 260 if (::fclose (m_stream) == EOF) 261 error.SetErrorToErrno(); 262 } 263 264 if (DescriptorIsValid()) 265 { 266 if (::close (m_descriptor) != 0) 267 error.SetErrorToErrno(); 268 } 269 } 270 m_descriptor = kInvalidDescriptor; 271 m_stream = kInvalidStream; 272 m_options = 0; 273 m_owned = false; 274 } 275 return error; 276} 277 278 279Error 280File::GetFileSpec (FileSpec &file_spec) const 281{ 282 Error error; 283#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED 284 if (IsValid ()) 285 { 286 char path[PATH_MAX]; 287 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) 288 error.SetErrorToErrno(); 289 else 290 file_spec.SetFile (path, false); 291 } 292 else 293 { 294 error.SetErrorString("invalid file handle"); 295 } 296#elif defined(__linux__) 297 char proc[64]; 298 char path[PATH_MAX]; 299 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) 300 error.SetErrorString ("cannot resolve file descriptor"); 301 else 302 { 303 ssize_t len; 304 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) 305 error.SetErrorToErrno(); 306 else 307 { 308 path[len] = '\0'; 309 file_spec.SetFile (path, false); 310 } 311 } 312#else 313 error.SetErrorString ("File::GetFileSpec is not supported on this platform"); 314#endif 315 316 if (error.Fail()) 317 file_spec.Clear(); 318 return error; 319} 320 321off_t 322File::SeekFromStart (off_t offset, Error *error_ptr) 323{ 324 off_t result = 0; 325 if (DescriptorIsValid()) 326 { 327 result = ::lseek (m_descriptor, offset, SEEK_SET); 328 329 if (error_ptr) 330 { 331 if (result == -1) 332 error_ptr->SetErrorToErrno(); 333 else 334 error_ptr->Clear(); 335 } 336 } 337 else if (StreamIsValid ()) 338 { 339 result = ::fseek(m_stream, offset, SEEK_SET); 340 341 if (error_ptr) 342 { 343 if (result == -1) 344 error_ptr->SetErrorToErrno(); 345 else 346 error_ptr->Clear(); 347 } 348 } 349 else if (error_ptr) 350 { 351 error_ptr->SetErrorString("invalid file handle"); 352 } 353 return result; 354} 355 356off_t 357File::SeekFromCurrent (off_t offset, Error *error_ptr) 358{ 359 off_t result = -1; 360 if (DescriptorIsValid()) 361 { 362 result = ::lseek (m_descriptor, offset, SEEK_CUR); 363 364 if (error_ptr) 365 { 366 if (result == -1) 367 error_ptr->SetErrorToErrno(); 368 else 369 error_ptr->Clear(); 370 } 371 } 372 else if (StreamIsValid ()) 373 { 374 result = ::fseek(m_stream, offset, SEEK_CUR); 375 376 if (error_ptr) 377 { 378 if (result == -1) 379 error_ptr->SetErrorToErrno(); 380 else 381 error_ptr->Clear(); 382 } 383 } 384 else if (error_ptr) 385 { 386 error_ptr->SetErrorString("invalid file handle"); 387 } 388 return result; 389} 390 391off_t 392File::SeekFromEnd (off_t offset, Error *error_ptr) 393{ 394 off_t result = -1; 395 if (DescriptorIsValid()) 396 { 397 result = ::lseek (m_descriptor, offset, SEEK_END); 398 399 if (error_ptr) 400 { 401 if (result == -1) 402 error_ptr->SetErrorToErrno(); 403 else 404 error_ptr->Clear(); 405 } 406 } 407 else if (StreamIsValid ()) 408 { 409 result = ::fseek(m_stream, offset, SEEK_END); 410 411 if (error_ptr) 412 { 413 if (result == -1) 414 error_ptr->SetErrorToErrno(); 415 else 416 error_ptr->Clear(); 417 } 418 } 419 else if (error_ptr) 420 { 421 error_ptr->SetErrorString("invalid file handle"); 422 } 423 return result; 424} 425 426Error 427File::Flush () 428{ 429 Error error; 430 if (StreamIsValid()) 431 { 432 int err = 0; 433 do 434 { 435 err = ::fflush (m_stream); 436 } while (err == EOF && errno == EINTR); 437 438 if (err == EOF) 439 error.SetErrorToErrno(); 440 } 441 else if (!DescriptorIsValid()) 442 { 443 error.SetErrorString("invalid file handle"); 444 } 445 return error; 446} 447 448 449Error 450File::Sync () 451{ 452 Error error; 453 if (DescriptorIsValid()) 454 { 455 int err = 0; 456 do 457 { 458 err = ::fsync (m_descriptor); 459 } while (err == -1 && errno == EINTR); 460 461 if (err == -1) 462 error.SetErrorToErrno(); 463 } 464 else 465 { 466 error.SetErrorString("invalid file handle"); 467 } 468 return error; 469} 470 471Error 472File::Read (void *buf, size_t &num_bytes) 473{ 474 Error error; 475 ssize_t bytes_read = -1; 476 if (DescriptorIsValid()) 477 { 478 do 479 { 480 bytes_read = ::read (m_descriptor, buf, num_bytes); 481 } while (bytes_read < 0 && errno == EINTR); 482 483 if (bytes_read == -1) 484 { 485 error.SetErrorToErrno(); 486 num_bytes = 0; 487 } 488 else 489 num_bytes = bytes_read; 490 } 491 else if (StreamIsValid()) 492 { 493 bytes_read = ::fread (buf, 1, num_bytes, m_stream); 494 495 if (bytes_read == 0) 496 { 497 if (::feof(m_stream)) 498 error.SetErrorString ("feof"); 499 else if (::ferror (m_stream)) 500 error.SetErrorString ("ferror"); 501 num_bytes = 0; 502 } 503 else 504 num_bytes = bytes_read; 505 } 506 else 507 { 508 num_bytes = 0; 509 error.SetErrorString("invalid file handle"); 510 } 511 return error; 512} 513 514Error 515File::Write (const void *buf, size_t &num_bytes) 516{ 517 Error error; 518 ssize_t bytes_written = -1; 519 if (DescriptorIsValid()) 520 { 521 do 522 { 523 bytes_written = ::write (m_descriptor, buf, num_bytes); 524 } while (bytes_written < 0 && errno == EINTR); 525 526 if (bytes_written == -1) 527 { 528 error.SetErrorToErrno(); 529 num_bytes = 0; 530 } 531 else 532 num_bytes = bytes_written; 533 } 534 else if (StreamIsValid()) 535 { 536 bytes_written = ::fwrite (buf, 1, num_bytes, m_stream); 537 538 if (bytes_written == 0) 539 { 540 if (::feof(m_stream)) 541 error.SetErrorString ("feof"); 542 else if (::ferror (m_stream)) 543 error.SetErrorString ("ferror"); 544 num_bytes = 0; 545 } 546 else 547 num_bytes = bytes_written; 548 549 } 550 else 551 { 552 num_bytes = 0; 553 error.SetErrorString("invalid file handle"); 554 } 555 return error; 556} 557 558 559Error 560File::Read (void *buf, size_t &num_bytes, off_t &offset) 561{ 562 Error error; 563 int fd = GetDescriptor(); 564 if (fd != kInvalidDescriptor) 565 { 566 ssize_t bytes_read = -1; 567 do 568 { 569 bytes_read = ::pread (fd, buf, num_bytes, offset); 570 } while (bytes_read < 0 && errno == EINTR); 571 572 if (bytes_read < 0) 573 { 574 num_bytes = 0; 575 error.SetErrorToErrno(); 576 } 577 else 578 { 579 offset += bytes_read; 580 num_bytes = bytes_read; 581 } 582 } 583 else 584 { 585 num_bytes = 0; 586 error.SetErrorString("invalid file handle"); 587 } 588 return error; 589} 590 591Error 592File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp) 593{ 594 Error error; 595 596 if (num_bytes > 0) 597 { 598 int fd = GetDescriptor(); 599 if (fd != kInvalidDescriptor) 600 { 601 struct stat file_stats; 602 if (::fstat (fd, &file_stats) == 0) 603 { 604 if (file_stats.st_size > offset) 605 { 606 const size_t bytes_left = file_stats.st_size - offset; 607 if (num_bytes > bytes_left) 608 num_bytes = bytes_left; 609 610 std::unique_ptr<DataBufferHeap> data_heap_ap; 611 data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0')); 612 613 if (data_heap_ap.get()) 614 { 615 error = Read (data_heap_ap->GetBytes(), num_bytes, offset); 616 if (error.Success()) 617 { 618 // Make sure we read exactly what we asked for and if we got 619 // less, adjust the array 620 if (num_bytes < data_heap_ap->GetByteSize()) 621 data_heap_ap->SetByteSize(num_bytes); 622 data_buffer_sp.reset(data_heap_ap.release()); 623 return error; 624 } 625 } 626 } 627 else 628 error.SetErrorString("file is empty"); 629 } 630 else 631 error.SetErrorToErrno(); 632 } 633 else 634 error.SetErrorString("invalid file handle"); 635 } 636 else 637 error.SetErrorString("invalid file handle"); 638 639 num_bytes = 0; 640 data_buffer_sp.reset(); 641 return error; 642} 643 644Error 645File::Write (const void *buf, size_t &num_bytes, off_t &offset) 646{ 647 Error error; 648 int fd = GetDescriptor(); 649 if (fd != kInvalidDescriptor) 650 { 651 ssize_t bytes_written = -1; 652 do 653 { 654 bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset); 655 } while (bytes_written < 0 && errno == EINTR); 656 657 if (bytes_written < 0) 658 { 659 num_bytes = 0; 660 error.SetErrorToErrno(); 661 } 662 else 663 { 664 offset += bytes_written; 665 num_bytes = bytes_written; 666 } 667 } 668 else 669 { 670 num_bytes = 0; 671 error.SetErrorString("invalid file handle"); 672 } 673 return error; 674} 675 676//------------------------------------------------------------------ 677// Print some formatted output to the stream. 678//------------------------------------------------------------------ 679size_t 680File::Printf (const char *format, ...) 681{ 682 va_list args; 683 va_start (args, format); 684 size_t result = PrintfVarArg (format, args); 685 va_end (args); 686 return result; 687} 688 689//------------------------------------------------------------------ 690// Print some formatted output to the stream. 691//------------------------------------------------------------------ 692size_t 693File::PrintfVarArg (const char *format, va_list args) 694{ 695 size_t result = 0; 696 if (DescriptorIsValid()) 697 { 698 char *s = NULL; 699 result = vasprintf(&s, format, args); 700 if (s != NULL) 701 { 702 if (result > 0) 703 { 704 size_t s_len = result; 705 Write (s, s_len); 706 result = s_len; 707 } 708 free (s); 709 } 710 } 711 else if (StreamIsValid()) 712 { 713 result = ::vfprintf (m_stream, format, args); 714 } 715 return result; 716} 717