@@ -52,3 +52,126 @@ func TestStringifyMountFlags(t *testing.T) {
5252 }
5353 }
5454}
55+
56+ func TestMsFlagsToMountAttr (t * testing.T ) {
57+ // allBinaryAttrs is the bitmask of all binary (non-atime) mount attributes.
58+ allBinaryAttrs := uint64 (unix .MOUNT_ATTR_RDONLY | unix .MOUNT_ATTR_NOSUID |
59+ unix .MOUNT_ATTR_NODEV | unix .MOUNT_ATTR_NOEXEC |
60+ unix .MOUNT_ATTR_NODIRATIME | unix .MOUNT_ATTR_NOSYMFOLLOW )
61+
62+ // Helper to compute the expected "cls" when only a subset of binary attrs
63+ // is set: the set attrs are removed from cls, the rest stay, and the atime
64+ // field is always cleared.
65+ expectCls := func (setAttrs uint64 ) uint64 {
66+ return (allBinaryAttrs &^ setAttrs ) | unix .MOUNT_ATTR__ATIME
67+ }
68+
69+ for _ , test := range []struct {
70+ name string
71+ flags int
72+ wantSet uint64
73+ wantCls uint64
74+ }{
75+ // No flags: all binary attrs cleared, atime defaults to RELATIME.
76+ {"empty" , 0 , 0 , allBinaryAttrs | unix .MOUNT_ATTR__ATIME },
77+
78+ // --- Individual binary flags ---
79+ // Each set flag moves its attr from "cls" to "set"; the rest stay in "cls".
80+ {
81+ "rdonly" , unix .MS_RDONLY ,
82+ unix .MOUNT_ATTR_RDONLY , expectCls (unix .MOUNT_ATTR_RDONLY ),
83+ },
84+ {
85+ "nosuid" , unix .MS_NOSUID ,
86+ unix .MOUNT_ATTR_NOSUID , expectCls (unix .MOUNT_ATTR_NOSUID ),
87+ },
88+ {
89+ "nodev" , unix .MS_NODEV ,
90+ unix .MOUNT_ATTR_NODEV , expectCls (unix .MOUNT_ATTR_NODEV ),
91+ },
92+ {
93+ "noexec" , unix .MS_NOEXEC ,
94+ unix .MOUNT_ATTR_NOEXEC , expectCls (unix .MOUNT_ATTR_NOEXEC ),
95+ },
96+ {
97+ "nodiratime" , unix .MS_NODIRATIME ,
98+ unix .MOUNT_ATTR_NODIRATIME , expectCls (unix .MOUNT_ATTR_NODIRATIME ),
99+ },
100+ {
101+ "nosymfollow" , unix .MS_NOSYMFOLLOW ,
102+ unix .MOUNT_ATTR_NOSYMFOLLOW , expectCls (unix .MOUNT_ATTR_NOSYMFOLLOW ),
103+ },
104+
105+ // --- Individual atime modes ---
106+ // MOUNT_ATTR__ATIME is always in "cls" to clear the atime field first.
107+ {
108+ "noatime" , unix .MS_NOATIME ,
109+ unix .MOUNT_ATTR_NOATIME , expectCls (0 ),
110+ },
111+ {
112+ "strictatime" , unix .MS_STRICTATIME ,
113+ unix .MOUNT_ATTR_STRICTATIME , expectCls (0 ),
114+ },
115+ {
116+ "relatime" , unix .MS_RELATIME ,
117+ 0 , // MOUNT_ATTR_RELATIME is 0x00, clearing the field is sufficient
118+ expectCls (0 ),
119+ },
120+
121+ // --- Combinations ---
122+ {
123+ "all-binary-flags" ,
124+ unix .MS_RDONLY | unix .MS_NOSUID | unix .MS_NODEV | unix .MS_NOEXEC |
125+ unix .MS_NODIRATIME | unix .MS_NOSYMFOLLOW ,
126+ allBinaryAttrs , unix .MOUNT_ATTR__ATIME ,
127+ },
128+
129+ {
130+ "all-binary-plus-noatime" ,
131+ unix .MS_RDONLY | unix .MS_NOSUID | unix .MS_NODEV | unix .MS_NOEXEC |
132+ unix .MS_NODIRATIME | unix .MS_NOSYMFOLLOW | unix .MS_NOATIME ,
133+ allBinaryAttrs | unix .MOUNT_ATTR_NOATIME , unix .MOUNT_ATTR__ATIME ,
134+ },
135+
136+ {
137+ "all-binary-plus-strictatime" ,
138+ unix .MS_RDONLY | unix .MS_NOSUID | unix .MS_NODEV | unix .MS_NOEXEC |
139+ unix .MS_NODIRATIME | unix .MS_NOSYMFOLLOW | unix .MS_STRICTATIME ,
140+ allBinaryAttrs | unix .MOUNT_ATTR_STRICTATIME , unix .MOUNT_ATTR__ATIME ,
141+ },
142+
143+ {
144+ "all-binary-plus-relatime" ,
145+ unix .MS_RDONLY | unix .MS_NOSUID | unix .MS_NODEV | unix .MS_NOEXEC |
146+ unix .MS_NODIRATIME | unix .MS_NOSYMFOLLOW | unix .MS_RELATIME ,
147+ allBinaryAttrs , // RELATIME is 0x00, so nothing extra in "set"
148+ unix .MOUNT_ATTR__ATIME ,
149+ },
150+
151+ {
152+ "rdonly-plus-noatime" ,
153+ unix .MS_RDONLY | unix .MS_NOATIME ,
154+ unix .MOUNT_ATTR_RDONLY | unix .MOUNT_ATTR_NOATIME ,
155+ expectCls (unix .MOUNT_ATTR_RDONLY ),
156+ },
157+
158+ // Multiple atime flags set (should not happen in practice, but the
159+ // switch picks the first: NOATIME > STRICTATIME > RELATIME).
160+ {
161+ "noatime-plus-strictatime" ,
162+ unix .MS_NOATIME | unix .MS_STRICTATIME ,
163+ unix .MOUNT_ATTR_NOATIME , expectCls (0 ),
164+ },
165+ {
166+ "strictatime-plus-relatime" ,
167+ unix .MS_STRICTATIME | unix .MS_RELATIME ,
168+ unix .MOUNT_ATTR_STRICTATIME , expectCls (0 ),
169+ },
170+ } {
171+ gotSet , gotCls := msFlagsToMountAttr (test .flags )
172+ if gotSet != test .wantSet || gotCls != test .wantCls {
173+ t .Errorf ("%s: msFlagsToMountAttr(0x%x) = (set=0x%x, cls=0x%x), want (set=0x%x, cls=0x%x)" ,
174+ test .name , test .flags , gotSet , gotCls , test .wantSet , test .wantCls )
175+ }
176+ }
177+ }
0 commit comments