4 # fuse_xattrs - Add xattrs support using sidecar files
6 # Copyright (C) 2016 Felipe Barriga Richards <felipe {at} felipebarriga.cl>
8 # This program can be distributed under the terms of the GNU GPL.
9 # See the file COPYING.
14 from pathlib import Path
18 # - listxattr: list too long
19 # - sidecar file permissions
20 # - corrupt metadata files
23 class TestXAttrs(unittest.TestCase):
25 self.randomFile = "./mount/foo.txt"
26 self.randomFileSidecar = "./mount/foo.txt.xattr"
27 if os.path.isfile(self.randomFile):
28 os.remove(self.randomFile)
29 Path(self.randomFile).touch()
31 if os.path.isfile(self.randomFileSidecar):
32 os.remove(self.randomFileSidecar)
35 os.remove(self.randomFile)
36 if os.path.isfile(self.randomFileSidecar):
37 os.remove(self.randomFileSidecar)
39 def test_xattr_set(self):
40 xattr.setxattr(self.randomFile, "user.foo", bytes("bar", "utf-8"))
42 def test_xattr_set_name_max_length(self):
44 key = "user." + "x" * 250
46 self.assertEqual(len(key), 255)
47 xattr.setxattr(self.randomFile, key, bytes(value, enc))
49 key = "user." + "x" * 251
50 self.assertEqual(len(key), 256)
51 with self.assertRaises(OSError) as ex:
52 xattr.setxattr(self.randomFile, key, bytes(value, enc))
53 self.assertEqual(ex.exception.errno, 34)
54 self.assertEqual(ex.exception.strerror, "Numerical result out of range")
56 @unittest.expectedFailure
57 def test_xattr_set_value_max_size(self):
60 value = "x" * (64 * 1024 + 1) # we want max 64KiB of data
61 with self.assertRaises(OSError) as ex:
62 xattr.setxattr(self.randomFile, key, bytes(value, enc))
64 # on btrfs we get "no space left on device"
65 self.assertEqual(ex.exception.errno, 28)
66 self.assertEqual(ex.exception.strerror, "No space left on device")
68 # on fuse_xattr we get "Argument list too long"
69 # the error is thrown by fuse, not by fuse_xattr code
71 def test_xattr_set_namespaces(self):
72 with self.assertRaises(OSError) as ex:
73 xattr.setxattr(self.randomFile, "system.foo", bytes("bar", "utf-8"))
74 self.assertEqual(ex.exception.errno, 95)
75 self.assertEqual(ex.exception.strerror, "Operation not supported")
77 with self.assertRaises(OSError) as ex:
78 xattr.setxattr(self.randomFile, "trust.foo", bytes("bar", "utf-8"))
79 self.assertEqual(ex.exception.errno, 95)
80 self.assertEqual(ex.exception.strerror, "Operation not supported")
82 with self.assertRaises(OSError) as ex:
83 xattr.setxattr(self.randomFile, "foo.foo", bytes("bar", "utf-8"))
84 self.assertEqual(ex.exception.errno, 95)
85 self.assertEqual(ex.exception.strerror, "Operation not supported")
87 with self.assertRaises(PermissionError) as ex:
88 xattr.setxattr(self.randomFile, "security.foo", bytes("bar", "utf-8"))
89 self.assertEqual(ex.exception.errno, 1)
90 self.assertEqual(ex.exception.strerror, "Operation not permitted")
92 def test_xattr_get_non_existent(self):
94 with self.assertRaises(OSError) as ex:
95 xattr.getxattr(self.randomFile, key)
96 self.assertEqual(ex.exception.errno, 61)
97 self.assertEqual(ex.exception.strerror, "No data available")
99 def test_xattr_get(self):
103 xattr.setxattr(self.randomFile, key, bytes(value, enc))
104 read_value = xattr.getxattr(self.randomFile, key)
105 self.assertEqual(value, read_value.decode(enc))
107 def test_xattr_set_override(self):
112 xattr.setxattr(self.randomFile, key, bytes(value1, enc))
113 xattr.setxattr(self.randomFile, key, bytes(value2, enc))
114 read_value = xattr.getxattr(self.randomFile, key)
115 self.assertEqual(value2, read_value.decode(enc))
117 def test_xattr_set_create(self):
122 xattr.setxattr(self.randomFile, key, bytes(value1, enc), xattr.XATTR_CREATE)
123 with self.assertRaises(FileExistsError) as ex:
124 xattr.setxattr(self.randomFile, key, bytes(value2, enc), xattr.XATTR_CREATE)
125 self.assertEqual(ex.exception.errno, 17)
126 self.assertEqual(ex.exception.strerror, "File exists")
128 read_value = xattr.getxattr(self.randomFile, key)
129 self.assertEqual(value1, read_value.decode(enc))
131 def test_xattr_set_replace(self):
135 with self.assertRaises(OSError) as ex:
136 xattr.setxattr(self.randomFile, key, bytes(value, enc), xattr.XATTR_REPLACE)
137 self.assertEqual(ex.exception.errno, 61)
138 self.assertEqual(ex.exception.strerror, "No data available")
140 with self.assertRaises(OSError) as ex:
141 xattr.getxattr(self.randomFile, key)
142 self.assertEqual(ex.exception.errno, 61)
143 self.assertEqual(ex.exception.strerror, "No data available")
145 def test_xattr_list_empty(self):
146 attrs = xattr.listxattr(self.randomFile)
147 self.assertEqual(len(attrs), 0)
149 def test_xattr_list(self):
157 xattr.setxattr(self.randomFile, key1, bytes(value, enc))
158 xattr.setxattr(self.randomFile, key2, bytes(value, enc))
159 xattr.setxattr(self.randomFile, key3, bytes(value, enc))
161 # get and check the list
162 attrs = xattr.listxattr(self.randomFile)
164 self.assertEqual(len(attrs), 3)
165 self.assertTrue(key1 in attrs)
166 self.assertTrue(key2 in attrs)
167 self.assertTrue(key3 in attrs)
169 def test_xattr_unicode(self):
171 key = "user.fooシüßてЙĘ𝄠✠"
175 xattr.setxattr(self.randomFile, key, bytes(value, enc))
178 attrs = xattr.listxattr(self.randomFile)
179 self.assertEqual(len(attrs), 1)
180 self.assertTrue(key.encode() in attrs)
183 read_value = xattr.getxattr(self.randomFile, key)
184 self.assertEqual(value, read_value.decode(enc))
187 xattr.removexattr(self.randomFile, key)
189 def test_xattr_remove(self):
195 xattr.setxattr(self.randomFile, key, bytes(value, enc))
198 xattr.removexattr(self.randomFile, key)
200 # list should be empty
201 attrs = xattr.listxattr(self.randomFile)
202 self.assertEqual(len(attrs), 0)
204 # should fail when trying to read it
205 with self.assertRaises(OSError) as ex:
206 xattr.getxattr(self.randomFile, key)
207 self.assertEqual(ex.exception.errno, 61)
208 self.assertEqual(ex.exception.strerror, "No data available")
210 # removing twice should fail
211 with self.assertRaises(OSError) as ex:
212 xattr.getxattr(self.randomFile, key)
213 self.assertEqual(ex.exception.errno, 61)
214 self.assertEqual(ex.exception.strerror, "No data available")
217 if __name__ == '__main__':