5#include <cosmos/compiler.hxx>
6#include <cosmos/error/RuntimeError.hxx>
7#include <cosmos/fs/filesystem.hxx>
8#include <cosmos/fs/types.hxx>
9#include <cosmos/string.hxx>
12#include <clues/Engine.hxx>
13#include <clues/format.hxx>
14#include <clues/items/fs.hxx>
15#include <clues/macros.h>
16#include <clues/syscalls/fs.hxx>
17#include <clues/sysnrs/generic.hxx>
18#include <clues/Tracee.hxx>
20#include <clues/private/kernel/stat.hxx>
21#include <clues/private/kernel/dirent.hxx>
22#include <clues/private/utils.hxx>
24namespace clues::item {
27 if (m_at_semantics && m_fd == cosmos::FileNum::AT_CWD)
30 auto ret = std::to_string(cosmos::to_integral(m_fd));
33 ret += format::fd_info(*
m_info);
47 if (
auto it = map.find(m_fd); it != map.end()) {
65# define RESTORE_LARGEFILE
66# pragma push_macro("O_LARGEFILE")
68# define O_LARGEFILE 0100000
74 default: BITFLAGS_STREAM() <<
"O_???";
break;
75 case cosmos::OpenMode::READ_ONLY: BITFLAGS_STREAM() <<
"O_RDONLY";
break;
76 case cosmos::OpenMode::WRITE_ONLY: BITFLAGS_STREAM() <<
"O_WRONLY";
break;
77 case cosmos::OpenMode::READ_WRITE: BITFLAGS_STREAM() <<
"O_RDWR";
break;
80 BITFLAGS_STREAM() <<
'|';
82 BITFLAGS_ADD(O_APPEND);
83 BITFLAGS_ADD(O_ASYNC);
84 BITFLAGS_ADD(O_CLOEXEC);
85 BITFLAGS_ADD(O_CREAT);
86 BITFLAGS_ADD(O_DIRECT);
87 BITFLAGS_ADD(O_DIRECTORY);
88 BITFLAGS_ADD(O_DSYNC);
90 BITFLAGS_ADD(O_LARGEFILE);
91 BITFLAGS_ADD(O_NOATIME);
92 BITFLAGS_ADD(O_NOCTTY);
93 BITFLAGS_ADD(O_NOFOLLOW);
94 BITFLAGS_ADD(O_NONBLOCK);
97 BITFLAGS_ADD(O_TMPFILE);
98 BITFLAGS_ADD(O_TRUNC);
100 return BITFLAGS_STR();
101#ifdef RESTORE_LARGEFILE
102# pragma pop_macro("O_LARGEFILE")
109 m_mode = cosmos::OpenMode{raw & 0x3};
110 m_flags = cosmos::OpenFlags{raw & ~0x3};
114 BITFLAGS_FORMAT_START(m_flags);
116 BITFLAGS_ADD(AT_EMPTY_PATH);
117 BITFLAGS_ADD(AT_SYMLINK_NOFOLLOW);
118 BITFLAGS_ADD(AT_SYMLINK_FOLLOW);
123 if (
m_call->callNr() == SystemCallNr::UNLINKAT)
124 BITFLAGS_ADD(AT_REMOVEDIR);
125 if (
m_call->callNr() == SystemCallNr::FACCESSAT2)
126 BITFLAGS_ADD(AT_EACCESS);
127 if (
m_call->callNr() == SystemCallNr::FSTATAT64 ||
m_call->callNr() == SystemCallNr::NEWFSTATAT)
128 BITFLAGS_ADD(AT_NO_AUTOMOUNT);
130 return BITFLAGS_STR();
142 using cosmos::fs::AccessCheck;
144 std::stringstream ss;
146 if (m_checks.none()) {
149 if (m_checks[AccessCheck::READ_OK]) {
152 if (m_checks[AccessCheck::WRITE_OK]) {
155 if (m_checks[AccessCheck::EXEC_OK]) {
166 return strip_back(std::move(ret));
170 return format::file_mode_numeric(m_mode.mask()) +
171 " (" + m_mode.symbolic() +
")";
183 std::stringstream ss;
185 const auto st = *m_stat->raw();
186 using namespace std::string_literals;
192 <<
"ino=" << st.st_ino <<
", "
193 <<
"dev=" << format::device_id(m_stat->device()) <<
", "
194 <<
"mode=" << format::file_type(m_stat->type()) <<
"|" << format::file_mode_numeric(m_stat->mode().mask()) <<
", "
195 <<
"nlink=" << m_stat->numLinks() <<
", "
196 <<
"uid=" << st.st_uid <<
", "
197 <<
"gid=" << st.st_gid <<
", "
198 << (m_stat->type().isCharDev() || m_stat->type().isBlockDev() ?
"rdev="s + format::device_id(m_stat->representedDevice()) +
", " :
"")
199 <<
"size=" << st.st_size <<
", ";
205 ss <<
"blksize=" << st.st_blksize <<
", " <<
"blocks=" << st.st_blocks <<
", ";
209 <<
"atim=" << format::timespec(m_stat->accessTime(), is_old_stat) <<
", "
210 <<
"mtim=" << format::timespec(m_stat->modTime(), is_old_stat) <<
", "
211 <<
"ctim=" << format::timespec(m_stat->statusTime(), is_old_stat)
220 switch (
m_call->callNr()) {
221 case OLDSTAT: [[fallthrough]];
222 case OLDLSTAT: [[fallthrough]];
223 case OLDFSTAT:
return true;
224 default:
return false;
231 switch (
m_call->callNr()) {
232 case STAT64: [[fallthrough]];
233 case LSTAT64: [[fallthrough]];
234 case FSTAT64: [[fallthrough]];
235 case FSTATAT64:
return true;
236 default:
return false;
243 switch (
m_call->callNr()) {
244 case SystemCallNr::STAT: [[fallthrough]];
245 case SystemCallNr::LSTAT: [[fallthrough]];
246 case SystemCallNr::FSTAT:
return true;
247 default:
return false;
253 m_stat = std::make_optional<cosmos::FileStatus>();
256#if defined(COSMOS_X86_64) || defined(COSMOS_AARCH64)
263 static_assert(
sizeof(*m_stat->raw()) ==
sizeof(
stat64));
269 static_assert(
sizeof(*m_stat->raw()) ==
sizeof(
stat32_64));
272 auto fetch_and_copy = [
this, &proc]<
typename STAT>() {
279 auto &raw = *m_stat->raw();
285 raw.st_mode = st.mode;
286 raw.st_nlink = st.nlink;
289 raw.st_rdev = st.rdev;
290 raw.st_size = st.size;
292 if constexpr (std::is_same_v<STAT, old_kernel_stat>) {
294 raw.st_atim.tv_sec = st.atime;
295 raw.st_atim.tv_nsec = 0;
296 raw.st_mtim.tv_sec = st.mtime;
297 raw.st_mtim.tv_nsec = 0;
298 raw.st_ctim.tv_sec = st.ctime;
299 raw.st_ctim.tv_nsec = 0;
304 if constexpr (!std::is_same_v<STAT, old_kernel_stat>) {
305 raw.st_blksize = st.blksize;
306 raw.st_blocks = st.blocks;
307 raw.st_atim.tv_sec = st.atime;
308 raw.st_atim.tv_nsec = st.atime_nsec;
309 raw.st_mtim.tv_sec = st.mtime;
310 raw.st_mtim.tv_nsec = st.mtime_nsec;
311 raw.st_ctim.tv_sec = st.ctime;
312 raw.st_ctim.tv_nsec = st.ctime_nsec;
317 case ABI::X86_64: [[fallthrough]];
324 if (!proc.
readStruct(asPtr(), *m_stat->raw())) {
340 fetch_and_copy.operator()<
stat32>();
342 throw cosmos::RuntimeError{
"unexpected syscall nr for struct stat"};
345 }
default:
throw cosmos::RuntimeError{
"unexpected ABI for struct stat"};
349static std::string_view entry_type_label(
const cosmos::DirEntry::Type
type) {
350 switch (cosmos::to_integral(
type)) {
351 CASE_ENUM_TO_STR(DT_BLK);
352 CASE_ENUM_TO_STR(DT_CHR);
353 CASE_ENUM_TO_STR(DT_DIR);
354 CASE_ENUM_TO_STR(DT_FIFO);
355 CASE_ENUM_TO_STR(DT_LNK);
356 CASE_ENUM_TO_STR(DT_REG);
357 CASE_ENUM_TO_STR(DT_SOCK);
358 CASE_ENUM_TO_STR(DT_UNKNOWN);
359 default:
return "???";
364 std::stringstream ss;
365 auto result =
m_call->result();
369 }
else if (m_entries.empty()) {
372 ss << m_entries.size() <<
" entries: ";
376 for (
const auto &entry: m_entries) {
377 ss << comma <<
"{d_ino=" << entry.inode
378 <<
", d_off=" << entry.offset
379 <<
", d_reclen=" << offsetof(
struct linux_dirent, d_name) + entry.name.length() + 2
380 <<
", d_name=\"" << entry.name
381 <<
"\", d_type=" << entry_type_label(entry.type)
396 auto result =
m_call->result();
401 const auto bytes = result->valueAs<
size_t>();
409 m_buffer = std::unique_ptr<char[]>(
new char[bytes]);
412 if (
m_call->callNr() == SystemCallNr::GETDENTS64) {
415 if (
m_call->is32BitEmulationABI()) {
423template <
typename DIRENT>
426 DIRENT *cur =
nullptr;
428 constexpr auto NAME_OFFSET = offsetof(DIRENT, d_name);
430 while (pos < bytes) {
431 cur = (DIRENT*)(
m_buffer.get() + pos);
432 auto namelen = cur->d_reclen - NAME_OFFSET - 2;
438 for (
char *last = cur->d_name + namelen - 1; last > cur->d_name && *last ==
'\0'; last--, namelen--);
440 const auto type = *(
m_buffer.get() + pos + cur->d_reclen - 1);
442 m_entries.emplace_back(
Entry{
444 static_cast<int64_t
>(cur->d_off),
447 std::string_view{cur->d_name, namelen},
448 cosmos::DirEntry::Type{
static_cast<unsigned char>(type)}
450 pos += cur->d_reclen;
459 while (pos < bytes) {
461 auto namelen = cur->d_reclen - NAME_OFFSET;
465 for (
char *last = cur->d_name + namelen - 1; last > cur->d_name && *last ==
'\0'; last--, namelen--);
467 m_entries.emplace_back(
Entry{
470 std::string_view{cur->d_name, namelen},
471 cosmos::DirEntry::Type{
static_cast<unsigned char>(cur->d_type)}
474 pos += cur->d_reclen;
@ FD_INFO
print detailed file descriptor information
const SystemCall * m_call
The system call context this item part of.
bool isZero() const
Returns whether the parameter is set to 0 / NULL.
OTHER valueAs() const
Helper to cast the strongly typed Word m_val to other strong enum types.
Base class for traced processes.
bool readStruct(const ForeignPtr addr, T &out) const
Reads a system call struct from the tracee's address space into out.
const FDInfoMap & fdInfoMap() const
Provides access to the current knowledge about file descriptors in the tracee.
void readBlob(const ForeignPtr addr, char *buffer, const size_t bytes) const
Reads an arbitrary binary blob of fixed length from the tracee.
std::string str() const override
Returns a human readable string representation of the item.
void processValue(const Tracee &) override
Processes the value stored in m_val acc. to the actual item type.
void processValue(const Tracee &) override
Processes the value stored in m_val acc. to the actual item type.
std::string str() const override
Returns a human readable string representation of the item.
void parseEntries32(const size_t bytes)
Parses the dirent structures from m_buffer.
std::string str() const override
Returns a human readable string representation of the item.
void updateData(const Tracee &proc) override
Called upon exit of the system call to update possible out parameters.
std::unique_ptr< char[]> m_buffer
the raw buffer backing m_entries
void parseEntries64(const size_t bytes)
Parses the dirent structures for getdents64().
std::optional< FDInfo > m_info
filled if FormatFlag::FD_INFO is set.
std::string str() const override
Returns a human readable string representation of the item.
void processValue(const Tracee &) override
Processes the value stored in m_val acc. to the actual item type.
std::string str() const override
Returns a human readable string representation of the item.
std::string str() const override
Returns a human readable string representation of the item.
void processValue(const Tracee &) override
Processes the value stored in m_val acc. to the actual item type.
std::string str() const override
Returns a human readable string representation of the item.
bool isOldStat() const
Whether this is related to one of the OLDSTAT family of system calls.
bool isRegularStat() const
Whether this is related to one of the STAT family of system calls.
void updateData(const Tracee &proc) override
Called upon exit of the system call to update possible out parameters.
bool isStat64() const
Whether this is related to one of the STAT64 family of system calls.
@ X32
X86_64 with 32-bit pointers.
SystemCallNr
Abstract system call number usable across architectures and ABIs.
64-bit entries used with getdents64() on both 32-bit and 64-bit ABIs
32-bit getdents() directory entries.used on native 32-bit/64-bit ABIs.
Original Linux stat data structure for SystemCallNr::OLDSTAT, OLDLSTAT and OLDFSTAT.
64-bit sized stat data structure used with the stat64 family of system calls on 32-bit ABIs like i386...
32-bit sized stat data structure with some padding for SystemCallNR::STAT, LSTAT and FSTAT on 32-bit ...
The single stat structure from asm-generic used e.g. on AARCH64.