1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2024 FUJITSU LIMITED. All Rights Reserved.
4 * Author: Yang Xu <[email protected]>
5 */
6
7 /*\
8 * [Description]
9 *
10 * Verify that unlink(2) fails with
11 *
12 * - EPERM when target file is marked as immutable or append-only
13 * - EROFS when target file is on a read-only filesystem.
14 */
15
16 #include <sys/ioctl.h>
17 #include "tst_test.h"
18 #include "lapi/fs.h"
19
20 #define TEST_EPERM_IMMUTABLE "test_eperm_immutable"
21 #define TEST_EPERM_APPEND_ONLY "test_eperm_append_only"
22 #define DIR_EROFS "erofs"
23 #define TEST_EROFS "erofs/test_erofs"
24
25 static int fd_immutable;
26 static int fd_append_only;
27
28 static struct test_case_t {
29 char *filename;
30 int *fd;
31 int flag;
32 int expected_errno;
33 char *desc;
34 } tcases[] = {
35 {TEST_EPERM_IMMUTABLE, &fd_immutable, FS_IMMUTABLE_FL, EPERM,
36 "target file is immutable"},
37 {TEST_EPERM_APPEND_ONLY, &fd_append_only, FS_APPEND_FL, EPERM,
38 "target file is append-only"},
39 {TEST_EROFS, NULL, 0, EROFS, "target file in read-only filesystem"},
40 };
41
setup(void)42 static void setup(void)
43 {
44 int attr;
45
46 fd_immutable = SAFE_OPEN(TEST_EPERM_IMMUTABLE, O_CREAT, 0600);
47 SAFE_IOCTL(fd_immutable, FS_IOC_GETFLAGS, &attr);
48 attr |= FS_IMMUTABLE_FL;
49 SAFE_IOCTL(fd_immutable, FS_IOC_SETFLAGS, &attr);
50
51 fd_append_only = SAFE_OPEN(TEST_EPERM_APPEND_ONLY, O_CREAT, 0600);
52 SAFE_IOCTL(fd_append_only, FS_IOC_GETFLAGS, &attr);
53 attr |= FS_APPEND_FL;
54 SAFE_IOCTL(fd_append_only, FS_IOC_SETFLAGS, &attr);
55 }
56
cleanup(void)57 static void cleanup(void)
58 {
59 int attr;
60
61 SAFE_IOCTL(fd_immutable, FS_IOC_GETFLAGS, &attr);
62 attr &= ~FS_IMMUTABLE_FL;
63 SAFE_IOCTL(fd_immutable, FS_IOC_SETFLAGS, &attr);
64 SAFE_CLOSE(fd_immutable);
65
66 SAFE_IOCTL(fd_append_only, FS_IOC_GETFLAGS, &attr);
67 attr &= ~FS_APPEND_FL;
68 SAFE_IOCTL(fd_append_only, FS_IOC_SETFLAGS, &attr);
69 SAFE_CLOSE(fd_append_only);
70 }
71
verify_unlink(unsigned int i)72 static void verify_unlink(unsigned int i)
73 {
74 struct test_case_t *tc = &tcases[i];
75 int attr;
76
77 TST_EXP_FAIL(unlink(tc->filename), tc->expected_errno, "%s", tc->desc);
78
79 /* If unlink() succeeded unexpectedly, test file should be restored. */
80 if (!TST_RET) {
81 if (tc->fd) {
82 *(tc->fd) = SAFE_OPEN(tc->filename, O_CREAT, 0600);
83 if (tc->flag) {
84 SAFE_IOCTL(*(tc->fd), FS_IOC_GETFLAGS, &attr);
85 attr |= tc->flag;
86 SAFE_IOCTL(*(tc->fd), FS_IOC_SETFLAGS, &attr);
87 }
88 } else {
89 SAFE_TOUCH(tc->filename, 0600, 0);
90 }
91 }
92 }
93
94 static struct tst_test test = {
95 .setup = setup,
96 .tcnt = ARRAY_SIZE(tcases),
97 .cleanup = cleanup,
98 .test = verify_unlink,
99 .needs_rofs = 1,
100 .mntpoint = DIR_EROFS,
101 .needs_root = 1,
102 };
103