From: Lennart Poettering Date: Tue, 28 Apr 2020 16:16:25 +0000 (+0200) Subject: stat-util: add stat_inode_unmodified() helper that checks if an inode was modified X-Git-Tag: v246-rc1~348^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fee5c52ac260d021466c1062499f0ebd5241db5f;p=thirdparty%2Fsystemd.git stat-util: add stat_inode_unmodified() helper that checks if an inode was modified --- diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 1f3de56cf92..e4e4d8f0762 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -388,3 +388,24 @@ int proc_mounted(void) { return r; } + +bool stat_inode_unmodified(const struct stat *a, const struct stat *b) { + + /* Returns if the specified stat structures reference the same, unmodified inode. This check tries to + * be reasonably careful when detecting changes: we check both inode and mtime, to cater for file + * systems where mtimes are fixed to 0 (think: ostree/nixos type installations). We also check file + * size, backing device, inode type and if this refers to a device not the major/minor. + * + * Note that we don't care if file attributes such as ownership or access mode change, this here is + * about contents of the file. The purpose here is to detect file contents changes, and nothing + * else. */ + + return a && b && + (a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */ + ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 && /* same inode type */ + a->st_mtime == b->st_mtime && + (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */ + a->st_dev == b->st_dev && + a->st_ino == b->st_ino && + (!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */ +} diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index 81607483121..59aedcb7c4d 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -89,3 +89,5 @@ int device_path_make_canonical(mode_t mode, dev_t devno, char **ret); int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno); int proc_mounted(void); + +bool stat_inode_unmodified(const struct stat *a, const struct stat *b);