1#include "fs/ext2/tests/test_internal.h"
2
3TEST_GROUP_DECLARE(ext2_mode);
4
5/* ext2 file type is a 4 bit enumerated field in the top nibble of mode */
6struct ftype_case {
7 uint16_t mode;
8 uint8_t expect;
9 const char *name;
10};
11
12static const struct ftype_case ftype_cases[] = {
13 {EXT2_S_IFREG, EXT2_FT_REG_FILE, "regular"},
14 {EXT2_S_IFDIR, EXT2_FT_DIR, "directory"},
15 {EXT2_S_IFCHR, EXT2_FT_CHRDEV, "chardev"},
16 {EXT2_S_IFBLK, EXT2_FT_BLKDEV, "blockdev"},
17 {EXT2_S_IFIFO, EXT2_FT_FIFO, "fifo"},
18 {EXT2_S_IFSOCK, EXT2_FT_SOCK, "socket"},
19 {EXT2_S_IFLNK, EXT2_FT_SYMLINK, "symlink"},
20};
21
22TEST_DECLARE_UNIT(ext2_mode, ftype_all_types) {
23 for (size_t i = 0; i < TEST_ARRAY_LEN(ftype_cases); i++) {
24 const struct ftype_case *c = &ftype_cases[i];
25 uint8_t got = ext2_extract_ftype(mode: c->mode);
26
27 if (got != c->expect) {
28 test_err("ftype(%s / %04x) = %u, want %u", c->name, c->mode, got,
29 c->expect);
30 return TEST_FAIL("ext2_extract_ftype");
31 }
32 }
33
34 return TEST_SUCCESS;
35}
36
37/* Perm bits share word with type */
38TEST_DECLARE_UNIT(ext2_mode, ftype_ignores_permissions) {
39 const uint16_t perms = 0x0FFF;
40
41 for (size_t i = 0; i < TEST_ARRAY_LEN(ftype_cases); i++) {
42 const struct ftype_case *c = &ftype_cases[i];
43 TEST_ASSERT_EQ(ext2_extract_ftype(c->mode | perms), c->expect);
44 TEST_ASSERT_EQ(ext2_extract_ftype(c->mode), c->expect);
45 }
46
47 return TEST_SUCCESS;
48}
49
50TEST_DECLARE_UNIT(ext2_mode, ftype_unknown) {
51 /* Zero type field is not any of the seven, must not be guessed */
52 TEST_ASSERT_EQ(ext2_extract_ftype(0), EXT2_FT_UNKNOWN);
53 TEST_ASSERT_EQ(ext2_extract_ftype(0x0FFF), EXT2_FT_UNKNOWN);
54
55 /* Each type maps to a distinct value in the defined range */
56 for (size_t i = 0; i < TEST_ARRAY_LEN(ftype_cases); i++) {
57 TEST_ASSERT_LT(ftype_cases[i].expect, EXT2_FT_MAX);
58 for (size_t j = i + 1; j < TEST_ARRAY_LEN(ftype_cases); j++)
59 TEST_ASSERT_NE(ftype_cases[i].expect, ftype_cases[j].expect);
60 }
61
62 return TEST_SUCCESS;
63}
64
65TEST_DECLARE_UNIT(ext2_mode, mode_type_roundtrip) {
66 for (size_t i = 0; i < TEST_ARRAY_LEN(ftype_cases); i++) {
67 uint16_t ext2 = ftype_cases[i].mode;
68 uint16_t vfs = TEST_CALL(ext2_to_vfs_mode)(ext2_mode: ext2);
69
70 TEST_ASSERT_EQ((TEST_CALL(vfs_to_ext2_mode)(vfs) & EXT2_S_IFMT),
71 (ext2 & EXT2_S_IFMT));
72 }
73
74 return TEST_SUCCESS;
75}
76
77TEST_DECLARE_UNIT(ext2_mode, mode_permission_roundtrip) {
78 static const uint16_t perm_bits[] = {
79 EXT2_S_IRUSR, EXT2_S_IWUSR, EXT2_S_IXUSR, EXT2_S_IRGRP, EXT2_S_IWGRP,
80 EXT2_S_IXGRP, EXT2_S_IROTH, EXT2_S_IWOTH, EXT2_S_IXOTH,
81 };
82
83 /* One bit at a time isolates a swapped owner/group/other mappings, which
84 * 0777 round trip would hide away */
85 for (size_t i = 0; i < TEST_ARRAY_LEN(perm_bits); i++) {
86 uint16_t ext2 = EXT2_S_IFREG | perm_bits[i];
87 uint16_t back =
88 TEST_CALL(vfs_to_ext2_mode)(TEST_CALL(ext2_to_vfs_mode)(ext2_mode: ext2));
89
90 TEST_ASSERT_EQ(back, ext2);
91 }
92
93 /* full set together */
94 uint16_t all = EXT2_S_IFREG;
95 for (size_t i = 0; i < TEST_ARRAY_LEN(perm_bits); i++)
96 all |= perm_bits[i];
97
98 TEST_ASSERT_EQ(
99 TEST_CALL(vfs_to_ext2_mode)(TEST_CALL(ext2_to_vfs_mode)(all)), all);
100
101 return TEST_SUCCESS;
102}
103
104TEST_DECLARE_UNIT(ext2_mode, flags_roundtrip) {
105 static const uint32_t flags[] = {
106 EXT2_APPEND_FL, EXT2_IMMUTABLE_FL, EXT2_NOATIME_FL,
107 EXT2_SYNC_FL, EXT2_DIRSYNC_FL,
108 };
109
110 uint32_t all = 0;
111 for (size_t i = 0; i < TEST_ARRAY_LEN(flags); i++) {
112 uint32_t back = TEST_CALL(vfs_to_ext2_flags)(
113 TEST_CALL(ext2_to_vfs_flags)(ext2_flags: flags[i]));
114
115 TEST_ASSERT_EQ(back, flags[i]);
116 all |= flags[i];
117 }
118
119 TEST_ASSERT_EQ(
120 TEST_CALL(vfs_to_ext2_flags)(TEST_CALL(ext2_to_vfs_flags)(all)), all);
121
122 TEST_ASSERT_EQ(TEST_CALL(ext2_to_vfs_flags)(0), 0);
123 TEST_ASSERT_EQ(TEST_CALL(vfs_to_ext2_flags)(0), 0);
124
125 /* Flags we don't model mustn't be dropped */
126 TEST_ASSERT_EQ(
127 (TEST_CALL(vfs_to_ext2_flags)(TEST_CALL(ext2_to_vfs_flags)(~all)) &
128 all),
129 0);
130
131 return TEST_SUCCESS;
132}
133