⛏️ index : haiku.git

/*
 * Copyright 2025, Haiku Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 */


#include <sys/stat.h>

#include <NodeMonitor.h>

#include "Context.h"
#include "MemoryReader.h"
#include "strace.h"
#include "Syscall.h"
#include "TypeHandler.h"
#include "util.h"


static string
format_mode(Context &context, mode_t mode)
{
	if (context.GetContents(Context::ENUMERATIONS)) {
#define MODE_TYPE(mode) \
		case mode: \
			return #mode

		switch (mode) {
			MODE_TYPE(S_IFSOCK);
			MODE_TYPE(S_IFLNK);
			MODE_TYPE(S_IFREG);
			MODE_TYPE(S_IFBLK);
			MODE_TYPE(S_IFDIR);
			MODE_TYPE(S_IFIFO);
			MODE_TYPE(S_IFCHR);
		}
	}

	return context.FormatSigned(mode);
}


static string
read_stat(Context &context, Parameter *param, void *data)
{
	int statMask = 0xffffffff;
	if (param->Out()) {
		if ((status_t)context.GetReturnValue() < 0)
			return "";
	} else {
		Parameter* nextParam = context.GetNextSibling(param);
		if (nextParam != NULL) {
			nextParam = context.GetNextSibling(nextParam);
			if (nextParam != NULL && nextParam->Name() == "statMask")
				statMask = context.ReadValue<int>(nextParam);
		}
	}

	struct stat s;
	int32 bytesRead;

	status_t err = context.Reader().Read(data, &s, sizeof(s), bytesRead);
	if (err != B_OK)
		return context.FormatPointer(data);

	string r;
	if ((statMask & 0xffffffff) == 0xffffffff) {
		char mode[12];
		r += ", st_dev = " + format_unsigned(s.st_dev);
		r += ", st_ino = " + format_unsigned(s.st_ino);
		snprintf(mode, sizeof(mode), "%03" B_PRIo32,
			(uint32)(s.st_mode & ~(S_IFMT | S_ISUID | S_ISGID | S_ISVTX)));
		r += ", st_mode = " + format_mode(context, s.st_mode & S_IFMT) + "|";
		r += mode;
		r += ", st_nlink = " + format_unsigned(s.st_nlink);
	}
	if ((statMask & B_STAT_UID) != 0)
		r += ", st_uid = " + format_unsigned(s.st_uid);
	if ((statMask & B_STAT_GID) != 0)
		r += ", st_gid = " + format_unsigned(s.st_gid);
	if ((statMask & B_STAT_SIZE) != 0)
		r += ", st_size = " + format_unsigned64(s.st_size);
	if ((statMask & 0xffffffff) == 0xffffffff)
		r += ", st_blksize = " + format_unsigned(s.st_blksize);
	if ((statMask & B_STAT_ACCESS_TIME) != 0)
		r += ", st_atim = " + format_timespec(context, s.st_atim);
	if ((statMask & B_STAT_MODIFICATION_TIME) != 0)
		r += ", st_mtim = " + format_timespec(context, s.st_mtim);
	if ((statMask & B_STAT_CHANGE_TIME) != 0)
		r += ", st_ctim = " + format_timespec(context, s.st_ctim);
	if ((statMask & B_STAT_CREATION_TIME) != 0)
		r += ", st_crtim = " + format_timespec(context, s.st_crtim);
	if ((statMask & 0xffffffff) == 0xffffffff) {
		r += ", st_type = " + format_unsigned(s.st_type);
		r += ", st_blocks = " + format_unsigned(s.st_blocks);
	}
	return "{" + r.substr(2) + "}";
}


template<>
string
TypeHandlerImpl<struct stat *>::GetParameterValue(Context &context, Parameter *param,
	const void *address)
{
	void *data = *(void **)address;
	if (data != NULL && context.GetContents(Context::SIMPLE_STRUCTS))
		return read_stat(context, param, data);
	return context.FormatPointer(data);
}


template<>
string
TypeHandlerImpl<struct stat *>::GetReturnValue(Context &context, uint64 value)
{
	return context.FormatPointer((void *)value);
}


DEFINE_TYPE(stat_ptr, struct stat*);


void
patch_file()
{
	Syscall *readStat = get_syscall("_kern_read_stat");
	readStat->GetParameter("stat")->SetOut(true);
	Syscall *readIndexStat = get_syscall("_kern_read_index_stat");
	readIndexStat->GetParameter("stat")->SetOut(true);
}