diff options
Diffstat (limited to 'lib/Support/MemoryBuffer.cpp')
| -rw-r--r-- | lib/Support/MemoryBuffer.cpp | 43 | 
1 files changed, 26 insertions, 17 deletions
| diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index 345a78c190c0..4f135ead182c 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -14,6 +14,7 @@  #include "llvm/Support/MemoryBuffer.h"  #include "llvm/ADT/OwningPtr.h"  #include "llvm/ADT/SmallString.h" +#include "llvm/System/Errno.h"  #include "llvm/System/Path.h"  #include "llvm/System/Process.h"  #include "llvm/System/Program.h" @@ -167,6 +168,14 @@ public:      sys::Path::UnMapFilePages(getBufferStart(), getBufferSize());    }  }; + +/// FileCloser - RAII object to make sure an FD gets closed properly. +class FileCloser { +  int FD; +public: +  FileCloser(int FD) : FD(FD) {} +  ~FileCloser() { ::close(FD); } +};  }  MemoryBuffer *MemoryBuffer::getFile(StringRef Filename, std::string *ErrStr, @@ -178,9 +187,10 @@ MemoryBuffer *MemoryBuffer::getFile(StringRef Filename, std::string *ErrStr,    SmallString<256> PathBuf(Filename.begin(), Filename.end());    int FD = ::open(PathBuf.c_str(), O_RDONLY|OpenFlags);    if (FD == -1) { -    if (ErrStr) *ErrStr = strerror(errno); +    if (ErrStr) *ErrStr = sys::StrError();      return 0;    } +  FileCloser FC(FD); // Close FD on return.    // If we don't know the file size, use fstat to find out.  fstat on an open    // file descriptor is cheaper than stat on a random path. @@ -190,8 +200,7 @@ MemoryBuffer *MemoryBuffer::getFile(StringRef Filename, std::string *ErrStr,      // TODO: This should use fstat64 when available.      if (fstat(FD, FileInfoPtr) == -1) { -      if (ErrStr) *ErrStr = strerror(errno); -      ::close(FD); +      if (ErrStr) *ErrStr = sys::StrError();        return 0;      }      FileSize = FileInfoPtr->st_size; @@ -208,7 +217,6 @@ MemoryBuffer *MemoryBuffer::getFile(StringRef Filename, std::string *ErrStr,        (FileSize & (sys::Process::GetPageSize()-1)) != 0) {      if (const char *Pages = sys::Path::MapInFilePages(FD, FileSize)) {        // Close the file descriptor, now that the whole file is in memory. -      ::close(FD);        return new MemoryBufferMMapFile(Filename, Pages, FileSize);      }    } @@ -217,30 +225,31 @@ MemoryBuffer *MemoryBuffer::getFile(StringRef Filename, std::string *ErrStr,    if (!Buf) {      // Failed to create a buffer.      if (ErrStr) *ErrStr = "could not allocate buffer"; -    ::close(FD);      return 0;    }    OwningPtr<MemoryBuffer> SB(Buf);    char *BufPtr = const_cast<char*>(SB->getBufferStart()); -   +    size_t BytesLeft = FileSize;    while (BytesLeft) {      ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); -    if (NumRead > 0) { -      BytesLeft -= NumRead; -      BufPtr += NumRead; -    } else if (NumRead == -1 && errno == EINTR) { -      // try again -    } else { -      // error reading. -      if (ErrStr) *ErrStr = strerror(errno); -      close(FD); +    if (NumRead == -1) { +      if (errno == EINTR) +        continue; +      // Error while reading. +      if (ErrStr) *ErrStr = sys::StrError();        return 0; +    } else if (NumRead == 0) { +      // We hit EOF early, truncate and terminate buffer. +      Buf->BufferEnd = BufPtr; +      *BufPtr = 0; +      return SB.take();      } +    BytesLeft -= NumRead; +    BufPtr += NumRead;    } -  close(FD); -   +    return SB.take();  } | 
