zturner created this revision.
zturner added reviewers: clayborg, beanz, EugeneBi.
zturner added a subscriber: lldb-commits.
The original motivation for this came from https://reviews.llvm.org/D25712, in
which Eugene pointed out that `File::Read()` does not correctly handle short
reads. However, I felt the fix was incomplete because it left the bug in other
functions, and the code in general could have used some cleanup since there was
a ton of duplication, which may be what led to this bug showing up in the first
place.
Changes in this patch are:
1. Have the normal `Read()` and `Write()` functions delegate to the versions
that read and write with offset.
2. Supply thread-safe versions of the Windows codepaths, which were previously
incorrect in a multi-threaded environment.
3. Delete a bunch of dead functions that are not used anywhere in LLDB.
4. Remove the apple specific path due to `MAX_READ_SIZE` and `MAX_WRITE_SIZE`
and merge with the standard non-Windows path.
The only real tricky part about this patch was that when you open a file in
append mode, the old version of `Write()` with no offset would write at the
end, whereas `pwrite()` always writes at the offset you specify. So to fix
this I made the version of `Write()` with no offset explicitly compute the
offset of the end of the file and pass that to the offset-version of `Write()`.
https://reviews.llvm.org/D25783
Files:
include/lldb/Host/File.h
source/Host/common/File.cpp
Index: source/Host/common/File.cpp
===================================================================
--- source/Host/common/File.cpp
+++ source/Host/common/File.cpp
@@ -367,58 +367,6 @@
return result;
}
-off_t File::SeekFromCurrent(off_t offset, Error *error_ptr) {
- off_t result = -1;
- if (DescriptorIsValid()) {
- result = ::lseek(m_descriptor, offset, SEEK_CUR);
-
- if (error_ptr) {
- if (result == -1)
- error_ptr->SetErrorToErrno();
- else
- error_ptr->Clear();
- }
- } else if (StreamIsValid()) {
- result = ::fseek(m_stream, offset, SEEK_CUR);
-
- if (error_ptr) {
- if (result == -1)
- error_ptr->SetErrorToErrno();
- else
- error_ptr->Clear();
- }
- } else if (error_ptr) {
- error_ptr->SetErrorString("invalid file handle");
- }
- return result;
-}
-
-off_t File::SeekFromEnd(off_t offset, Error *error_ptr) {
- off_t result = -1;
- if (DescriptorIsValid()) {
- result = ::lseek(m_descriptor, offset, SEEK_END);
-
- if (error_ptr) {
- if (result == -1)
- error_ptr->SetErrorToErrno();
- else
- error_ptr->Clear();
- }
- } else if (StreamIsValid()) {
- result = ::fseek(m_stream, offset, SEEK_END);
-
- if (error_ptr) {
- if (result == -1)
- error_ptr->SetErrorToErrno();
- else
- error_ptr->Clear();
- }
- } else if (error_ptr) {
- error_ptr->SetErrorString("invalid file handle");
- }
- return result;
-}
-
Error File::Flush() {
Error error;
if (StreamIsValid()) {
@@ -435,218 +383,103 @@
return error;
}
-Error File::Sync() {
- Error error;
- if (DescriptorIsValid()) {
-#ifdef _WIN32
- int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
- if (err == 0)
- error.SetErrorToGenericError();
-#else
- int err = 0;
- do {
- err = ::fsync(m_descriptor);
- } while (err == -1 && errno == EINTR);
-
- if (err == -1)
- error.SetErrorToErrno();
-#endif
- } else {
- error.SetErrorString("invalid file handle");
- }
- return error;
-}
-
#if defined(__APPLE__)
// Darwin kernels only can read/write <= INT_MAX bytes
-#define MAX_READ_SIZE INT_MAX
-#define MAX_WRITE_SIZE INT_MAX
+constexpr size_t MAX_READ_SIZE = INT_MAX;
+constexpr size_t MAX_WRITE_SIZE = INT_MAX;
+#elif defined(LLVM_ON_WIN32)
+constexpr size_t MAX_READ_SIZE = ULONG_MAX;
+constexpr size_t MAX_WRITE_SIZE = ULONG_MAX;
+#else
+constexpr size_t MAX_READ_SIZE = SIZE_MAX;
+constexpr size_t MAX_WRITE_SIZE = SIZE_MAX;
#endif
Error File::Read(void *buf, size_t &num_bytes) {
- Error error;
-
-#if defined(MAX_READ_SIZE)
- if (num_bytes > MAX_READ_SIZE) {
- uint8_t *p = (uint8_t *)buf;
- size_t bytes_left = num_bytes;
- // Init the num_bytes read to zero
+ int fd = GetDescriptor();
+ if (fd == kInvalidDescriptor) {
num_bytes = 0;
-
- while (bytes_left > 0) {
- size_t curr_num_bytes;
- if (bytes_left > MAX_READ_SIZE)
- curr_num_bytes = MAX_READ_SIZE;
- else
- curr_num_bytes = bytes_left;
-
- error = Read(p + num_bytes, curr_num_bytes);
-
- // Update how many bytes were read
- num_bytes += curr_num_bytes;
- if (bytes_left < curr_num_bytes)
- bytes_left = 0;
- else
- bytes_left -= curr_num_bytes;
-
- if (error.Fail())
- break;
- }
- return error;
+ return Error("invalid file handle");
}
-#endif
-
- ssize_t bytes_read = -1;
- if (DescriptorIsValid()) {
- do {
- bytes_read = ::read(m_descriptor, buf, num_bytes);
- } while (bytes_read < 0 && errno == EINTR);
-
- if (bytes_read == -1) {
- error.SetErrorToErrno();
- num_bytes = 0;
- } else
- num_bytes = bytes_read;
- } else if (StreamIsValid()) {
- bytes_read = ::fread(buf, 1, num_bytes, m_stream);
- if (bytes_read == 0) {
- if (::feof(m_stream))
- error.SetErrorString("feof");
- else if (::ferror(m_stream))
- error.SetErrorString("ferror");
- num_bytes = 0;
- } else
- num_bytes = bytes_read;
- } else {
- num_bytes = 0;
- error.SetErrorString("invalid file handle");
- }
- return error;
+ off_t offset = lseek(fd, 0, SEEK_CUR);
+ return Read(buf, num_bytes, offset);
}
Error File::Write(const void *buf, size_t &num_bytes) {
- Error error;
-
-#if defined(MAX_WRITE_SIZE)
- if (num_bytes > MAX_WRITE_SIZE) {
- const uint8_t *p = (const uint8_t *)buf;
- size_t bytes_left = num_bytes;
- // Init the num_bytes written to zero
+ int fd = GetDescriptor();
+ if (fd == kInvalidDescriptor) {
num_bytes = 0;
-
- while (bytes_left > 0) {
- size_t curr_num_bytes;
- if (bytes_left > MAX_WRITE_SIZE)
- curr_num_bytes = MAX_WRITE_SIZE;
- else
- curr_num_bytes = bytes_left;
-
- error = Write(p + num_bytes, curr_num_bytes);
-
- // Update how many bytes were read
- num_bytes += curr_num_bytes;
- if (bytes_left < curr_num_bytes)
- bytes_left = 0;
- else
- bytes_left -= curr_num_bytes;
-
- if (error.Fail())
- break;
- }
- return error;
+ return Error("invalid file handle");
}
-#endif
- ssize_t bytes_written = -1;
- if (DescriptorIsValid()) {
- do {
- bytes_written = ::write(m_descriptor, buf, num_bytes);
- } while (bytes_written < 0 && errno == EINTR);
-
- if (bytes_written == -1) {
- error.SetErrorToErrno();
- num_bytes = 0;
- } else
- num_bytes = bytes_written;
- } else if (StreamIsValid()) {
- bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
-
- if (bytes_written == 0) {
- if (::feof(m_stream))
- error.SetErrorString("feof");
- else if (::ferror(m_stream))
- error.SetErrorString("ferror");
- num_bytes = 0;
- } else
- num_bytes = bytes_written;
-
- } else {
- num_bytes = 0;
- error.SetErrorString("invalid file handle");
+ off_t offset = lseek(fd, 0, SEEK_CUR);
+ if (m_options & File::eOpenOptionAppend) {
+ struct stat S;
+ if (::fstat(fd, &S) != 0)
+ return Error("Invalid file handle!");
+ offset = S.st_size;
}
-
- return error;
+ return Write(buf, num_bytes, offset);
}
Error File::Read(void *buf, size_t &num_bytes, off_t &offset) {
Error error;
-
-#if defined(MAX_READ_SIZE)
- if (num_bytes > MAX_READ_SIZE) {
- uint8_t *p = (uint8_t *)buf;
- size_t bytes_left = num_bytes;
- // Init the num_bytes read to zero
+ size_t bytes_left = num_bytes;
+ int fd = GetDescriptor();
+ if (fd == kInvalidDescriptor) {
num_bytes = 0;
-
- while (bytes_left > 0) {
- size_t curr_num_bytes;
- if (bytes_left > MAX_READ_SIZE)
- curr_num_bytes = MAX_READ_SIZE;
- else
- curr_num_bytes = bytes_left;
-
- error = Read(p + num_bytes, curr_num_bytes, offset);
-
- // Update how many bytes were read
- num_bytes += curr_num_bytes;
- if (bytes_left < curr_num_bytes)
- bytes_left = 0;
- else
- bytes_left -= curr_num_bytes;
-
- if (error.Fail())
- break;
- }
- return error;
+ return Error("invalid file handle");
}
-#endif
+ uint8_t *dest = static_cast<uint8_t *>(buf);
#ifndef _WIN32
- int fd = GetDescriptor();
- if (fd != kInvalidDescriptor) {
- ssize_t bytes_read = -1;
+ ssize_t bytes_read = -1;
+ size_t bytes_to_read = std::min(MAX_READ_SIZE, bytes_left);
+ while (bytes_left != 0 && bytes_read != 0) {
do {
- bytes_read = ::pread(fd, buf, num_bytes, offset);
+ bytes_read = ::pread(fd, dest, num_bytes, offset);
} while (bytes_read < 0 && errno == EINTR);
if (bytes_read < 0) {
num_bytes = 0;
error.SetErrorToErrno();
- } else {
- offset += bytes_read;
- num_bytes = bytes_read;
+ return error;
}
- } else {
- num_bytes = 0;
- error.SetErrorString("invalid file handle");
+
+ dest += bytes_read;
+ offset += bytes_read;
+ bytes_left -= bytes_read;
}
+ num_bytes -= bytes_left;
#else
- long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
- SeekFromStart(offset);
- error = Read(buf, num_bytes);
- if (!error.Fail())
- SeekFromStart(cur);
+ HANDLE H = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+ if (!H || H == INVALID_HANDLE_VALUE)
+ return Error("invalid file handle");
+
+ LARGE_INTEGER large_off;
+ large_off.QuadPart = offset;
+
+ OVERLAPPED OV = {};
+ OV.Offset = large_off.LowPart;
+ OV.OffsetHigh = large_off.HighPart;
+
+ while (bytes_left != 0) {
+ DWORD req_size = static_cast<DWORD>(std::min(MAX_READ_SIZE, bytes_left));
+ DWORD actual_size = 0;
+ BOOL result = ::ReadFile(H, dest, req_size, &actual_size, &OV);
+ if (!result) {
+ error.SetError(GetLastError(), eErrorTypeWin32);
+ return error;
+ }
+ if (actual_size == 0) {
+ // EOF was reached.
+ break;
+ }
+ dest += actual_size;
+ bytes_left -= actual_size;
+ }
+ num_bytes -= bytes_left;
#endif
return error;
}
@@ -697,66 +530,56 @@
Error File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
Error error;
-
-#if defined(MAX_WRITE_SIZE)
- if (num_bytes > MAX_WRITE_SIZE) {
- const uint8_t *p = (const uint8_t *)buf;
- size_t bytes_left = num_bytes;
- // Init the num_bytes written to zero
+ size_t bytes_left = num_bytes;
+ int fd = GetDescriptor();
+ if (fd == kInvalidDescriptor) {
num_bytes = 0;
-
- while (bytes_left > 0) {
- size_t curr_num_bytes;
- if (bytes_left > MAX_WRITE_SIZE)
- curr_num_bytes = MAX_WRITE_SIZE;
- else
- curr_num_bytes = bytes_left;
-
- error = Write(p + num_bytes, curr_num_bytes, offset);
-
- // Update how many bytes were read
- num_bytes += curr_num_bytes;
- if (bytes_left < curr_num_bytes)
- bytes_left = 0;
- else
- bytes_left -= curr_num_bytes;
-
- if (error.Fail())
- break;
- }
- return error;
+ return Error("invalid file handle");
}
-#endif
- int fd = GetDescriptor();
- if (fd != kInvalidDescriptor) {
+ const uint8_t *src = static_cast<const uint8_t *>(buf);
#ifndef _WIN32
- ssize_t bytes_written = -1;
+ ssize_t bytes_written = -1;
+ size_t bytes_to_write = std::min(MAX_WRITE_SIZE, bytes_left);
+ while (bytes_left != 0) {
do {
- bytes_written = ::pwrite(m_descriptor, buf, num_bytes, offset);
+ bytes_written = ::pwrite(fd, src, num_bytes, offset);
} while (bytes_written < 0 && errno == EINTR);
if (bytes_written < 0) {
num_bytes = 0;
error.SetErrorToErrno();
- } else {
- offset += bytes_written;
- num_bytes = bytes_written;
+ return error;
}
-#else
- long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
- error = Write(buf, num_bytes);
- long after = ::lseek(m_descriptor, 0, SEEK_CUR);
- if (!error.Fail())
- SeekFromStart(cur);
-
- offset = after;
-#endif
- } else {
- num_bytes = 0;
- error.SetErrorString("invalid file handle");
+ src += bytes_written;
+ offset += bytes_written;
+ bytes_left -= bytes_written;
}
+#else
+ HANDLE H = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+ if (!H || H == INVALID_HANDLE_VALUE)
+ return Error("invalid file handle");
+
+ LARGE_INTEGER large_off;
+ large_off.QuadPart = offset;
+
+ OVERLAPPED OV = {};
+ OV.Offset = large_off.LowPart;
+ OV.OffsetHigh = large_off.HighPart;
+
+ while (bytes_left != 0) {
+ DWORD req_size = static_cast<DWORD>(std::min(MAX_WRITE_SIZE, bytes_left));
+ DWORD actual_size = 0;
+ BOOL result = ::WriteFile(H, src, req_size, &actual_size, &OV);
+ if (!result) {
+ error.SetError(GetLastError(), eErrorTypeWin32);
+ return error;
+ }
+ src += actual_size;
+ bytes_left -= actual_size;
+ }
+#endif
return error;
}
Index: include/lldb/Host/File.h
===================================================================
--- include/lldb/Host/File.h
+++ include/lldb/Host/File.h
@@ -265,51 +265,6 @@
off_t SeekFromStart(off_t offset, Error *error_ptr = nullptr);
//------------------------------------------------------------------
- /// Seek to an offset relative to the current file position.
- ///
- /// NOTE: This function is NOT thread safe, other threads that
- /// access this object might also change the current file position.
- /// For thread safe reads and writes see the following functions:
- /// @see File::Read (void *, size_t, off_t &)
- /// @see File::Write (const void *, size_t, off_t &)
- ///
- /// @param[in] offset
- /// The offset to seek to within the file relative to the
- /// current file position.
- ///
- /// @param[in] error_ptr
- /// A pointer to a lldb_private::Error object that will be
- /// filled in if non-nullptr.
- ///
- /// @return
- /// The resulting seek offset, or -1 on error.
- //------------------------------------------------------------------
- off_t SeekFromCurrent(off_t offset, Error *error_ptr = nullptr);
-
- //------------------------------------------------------------------
- /// Seek to an offset relative to the end of the file.
- ///
- /// NOTE: This function is NOT thread safe, other threads that
- /// access this object might also change the current file position.
- /// For thread safe reads and writes see the following functions:
- /// @see File::Read (void *, size_t, off_t &)
- /// @see File::Write (const void *, size_t, off_t &)
- ///
- /// @param[in,out] offset
- /// The offset to seek to within the file relative to the
- /// end of the file which gets filled in with the resulting
- /// absolute file offset.
- ///
- /// @param[in] error_ptr
- /// A pointer to a lldb_private::Error object that will be
- /// filled in if non-nullptr.
- ///
- /// @return
- /// The resulting seek offset, or -1 on error.
- //------------------------------------------------------------------
- off_t SeekFromEnd(off_t offset, Error *error_ptr = nullptr);
-
- //------------------------------------------------------------------
/// Read bytes from a file from the specified file offset.
///
/// NOTE: This function is thread safe in that clients manager their
@@ -403,15 +358,6 @@
Error Flush();
//------------------------------------------------------------------
- /// Sync to disk.
- ///
- /// @return
- /// An error object that indicates success or the reason for
- /// failure.
- //------------------------------------------------------------------
- Error Sync();
-
- //------------------------------------------------------------------
/// Get the permissions for a this file.
///
/// @return
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits