1263367Semaste//===-- File.cpp ------------------------------------------------*- C++ -*-===// 2254721Semaste// 3254721Semaste// The LLVM Compiler Infrastructure 4254721Semaste// 5254721Semaste// This file is distributed under the University of Illinois Open Source 6254721Semaste// License. See LICENSE.TXT for details. 7254721Semaste// 8254721Semaste//===----------------------------------------------------------------------===// 9254721Semaste 10254721Semaste#include "lldb/Host/File.h" 11254721Semaste 12254721Semaste#include <errno.h> 13254721Semaste#include <fcntl.h> 14254721Semaste#include <limits.h> 15254721Semaste#include <stdarg.h> 16269024Semaste#include <stdio.h> 17254721Semaste#include <sys/stat.h> 18254721Semaste 19263363Semaste#ifdef _WIN32 20263363Semaste#include "lldb/Host/windows/windows.h" 21269024Semaste#else 22269024Semaste#include <sys/ioctl.h> 23263363Semaste#endif 24263363Semaste 25254721Semaste#include "lldb/Core/DataBufferHeap.h" 26254721Semaste#include "lldb/Core/Error.h" 27254721Semaste#include "lldb/Host/Config.h" 28254721Semaste#include "lldb/Host/FileSpec.h" 29254721Semaste 30254721Semasteusing namespace lldb; 31254721Semasteusing namespace lldb_private; 32254721Semaste 33254721Semastestatic const char * 34254721SemasteGetStreamOpenModeFromOptions (uint32_t options) 35254721Semaste{ 36254721Semaste if (options & File::eOpenOptionAppend) 37254721Semaste { 38254721Semaste if (options & File::eOpenOptionRead) 39254721Semaste { 40254721Semaste if (options & File::eOpenOptionCanCreateNewOnly) 41254721Semaste return "a+x"; 42254721Semaste else 43254721Semaste return "a+"; 44254721Semaste } 45254721Semaste else if (options & File::eOpenOptionWrite) 46254721Semaste { 47254721Semaste if (options & File::eOpenOptionCanCreateNewOnly) 48254721Semaste return "ax"; 49254721Semaste else 50254721Semaste return "a"; 51254721Semaste } 52254721Semaste } 53254721Semaste else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite) 54254721Semaste { 55254721Semaste if (options & File::eOpenOptionCanCreate) 56254721Semaste { 57254721Semaste if (options & File::eOpenOptionCanCreateNewOnly) 58254721Semaste return "w+x"; 59254721Semaste else 60254721Semaste return "w+"; 61254721Semaste } 62254721Semaste else 63254721Semaste return "r+"; 64254721Semaste } 65254721Semaste else if (options & File::eOpenOptionRead) 66254721Semaste { 67254721Semaste return "r"; 68254721Semaste } 69254721Semaste else if (options & File::eOpenOptionWrite) 70254721Semaste { 71254721Semaste return "w"; 72254721Semaste } 73254721Semaste return NULL; 74254721Semaste} 75254721Semaste 76254721Semasteint File::kInvalidDescriptor = -1; 77254721SemasteFILE * File::kInvalidStream = NULL; 78254721Semaste 79254721SemasteFile::File(const char *path, uint32_t options, uint32_t permissions) : 80254721Semaste m_descriptor (kInvalidDescriptor), 81254721Semaste m_stream (kInvalidStream), 82269024Semaste m_options (), 83269024Semaste m_own_stream (false), 84269024Semaste m_own_descriptor (false), 85269024Semaste m_is_interactive (eLazyBoolCalculate), 86269024Semaste m_is_real_terminal (eLazyBoolCalculate) 87254721Semaste{ 88254721Semaste Open (path, options, permissions); 89254721Semaste} 90254721Semaste 91263363SemasteFile::File (const FileSpec& filespec, 92263363Semaste uint32_t options, 93263363Semaste uint32_t permissions) : 94263363Semaste m_descriptor (kInvalidDescriptor), 95263363Semaste m_stream (kInvalidStream), 96263363Semaste m_options (0), 97269024Semaste m_own_stream (false), 98269024Semaste m_own_descriptor (false), 99269024Semaste m_is_interactive (eLazyBoolCalculate), 100269024Semaste m_is_real_terminal (eLazyBoolCalculate) 101269024Semaste 102263363Semaste{ 103263363Semaste if (filespec) 104263363Semaste { 105263363Semaste Open (filespec.GetPath().c_str(), options, permissions); 106263363Semaste } 107263363Semaste} 108263363Semaste 109254721SemasteFile::File (const File &rhs) : 110254721Semaste m_descriptor (kInvalidDescriptor), 111254721Semaste m_stream (kInvalidStream), 112254721Semaste m_options (0), 113269024Semaste m_own_stream (false), 114269024Semaste m_own_descriptor (false), 115269024Semaste m_is_interactive (eLazyBoolCalculate), 116269024Semaste m_is_real_terminal (eLazyBoolCalculate) 117254721Semaste{ 118254721Semaste Duplicate (rhs); 119254721Semaste} 120254721Semaste 121254721Semaste 122254721SemasteFile & 123254721SemasteFile::operator = (const File &rhs) 124254721Semaste{ 125254721Semaste if (this != &rhs) 126254721Semaste Duplicate (rhs); 127254721Semaste return *this; 128254721Semaste} 129254721Semaste 130254721SemasteFile::~File() 131254721Semaste{ 132254721Semaste Close (); 133254721Semaste} 134254721Semaste 135254721Semaste 136254721Semasteint 137254721SemasteFile::GetDescriptor() const 138254721Semaste{ 139254721Semaste if (DescriptorIsValid()) 140254721Semaste return m_descriptor; 141254721Semaste 142254721Semaste // Don't open the file descriptor if we don't need to, just get it from the 143254721Semaste // stream if we have one. 144254721Semaste if (StreamIsValid()) 145254721Semaste return fileno (m_stream); 146254721Semaste 147254721Semaste // Invalid descriptor and invalid stream, return invalid descriptor. 148254721Semaste return kInvalidDescriptor; 149254721Semaste} 150254721Semaste 151254721Semastevoid 152254721SemasteFile::SetDescriptor (int fd, bool transfer_ownership) 153254721Semaste{ 154254721Semaste if (IsValid()) 155254721Semaste Close(); 156254721Semaste m_descriptor = fd; 157269024Semaste m_own_descriptor = transfer_ownership; 158254721Semaste} 159254721Semaste 160254721Semaste 161254721SemasteFILE * 162254721SemasteFile::GetStream () 163254721Semaste{ 164254721Semaste if (!StreamIsValid()) 165254721Semaste { 166254721Semaste if (DescriptorIsValid()) 167254721Semaste { 168254721Semaste const char *mode = GetStreamOpenModeFromOptions (m_options); 169254721Semaste if (mode) 170254721Semaste { 171269024Semaste if (!m_own_descriptor) 172269024Semaste { 173269024Semaste // We must duplicate the file descriptor if we don't own it because 174269024Semaste // when you call fdopen, the stream will own the fd 175269024Semaste#ifdef _WIN32 176269024Semaste m_descriptor = ::_dup(GetDescriptor()); 177269024Semaste#else 178269024Semaste m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD); 179269024Semaste#endif 180269024Semaste m_own_descriptor = true; 181269024Semaste } 182269024Semaste 183254721Semaste do 184254721Semaste { 185254721Semaste m_stream = ::fdopen (m_descriptor, mode); 186254721Semaste } while (m_stream == NULL && errno == EINTR); 187269024Semaste 188269024Semaste // If we got a stream, then we own the stream and should no 189269024Semaste // longer own the descriptor because fclose() will close it for us 190269024Semaste 191269024Semaste if (m_stream) 192269024Semaste { 193269024Semaste m_own_stream = true; 194269024Semaste m_own_descriptor = false; 195269024Semaste } 196254721Semaste } 197254721Semaste } 198254721Semaste } 199254721Semaste return m_stream; 200254721Semaste} 201254721Semaste 202254721Semaste 203254721Semastevoid 204254721SemasteFile::SetStream (FILE *fh, bool transfer_ownership) 205254721Semaste{ 206254721Semaste if (IsValid()) 207254721Semaste Close(); 208254721Semaste m_stream = fh; 209269024Semaste m_own_stream = transfer_ownership; 210254721Semaste} 211254721Semaste 212254721SemasteError 213254721SemasteFile::Duplicate (const File &rhs) 214254721Semaste{ 215254721Semaste Error error; 216254721Semaste if (IsValid ()) 217254721Semaste Close(); 218254721Semaste 219254721Semaste if (rhs.DescriptorIsValid()) 220254721Semaste { 221263363Semaste#ifdef _WIN32 222263363Semaste m_descriptor = ::_dup(rhs.GetDescriptor()); 223263363Semaste#else 224254721Semaste m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD); 225263363Semaste#endif 226254721Semaste if (!DescriptorIsValid()) 227254721Semaste error.SetErrorToErrno(); 228254721Semaste else 229254721Semaste { 230254721Semaste m_options = rhs.m_options; 231269024Semaste m_own_descriptor = true; 232254721Semaste } 233254721Semaste } 234254721Semaste else 235254721Semaste { 236254721Semaste error.SetErrorString ("invalid file to duplicate"); 237254721Semaste } 238254721Semaste return error; 239254721Semaste} 240254721Semaste 241254721SemasteError 242254721SemasteFile::Open (const char *path, uint32_t options, uint32_t permissions) 243254721Semaste{ 244254721Semaste Error error; 245254721Semaste if (IsValid()) 246254721Semaste Close (); 247254721Semaste 248254721Semaste int oflag = 0; 249254721Semaste const bool read = options & eOpenOptionRead; 250254721Semaste const bool write = options & eOpenOptionWrite; 251254721Semaste if (write) 252254721Semaste { 253254721Semaste if (read) 254254721Semaste oflag |= O_RDWR; 255254721Semaste else 256254721Semaste oflag |= O_WRONLY; 257254721Semaste 258254721Semaste if (options & eOpenOptionAppend) 259254721Semaste oflag |= O_APPEND; 260254721Semaste 261254721Semaste if (options & eOpenOptionTruncate) 262254721Semaste oflag |= O_TRUNC; 263254721Semaste 264254721Semaste if (options & eOpenOptionCanCreate) 265254721Semaste oflag |= O_CREAT; 266254721Semaste 267254721Semaste if (options & eOpenOptionCanCreateNewOnly) 268254721Semaste oflag |= O_CREAT | O_EXCL; 269254721Semaste } 270254721Semaste else if (read) 271254721Semaste { 272254721Semaste oflag |= O_RDONLY; 273263367Semaste 274263367Semaste#ifndef _WIN32 275263367Semaste if (options & eOpenoptionDontFollowSymlinks) 276263367Semaste oflag |= O_NOFOLLOW; 277263367Semaste#endif 278254721Semaste } 279254721Semaste 280263363Semaste#ifndef _WIN32 281254721Semaste if (options & eOpenOptionNonBlocking) 282254721Semaste oflag |= O_NONBLOCK; 283263363Semaste#else 284263363Semaste oflag |= O_BINARY; 285263363Semaste#endif 286254721Semaste 287254721Semaste mode_t mode = 0; 288254721Semaste if (oflag & O_CREAT) 289254721Semaste { 290263367Semaste if (permissions & lldb::eFilePermissionsUserRead) mode |= S_IRUSR; 291263367Semaste if (permissions & lldb::eFilePermissionsUserWrite) mode |= S_IWUSR; 292263367Semaste if (permissions & lldb::eFilePermissionsUserExecute) mode |= S_IXUSR; 293263367Semaste if (permissions & lldb::eFilePermissionsGroupRead) mode |= S_IRGRP; 294263367Semaste if (permissions & lldb::eFilePermissionsGroupWrite) mode |= S_IWGRP; 295263367Semaste if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP; 296263367Semaste if (permissions & lldb::eFilePermissionsWorldRead) mode |= S_IROTH; 297263367Semaste if (permissions & lldb::eFilePermissionsWorldWrite) mode |= S_IWOTH; 298263367Semaste if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH; 299254721Semaste } 300254721Semaste 301254721Semaste do 302254721Semaste { 303254721Semaste m_descriptor = ::open(path, oflag, mode); 304254721Semaste } while (m_descriptor < 0 && errno == EINTR); 305254721Semaste 306254721Semaste if (!DescriptorIsValid()) 307254721Semaste error.SetErrorToErrno(); 308254721Semaste else 309269024Semaste { 310269024Semaste m_own_descriptor = true; 311269024Semaste m_options = options; 312269024Semaste } 313254721Semaste 314254721Semaste return error; 315254721Semaste} 316254721Semaste 317263363Semasteuint32_t 318263363SemasteFile::GetPermissions (const char *path, Error &error) 319263363Semaste{ 320263363Semaste if (path && path[0]) 321263363Semaste { 322263363Semaste struct stat file_stats; 323263363Semaste if (::stat (path, &file_stats) == -1) 324263363Semaste error.SetErrorToErrno(); 325263363Semaste else 326263363Semaste { 327263363Semaste error.Clear(); 328263367Semaste return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 329263363Semaste } 330263363Semaste } 331263363Semaste else 332263363Semaste { 333263363Semaste if (path) 334263363Semaste error.SetErrorString ("invalid path"); 335263363Semaste else 336263363Semaste error.SetErrorString ("empty path"); 337263363Semaste } 338263363Semaste return 0; 339263363Semaste} 340263363Semaste 341263363Semasteuint32_t 342263363SemasteFile::GetPermissions(Error &error) const 343263363Semaste{ 344263363Semaste int fd = GetDescriptor(); 345263363Semaste if (fd != kInvalidDescriptor) 346263363Semaste { 347263363Semaste struct stat file_stats; 348263363Semaste if (::fstat (fd, &file_stats) == -1) 349263363Semaste error.SetErrorToErrno(); 350263363Semaste else 351263363Semaste { 352263363Semaste error.Clear(); 353263367Semaste return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 354263363Semaste } 355263363Semaste } 356263363Semaste else 357263363Semaste { 358263363Semaste error.SetErrorString ("invalid file descriptor"); 359263363Semaste } 360263363Semaste return 0; 361263363Semaste} 362263363Semaste 363263363Semaste 364254721SemasteError 365254721SemasteFile::Close () 366254721Semaste{ 367254721Semaste Error error; 368269024Semaste if (StreamIsValid() && m_own_stream) 369254721Semaste { 370269024Semaste if (::fclose (m_stream) == EOF) 371269024Semaste error.SetErrorToErrno(); 372254721Semaste } 373269024Semaste 374269024Semaste if (DescriptorIsValid() && m_own_descriptor) 375269024Semaste { 376269024Semaste if (::close (m_descriptor) != 0) 377269024Semaste error.SetErrorToErrno(); 378269024Semaste } 379269024Semaste m_descriptor = kInvalidDescriptor; 380269024Semaste m_stream = kInvalidStream; 381269024Semaste m_options = 0; 382269024Semaste m_own_stream = false; 383269024Semaste m_own_descriptor = false; 384269024Semaste m_is_interactive = eLazyBoolCalculate; 385269024Semaste m_is_real_terminal = eLazyBoolCalculate; 386254721Semaste return error; 387254721Semaste} 388254721Semaste 389254721Semaste 390254721SemasteError 391254721SemasteFile::GetFileSpec (FileSpec &file_spec) const 392254721Semaste{ 393254721Semaste Error error; 394254721Semaste#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED 395254721Semaste if (IsValid ()) 396254721Semaste { 397254721Semaste char path[PATH_MAX]; 398254721Semaste if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) 399254721Semaste error.SetErrorToErrno(); 400254721Semaste else 401254721Semaste file_spec.SetFile (path, false); 402254721Semaste } 403254721Semaste else 404254721Semaste { 405254721Semaste error.SetErrorString("invalid file handle"); 406254721Semaste } 407254721Semaste#elif defined(__linux__) 408254721Semaste char proc[64]; 409254721Semaste char path[PATH_MAX]; 410254721Semaste if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) 411254721Semaste error.SetErrorString ("cannot resolve file descriptor"); 412254721Semaste else 413254721Semaste { 414254721Semaste ssize_t len; 415254721Semaste if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) 416254721Semaste error.SetErrorToErrno(); 417254721Semaste else 418254721Semaste { 419254721Semaste path[len] = '\0'; 420254721Semaste file_spec.SetFile (path, false); 421254721Semaste } 422254721Semaste } 423254721Semaste#else 424254721Semaste error.SetErrorString ("File::GetFileSpec is not supported on this platform"); 425254721Semaste#endif 426254721Semaste 427254721Semaste if (error.Fail()) 428254721Semaste file_spec.Clear(); 429254721Semaste return error; 430254721Semaste} 431254721Semaste 432254721Semasteoff_t 433254721SemasteFile::SeekFromStart (off_t offset, Error *error_ptr) 434254721Semaste{ 435254721Semaste off_t result = 0; 436254721Semaste if (DescriptorIsValid()) 437254721Semaste { 438254721Semaste result = ::lseek (m_descriptor, offset, SEEK_SET); 439254721Semaste 440254721Semaste if (error_ptr) 441254721Semaste { 442254721Semaste if (result == -1) 443254721Semaste error_ptr->SetErrorToErrno(); 444254721Semaste else 445254721Semaste error_ptr->Clear(); 446254721Semaste } 447254721Semaste } 448254721Semaste else if (StreamIsValid ()) 449254721Semaste { 450254721Semaste result = ::fseek(m_stream, offset, SEEK_SET); 451254721Semaste 452254721Semaste if (error_ptr) 453254721Semaste { 454254721Semaste if (result == -1) 455254721Semaste error_ptr->SetErrorToErrno(); 456254721Semaste else 457254721Semaste error_ptr->Clear(); 458254721Semaste } 459254721Semaste } 460254721Semaste else if (error_ptr) 461254721Semaste { 462254721Semaste error_ptr->SetErrorString("invalid file handle"); 463254721Semaste } 464254721Semaste return result; 465254721Semaste} 466254721Semaste 467254721Semasteoff_t 468254721SemasteFile::SeekFromCurrent (off_t offset, Error *error_ptr) 469254721Semaste{ 470254721Semaste off_t result = -1; 471254721Semaste if (DescriptorIsValid()) 472254721Semaste { 473254721Semaste result = ::lseek (m_descriptor, offset, SEEK_CUR); 474254721Semaste 475254721Semaste if (error_ptr) 476254721Semaste { 477254721Semaste if (result == -1) 478254721Semaste error_ptr->SetErrorToErrno(); 479254721Semaste else 480254721Semaste error_ptr->Clear(); 481254721Semaste } 482254721Semaste } 483254721Semaste else if (StreamIsValid ()) 484254721Semaste { 485254721Semaste result = ::fseek(m_stream, offset, SEEK_CUR); 486254721Semaste 487254721Semaste if (error_ptr) 488254721Semaste { 489254721Semaste if (result == -1) 490254721Semaste error_ptr->SetErrorToErrno(); 491254721Semaste else 492254721Semaste error_ptr->Clear(); 493254721Semaste } 494254721Semaste } 495254721Semaste else if (error_ptr) 496254721Semaste { 497254721Semaste error_ptr->SetErrorString("invalid file handle"); 498254721Semaste } 499254721Semaste return result; 500254721Semaste} 501254721Semaste 502254721Semasteoff_t 503254721SemasteFile::SeekFromEnd (off_t offset, Error *error_ptr) 504254721Semaste{ 505254721Semaste off_t result = -1; 506254721Semaste if (DescriptorIsValid()) 507254721Semaste { 508254721Semaste result = ::lseek (m_descriptor, offset, SEEK_END); 509254721Semaste 510254721Semaste if (error_ptr) 511254721Semaste { 512254721Semaste if (result == -1) 513254721Semaste error_ptr->SetErrorToErrno(); 514254721Semaste else 515254721Semaste error_ptr->Clear(); 516254721Semaste } 517254721Semaste } 518254721Semaste else if (StreamIsValid ()) 519254721Semaste { 520254721Semaste result = ::fseek(m_stream, offset, SEEK_END); 521254721Semaste 522254721Semaste if (error_ptr) 523254721Semaste { 524254721Semaste if (result == -1) 525254721Semaste error_ptr->SetErrorToErrno(); 526254721Semaste else 527254721Semaste error_ptr->Clear(); 528254721Semaste } 529254721Semaste } 530254721Semaste else if (error_ptr) 531254721Semaste { 532254721Semaste error_ptr->SetErrorString("invalid file handle"); 533254721Semaste } 534254721Semaste return result; 535254721Semaste} 536254721Semaste 537254721SemasteError 538254721SemasteFile::Flush () 539254721Semaste{ 540254721Semaste Error error; 541254721Semaste if (StreamIsValid()) 542254721Semaste { 543254721Semaste int err = 0; 544254721Semaste do 545254721Semaste { 546254721Semaste err = ::fflush (m_stream); 547254721Semaste } while (err == EOF && errno == EINTR); 548254721Semaste 549254721Semaste if (err == EOF) 550254721Semaste error.SetErrorToErrno(); 551254721Semaste } 552254721Semaste else if (!DescriptorIsValid()) 553254721Semaste { 554254721Semaste error.SetErrorString("invalid file handle"); 555254721Semaste } 556254721Semaste return error; 557254721Semaste} 558254721Semaste 559254721Semaste 560254721SemasteError 561254721SemasteFile::Sync () 562254721Semaste{ 563254721Semaste Error error; 564254721Semaste if (DescriptorIsValid()) 565254721Semaste { 566263363Semaste#ifdef _WIN32 567263363Semaste int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor)); 568263363Semaste if (err == 0) 569263363Semaste error.SetErrorToGenericError(); 570263363Semaste#else 571254721Semaste int err = 0; 572254721Semaste do 573254721Semaste { 574254721Semaste err = ::fsync (m_descriptor); 575254721Semaste } while (err == -1 && errno == EINTR); 576254721Semaste 577254721Semaste if (err == -1) 578254721Semaste error.SetErrorToErrno(); 579263363Semaste#endif 580254721Semaste } 581254721Semaste else 582254721Semaste { 583254721Semaste error.SetErrorString("invalid file handle"); 584254721Semaste } 585254721Semaste return error; 586254721Semaste} 587254721Semaste 588254721SemasteError 589254721SemasteFile::Read (void *buf, size_t &num_bytes) 590254721Semaste{ 591254721Semaste Error error; 592254721Semaste ssize_t bytes_read = -1; 593254721Semaste if (DescriptorIsValid()) 594254721Semaste { 595254721Semaste do 596254721Semaste { 597254721Semaste bytes_read = ::read (m_descriptor, buf, num_bytes); 598254721Semaste } while (bytes_read < 0 && errno == EINTR); 599254721Semaste 600254721Semaste if (bytes_read == -1) 601254721Semaste { 602254721Semaste error.SetErrorToErrno(); 603254721Semaste num_bytes = 0; 604254721Semaste } 605254721Semaste else 606254721Semaste num_bytes = bytes_read; 607254721Semaste } 608254721Semaste else if (StreamIsValid()) 609254721Semaste { 610254721Semaste bytes_read = ::fread (buf, 1, num_bytes, m_stream); 611254721Semaste 612254721Semaste if (bytes_read == 0) 613254721Semaste { 614254721Semaste if (::feof(m_stream)) 615254721Semaste error.SetErrorString ("feof"); 616254721Semaste else if (::ferror (m_stream)) 617254721Semaste error.SetErrorString ("ferror"); 618254721Semaste num_bytes = 0; 619254721Semaste } 620254721Semaste else 621254721Semaste num_bytes = bytes_read; 622254721Semaste } 623254721Semaste else 624254721Semaste { 625254721Semaste num_bytes = 0; 626254721Semaste error.SetErrorString("invalid file handle"); 627254721Semaste } 628254721Semaste return error; 629254721Semaste} 630254721Semaste 631254721SemasteError 632254721SemasteFile::Write (const void *buf, size_t &num_bytes) 633254721Semaste{ 634254721Semaste Error error; 635254721Semaste ssize_t bytes_written = -1; 636254721Semaste if (DescriptorIsValid()) 637254721Semaste { 638254721Semaste do 639254721Semaste { 640254721Semaste bytes_written = ::write (m_descriptor, buf, num_bytes); 641254721Semaste } while (bytes_written < 0 && errno == EINTR); 642254721Semaste 643254721Semaste if (bytes_written == -1) 644254721Semaste { 645254721Semaste error.SetErrorToErrno(); 646254721Semaste num_bytes = 0; 647254721Semaste } 648254721Semaste else 649254721Semaste num_bytes = bytes_written; 650254721Semaste } 651254721Semaste else if (StreamIsValid()) 652254721Semaste { 653254721Semaste bytes_written = ::fwrite (buf, 1, num_bytes, m_stream); 654254721Semaste 655254721Semaste if (bytes_written == 0) 656254721Semaste { 657254721Semaste if (::feof(m_stream)) 658254721Semaste error.SetErrorString ("feof"); 659254721Semaste else if (::ferror (m_stream)) 660254721Semaste error.SetErrorString ("ferror"); 661254721Semaste num_bytes = 0; 662254721Semaste } 663254721Semaste else 664254721Semaste num_bytes = bytes_written; 665254721Semaste 666254721Semaste } 667254721Semaste else 668254721Semaste { 669254721Semaste num_bytes = 0; 670254721Semaste error.SetErrorString("invalid file handle"); 671254721Semaste } 672254721Semaste return error; 673254721Semaste} 674254721Semaste 675254721Semaste 676254721SemasteError 677254721SemasteFile::Read (void *buf, size_t &num_bytes, off_t &offset) 678254721Semaste{ 679263363Semaste#ifndef _WIN32 680254721Semaste Error error; 681254721Semaste int fd = GetDescriptor(); 682254721Semaste if (fd != kInvalidDescriptor) 683254721Semaste { 684254721Semaste ssize_t bytes_read = -1; 685254721Semaste do 686254721Semaste { 687254721Semaste bytes_read = ::pread (fd, buf, num_bytes, offset); 688254721Semaste } while (bytes_read < 0 && errno == EINTR); 689254721Semaste 690254721Semaste if (bytes_read < 0) 691254721Semaste { 692254721Semaste num_bytes = 0; 693254721Semaste error.SetErrorToErrno(); 694254721Semaste } 695254721Semaste else 696254721Semaste { 697254721Semaste offset += bytes_read; 698254721Semaste num_bytes = bytes_read; 699254721Semaste } 700254721Semaste } 701254721Semaste else 702254721Semaste { 703254721Semaste num_bytes = 0; 704254721Semaste error.SetErrorString("invalid file handle"); 705254721Semaste } 706254721Semaste return error; 707263363Semaste#else 708263363Semaste long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 709263363Semaste SeekFromStart(offset); 710263363Semaste Error error = Read(buf, num_bytes); 711263363Semaste if (!error.Fail()) 712263363Semaste SeekFromStart(cur); 713263363Semaste return error; 714263363Semaste#endif 715254721Semaste} 716254721Semaste 717254721SemasteError 718254721SemasteFile::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp) 719254721Semaste{ 720254721Semaste Error error; 721254721Semaste 722254721Semaste if (num_bytes > 0) 723254721Semaste { 724254721Semaste int fd = GetDescriptor(); 725254721Semaste if (fd != kInvalidDescriptor) 726254721Semaste { 727254721Semaste struct stat file_stats; 728254721Semaste if (::fstat (fd, &file_stats) == 0) 729254721Semaste { 730254721Semaste if (file_stats.st_size > offset) 731254721Semaste { 732254721Semaste const size_t bytes_left = file_stats.st_size - offset; 733254721Semaste if (num_bytes > bytes_left) 734254721Semaste num_bytes = bytes_left; 735254721Semaste 736254721Semaste std::unique_ptr<DataBufferHeap> data_heap_ap; 737254721Semaste data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0')); 738254721Semaste 739254721Semaste if (data_heap_ap.get()) 740254721Semaste { 741254721Semaste error = Read (data_heap_ap->GetBytes(), num_bytes, offset); 742254721Semaste if (error.Success()) 743254721Semaste { 744254721Semaste // Make sure we read exactly what we asked for and if we got 745254721Semaste // less, adjust the array 746254721Semaste if (num_bytes < data_heap_ap->GetByteSize()) 747254721Semaste data_heap_ap->SetByteSize(num_bytes); 748254721Semaste data_buffer_sp.reset(data_heap_ap.release()); 749254721Semaste return error; 750254721Semaste } 751254721Semaste } 752254721Semaste } 753254721Semaste else 754254721Semaste error.SetErrorString("file is empty"); 755254721Semaste } 756254721Semaste else 757254721Semaste error.SetErrorToErrno(); 758254721Semaste } 759254721Semaste else 760254721Semaste error.SetErrorString("invalid file handle"); 761254721Semaste } 762254721Semaste else 763254721Semaste error.SetErrorString("invalid file handle"); 764254721Semaste 765254721Semaste num_bytes = 0; 766254721Semaste data_buffer_sp.reset(); 767254721Semaste return error; 768254721Semaste} 769254721Semaste 770254721SemasteError 771254721SemasteFile::Write (const void *buf, size_t &num_bytes, off_t &offset) 772254721Semaste{ 773254721Semaste Error error; 774254721Semaste int fd = GetDescriptor(); 775254721Semaste if (fd != kInvalidDescriptor) 776254721Semaste { 777263363Semaste#ifndef _WIN32 778254721Semaste ssize_t bytes_written = -1; 779254721Semaste do 780254721Semaste { 781254721Semaste bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset); 782254721Semaste } while (bytes_written < 0 && errno == EINTR); 783254721Semaste 784254721Semaste if (bytes_written < 0) 785254721Semaste { 786254721Semaste num_bytes = 0; 787254721Semaste error.SetErrorToErrno(); 788254721Semaste } 789254721Semaste else 790254721Semaste { 791254721Semaste offset += bytes_written; 792254721Semaste num_bytes = bytes_written; 793254721Semaste } 794263363Semaste#else 795263363Semaste long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 796263363Semaste error = Write(buf, num_bytes); 797263363Semaste long after = ::lseek(m_descriptor, 0, SEEK_CUR); 798263363Semaste 799263363Semaste if (!error.Fail()) 800263363Semaste SeekFromStart(cur); 801263363Semaste 802263363Semaste ssize_t bytes_written = after - cur; 803263363Semaste offset = after; 804263363Semaste#endif 805254721Semaste } 806254721Semaste else 807254721Semaste { 808254721Semaste num_bytes = 0; 809254721Semaste error.SetErrorString("invalid file handle"); 810254721Semaste } 811254721Semaste return error; 812254721Semaste} 813254721Semaste 814254721Semaste//------------------------------------------------------------------ 815254721Semaste// Print some formatted output to the stream. 816254721Semaste//------------------------------------------------------------------ 817254721Semastesize_t 818254721SemasteFile::Printf (const char *format, ...) 819254721Semaste{ 820254721Semaste va_list args; 821254721Semaste va_start (args, format); 822254721Semaste size_t result = PrintfVarArg (format, args); 823254721Semaste va_end (args); 824254721Semaste return result; 825254721Semaste} 826254721Semaste 827254721Semaste//------------------------------------------------------------------ 828254721Semaste// Print some formatted output to the stream. 829254721Semaste//------------------------------------------------------------------ 830254721Semastesize_t 831254721SemasteFile::PrintfVarArg (const char *format, va_list args) 832254721Semaste{ 833254721Semaste size_t result = 0; 834254721Semaste if (DescriptorIsValid()) 835254721Semaste { 836254721Semaste char *s = NULL; 837254721Semaste result = vasprintf(&s, format, args); 838254721Semaste if (s != NULL) 839254721Semaste { 840254721Semaste if (result > 0) 841254721Semaste { 842254721Semaste size_t s_len = result; 843254721Semaste Write (s, s_len); 844254721Semaste result = s_len; 845254721Semaste } 846254721Semaste free (s); 847254721Semaste } 848254721Semaste } 849254721Semaste else if (StreamIsValid()) 850254721Semaste { 851254721Semaste result = ::vfprintf (m_stream, format, args); 852254721Semaste } 853254721Semaste return result; 854254721Semaste} 855263363Semaste 856263363Semastemode_t 857263363SemasteFile::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options) 858263363Semaste{ 859263363Semaste mode_t mode = 0; 860263363Semaste if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite) 861263363Semaste mode |= O_RDWR; 862263363Semaste else if (open_options & eOpenOptionWrite) 863263363Semaste mode |= O_WRONLY; 864263363Semaste 865263363Semaste if (open_options & eOpenOptionAppend) 866263363Semaste mode |= O_APPEND; 867263363Semaste 868263363Semaste if (open_options & eOpenOptionTruncate) 869263363Semaste mode |= O_TRUNC; 870263363Semaste 871263363Semaste if (open_options & eOpenOptionNonBlocking) 872263363Semaste mode |= O_NONBLOCK; 873263363Semaste 874263363Semaste if (open_options & eOpenOptionCanCreateNewOnly) 875263363Semaste mode |= O_CREAT | O_EXCL; 876263363Semaste else if (open_options & eOpenOptionCanCreate) 877263363Semaste mode |= O_CREAT; 878263363Semaste 879263363Semaste return mode; 880263363Semaste} 881269024Semaste 882269024Semastevoid 883269024SemasteFile::CalculateInteractiveAndTerminal () 884269024Semaste{ 885269024Semaste const int fd = GetDescriptor(); 886269024Semaste if (fd >= 0) 887269024Semaste { 888269024Semaste m_is_interactive = eLazyBoolNo; 889269024Semaste m_is_real_terminal = eLazyBoolNo; 890269024Semaste#ifndef _MSC_VER 891269024Semaste if (isatty(fd)) 892269024Semaste { 893269024Semaste m_is_interactive = eLazyBoolYes; 894269024Semaste struct winsize window_size; 895269024Semaste if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0) 896269024Semaste { 897269024Semaste if (window_size.ws_col > 0) 898269024Semaste m_is_real_terminal = eLazyBoolYes; 899269024Semaste } 900269024Semaste } 901269024Semaste#endif 902269024Semaste } 903269024Semaste} 904269024Semaste 905269024Semastebool 906269024SemasteFile::GetIsInteractive () 907269024Semaste{ 908269024Semaste if (m_is_interactive == eLazyBoolCalculate) 909269024Semaste CalculateInteractiveAndTerminal (); 910269024Semaste return m_is_interactive == eLazyBoolYes; 911269024Semaste} 912269024Semaste 913269024Semastebool 914269024SemasteFile::GetIsRealTerminal () 915269024Semaste{ 916269024Semaste if (m_is_real_terminal == eLazyBoolCalculate) 917269024Semaste CalculateInteractiveAndTerminal(); 918269024Semaste return m_is_real_terminal == eLazyBoolYes; 919269024Semaste} 920269024Semaste 921