coreutils / tests /chmod /tests_for_mode_changed.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
// The function under test is static in this translation unit and thus directly callable:
// static bool mode_changed (int dir_fd, char const *file, char const *file_full_name,
// mode_t old_mode, mode_t new_mode);
// Access the existing file-scope static 'force_silent' defined in the program source.
extern bool force_silent; // The variable is defined above in the same translation unit.
// Helpers
static mode_t get_mode(const char *path) {
struct stat st;
TEST_ASSERT_EQUAL_INT_MESSAGE(0, stat(path, &st), "stat on temp file failed");
return st.st_mode;
}
static void make_temp_path(char *buf, size_t buflen) {
// Create a unique template in /tmp
snprintf(buf, buflen, "/tmp/chmod_mode_changed_%ld_XXXXXX", (long)getpid());
}
static void create_temp_file(char *path_buf, size_t buflen) {
make_temp_path(path_buf, buflen);
int fd = mkstemp(path_buf);
TEST_ASSERT_MESSAGE(fd >= 0, "mkstemp failed");
// Close immediately; we only need the file to exist for stat/chmod
close(fd);
}
static void remove_temp_file(const char *path) {
// Best-effort cleanup
unlink(path);
}
void setUp(void) {
/* Setup code here, or leave empty */
}
void tearDown(void) {
/* Cleanup code here, or leave empty */
}
// 1) No special bits, no change => expect false
void test_mode_changed_no_special_no_change(void) {
char path[256];
create_temp_file(path, sizeof(path));
mode_t old_mode = get_mode(path);
mode_t new_mode = old_mode; // No change, and no special bits added
bool changed = mode_changed(AT_FDCWD, path, path, old_mode, new_mode);
TEST_ASSERT_FALSE(changed);
remove_temp_file(path);
}
// 2) No special bits, with a permission bit change => expect true
void test_mode_changed_no_special_with_change(void) {
char path[256];
create_temp_file(path, sizeof(path));
mode_t old_mode = get_mode(path);
// Flip owner execute bit (does not include suid/sgid/sticky)
mode_t new_mode = old_mode ^ S_IXUSR;
bool changed = mode_changed(AT_FDCWD, path, path, old_mode, new_mode);
TEST_ASSERT_TRUE(changed);
remove_temp_file(path);
}
// 3) Special bits present; fstatat fails (nonexistent file) => expect false
void test_mode_changed_special_fstatat_failure(void) {
// Suppress error diagnostics from the function for this test
bool prev_silent = force_silent;
force_silent = true;
const char *missing = "/this/path/does/not/exist/___definitely___";
mode_t old_mode = 0;
// Set a special bit to trigger the fstatat path
mode_t new_mode = old_mode | S_ISUID;
bool changed = mode_changed(AT_FDCWD, missing, missing, old_mode, new_mode);
TEST_ASSERT_FALSE(changed);
force_silent = prev_silent;
}
// 4) Special bits present; fstatat succeeds; no actual change to file => expect false
void test_mode_changed_special_no_actual_change(void) {
char path[256];
create_temp_file(path, sizeof(path));
mode_t old_mode = get_mode(path);
// Trigger special-bit path; function will use fstatat to get actual (unchanged) mode
mode_t new_mode = old_mode | S_ISUID;
bool changed = mode_changed(AT_FDCWD, path, path, old_mode, new_mode);
TEST_ASSERT_FALSE(changed);
remove_temp_file(path);
}
// 5) Special bits present; fstatat succeeds; actual mode changed via chmod => expect true
void test_mode_changed_special_actual_change(void) {
char path[256];
create_temp_file(path, sizeof(path));
mode_t old_mode = get_mode(path);
// Change a permission bit on the actual file (mask to permissions only for chmod)
mode_t changed_perm = (old_mode ^ S_IXUSR) & 07777;
int rc = chmod(path, changed_perm);
TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, "chmod to alter file mode failed");
// Trigger special-bit path; function will pick up the actual new mode from stat
mode_t new_mode_param = old_mode | S_ISUID;
bool changed = mode_changed(AT_FDCWD, path, path, old_mode, new_mode_param);
TEST_ASSERT_TRUE(changed);
// Restore original perms (best effort)
chmod(path, old_mode & 07777);
remove_temp_file(path);
}
// 6) No special bits, difference only in file type bits should be ignored => expect false
void test_mode_changed_ignores_file_type_bits(void) {
// Craft synthetic modes: permission bits equal, file type bits different.
mode_t old_mode = S_IFREG | 0644;
mode_t new_mode = S_IFDIR | 0644; // Different type, same perms; no special bits
bool changed = mode_changed(AT_FDCWD, "unused", "unused", old_mode, new_mode);
TEST_ASSERT_FALSE(changed);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_mode_changed_no_special_no_change);
RUN_TEST(test_mode_changed_no_special_with_change);
RUN_TEST(test_mode_changed_special_fstatat_failure);
RUN_TEST(test_mode_changed_special_no_actual_change);
RUN_TEST(test_mode_changed_special_actual_change);
RUN_TEST(test_mode_changed_ignores_file_type_bits);
return UNITY_END();
}