#3130: fix error handling: report original error before close()

This commit is contained in:
Günter Obiltschnig 2021-06-14 18:59:56 +02:00
parent 90be9b0e53
commit 97ae6924dd
2 changed files with 36 additions and 22 deletions

View File

@ -27,7 +27,7 @@ namespace Poco {
class FileImpl class FileImpl
{ {
protected: protected:
enum Options enum Options
{ {
OPT_FAIL_ON_OVERWRITE_IMPL = 0x01 OPT_FAIL_ON_OVERWRITE_IMPL = 0x01
}; };
@ -65,6 +65,7 @@ protected:
FileSizeImpl totalSpaceImpl() const; FileSizeImpl totalSpaceImpl() const;
FileSizeImpl usableSpaceImpl() const; FileSizeImpl usableSpaceImpl() const;
FileSizeImpl freeSpaceImpl() const; FileSizeImpl freeSpaceImpl() const;
static void handleLastErrorImpl(int err, const std::string& path);
static void handleLastErrorImpl(const std::string& path); static void handleLastErrorImpl(const std::string& path);
private: private:

View File

@ -336,20 +336,22 @@ void FileImpl::copyToImpl(const std::string& path, int options) const
struct stat st; struct stat st;
if (fstat(sd, &st) != 0) if (fstat(sd, &st) != 0)
{ {
int err = errno;
close(sd); close(sd);
handleLastErrorImpl(_path); handleLastErrorImpl(err, _path);
} }
const long blockSize = st.st_blksize; const long blockSize = st.st_blksize;
int dd; int dd;
if (options & OPT_FAIL_ON_OVERWRITE_IMPL) { if (options & OPT_FAIL_ON_OVERWRITE_IMPL) {
dd = open(path.c_str(), O_CREAT | O_TRUNC | O_EXCL | O_WRONLY, st.st_mode); dd = open(path.c_str(), O_CREAT | O_TRUNC | O_EXCL | O_WRONLY, st.st_mode);
} else { } else {
dd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, st.st_mode); dd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, st.st_mode);
} }
if (dd == -1) if (dd == -1)
{ {
int err = errno;
close(sd); close(sd);
handleLastErrorImpl(path); handleLastErrorImpl(err, path);
} }
Buffer<char> buffer(blockSize); Buffer<char> buffer(blockSize);
try try
@ -361,7 +363,9 @@ void FileImpl::copyToImpl(const std::string& path, int options) const
handleLastErrorImpl(path); handleLastErrorImpl(path);
} }
if (n < 0) if (n < 0)
{
handleLastErrorImpl(_path); handleLastErrorImpl(_path);
}
} }
catch (...) catch (...)
{ {
@ -372,11 +376,14 @@ void FileImpl::copyToImpl(const std::string& path, int options) const
close(sd); close(sd);
if (fsync(dd) != 0) if (fsync(dd) != 0)
{ {
int err = errno;
close(dd); close(dd);
handleLastErrorImpl(path); handleLastErrorImpl(err, path);
} }
if (close(dd) != 0) if (close(dd) != 0)
{
handleLastErrorImpl(path); handleLastErrorImpl(path);
}
} }
@ -387,7 +394,7 @@ void FileImpl::renameToImpl(const std::string& path, int options)
struct stat st; struct stat st;
if (stat(path.c_str(), &st) == 0 && (options & OPT_FAIL_ON_OVERWRITE_IMPL)) if (stat(path.c_str(), &st) == 0 && (options & OPT_FAIL_ON_OVERWRITE_IMPL))
throw FileExistsException(path, EEXIST); throw FileExistsException(path, EEXIST);
if (rename(_path.c_str(), path.c_str()) != 0) if (rename(_path.c_str(), path.c_str()) != 0)
handleLastErrorImpl(_path); handleLastErrorImpl(_path);
@ -490,43 +497,49 @@ FileImpl::FileSizeImpl FileImpl::freeSpaceImpl() const
} }
void FileImpl::handleLastErrorImpl(const std::string& path) void FileImpl::handleLastErrorImpl(int err, const std::string& path)
{ {
switch (errno) switch (err)
{ {
case EIO: case EIO:
throw IOException(path, errno); throw IOException(path, err);
case EPERM: case EPERM:
throw FileAccessDeniedException("insufficient permissions", path, errno); throw FileAccessDeniedException("insufficient permissions", path, err);
case EACCES: case EACCES:
throw FileAccessDeniedException(path, errno); throw FileAccessDeniedException(path, err);
case ENOENT: case ENOENT:
throw FileNotFoundException(path, errno); throw FileNotFoundException(path, err);
case ENOTDIR: case ENOTDIR:
throw OpenFileException("not a directory", path, errno); throw OpenFileException("not a directory", path, err);
case EISDIR: case EISDIR:
throw OpenFileException("not a file", path, errno); throw OpenFileException("not a file", path, err);
case EROFS: case EROFS:
throw FileReadOnlyException(path, errno); throw FileReadOnlyException(path, err);
case EEXIST: case EEXIST:
throw FileExistsException(path, errno); throw FileExistsException(path, err);
case ENOSPC: case ENOSPC:
throw FileException("no space left on device", path, errno); throw FileException("no space left on device", path, err);
case EDQUOT: case EDQUOT:
throw FileException("disk quota exceeded", path, errno); throw FileException("disk quota exceeded", path, err);
#if !defined(_AIX) #if !defined(_AIX)
case ENOTEMPTY: case ENOTEMPTY:
throw DirectoryNotEmptyException(path, errno); throw DirectoryNotEmptyException(path, err);
#endif #endif
case ENAMETOOLONG: case ENAMETOOLONG:
throw PathSyntaxException(path, errno); throw PathSyntaxException(path, err);
case ENFILE: case ENFILE:
case EMFILE: case EMFILE:
throw FileException("too many open files", path, errno); throw FileException("too many open files", path, err);
default: default:
throw FileException(Error::getMessage(errno), path, errno); throw FileException(Error::getMessage(err), path, err);
} }
} }
void FileImpl::handleLastErrorImpl(const std::string& path)
{
handleLastErrorImpl(errno, path);
}
} // namespace Poco } // namespace Poco