summaryrefslogtreecommitdiff
path: root/zen/file_io.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/file_io.cpp')
-rw-r--r--zen/file_io.cpp93
1 files changed, 43 insertions, 50 deletions
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index b385ce33..b4351ee8 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -152,6 +152,7 @@ FileInput::FileInput(const Zstring& filepath) : //throw FileError, ErrorFileLock
#ifdef ZEN_WIN //destructor call would lead to member double clean-up!!!
ZEN_ON_SCOPE_FAIL(::CloseHandle(fileHandle));
+
#elif defined ZEN_LINUX || defined ZEN_MAC
ZEN_ON_SCOPE_FAIL(::close(fileHandle));
#endif
@@ -178,45 +179,38 @@ FileInput::~FileInput()
}
-size_t FileInput::read(void* buffer, size_t bytesToRead) //throw FileError; returns actual number of bytes read
+size_t FileInput::tryRead(void* buffer, size_t bytesToRead) //throw FileError; may return short, only 0 means EOF!
{
- size_t bytesReadTotal = 0;
+ if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
- while (bytesToRead > 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- {
#ifdef ZEN_WIN
- //test for end of file: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365690%28v=vs.85%29.aspx
- DWORD bytesRead = 0;
- if (!::ReadFile(fileHandle, //__in HANDLE hFile,
- buffer, //__out LPVOID lpBuffer,
- static_cast<DWORD>(bytesToRead), //__in DWORD nNumberOfBytesToRead,
- &bytesRead, //__out_opt LPDWORD lpNumberOfBytesRead,
- nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), L"ReadFile");
+ //posix ::read() semantics: test for end of file: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365690%28v=vs.85%29.aspx
+ DWORD bytesRead = 0;
+ if (!::ReadFile(fileHandle, //__in HANDLE hFile,
+ buffer, //__out LPVOID lpBuffer,
+ static_cast<DWORD>(bytesToRead), //__in DWORD nNumberOfBytesToRead,
+ &bytesRead, //__out_opt LPDWORD lpNumberOfBytesRead,
+ nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), L"ReadFile");
#elif defined ZEN_LINUX || defined ZEN_MAC
- ssize_t bytesRead = 0;
- do
- {
- bytesRead = ::read(fileHandle, buffer, bytesToRead);
- }
- while (bytesRead < 0 && errno == EINTR); //Compare copy_reg() in copy.c: ftp://ftp.gnu.org/gnu/coreutils/coreutils-8.23.tar.xz
+ ssize_t bytesRead = 0;
+ do
+ {
+ bytesRead = ::read(fileHandle, buffer, bytesToRead);
+ }
+ while (bytesRead < 0 && errno == EINTR); //Compare copy_reg() in copy.c: ftp://ftp.gnu.org/gnu/coreutils/coreutils-8.23.tar.xz
- if (bytesRead < 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), L"read");
+ if (bytesRead < 0)
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), L"read");
#endif
- if (bytesRead == 0) //"zero indicates end of file"
- return bytesReadTotal;
+ if (static_cast<size_t>(bytesRead) > bytesToRead) //better safe than sorry
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), L"ReadFile: buffer overflow."); //user should never see this
- if (static_cast<size_t>(bytesRead) > bytesToRead) //better safe than sorry
- throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), L"ReadFile: buffer overflow."); //user should never see this
+ //if ::read is interrupted (EINTR) right in the middle, it will return successfully with "bytesRead < bytesToRead" => loop!
- //if ::read is interrupted (EINTR) right in the middle, it will return successfully with "bytesRead < bytesToRead" => loop!
- buffer = static_cast<char*>(buffer) + bytesRead; //suppress warning about pointer arithmetics on void*
- bytesToRead -= bytesRead;
- bytesReadTotal += bytesRead;
- }
- return bytesReadTotal;
+ return bytesRead; //"zero indicates end of file"
}
//----------------------------------------------------------------------------------------------------
@@ -355,8 +349,11 @@ void FileOutput::close() //throw FileError
}
-void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileError
+size_t FileOutput::tryWrite(const void* buffer, size_t bytesToWrite) //throw FileError; may return short! CONTRACT: bytesToWrite > 0
{
+ if (bytesToWrite == 0)
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+
#ifdef ZEN_WIN
DWORD bytesWritten = 0; //this parameter is NOT optional: http://blogs.msdn.com/b/oldnewthing/archive/2013/04/04/10407417.aspx
if (!::WriteFile(fileHandle, //__in HANDLE hFile,
@@ -370,28 +367,24 @@ void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileErro
throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"WriteFile: incomplete write."); //user should never see this
#elif defined ZEN_LINUX || defined ZEN_MAC
- while (bytesToWrite > 0)
+ ssize_t bytesWritten = 0;
+ do
{
- ssize_t bytesWritten = 0;
- do
- {
- bytesWritten = ::write(fileHandle, buffer, bytesToWrite);
- }
- while (bytesWritten < 0 && errno == EINTR);
-
- if (bytesWritten <= 0)
- {
- if (bytesWritten == 0) //comment in safe-read.c suggests to treat this as an error due to buggy drivers
- errno = ENOSPC;
+ bytesWritten = ::write(fileHandle, buffer, bytesToWrite);
+ }
+ while (bytesWritten < 0 && errno == EINTR);
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"write");
- }
- if (bytesWritten > static_cast<ssize_t>(bytesToWrite)) //better safe than sorry
- throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"write: buffer overflow."); //user should never see this
+ if (bytesWritten <= 0)
+ {
+ if (bytesWritten == 0) //comment in safe-read.c suggests to treat this as an error due to buggy drivers
+ errno = ENOSPC;
- //if ::write() is interrupted (EINTR) right in the middle, it will return successfully with "bytesWritten < bytesToWrite"!
- buffer = static_cast<const char*>(buffer) + bytesWritten; //suppress warning about pointer arithmetics on void*
- bytesToWrite -= bytesWritten;
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"write");
}
+ if (bytesWritten > static_cast<ssize_t>(bytesToWrite)) //better safe than sorry
+ throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"write: buffer overflow."); //user should never see this
+
+ //if ::write() is interrupted (EINTR) right in the middle, it will return successfully with "bytesWritten < bytesToWrite"!
#endif
+ return bytesWritten;
}
bgstack15