From 90fbede55256cb672a67d8181b4f0435047d4e13 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 24 Nov 2018 14:44:21 +0200 Subject: Add fdtruncate(), fdseek(), file position to [io]fdstream ctors --- libbutl/fdstream.cxx | 66 +++++++++++++++++++++++++++++++++---------- libbutl/fdstream.ixx | 23 +++++++++------ libbutl/fdstream.mxx | 79 +++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 126 insertions(+), 42 deletions(-) diff --git a/libbutl/fdstream.cxx b/libbutl/fdstream.cxx index 72439ae..26d5da3 100644 --- a/libbutl/fdstream.cxx +++ b/libbutl/fdstream.cxx @@ -11,7 +11,7 @@ #ifndef _WIN32 # include // open(), O_*, fcntl() # include // close(), read(), write(), lseek(), dup(), pipe(), - // isatty(), ssize_t, STD*_FILENO + // ftruncate(), isatty(), ssize_t, STD*_FILENO # include // writev(), iovec # include // stat(), S_I* # include // stat, off_t @@ -19,9 +19,10 @@ # include # include // _close(), _read(), _write(), _setmode(), _sopen(), - // _lseek(), _dup(), _pipe(), _get_osfhandle() + // _lseek(), _dup(), _pipe(), _chsize_s, + // _get_osfhandle() # include // _SH_DENYNO -# include // _fileno(), stdin, stdout, stderr +# include // _fileno(), stdin, stdout, stderr, SEEK_* # include // _O_* # include // S_I* @@ -95,15 +96,8 @@ namespace butl // fdbuf // - fdbuf:: - fdbuf (auto_fd&& fd) - { - if (fd.get () >= 0) - open (move (fd)); - } - void fdbuf:: - open (auto_fd&& fd) + open (auto_fd&& fd, uint64_t pos) { close (); @@ -118,7 +112,7 @@ namespace butl setg (buf_, buf_, buf_); setp (buf_, buf_ + sizeof (buf_) - 1); // Keep space for overflow's char. - off_ = 0; // @@ Strictly speaking, need to query, can be at end. + off_ = pos; fd_ = move (fd); } @@ -457,8 +451,8 @@ namespace butl // fdstream_base // fdstream_base:: - fdstream_base (auto_fd&& fd, fdstream_mode m) - : fdstream_base (mode (move (fd), m)) // Delegate. + fdstream_base (auto_fd&& fd, fdstream_mode m, std::uint64_t pos) + : fdstream_base (mode (move (fd), m), pos) { } @@ -635,8 +629,9 @@ namespace butl open (fdopen (f, m | fdopen_mode::out)); } - // Utility functions + // fd*() functions // + auto_fd fdopen (const char* f, fdopen_mode m, permissions p) { @@ -788,6 +783,33 @@ namespace butl return auto_fd (fd); } + uint64_t + fdseek (int fd, uint64_t o, fdseek_mode fdm) + { + int m (-1); + + switch (fdm) + { + case fdseek_mode::set: m = SEEK_SET; break; + case fdseek_mode::cur: m = SEEK_CUR; break; + case fdseek_mode::end: m = SEEK_END; break; + } + +#ifndef _WIN32 + off_t r (lseek (fd, static_cast (o), m)); + if (r == static_cast (-1)) + throw_generic_ios_failure (errno); +#else + __int64 r (_lseeki64 (fd, static_cast<__int64> (o), m)); + if (r == -1) + throw_generic_ios_failure (errno); +#endif + + return static_cast (r); + } + + // The rest is platform-specific. + // #ifndef _WIN32 auto_fd @@ -927,6 +949,13 @@ namespace butl return r; } + void + fdtruncate (int fd, uint64_t n) + { + if (ftruncate (fd, static_cast (n)) != 0) + throw_generic_ios_failure (errno); + } + bool fdterm (int fd) { @@ -1128,6 +1157,13 @@ namespace butl return {auto_fd (pd[0]), auto_fd (pd[1])}; } + void + fdtruncate (int fd, uint64_t n) + { + if (errno_t e = _chsize_s (fd, static_cast<__int64> (n))) + throw_generic_ios_failure (e); + } + bool fdterm (int fd) { diff --git a/libbutl/fdstream.ixx b/libbutl/fdstream.ixx index 50e2018..4323954 100644 --- a/libbutl/fdstream.ixx +++ b/libbutl/fdstream.ixx @@ -30,6 +30,13 @@ namespace butl // fdbuf // + inline fdbuf:: + fdbuf (auto_fd&& fd, std::uint64_t pos) + { + if (fd.get () >= 0) + open (std::move (fd), pos); + } + inline auto_fd fdbuf:: release () { @@ -39,8 +46,8 @@ namespace butl // ifdstream // inline ifdstream:: - ifdstream (auto_fd&& fd, iostate e) - : fdstream_base (std::move (fd)), std::istream (&buf_) + ifdstream (auto_fd&& fd, iostate e, std::uint64_t pos) + : fdstream_base (std::move (fd), pos), std::istream (&buf_) { assert (e & badbit); exceptions (e); @@ -53,8 +60,8 @@ namespace butl } inline ifdstream:: - ifdstream (auto_fd&& fd, fdstream_mode m, iostate e) - : fdstream_base (std::move (fd), m), + ifdstream (auto_fd&& fd, fdstream_mode m, iostate e, std::uint64_t pos) + : fdstream_base (std::move (fd), m, pos), std::istream (&buf_), skip_ ((m & fdstream_mode::skip) == fdstream_mode::skip) { @@ -141,8 +148,8 @@ namespace butl // ofdstream // inline ofdstream:: - ofdstream (auto_fd&& fd, iostate e) - : fdstream_base (std::move (fd)), std::ostream (&buf_) + ofdstream (auto_fd&& fd, iostate e, std::uint64_t pos) + : fdstream_base (std::move (fd), pos), std::ostream (&buf_) { assert (e & badbit); exceptions (e); @@ -155,8 +162,8 @@ namespace butl } inline ofdstream:: - ofdstream (auto_fd&& fd, fdstream_mode m, iostate e) - : fdstream_base (std::move (fd), m), std::ostream (&buf_) + ofdstream (auto_fd&& fd, fdstream_mode m, iostate e, std::uint64_t pos) + : fdstream_base (std::move (fd), m, pos), std::ostream (&buf_) { assert (e & badbit); exceptions (e); diff --git a/libbutl/fdstream.mxx b/libbutl/fdstream.mxx index 440e637..2bb3807 100644 --- a/libbutl/fdstream.mxx +++ b/libbutl/fdstream.mxx @@ -106,15 +106,18 @@ LIBBUTL_MODEXPORT namespace butl // Notes and limitations: // // - char only - // - input or output but not both + // - input or output but not both (can use a union of two streams for that) // - no support for put back + // - no support for tell[gp]()/seek[gp]() (but see non-standard tellg() and + // tellp() in fdbuf) // - non-blocking file descriptor is supported only by showmanyc() function // and only on POSIX // - throws ios::failure in case of open()/read()/write()/close() errors // - exception mask has at least badbit // - after catching an exception caused by badbit the stream is no longer - // used - // - not movable, though can be easily supported + // usable + // - not movable, though can be easily supported (or not: there is no move + // constructor for istream/ostream in GCC 4.9) // - passing to constructor auto_fd with a negative file descriptor is valid // and results in the creation of an unopened object // @@ -122,7 +125,11 @@ LIBBUTL_MODEXPORT namespace butl { public: fdbuf () = default; - fdbuf (auto_fd&&); + + // Unless specified, the current read/write position is assumed to + // be 0 (note: not queried). + // + fdbuf (auto_fd&&, std::uint64_t pos = 0); // Before we invented auto_fd into fdstreams we keept fdbuf opened on // faulty close attempt. Now fdbuf is always closed by close() function. @@ -136,7 +143,7 @@ LIBBUTL_MODEXPORT namespace butl release (); void - open (auto_fd&&); + open (auto_fd&&, std::uint64_t pos = 0); bool is_open () const {return fd_.get () >= 0;} @@ -167,7 +174,7 @@ LIBBUTL_MODEXPORT namespace butl // Return the (logical) position of the next byte to be read. // - uint64_t + std::uint64_t tellg () const {return off_ - (egptr () - gptr ());} private: @@ -188,7 +195,7 @@ LIBBUTL_MODEXPORT namespace butl // Return the (logical) position of the next byte to be written. // - uint64_t + std::uint64_t tellp () const {return off_ + (pptr () - buf_);} private: @@ -197,7 +204,7 @@ LIBBUTL_MODEXPORT namespace butl private: auto_fd fd_; - uint64_t off_; + std::uint64_t off_; char buf_[8192]; bool non_blocking_ = false; }; @@ -251,7 +258,7 @@ LIBBUTL_MODEXPORT namespace butl binary = 0x40, // Set binary translation mode. at_end = 0x80, // Seek to the end of stream immediately after open. - none = 0 // Usefull when build the mode incrementally. + none = 0 // Usefull when building the mode incrementally. }; inline fdopen_mode operator& (fdopen_mode, fdopen_mode); @@ -263,8 +270,9 @@ LIBBUTL_MODEXPORT namespace butl { protected: fdstream_base () = default; - fdstream_base (auto_fd&& fd): buf_ (std::move (fd)) {} - fdstream_base (auto_fd&&, fdstream_mode); + fdstream_base (auto_fd&& fd, std::uint64_t pos) + : buf_ (std::move (fd), pos) {} + fdstream_base (auto_fd&&, fdstream_mode, std::uint64_t); public: int @@ -368,8 +376,14 @@ LIBBUTL_MODEXPORT namespace butl ifdstream (iostate e = badbit | failbit); explicit - ifdstream (auto_fd&&, iostate e = badbit | failbit); - ifdstream (auto_fd&&, fdstream_mode m, iostate e = badbit | failbit); + ifdstream (auto_fd&&, + iostate e = badbit | failbit, + std::uint64_t pos = 0); + + ifdstream (auto_fd&&, + fdstream_mode m, + iostate e = badbit | failbit, + std::uint64_t pos = 0); explicit ifdstream (const char*, @@ -419,12 +433,16 @@ LIBBUTL_MODEXPORT namespace butl open (const path&, fdopen_mode); void - open (auto_fd&& fd) {buf_.open (std::move (fd)); clear ();} + open (auto_fd&& fd, std::uint64_t pos = 0) + { + buf_.open (std::move (fd), pos); + clear (); + } void - open (auto_fd&& fd, fdstream_mode m) + open (auto_fd&& fd, fdstream_mode m, std::uint64_t pos = 0) { - open (std::move (fd)); + open (std::move (fd), pos); skip_ = (m & fdstream_mode::skip) == fdstream_mode::skip; } @@ -464,8 +482,14 @@ LIBBUTL_MODEXPORT namespace butl ofdstream (iostate e = badbit | failbit); explicit - ofdstream (auto_fd&&, iostate e = badbit | failbit); - ofdstream (auto_fd&&, fdstream_mode m, iostate e = badbit | failbit); + ofdstream (auto_fd&&, + iostate e = badbit | failbit, + std::uint64_t pos = 0); + + ofdstream (auto_fd&&, + fdstream_mode m, + iostate e = badbit | failbit, + std::uint64_t pos = 0); explicit ofdstream (const char*, @@ -515,7 +539,11 @@ LIBBUTL_MODEXPORT namespace butl open (const path&, fdopen_mode); void - open (auto_fd&& fd) {buf_.open (std::move (fd)); clear ();} + open (auto_fd&& fd, std::uint64_t pos = 0) + { + buf_.open (std::move (fd), pos); + clear (); + } void close () {if (is_open ()) flush (); buf_.close ();} auto_fd release (); @@ -709,6 +737,19 @@ LIBBUTL_MODEXPORT namespace butl LIBBUTL_SYMEXPORT fdpipe fdopen_pipe (fdopen_mode = fdopen_mode::none); + // Seeking. + // + enum class fdseek_mode {set, cur, end}; + + LIBBUTL_SYMEXPORT std::uint64_t + fdseek (int, std::uint64_t, fdseek_mode); + + // Truncate or expand the file to the specified size. Throw ios::failure on + // the underlying OS error. + // + LIBBUTL_SYMEXPORT void + fdtruncate (int, std::uint64_t); + // Test whether a file descriptor refers to a terminal. Throw ios::failure on // the underlying OS error. // -- cgit v1.1