From e283b08481cfec9aa55b3ddbf369d632c7aa7b0f Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 18 Mar 2021 15:53:49 +0200 Subject: Add fdstat() --- libbutl/fdstream.cxx | 67 ++++++++++++++++++++++++++++++++++++++++++++------ libbutl/fdstream.mxx | 12 +++++++-- libbutl/filesystem.cxx | 7 +++--- libbutl/filesystem.mxx | 2 ++ tests/lz4/driver.cxx | 6 +---- 5 files changed, 76 insertions(+), 18 deletions(-) diff --git a/libbutl/fdstream.cxx b/libbutl/fdstream.cxx index 4948052..308d76c 100644 --- a/libbutl/fdstream.cxx +++ b/libbutl/fdstream.cxx @@ -12,20 +12,27 @@ # include // close(), read(), write(), lseek(), dup(), pipe(), // ftruncate(), isatty(), ssize_t, STD*_FILENO # include // writev(), iovec -# include // stat(), S_I* +# include // stat(), fstat(), S_I* # include // timeval # include // stat, off_t # include #else # include -# include // _close(), _read(), _write(), _setmode(), _sopen(), - // _lseek(), _dup(), _pipe(), _chsize_s, - // _get_osfhandle() -# include // _SH_DENYNO -# include // _fileno(), stdin, stdout, stderr, SEEK_* -# include // _O_* -# include // S_I* +# include // _close(), _read(), _write(), _setmode(), _sopen(), + // _lseek(), _dup(), _pipe(), _chsize_s, + // _get_osfhandle() +# include // _SH_DENYNO +# include // _fileno(), stdin, stdout, stderr, SEEK_* +# include // _O_* +# include // _stat +# include // fstat(), S_I* + +# ifdef _MSC_VER // Unlikely to be fixed in newer versions. +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +# endif # include // wcsncmp(), wcsstr() @@ -1372,6 +1379,28 @@ namespace butl throw_generic_ios_failure (errno); } + entry_stat + fdstat (int fd) + { + struct stat s; + if (fstat (fd, &s) != 0) + throw_generic_error (errno); + + auto m (s.st_mode); + entry_type t (entry_type::unknown); + + // Note: cannot be a symlink. + // + if (S_ISREG (m)) + t = entry_type::regular; + else if (S_ISDIR (m)) + t = entry_type::directory; + else if (S_ISBLK (m) || S_ISCHR (m) || S_ISFIFO (m) || S_ISSOCK (m)) + t = entry_type::other; + + return entry_stat {t, static_cast (s.st_size)}; + } + bool fdterm (int fd) { @@ -1779,6 +1808,28 @@ namespace butl throw_generic_ios_failure (e); } + entry_stat + fdstat (int fd) + { + // Since symlinks have been taken care of, we can just _fstat(). + // + struct __stat64 s; + if (_fstat64 (fd, &s) != 0) + throw_generic_error (errno); + + auto m (s.st_mode); + entry_type t (entry_type::unknown); + + if (S_ISREG (m)) + t = entry_type::regular; + else if (S_ISDIR (m)) + t = entry_type::directory; + else if (S_ISCHR (m)) + t = entry_type::other; + + return entry_stat {t, static_cast (s.st_size)}; + } + bool fdterm (int fd) { diff --git a/libbutl/fdstream.mxx b/libbutl/fdstream.mxx index c863d2c..9818732 100644 --- a/libbutl/fdstream.mxx +++ b/libbutl/fdstream.mxx @@ -30,7 +30,7 @@ import std.core; import std.io; #endif import butl.path; -import butl.filesystem; // permissions +import butl.filesystem; // permissions, entry_stat import butl.small_vector; #else #include @@ -862,9 +862,17 @@ LIBBUTL_MODEXPORT namespace butl LIBBUTL_SYMEXPORT void fdtruncate (int, std::uint64_t); - // Test whether a file descriptor refers to a terminal. Throw ios::failure on + // Return filesystem entry stat from file descriptor. Throw ios::failure on // the underlying OS error. // + // See also path_entry() in filesystem. + // + LIBBUTL_SYMEXPORT entry_stat + fdstat (int); + + // Test whether a file descriptor refers to a terminal. Throw ios::failure + // on the underlying OS error. + // LIBBUTL_SYMEXPORT bool fdterm (int); diff --git a/libbutl/filesystem.cxx b/libbutl/filesystem.cxx index 2147c6f..787747d 100644 --- a/libbutl/filesystem.cxx +++ b/libbutl/filesystem.cxx @@ -24,13 +24,14 @@ # include // _stat # include // _stat(), S_I* -# include // mbsrtowcs(), wcsrtombs(), mbstate_t -# include // strncmp() - # ifdef _MSC_VER // Unlikely to be fixed in newer versions. # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) # endif + +# include // mbsrtowcs(), wcsrtombs(), mbstate_t +# include // strncmp() #endif #include diff --git a/libbutl/filesystem.mxx b/libbutl/filesystem.mxx index 7506439..eb03ab2 100644 --- a/libbutl/filesystem.mxx +++ b/libbutl/filesystem.mxx @@ -125,6 +125,8 @@ LIBBUTL_MODEXPORT namespace butl // std::system_error, unless ignore_error is true (in which case erroneous // entries are treated as non-existent). // + // See also fdstat() in fdstream. + // LIBBUTL_SYMEXPORT std::pair path_entry (const char*, bool follow_symlinks = false, diff --git a/tests/lz4/driver.cxx b/tests/lz4/driver.cxx index e3da5e6..e2fd537 100644 --- a/tests/lz4/driver.cxx +++ b/tests/lz4/driver.cxx @@ -24,14 +24,10 @@ try if (argv[1][1] == 'c') { - // @@ TODO: would be nice to get it from fd. - // - entry_stat st (path_entry (argv[2], true /* follow_symlinks */).second); - lz4::compress (ofs, ifs, 1 /* compression_level */, 4 /* block_size_id (64KB) */, - st.size); + fdstat (ifs.fd ()).size); } else { -- cgit v1.1