aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-11-24 14:44:21 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-11-24 14:44:21 +0200
commit90fbede55256cb672a67d8181b4f0435047d4e13 (patch)
tree912917cdd3034d906b8e026153e901405d9a8227
parent582940c789fd767d9e8c09cb4147d48b596261be (diff)
Add fdtruncate(), fdseek(), file position to [io]fdstream ctors
-rw-r--r--libbutl/fdstream.cxx66
-rw-r--r--libbutl/fdstream.ixx23
-rw-r--r--libbutl/fdstream.mxx79
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 <fcntl.h> // open(), O_*, fcntl()
# include <unistd.h> // close(), read(), write(), lseek(), dup(), pipe(),
- // isatty(), ssize_t, STD*_FILENO
+ // ftruncate(), isatty(), ssize_t, STD*_FILENO
# include <sys/uio.h> // writev(), iovec
# include <sys/stat.h> // stat(), S_I*
# include <sys/types.h> // stat, off_t
@@ -19,9 +19,10 @@
# include <libbutl/win32-utility.hxx>
# include <io.h> // _close(), _read(), _write(), _setmode(), _sopen(),
- // _lseek(), _dup(), _pipe(), _get_osfhandle()
+ // _lseek(), _dup(), _pipe(), _chsize_s,
+ // _get_osfhandle()
# include <share.h> // _SH_DENYNO
-# include <stdio.h> // _fileno(), stdin, stdout, stderr
+# include <stdio.h> // _fileno(), stdin, stdout, stderr, SEEK_*
# include <fcntl.h> // _O_*
# include <sys/stat.h> // 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<off_t> (o), m));
+ if (r == static_cast<off_t> (-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<uint64_t> (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<off_t> (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.
//