summaryrefslogtreecommitdiffstats
path: root/src/test/test-fs-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-11-18 15:11:43 +0100
committerLennart Poettering <lennart@poettering.net>2020-12-02 10:32:17 +0100
commit1098142436f46b889f6b7bcc87af54bc5b95d560 (patch)
treeb1a21013091eddad2aee5bc9c4fb3e8bc104d803 /src/test/test-fs-util.c
parentcopy: teach copy_file() that a mode=-1 call means "take mode from original file" (diff)
downloadsystemd-1098142436f46b889f6b7bcc87af54bc5b95d560.tar.xz
systemd-1098142436f46b889f6b7bcc87af54bc5b95d560.zip
fs-util: add conservative_rename() that suppresses unnecessary renames
if the source and destination file match in contents and basic file attributes, don#t rename, but just remove source. This is a simple way to suppress inotify events + mtime changes when atomically updating files.
Diffstat (limited to 'src/test/test-fs-util.c')
-rw-r--r--src/test/test-fs-util.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index d1f9252521..e0ef8257bd 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -3,7 +3,9 @@
#include <unistd.h>
#include "alloc-util.h"
+#include "copy.h"
#include "fd-util.h"
+#include "fileio.h"
#include "fs-util.h"
#include "id128-util.h"
#include "macro.h"
@@ -834,6 +836,51 @@ static void test_path_is_encrypted(void) {
test_path_is_encrypted_one("/dev", booted > 0 ? false : -1);
}
+static void test_conservative_rename(void) {
+ _cleanup_(unlink_and_freep) char *p = NULL;
+ _cleanup_free_ char *q = NULL;
+
+ assert_se(tempfn_random_child(NULL, NULL, &p) >= 0);
+ assert_se(write_string_file(p, "this is a test", WRITE_STRING_FILE_CREATE) >= 0);
+
+ assert_se(tempfn_random_child(NULL, NULL, &q) >= 0);
+
+ /* Check that the hardlinked "copy" is detected */
+ assert_se(link(p, q) >= 0);
+ assert_se(conservative_rename(AT_FDCWD, q, AT_FDCWD, p) == 0);
+ assert_se(access(q, F_OK) < 0 && errno == ENOENT);
+
+ /* Check that a manual copy is detected */
+ assert_se(copy_file(p, q, 0, (mode_t) -1, 0, 0, COPY_REFLINK) >= 0);
+ assert_se(conservative_rename(AT_FDCWD, q, AT_FDCWD, p) == 0);
+ assert_se(access(q, F_OK) < 0 && errno == ENOENT);
+
+ /* Check that a manual new writeout is also detected */
+ assert_se(write_string_file(q, "this is a test", WRITE_STRING_FILE_CREATE) >= 0);
+ assert_se(conservative_rename(AT_FDCWD, q, AT_FDCWD, p) == 0);
+ assert_se(access(q, F_OK) < 0 && errno == ENOENT);
+
+ /* Check that a minimally changed version is detected */
+ assert_se(write_string_file(q, "this is a_test", WRITE_STRING_FILE_CREATE) >= 0);
+ assert_se(conservative_rename(AT_FDCWD, q, AT_FDCWD, p) > 0);
+ assert_se(access(q, F_OK) < 0 && errno == ENOENT);
+
+ /* Check that this really is new updated version */
+ assert_se(write_string_file(q, "this is a_test", WRITE_STRING_FILE_CREATE) >= 0);
+ assert_se(conservative_rename(AT_FDCWD, q, AT_FDCWD, p) == 0);
+ assert_se(access(q, F_OK) < 0 && errno == ENOENT);
+
+ /* Make sure we detect extended files */
+ assert_se(write_string_file(q, "this is a_testx", WRITE_STRING_FILE_CREATE) >= 0);
+ assert_se(conservative_rename(AT_FDCWD, q, AT_FDCWD, p) > 0);
+ assert_se(access(q, F_OK) < 0 && errno == ENOENT);
+
+ /* Make sure we detect truncated files */
+ assert_se(write_string_file(q, "this is a_test", WRITE_STRING_FILE_CREATE) >= 0);
+ assert_se(conservative_rename(AT_FDCWD, q, AT_FDCWD, p) > 0);
+ assert_se(access(q, F_OK) < 0 && errno == ENOENT);
+}
+
int main(int argc, char *argv[]) {
test_setup_logging(LOG_INFO);
@@ -852,6 +899,7 @@ int main(int argc, char *argv[]) {
test_rename_noreplace();
test_chmod_and_chown();
test_path_is_encrypted();
+ test_conservative_rename();
return 0;
}