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 24 using namespace lldb; 25 using namespace lldb_private; 26 27 static const char * 28 GetStreamOpenModeFromOptions (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 70 int File::kInvalidDescriptor = -1; 71 FILE * File::kInvalidStream = NULL; 72 73 File::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 82 File::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 92 File & 93 File::operator = (const File &rhs) 94 { 95 if (this != &rhs) 96 Duplicate (rhs); 97 return *this; 98 } 99 100 File::~File() 101 { 102 Close (); 103 } 104 105 106 int 107 File::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 121 void 122 File::SetDescriptor (int fd, bool transfer_ownership) 123 { 124 if (IsValid()) 125 Close(); 126 m_descriptor = fd; 127 m_owned = transfer_ownership; 128 } 129 130 131 FILE * 132 File::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 152 void 153 File::SetStream (FILE *fh, bool transfer_ownership) 154 { 155 if (IsValid()) 156 Close(); 157 m_stream = fh; 158 m_owned = transfer_ownership; 159 } 160 161 Error 162 File::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 186 Error 187 File::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 250 Error 251 File::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 279 Error 280 File::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 321 Error 322 File::SeekFromStart (off_t& offset) 323 { 324 Error error; 325 if (DescriptorIsValid()) 326 { 327 offset = ::lseek (m_descriptor, offset, SEEK_SET); 328 329 if (offset == -1) 330 error.SetErrorToErrno(); 331 } 332 else 333 { 334 error.SetErrorString("invalid file handle"); 335 } 336 return error; 337 } 338 339 Error 340 File::SeekFromCurrent (off_t& offset) 341 { 342 Error error; 343 if (DescriptorIsValid()) 344 { 345 offset = ::lseek (m_descriptor, offset, SEEK_CUR); 346 347 if (offset == -1) 348 error.SetErrorToErrno(); 349 } 350 else 351 { 352 error.SetErrorString("invalid file handle"); 353 } 354 return error; 355 } 356 357 Error 358 File::SeekFromEnd (off_t& offset) 359 { 360 Error error; 361 if (DescriptorIsValid()) 362 { 363 offset = ::lseek (m_descriptor, offset, SEEK_CUR); 364 365 if (offset == -1) 366 error.SetErrorToErrno(); 367 } 368 else 369 { 370 error.SetErrorString("invalid file handle"); 371 } 372 return error; 373 } 374 375 Error 376 File::Flush () 377 { 378 Error error; 379 if (StreamIsValid()) 380 { 381 int err = 0; 382 do 383 { 384 err = ::fflush (m_stream); 385 } while (err == EOF && errno == EINTR); 386 387 if (err == EOF) 388 error.SetErrorToErrno(); 389 } 390 else if (!DescriptorIsValid()) 391 { 392 error.SetErrorString("invalid file handle"); 393 } 394 return error; 395 } 396 397 398 Error 399 File::Sync () 400 { 401 Error error; 402 if (DescriptorIsValid()) 403 { 404 int err = 0; 405 do 406 { 407 err = ::fsync (m_descriptor); 408 } while (err == -1 && errno == EINTR); 409 410 if (err == -1) 411 error.SetErrorToErrno(); 412 } 413 else 414 { 415 error.SetErrorString("invalid file handle"); 416 } 417 return error; 418 } 419 420 Error 421 File::Read (void *buf, size_t &num_bytes) 422 { 423 Error error; 424 ssize_t bytes_read = -1; 425 if (DescriptorIsValid()) 426 { 427 do 428 { 429 bytes_read = ::read (m_descriptor, buf, num_bytes); 430 } while (bytes_read < 0 && errno == EINTR); 431 432 if (bytes_read == -1) 433 { 434 error.SetErrorToErrno(); 435 num_bytes = 0; 436 } 437 else 438 num_bytes = bytes_read; 439 } 440 else if (StreamIsValid()) 441 { 442 bytes_read = ::fread (buf, 1, num_bytes, m_stream); 443 444 if (bytes_read == 0) 445 { 446 if (::feof(m_stream)) 447 error.SetErrorString ("feof"); 448 else if (::ferror (m_stream)) 449 error.SetErrorString ("ferror"); 450 num_bytes = 0; 451 } 452 else 453 num_bytes = bytes_read; 454 } 455 else 456 { 457 num_bytes = 0; 458 error.SetErrorString("invalid file handle"); 459 } 460 return error; 461 } 462 463 Error 464 File::Write (const void *buf, size_t &num_bytes) 465 { 466 Error error; 467 ssize_t bytes_written = -1; 468 if (DescriptorIsValid()) 469 { 470 do 471 { 472 bytes_written = ::write (m_descriptor, buf, num_bytes); 473 } while (bytes_written < 0 && errno == EINTR); 474 475 if (bytes_written == -1) 476 { 477 error.SetErrorToErrno(); 478 num_bytes = 0; 479 } 480 else 481 num_bytes = bytes_written; 482 } 483 else if (StreamIsValid()) 484 { 485 bytes_written = ::fwrite (buf, 1, num_bytes, m_stream); 486 487 if (bytes_written == 0) 488 { 489 if (::feof(m_stream)) 490 error.SetErrorString ("feof"); 491 else if (::ferror (m_stream)) 492 error.SetErrorString ("ferror"); 493 num_bytes = 0; 494 } 495 else 496 num_bytes = bytes_written; 497 498 } 499 else 500 { 501 num_bytes = 0; 502 error.SetErrorString("invalid file handle"); 503 } 504 return error; 505 } 506 507 508 Error 509 File::Read (void *buf, size_t &num_bytes, off_t &offset) 510 { 511 Error error; 512 int fd = GetDescriptor(); 513 if (fd != kInvalidDescriptor) 514 { 515 ssize_t bytes_read = -1; 516 do 517 { 518 bytes_read = ::pread (fd, buf, num_bytes, offset); 519 } while (bytes_read < 0 && errno == EINTR); 520 521 if (bytes_read < 0) 522 { 523 num_bytes = 0; 524 error.SetErrorToErrno(); 525 } 526 else 527 { 528 offset += bytes_read; 529 num_bytes = bytes_read; 530 } 531 } 532 else 533 { 534 num_bytes = 0; 535 error.SetErrorString("invalid file handle"); 536 } 537 return error; 538 } 539 540 Error 541 File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp) 542 { 543 Error error; 544 545 if (num_bytes > 0) 546 { 547 int fd = GetDescriptor(); 548 if (fd != kInvalidDescriptor) 549 { 550 struct stat file_stats; 551 if (::fstat (fd, &file_stats) == 0) 552 { 553 if (file_stats.st_size > offset) 554 { 555 const size_t bytes_left = file_stats.st_size - offset; 556 if (num_bytes > bytes_left) 557 num_bytes = bytes_left; 558 559 std::auto_ptr<DataBufferHeap> data_heap_ap; 560 data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0')); 561 562 if (data_heap_ap.get()) 563 { 564 error = Read (data_heap_ap->GetBytes(), num_bytes, offset); 565 if (error.Success()) 566 { 567 // Make sure we read exactly what we asked for and if we got 568 // less, adjust the array 569 if (num_bytes < data_heap_ap->GetByteSize()) 570 data_heap_ap->SetByteSize(num_bytes); 571 data_buffer_sp.reset(data_heap_ap.release()); 572 return error; 573 } 574 } 575 } 576 else 577 error.SetErrorString("file is empty"); 578 } 579 else 580 error.SetErrorToErrno(); 581 } 582 else 583 error.SetErrorString("invalid file handle"); 584 } 585 else 586 error.SetErrorString("invalid file handle"); 587 588 num_bytes = 0; 589 data_buffer_sp.reset(); 590 return error; 591 } 592 593 Error 594 File::Write (const void *buf, size_t &num_bytes, off_t &offset) 595 { 596 Error error; 597 int fd = GetDescriptor(); 598 if (fd != kInvalidDescriptor) 599 { 600 ssize_t bytes_written = -1; 601 do 602 { 603 bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset); 604 } while (bytes_written < 0 && errno == EINTR); 605 606 if (bytes_written < 0) 607 { 608 num_bytes = 0; 609 error.SetErrorToErrno(); 610 } 611 else 612 { 613 offset += bytes_written; 614 num_bytes = bytes_written; 615 } 616 } 617 else 618 { 619 num_bytes = 0; 620 error.SetErrorString("invalid file handle"); 621 } 622 return error; 623 } 624 625 //------------------------------------------------------------------ 626 // Print some formatted output to the stream. 627 //------------------------------------------------------------------ 628 int 629 File::Printf (const char *format, ...) 630 { 631 va_list args; 632 va_start (args, format); 633 int result = PrintfVarArg (format, args); 634 va_end (args); 635 return result; 636 } 637 638 //------------------------------------------------------------------ 639 // Print some formatted output to the stream. 640 //------------------------------------------------------------------ 641 int 642 File::PrintfVarArg (const char *format, va_list args) 643 { 644 int result = 0; 645 if (DescriptorIsValid()) 646 { 647 char *s = NULL; 648 result = vasprintf(&s, format, args); 649 if (s != NULL) 650 { 651 if (result > 0) 652 { 653 size_t s_len = result; 654 Write (s, s_len); 655 result = s_len; 656 } 657 free (s); 658 } 659 } 660 else if (StreamIsValid()) 661 { 662 result = ::vfprintf (m_stream, format, args); 663 } 664 return result; 665 } 666