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 <fcntl.h> 14 #include <limits.h> 15 #include <stdarg.h> 16 #include <sys/stat.h> 17 18 #include "lldb/Core/Error.h" 19 #include "lldb/Host/Config.h" 20 #include "lldb/Host/FileSpec.h" 21 22 using namespace lldb; 23 using namespace lldb_private; 24 25 static const char * 26 GetStreamOpenModeFromOptions (uint32_t options) 27 { 28 if (options & File::eOpenOptionAppend) 29 { 30 if (options & File::eOpenOptionRead) 31 { 32 if (options & File::eOpenOptionCanCreateNewOnly) 33 return "a+x"; 34 else 35 return "a+"; 36 } 37 else if (options & File::eOpenOptionWrite) 38 { 39 if (options & File::eOpenOptionCanCreateNewOnly) 40 return "ax"; 41 else 42 return "a"; 43 } 44 } 45 else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite) 46 { 47 if (options & File::eOpenOptionCanCreate) 48 { 49 if (options & File::eOpenOptionCanCreateNewOnly) 50 return "w+x"; 51 else 52 return "w+"; 53 } 54 else 55 return "r+"; 56 } 57 else if (options & File::eOpenOptionRead) 58 { 59 return "r"; 60 } 61 else if (options & File::eOpenOptionWrite) 62 { 63 return "w"; 64 } 65 return NULL; 66 } 67 68 int File::kInvalidDescriptor = -1; 69 FILE * File::kInvalidStream = NULL; 70 71 File::File(const char *path, uint32_t options, uint32_t permissions) : 72 m_descriptor (kInvalidDescriptor), 73 m_stream (kInvalidStream), 74 m_options (0), 75 m_owned (false) 76 { 77 Open (path, options, permissions); 78 } 79 80 File::File (const File &rhs) : 81 m_descriptor (kInvalidDescriptor), 82 m_stream (kInvalidStream), 83 m_options (0), 84 m_owned (false) 85 { 86 Duplicate (rhs); 87 } 88 89 90 File & 91 File::operator = (const File &rhs) 92 { 93 if (this != &rhs) 94 Duplicate (rhs); 95 return *this; 96 } 97 98 File::~File() 99 { 100 Close (); 101 } 102 103 104 int 105 File::GetDescriptor() const 106 { 107 if (DescriptorIsValid()) 108 return m_descriptor; 109 110 // Don't open the file descriptor if we don't need to, just get it from the 111 // stream if we have one. 112 if (StreamIsValid()) 113 return fileno (m_stream); 114 115 // Invalid descriptor and invalid stream, return invalid descriptor. 116 return kInvalidDescriptor; 117 } 118 119 void 120 File::SetDescriptor (int fd, bool transfer_ownership) 121 { 122 if (IsValid()) 123 Close(); 124 m_descriptor = fd; 125 m_owned = transfer_ownership; 126 } 127 128 129 FILE * 130 File::GetStream () 131 { 132 if (!StreamIsValid()) 133 { 134 if (DescriptorIsValid()) 135 { 136 const char *mode = GetStreamOpenModeFromOptions (m_options); 137 if (mode) 138 m_stream = ::fdopen (m_descriptor, mode); 139 } 140 } 141 return m_stream; 142 } 143 144 145 void 146 File::SetStream (FILE *fh, bool transfer_ownership) 147 { 148 if (IsValid()) 149 Close(); 150 m_stream = fh; 151 m_owned = transfer_ownership; 152 } 153 154 Error 155 File::Duplicate (const File &rhs) 156 { 157 Error error; 158 if (IsValid ()) 159 Close(); 160 161 if (rhs.DescriptorIsValid()) 162 { 163 m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD); 164 if (!DescriptorIsValid()) 165 error.SetErrorToErrno(); 166 else 167 { 168 m_options = rhs.m_options; 169 m_owned = true; 170 } 171 } 172 else 173 { 174 error.SetErrorString ("invalid file to duplicate"); 175 } 176 return error; 177 } 178 179 Error 180 File::Open (const char *path, uint32_t options, uint32_t permissions) 181 { 182 Error error; 183 if (IsValid()) 184 Close (); 185 186 int oflag = 0; 187 if (options & eOpenOptionRead && 188 options & eOpenOptionWrite ) 189 oflag |= O_RDWR; 190 else if (options & eOpenOptionRead) 191 oflag |= O_RDONLY; 192 else if (options & eOpenOptionWrite) 193 oflag |= O_WRONLY; 194 195 if (options & eOpenOptionNonBlocking) 196 oflag |= O_NONBLOCK; 197 198 if (options & eOpenOptionAppend) 199 oflag |= O_APPEND; 200 else 201 oflag |= O_TRUNC; 202 203 if (options & eOpenOptionCanCreate) 204 oflag |= O_CREAT; 205 206 if (options & eOpenOptionCanCreateNewOnly) 207 oflag |= O_CREAT | O_EXCL; 208 209 mode_t mode = 0; 210 if (permissions & ePermissionsUserRead) mode |= S_IRUSR; 211 if (permissions & ePermissionsUserWrite) mode |= S_IWUSR; 212 if (permissions & ePermissionsUserExecute) mode |= S_IXUSR; 213 if (permissions & ePermissionsGroupRead) mode |= S_IRGRP; 214 if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP; 215 if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP; 216 if (permissions & ePermissionsWorldRead) mode |= S_IROTH; 217 if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH; 218 if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH; 219 220 m_descriptor = ::open(path, oflag, mode); 221 if (!DescriptorIsValid()) 222 error.SetErrorToErrno(); 223 else 224 m_owned = true; 225 226 return error; 227 } 228 229 Error 230 File::Close () 231 { 232 Error error; 233 if (IsValid ()) 234 { 235 if (m_owned) 236 { 237 if (StreamIsValid()) 238 { 239 if (::fclose (m_stream) == EOF) 240 error.SetErrorToErrno(); 241 } 242 243 if (DescriptorIsValid()) 244 { 245 if (::close (m_descriptor) != 0) 246 error.SetErrorToErrno(); 247 } 248 } 249 m_descriptor = kInvalidDescriptor; 250 m_stream = kInvalidStream; 251 m_options = 0; 252 m_owned = false; 253 } 254 return error; 255 } 256 257 258 Error 259 File::GetFileSpec (FileSpec &file_spec) const 260 { 261 Error error; 262 #ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED 263 if (IsValid ()) 264 { 265 char path[PATH_MAX]; 266 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) 267 error.SetErrorToErrno(); 268 else 269 file_spec.SetFile (path, false); 270 } 271 else 272 { 273 error.SetErrorString("invalid file handle"); 274 } 275 #elif defined(__linux__) 276 char proc[64]; 277 char path[PATH_MAX]; 278 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) 279 error.SetErrorString ("Cannot resolve file descriptor\n"); 280 else 281 { 282 ssize_t len; 283 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) 284 error.SetErrorToErrno(); 285 else 286 { 287 path[len] = '\0'; 288 file_spec.SetFile (path, false); 289 } 290 } 291 #else 292 error.SetErrorString ("File::GetFileSpec is not supported on this platform"); 293 #endif 294 295 if (error.Fail()) 296 file_spec.Clear(); 297 return error; 298 } 299 300 Error 301 File::SeekFromStart (off_t& offset) 302 { 303 Error error; 304 if (DescriptorIsValid()) 305 { 306 offset = ::lseek (m_descriptor, offset, SEEK_SET); 307 308 if (offset == -1) 309 error.SetErrorToErrno(); 310 } 311 else 312 { 313 error.SetErrorString("invalid file handle"); 314 } 315 return error; 316 } 317 318 Error 319 File::SeekFromCurrent (off_t& offset) 320 { 321 Error error; 322 if (DescriptorIsValid()) 323 { 324 offset = ::lseek (m_descriptor, offset, SEEK_CUR); 325 326 if (offset == -1) 327 error.SetErrorToErrno(); 328 } 329 else 330 { 331 error.SetErrorString("invalid file handle"); 332 } 333 return error; 334 } 335 336 Error 337 File::SeekFromEnd (off_t& offset) 338 { 339 Error error; 340 if (DescriptorIsValid()) 341 { 342 offset = ::lseek (m_descriptor, offset, SEEK_CUR); 343 344 if (offset == -1) 345 error.SetErrorToErrno(); 346 } 347 else 348 { 349 error.SetErrorString("invalid file handle"); 350 } 351 return error; 352 } 353 354 Error 355 File::Flush () 356 { 357 Error error; 358 if (StreamIsValid()) 359 { 360 if (::fflush (m_stream) == EOF) 361 error.SetErrorToErrno(); 362 } 363 else if (!DescriptorIsValid()) 364 { 365 error.SetErrorString("invalid file handle"); 366 } 367 return error; 368 } 369 370 371 Error 372 File::Sync () 373 { 374 Error error; 375 if (DescriptorIsValid()) 376 { 377 if (::fsync (m_descriptor) == -1) 378 error.SetErrorToErrno(); 379 } 380 else 381 { 382 error.SetErrorString("invalid file handle"); 383 } 384 return error; 385 } 386 387 Error 388 File::Read (void *buf, size_t &num_bytes) 389 { 390 Error error; 391 if (DescriptorIsValid()) 392 { 393 ssize_t bytes_read = ::read (m_descriptor, buf, num_bytes); 394 if (bytes_read == -1) 395 { 396 error.SetErrorToErrno(); 397 num_bytes = 0; 398 } 399 else 400 num_bytes = bytes_read; 401 } 402 else if (StreamIsValid()) 403 { 404 size_t bytes_read = ::fread (buf, 1, num_bytes, m_stream); 405 if (bytes_read == 0) 406 { 407 if (::feof(m_stream)) 408 error.SetErrorString ("feof"); 409 else if (::ferror (m_stream)) 410 error.SetErrorString ("ferror"); 411 num_bytes = 0; 412 } 413 else 414 num_bytes = bytes_read; 415 } 416 else 417 { 418 num_bytes = 0; 419 error.SetErrorString("invalid file handle"); 420 } 421 return error; 422 } 423 424 Error 425 File::Write (const void *buf, size_t &num_bytes) 426 { 427 Error error; 428 if (DescriptorIsValid()) 429 { 430 ssize_t bytes_written = ::write (m_descriptor, buf, num_bytes); 431 if (bytes_written == -1) 432 { 433 error.SetErrorToErrno(); 434 num_bytes = 0; 435 } 436 else 437 num_bytes = bytes_written; 438 } 439 else if (StreamIsValid()) 440 { 441 size_t bytes_written = ::fwrite (buf, 1, num_bytes, m_stream); 442 if (bytes_written == 0) 443 { 444 if (::feof(m_stream)) 445 error.SetErrorString ("feof"); 446 else if (::ferror (m_stream)) 447 error.SetErrorString ("ferror"); 448 num_bytes = 0; 449 } 450 else 451 num_bytes = bytes_written; 452 453 } 454 else 455 { 456 num_bytes = 0; 457 error.SetErrorString("invalid file handle"); 458 } 459 return error; 460 } 461 462 463 Error 464 File::Read (void *buf, size_t &num_bytes, off_t &offset) 465 { 466 Error error; 467 int fd = GetDescriptor(); 468 if (fd != kInvalidDescriptor) 469 { 470 ssize_t bytes_read = ::pread (fd, buf, num_bytes, offset); 471 if (bytes_read < 0) 472 { 473 num_bytes = 0; 474 error.SetErrorToErrno(); 475 } 476 else 477 { 478 offset += bytes_read; 479 num_bytes = bytes_read; 480 } 481 } 482 else 483 { 484 num_bytes = 0; 485 error.SetErrorString("invalid file handle"); 486 } 487 return error; 488 } 489 490 Error 491 File::Write (const void *buf, size_t &num_bytes, off_t &offset) 492 { 493 Error error; 494 int fd = GetDescriptor(); 495 if (fd != kInvalidDescriptor) 496 { 497 ssize_t bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset); 498 if (bytes_written < 0) 499 { 500 num_bytes = 0; 501 error.SetErrorToErrno(); 502 } 503 else 504 { 505 offset += bytes_written; 506 num_bytes = bytes_written; 507 } 508 } 509 else 510 { 511 num_bytes = 0; 512 error.SetErrorString("invalid file handle"); 513 } 514 return error; 515 } 516 517 //------------------------------------------------------------------ 518 // Print some formatted output to the stream. 519 //------------------------------------------------------------------ 520 int 521 File::Printf (const char *format, ...) 522 { 523 va_list args; 524 va_start (args, format); 525 int result = PrintfVarArg (format, args); 526 va_end (args); 527 return result; 528 } 529 530 //------------------------------------------------------------------ 531 // Print some formatted output to the stream. 532 //------------------------------------------------------------------ 533 int 534 File::PrintfVarArg (const char *format, va_list args) 535 { 536 int result = 0; 537 if (DescriptorIsValid()) 538 { 539 char *s = NULL; 540 result = vasprintf(&s, format, args); 541 if (s != NULL) 542 { 543 if (result > 0) 544 { 545 size_t s_len = result; 546 Write (s, s_len); 547 result = s_len; 548 } 549 free (s); 550 } 551 } 552 else if (StreamIsValid()) 553 { 554 result = ::vfprintf (m_stream, format, args); 555 } 556 return result; 557 } 558