diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d3abdc..5cf540d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ add_subdirectory(cruft/crypto) ############################################################################### -foreach (t analyse compare) +foreach (t analyse compare stat) add_executable ("${t}" "tools/${t}.cpp") target_link_libraries("${t}" cruft-crypto cruft-util) endforeach() diff --git a/cruft/util b/cruft/util index cc9b9b1..174bd62 160000 --- a/cruft/util +++ b/cruft/util @@ -1 +1 @@ -Subproject commit cc9b9b19c1a9a7002248d7f62053d49002a8b297 +Subproject commit 174bd62a293d3e15dc4fdc3112dea21443fc1d90 diff --git a/tools/stat.cpp b/tools/stat.cpp new file mode 100644 index 0000000..0733543 --- /dev/null +++ b/tools/stat.cpp @@ -0,0 +1,149 @@ +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + + +constexpr unsigned type_index (mode_t val) +{ + return (val & S_IFMT) >> cruft::ctz (unsigned {S_IFMT}); +} + + +struct type_printer { + type_printer (struct stat const &_data) + : data (_data) + { ; } + + struct stat const &data; +}; + +std::ostream& operator<< (std::ostream &os, type_printer const &val) +{ + os << "[ "; + if (val.data.st_mode & S_ISUID) os << "SUID, "; + if (val.data.st_mode & S_ISGID) os << "SGID, "; + if (val.data.st_mode & S_ISVTX) os << "STICKY, "; + + os << "{ user: " << (val.data.st_mode & S_IRUSR ? 'r' : '_') + << (val.data.st_mode & S_IWUSR ? 'w' : '_') + << (val.data.st_mode & S_IXUSR ? 'x' : '_') + << " }, " + << "{ group: " << (val.data.st_mode & S_IRGRP ? 'r' : '_') + << (val.data.st_mode & S_IWGRP ? 'w' : '_') + << (val.data.st_mode & S_IXGRP ? 'x' : '_') + << " }, " + << "{ group: " << (val.data.st_mode & S_IROTH ? 'r' : '_') + << (val.data.st_mode & S_IWOTH ? 'w' : '_') + << (val.data.st_mode & S_IXOTH ? 'x' : '_') + << " }"; + + return os; +} + + +struct mode_printer { + mode_printer (struct stat const &_data) + : data (_data) + { ; } + + struct stat const &data; +}; + + +std::ostream& operator<< (std::ostream &os, mode_printer const &val) +{ + return S_ISREG (val.data.st_mode) ? os << "REGULAR" + : S_ISDIR (val.data.st_mode) ? os << "DIRECTORY" + : S_ISCHR (val.data.st_mode) ? os << "CHARACTER" + : S_ISBLK (val.data.st_mode) ? os << "BLOCK" + : S_ISFIFO (val.data.st_mode) ? os << "FIFO" + : S_ISLNK (val.data.st_mode) ? os << "SYMLINK" + : S_ISSOCK (val.data.st_mode) ? os << "SOCKET" + : (throw std::invalid_argument ("Unhandled mode_t"), os << "_error"); +} + + +std::ostream& operator<< (std::ostream &os, struct stat const &val) +{ + return os << "{ dev: " << val.st_dev + << ", ino: " << val.st_ino + << ", type: " << type_printer (val) + << ", mode: " << mode_printer (val) + << ", uid: " << val.st_uid + << ", gid: " << val.st_gid + << ", size: " << val.st_size + << ", blocksize: " << val.st_blksize + << " }"; +} + + +int main (int argc, char **argv) +{ + if (argc < 2) { + std::cerr << argv[0] << " ...\n"; + return EXIT_FAILURE; + } + + for (int i = 1; i < argc; ++i) { + std::cout << "{ stat: "; + + char const *path = argv[i]; + + { + struct stat buffer; + cruft::posix::error::try_call (stat, path, &buffer); + std::cout << buffer; + } + + std::cout << ", xattr: "; + + { + std::cout << "{ "; + + std::string attr_list (1024, '\0'); + { + auto res = listxattr (path, attr_list.data (), attr_list.size ()); + if (res < 0) + cruft::posix::error::throw_code (); + attr_list.resize (res); + } + + std::string keybuffer (64, '\0'); + std::string val (128, '\0'); + cruft::view attr_view { attr_list.data (), attr_list.size () }; + for (auto const &key: cruft::tokeniser (attr_view, '\0')) { + keybuffer.resize (0); + std::copy (std::begin (key), std::end (key), std::back_inserter (keybuffer)); + + while (true) { + auto const res = getxattr (path, keybuffer.c_str (), val.data (), val.size ()); + if (res == E2BIG) { + val.resize (val.size () * 2); + continue; + } + + if (res < 0) + cruft::posix::error::throw_code (); + + val.resize (res); + break; + } + + std::cout << keybuffer << ": " << val << ", "; + } + + std::cout << "}"; + } + + std::cout << '\n'; + } +} \ No newline at end of file