stat-util: introduce inode_unmodified_hash_ops

This is almost the same as inode_hash_ops, but also hashes + compares
all attributes that could affect the contents of a file. It ignores
"superficial"/"external" attributes such as ownership or access mode
however.
This commit is contained in:
Lennart Poettering
2026-03-24 17:06:09 +01:00
parent cf6f65c5ea
commit 172ae47e65
2 changed files with 59 additions and 0 deletions

View File

@@ -731,6 +731,59 @@ int inode_compare_func(const struct stat *a, const struct stat *b) {
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_hash_ops, struct stat, inode_hash_func, inode_compare_func, free);
void inode_unmodified_hash_func(const struct stat *q, struct siphash *state) {
inode_hash_func(q, state);
siphash24_compress_typesafe(q->st_mtim.tv_sec, state);
siphash24_compress_typesafe(q->st_mtim.tv_nsec, state);
if (S_ISREG(q->st_mode))
siphash24_compress_typesafe(q->st_size, state);
else {
uint64_t invalid = UINT64_MAX;
siphash24_compress_typesafe(invalid, state);
}
if (S_ISCHR(q->st_mode) || S_ISBLK(q->st_mode))
siphash24_compress_typesafe(q->st_rdev, state);
else {
dev_t invalid = (dev_t) -1;
siphash24_compress_typesafe(invalid, state);
}
}
int inode_unmodified_compare_func(const struct stat *a, const struct stat *b) {
int r;
r = inode_compare_func(a, b);
if (r != 0)
return r;
r = CMP(a->st_mtim.tv_sec, b->st_mtim.tv_sec);
if (r != 0)
return r;
r = CMP(a->st_mtim.tv_nsec, b->st_mtim.tv_nsec);
if (r != 0)
return r;
if (S_ISREG(a->st_mode)) {
r = CMP(a->st_size, b->st_size);
if (r != 0)
return r;
}
if (S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) {
r = CMP(a->st_rdev, b->st_rdev);
if (r != 0)
return r;
}
return 0;
}
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_unmodified_hash_ops, struct stat, inode_unmodified_hash_func, inode_unmodified_compare_func, free);
const char* inode_type_to_string(mode_t m) {
/* Returns a short string for the inode type. We use the same name as the underlying macros for each

View File

@@ -127,6 +127,12 @@ void inode_hash_func(const struct stat *q, struct siphash *state);
int inode_compare_func(const struct stat *a, const struct stat *b);
extern const struct hash_ops inode_hash_ops;
/* This is a more thorough version of the above, and also checks the mtimes, the size, and the rdev. It does
* not check "external" attributes such as access mode or ownership. */
void inode_unmodified_hash_func(const struct stat *q, struct siphash *state);
int inode_unmodified_compare_func(const struct stat *a, const struct stat *b);
extern const struct hash_ops inode_unmodified_hash_ops;
DECLARE_STRING_TABLE_LOOKUP(inode_type, mode_t);
/* Macros that check whether the stat/statx structures have been initialized already. For "struct stat" we