1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2021 FUJITSU LIMITED. All rights reserved.
4 * Author: Yang Xu <xuyang2018.jy@fujitsu.com>
5 */
6
7/*\
8 * [Description]
9 *
10 * This case tests whether the attributes field of statx received expected value
11 * by using flags in the stx_attributes_mask field of statx.
12 * File set with following flags by using SAFE_IOCTL:
13 *
14 * - STATX_ATTR_COMPRESSED: The file is compressed by the filesystem.
15 * - STATX_ATTR_IMMUTABLE: The file cannot be modified.
16 * - STATX_ATTR_APPEND: The file can only be opened in append mode for writing.
17 * - STATX_ATTR_NODUMP: File is not a candidate for backup when a backup
18 *                        program such as dump(8) is run.
19 *
20 * Two directories are tested.
21 * First directory has all flags set. Second directory has no flags set.
22 */
23
24#define _GNU_SOURCE
25#include "tst_test.h"
26#include "lapi/fs.h"
27#include <stdlib.h>
28#include "lapi/stat.h"
29#include "lapi/fcntl.h"
30
31#define MOUNT_POINT "mntpoint"
32#define TESTDIR_FLAGGED MOUNT_POINT"/test_dir1"
33#define TESTDIR_UNFLAGGED MOUNT_POINT"/test_dir2"
34
35static int fd, clear_flags;
36static int supp_compr = 1, supp_append = 1, supp_immutable = 1, supp_nodump = 1;
37
38static void run(unsigned int flag)
39{
40	struct statx buf;
41
42	TEST(statx(AT_FDCWD, flag ? TESTDIR_FLAGGED : TESTDIR_UNFLAGGED, 0, 0, &buf));
43	if (TST_RET == 0)
44		tst_res(TPASS,
45			"sys_statx(AT_FDCWD, %s, 0, 0, &buf)",
46			flag ? TESTDIR_FLAGGED : TESTDIR_UNFLAGGED);
47	else
48		tst_brk(TFAIL | TTERRNO,
49			"sys_statx(AT_FDCWD, %s, 0, 0, &buf)",
50			flag ? TESTDIR_FLAGGED : TESTDIR_UNFLAGGED);
51
52	if (supp_compr) {
53		if (buf.stx_attributes & STATX_ATTR_COMPRESSED)
54			tst_res(flag ? TPASS : TFAIL,
55				"STATX_ATTR_COMPRESSED flag is set");
56		else
57			tst_res(flag ? TFAIL : TPASS,
58				"STATX_ATTR_COMPRESSED flag is not set");
59	}
60	if (supp_append) {
61		if (buf.stx_attributes & STATX_ATTR_APPEND)
62			tst_res(flag ? TPASS : TFAIL,
63				"STATX_ATTR_APPEND flag is set");
64		else
65			tst_res(flag ? TFAIL : TPASS,
66				"STATX_ATTR_APPEND flag is not set");
67	}
68	if (supp_immutable) {
69		if (buf.stx_attributes & STATX_ATTR_IMMUTABLE)
70			tst_res(flag ? TPASS : TFAIL,
71				"STATX_ATTR_IMMUTABLE flag is set");
72		else
73			tst_res(flag ? TFAIL : TPASS,
74				"STATX_ATTR_IMMUTABLE flag is not set");
75	}
76	if (supp_nodump) {
77		if (buf.stx_attributes & STATX_ATTR_NODUMP)
78			tst_res(flag ? TPASS : TFAIL,
79				"STATX_ATTR_NODUMP flag is set");
80		else
81			tst_res(flag ? TFAIL : TPASS,
82				"STATX_ATTR_NODUMP flag is not set");
83	}
84}
85
86static void caid_flags_setup(void)
87{
88	int attr, ret;
89
90	fd = SAFE_OPEN(TESTDIR_FLAGGED, O_RDONLY | O_DIRECTORY);
91
92	ret = ioctl(fd, FS_IOC_GETFLAGS, &attr);
93	if (ret < 0) {
94		if (errno == ENOTTY)
95			tst_brk(TCONF | TERRNO, "FS_IOC_GETFLAGS not supported");
96
97		/* ntfs3g fuse fs returns wrong errno for unimplemented ioctls */
98		if (!strcmp(tst_device->fs_type, "ntfs")) {
99			tst_brk(TCONF | TERRNO,
100				"ntfs3g does not support FS_IOC_GETFLAGS");
101		}
102
103		tst_brk(TBROK | TERRNO, "ioctl(%i, FS_IOC_GETFLAGS, ...)", fd);
104	}
105
106	if (supp_compr)
107		attr |= FS_COMPR_FL;
108	if (supp_append)
109		attr |= FS_APPEND_FL;
110	if (supp_immutable)
111		attr |= FS_IMMUTABLE_FL;
112	if (supp_nodump)
113		attr |= FS_NODUMP_FL;
114
115	ret = ioctl(fd, FS_IOC_SETFLAGS, &attr);
116	if (ret < 0)
117		tst_brk(TBROK | TERRNO, "ioctl(%i, FS_IOC_SETFLAGS, %i)", fd, attr);
118
119	clear_flags = 1;
120}
121
122static void setup(void)
123{
124	struct statx buf;
125
126	SAFE_MKDIR(TESTDIR_FLAGGED, 0777);
127	SAFE_MKDIR(TESTDIR_UNFLAGGED, 0777);
128
129	TEST(statx(AT_FDCWD, TESTDIR_FLAGGED, 0, 0, &buf));
130	if (TST_RET == -1)
131		tst_brk(TFAIL | TTERRNO,
132			"sys_statx(AT_FDCWD, %s, 0, 0, &buf)", TESTDIR_FLAGGED);
133
134	if ((buf.stx_attributes_mask & FS_COMPR_FL) == 0) {
135		supp_compr = 0;
136		tst_res(TCONF, "filesystem doesn't support FS_COMPR_FL");
137	}
138	if ((buf.stx_attributes_mask & FS_APPEND_FL) == 0) {
139		supp_append = 0;
140		tst_res(TCONF, "filesystem doesn't support FS_APPEND_FL");
141	}
142	if ((buf.stx_attributes_mask & FS_IMMUTABLE_FL) == 0) {
143		supp_immutable = 0;
144		tst_res(TCONF, "filesystem doesn't support FS_IMMUTABLE_FL");
145	}
146	if ((buf.stx_attributes_mask & FS_NODUMP_FL) == 0) {
147		supp_nodump = 0;
148		tst_res(TCONF, "filesystem doesn't support FS_NODUMP_FL");
149	}
150	if (!(supp_compr || supp_append || supp_immutable || supp_nodump))
151		tst_brk(TCONF,
152			"filesystem doesn't support the above any attr, skip it");
153
154	caid_flags_setup();
155}
156
157static void cleanup(void)
158{
159	int attr;
160
161	if (clear_flags) {
162		SAFE_IOCTL(fd, FS_IOC_GETFLAGS, &attr);
163		attr &= ~(FS_COMPR_FL | FS_APPEND_FL | FS_IMMUTABLE_FL | FS_NODUMP_FL);
164		SAFE_IOCTL(fd, FS_IOC_SETFLAGS, &attr);
165	}
166
167	if (fd > 0)
168		SAFE_CLOSE(fd);
169}
170
171static struct tst_test test = {
172	.test = run,
173	.tcnt = 2,
174	.setup = setup,
175	.cleanup = cleanup,
176	.needs_root = 1,
177	.all_filesystems = 1,
178	.mount_device = 1,
179	.mntpoint = MOUNT_POINT,
180	.min_kver = "4.11",
181};
182