From 07baed158175c3baf87a9edd523a9ec97bffd223 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Tue, 6 Nov 2007 03:21:32 +0100 Subject: [PATCH] Improved IO error checking. --- Makefile | 2 +- src/file.cpp | 31 ++++++++++++++++++------------- src/file.h | 2 +- src/work.cpp | 41 ++++++++++++++++++++++++++++------------- 4 files changed, 48 insertions(+), 28 deletions(-) diff --git a/Makefile b/Makefile index 741cfedf..9a171cbe 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ endif $(MAKE) -C doc $@ -ifneq ($(wildcard .hg/data/.),) +ifneq ($(wildcard .hg/.),) # automatically generate ChangeLog from local Mercurial repo ChangeLog: hg log --style=changelog > $@ diff --git a/src/file.cpp b/src/file.cpp index 81fcb2d3..398ca511 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -88,7 +88,7 @@ FileBase::~FileBase() } -void FileBase::sopen() +bool FileBase::do_sopen() { if (_shflags < 0) _fd = ::open(_name, _flags, _mode); @@ -101,13 +101,15 @@ void FileBase::sopen() #elif defined(SH_DENYRW) _fd = ::sopen(_name, _flags, _shflags, _mode); #else - assert(0); + throwInternalError("bad usage of do_sopen()"); #endif } - if (!(_fd < 0)) { - ::fstat(_fd, &st); - _length = st.st_size; - } + if (_fd < 0) + return false; + if (::fstat(_fd, &st) != 0) + throwIOException(_name, errno); + _length = st.st_size; + return true; } @@ -232,8 +234,7 @@ void InputFile::sopen(const char *name, int flags, int shflags) _mode = 0; _offset = 0; _length = 0; - FileBase::sopen(); - if (!isOpen()) + if (!FileBase::do_sopen()) { if (errno == ENOENT) throw FileNotFoundException(_name, errno); @@ -318,8 +319,7 @@ void OutputFile::sopen(const char *name, int flags, int shflags, int mode) _mode = mode; _offset = 0; _length = 0; - FileBase::sopen(); - if (!isOpen()) + if (!FileBase::do_sopen()) { #if 0 // don't throw FileNotFound here -- this is confusing @@ -366,7 +366,8 @@ off_t OutputFile::st_size() const return bytes_written; // too big if seek()+write() instead of rewrite() } struct stat my_st; - ::fstat(_fd, &my_st); + if (::fstat(_fd, &my_st) != 0) + throwIOException(_name, errno); return my_st.st_size; } @@ -402,15 +403,19 @@ void OutputFile::set_extent(off_t offset, off_t length) super::set_extent(offset, length); bytes_written = 0; if (0==offset && (off_t)~0u==length) { - ::fstat(_fd, &st); + if (::fstat(_fd, &st) != 0) + throwIOException(_name, errno); _length = st.st_size - offset; } } off_t OutputFile::unset_extent() { + off_t l = ::lseek(_fd, 0, SEEK_END); + if (l < 0) + throwIOException("lseek error", errno); _offset = 0; - _length = ::lseek(_fd, 0, SEEK_END); + _length = l; bytes_written = _length; return _length; } diff --git a/src/file.h b/src/file.h index 66b614ef..67f744ad 100644 --- a/src/file.h +++ b/src/file.h @@ -63,7 +63,7 @@ public: virtual void set_extent(off_t offset, off_t length); protected: - void sopen(); + bool do_sopen(); virtual int read(void *buf, int len); virtual int readx(void *buf, int len); virtual void write(const void *buf, int len); diff --git a/src/work.cpp b/src/work.cpp index 1dc2ed9d..838e1938 100644 --- a/src/work.cpp +++ b/src/work.cpp @@ -51,6 +51,9 @@ # define SH_DENYWR (-1) #endif +// ignore errors in some cases and silence __attribute__((__warn_unused_result__)) +#define IGNORE_ERROR(var) ACC_UNUSED(var) + /************************************************************************* // process one file @@ -98,8 +101,13 @@ void do_one_file(const char *iname, char *oname) fi.sopen(iname, O_RDONLY | O_BINARY, SH_DENYWR); #if defined(USE_FTIME) - struct ftime fit; - getftime(fi.getFd(),&fit); + struct ftime fi_ftime; + memset(&fi_ftime, 0, sizeof(fi_ftime)); + if (opt->preserve_timestamp) + { + if (getftime(fi.getFd(), &fi_ftime) != 0) + throwIOException("cannot determine file timestamp"); + } #endif // open output file @@ -124,9 +132,11 @@ void do_one_file(const char *iname, char *oname) if (opt->force >= 2) { #if defined(HAVE_CHMOD) - (void) ::chmod(tname, 0777); + r = chmod(tname, 0777); + IGNORE_ERROR(r); #endif - (void) ::unlink(tname); + r = unlink(tname); + IGNORE_ERROR(r); } int flags = O_CREAT | O_WRONLY | O_BINARY; if (opt->force) @@ -165,15 +175,17 @@ void do_one_file(const char *iname, char *oname) throwInternalError("invalid command"); // copy time stamp - if (oname[0] && fo.isOpen()) + if (opt->preserve_timestamp && oname[0] && fo.isOpen()) { #if defined(USE_FTIME) - setftime(fo.getFd(),&fit); + r = setftime(fo.getFd(), &fi_ftime); + IGNORE_ERROR(r); #elif defined(USE__FUTIME) struct _utimbuf u; u.actime = st.st_atime; u.modtime = st.st_mtime; - (void) _futime(fo.getFd(),&u); + r = _futime(fo.getFd(), &u); + IGNORE_ERROR(r); #endif } @@ -188,7 +200,8 @@ void do_one_file(const char *iname, char *oname) if (!opt->backup) { #if defined(HAVE_CHMOD) - (void) ::chmod(iname, 0777); + r = chmod(iname, 0777); + IGNORE_ERROR(r); #endif File::unlink(iname); } @@ -217,7 +230,7 @@ void do_one_file(const char *iname, char *oname) u.actime = st.st_atime; u.modtime = st.st_mtime; r = utime(name, &u); - UNUSED(r); + IGNORE_ERROR(r); } #endif #if defined(HAVE_CHMOD) @@ -225,7 +238,7 @@ void do_one_file(const char *iname, char *oname) if (opt->preserve_mode) { r = chmod(name, st.st_mode); - UNUSED(r); + IGNORE_ERROR(r); } #endif #if defined(HAVE_CHOWN) @@ -233,7 +246,7 @@ void do_one_file(const char *iname, char *oname) if (opt->preserve_ownership) { r = chown(name, st.st_uid, st.st_gid); - UNUSED(r); + IGNORE_ERROR(r); } #endif } @@ -251,9 +264,11 @@ static void unlink_ofile(char *oname) if (oname && oname[0]) { #if defined(HAVE_CHMOD) - (void) ::chmod(oname, 0777); + int r; + r = chmod(oname, 0777); + IGNORE_ERROR(r); #endif - if (::unlink(oname) == 0) + if (unlink(oname) == 0) oname[0] = 0; } }