* Copyright (C) 2024 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
*/
* This test verifies that fchmodat2() syscall is properly working with
* regular files, symbolic links and directories. AT_SYMLINK_NOFOLLOW is a
* special feature that is blocked by VFS since 5d1f903f75a8 and any of its
* usage on symlinks will raise EOPNOTSUPP.
*/
#define _GNU_SOURCE
#include "tst_test.h"
#include "tst_safe_file_at.h"
#include "lapi/fcntl.h"
#include "lapi/stat.h"
#define MNTPOINT "mntpoint"
#define FNAME "myfile"
#define SNAME "symlink"
#define DNAME "mydir"
#define DNAME_PATH MNTPOINT"/"DNAME
static int fd_dir = -1;
static void verify_mode(int dirfd, const char *path, mode_t mode)
{
struct stat st;
SAFE_FSTATAT(dirfd, path, &st, AT_SYMLINK_NOFOLLOW);
TST_EXP_EQ_LI(st.st_mode, mode);
}
static void test_regular_file(void)
{
tst_res(TINFO, "Using regular files");
SAFE_CHMOD(MNTPOINT"/"FNAME, 0640);
SAFE_FCHMODAT2(fd_dir, FNAME, 0700, 0);
verify_mode(fd_dir, FNAME, S_IFREG | 0700);
SAFE_FCHMODAT2(fd_dir, FNAME, 0700, AT_SYMLINK_NOFOLLOW);
verify_mode(fd_dir, FNAME, S_IFREG | 0700);
}
static void test_symbolic_link(void)
{
tst_res(TINFO, "Using symbolic link");
SAFE_FCHMODAT2(fd_dir, SNAME, 0700, 0);
verify_mode(fd_dir, FNAME, S_IFREG | 0700);
verify_mode(fd_dir, SNAME, S_IFLNK | 0777);
TST_EXP_FAIL(tst_syscall(__NR_fchmodat2,
fd_dir, SNAME, 0640, AT_SYMLINK_NOFOLLOW),
EOPNOTSUPP);
}
static void test_empty_folder(void)
{
tst_res(TINFO, "Using empty folder");
int fd;
SAFE_CHMOD(DNAME_PATH, 0640);
fd = SAFE_OPEN(DNAME_PATH, O_PATH | O_DIRECTORY, 0640);
SAFE_FCHMODAT2(fd, "", 0777, AT_EMPTY_PATH);
verify_mode(fd_dir, DNAME, S_IFDIR | 0777);
SAFE_CLOSE(fd);
}
static void run(void)
{
test_regular_file();
test_empty_folder();
test_symbolic_link();
}
static void setup(void)
{
fd_dir = SAFE_OPEN(MNTPOINT, O_PATH | O_DIRECTORY, 0640);
if (access(DNAME_PATH, F_OK) == -1)
SAFE_MKDIR(DNAME_PATH, 0640);
SAFE_TOUCH(MNTPOINT"/"FNAME, 0640, NULL);
SAFE_SYMLINKAT(FNAME, fd_dir, SNAME);
}
static void cleanup(void)
{
SAFE_UNLINKAT(fd_dir, SNAME, 0);
SAFE_RMDIR(DNAME_PATH);
if (fd_dir != -1)
SAFE_CLOSE(fd_dir);
}
static struct tst_test test = {
.timeout = 9,
.test_all = run,
.setup = setup,
.cleanup = cleanup,
.needs_root = 1,
.mntpoint = MNTPOINT,
.format_device = 1,
.all_filesystems = 1,
.tags = (const struct tst_tag[]) {
{"linux-git", "5d1f903f75a8"},
{}
}
};