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
22 class TestXAttrs(unittest.TestCase):
24 self.randomFile = "./mount/tmp/foo.txt"
25 self.randomFileSidecar = "./mount/tmp/foo.txt.xattr"
26 if os.path.isfile(self.randomFile):
27 os.remove(self.randomFile)
28 Path(self.randomFile).touch()
30 if os.path.isfile(self.randomFileSidecar):
31 os.remove(self.randomFileSidecar)
34 os.remove(self.randomFile)
36 def test_xattr_set(self):
37 xattr.setxattr(self.randomFile, "user.foo", bytes("bar", "utf-8"))
39 def test_xattr_set_name_max_length(self):
41 key = "user." + "x" * 250
43 self.assertEqual(len(key), 255)
44 xattr.setxattr(self.randomFile, key, bytes(value, enc))
46 key = "user." + "x" * 251
47 self.assertEqual(len(key), 256)
48 with self.assertRaises(OSError) as ex:
49 xattr.setxattr(self.randomFile, key, bytes(value, enc))
50 self.assertEqual(ex.exception.errno, 34)
51 self.assertEqual(ex.exception.strerror, "Numerical result out of range")
53 @unittest.expectedFailure
54 def test_xattr_set_value_max_size(self):
57 value = "x" * (64 * 1024 + 1) # we want max 64KiB of data
58 with self.assertRaises(OSError) as ex:
59 xattr.setxattr(self.randomFile, key, bytes(value, enc))
61 # on btrfs we get "no space left on device"
62 self.assertEqual(ex.exception.errno, 28)
63 self.assertEqual(ex.exception.strerror, "No space left on device")
65 # on fuse_xattr we get "Argument list too long"
66 # the error is thrown by fuse, not by fuse_xattr code
68 def test_xattr_set_namespaces(self):
69 with self.assertRaises(OSError) as ex:
70 xattr.setxattr(self.randomFile, "system.foo", bytes("bar", "utf-8"))
71 self.assertEqual(ex.exception.errno, 95)
72 self.assertEqual(ex.exception.strerror, "Operation not supported")
74 with self.assertRaises(OSError) as ex:
75 xattr.setxattr(self.randomFile, "trust.foo", bytes("bar", "utf-8"))
76 self.assertEqual(ex.exception.errno, 95)
77 self.assertEqual(ex.exception.strerror, "Operation not supported")
79 with self.assertRaises(OSError) as ex:
80 xattr.setxattr(self.randomFile, "foo.foo", bytes("bar", "utf-8"))
81 self.assertEqual(ex.exception.errno, 95)
82 self.assertEqual(ex.exception.strerror, "Operation not supported")
84 with self.assertRaises(PermissionError) as ex:
85 xattr.setxattr(self.randomFile, "security.foo", bytes("bar", "utf-8"))
86 self.assertEqual(ex.exception.errno, 1)
87 self.assertEqual(ex.exception.strerror, "Operation not permitted")
89 def test_xattr_get_non_existent(self):
91 with self.assertRaises(OSError) as ex:
92 xattr.getxattr(self.randomFile, key)
93 self.assertEqual(ex.exception.errno, 61)
94 self.assertEqual(ex.exception.strerror, "No data available")
96 def test_xattr_get(self):
100 xattr.setxattr(self.randomFile, key, bytes(value, enc))
101 read_value = xattr.getxattr(self.randomFile, key)
102 self.assertEqual(value, read_value.decode(enc))
104 def test_xattr_set_override(self):
109 xattr.setxattr(self.randomFile, key, bytes(value1, enc))
110 xattr.setxattr(self.randomFile, key, bytes(value2, enc))
111 read_value = xattr.getxattr(self.randomFile, key)
112 self.assertEqual(value2, read_value.decode(enc))
114 def test_xattr_set_create(self):
119 xattr.setxattr(self.randomFile, key, bytes(value1, enc), xattr.XATTR_CREATE)
120 with self.assertRaises(FileExistsError) as ex:
121 xattr.setxattr(self.randomFile, key, bytes(value2, enc), xattr.XATTR_CREATE)
122 self.assertEqual(ex.exception.errno, 17)
123 self.assertEqual(ex.exception.strerror, "File exists")
125 read_value = xattr.getxattr(self.randomFile, key)
126 self.assertEqual(value1, read_value.decode(enc))
128 def test_xattr_set_replace(self):
132 with self.assertRaises(OSError) as ex:
133 xattr.setxattr(self.randomFile, key, bytes(value, enc), xattr.XATTR_REPLACE)
134 self.assertEqual(ex.exception.errno, 61)
135 self.assertEqual(ex.exception.strerror, "No data available")
137 with self.assertRaises(OSError) as ex:
138 xattr.getxattr(self.randomFile, key)
139 self.assertEqual(ex.exception.errno, 61)
140 self.assertEqual(ex.exception.strerror, "No data available")
142 def test_xattr_list_empty(self):
143 attrs = xattr.listxattr(self.randomFile)
144 self.assertEqual(len(attrs), 0)
146 def test_xattr_list(self):
154 xattr.setxattr(self.randomFile, key1, bytes(value, enc))
155 xattr.setxattr(self.randomFile, key2, bytes(value, enc))
156 xattr.setxattr(self.randomFile, key3, bytes(value, enc))
158 # get and check the list
159 attrs = xattr.listxattr(self.randomFile)
161 self.assertEqual(len(attrs), 3)
162 self.assertTrue(key1 in attrs)
163 self.assertTrue(key2 in attrs)
164 self.assertTrue(key3 in attrs)
166 def test_xattr_unicode(self):
168 key = "user.fooシüßてЙĘ𝄠✠"
172 xattr.setxattr(self.randomFile, key, bytes(value, enc))
175 attrs = xattr.listxattr(self.randomFile)
176 self.assertEqual(len(attrs), 1)
177 self.assertTrue(key in attrs)
180 read_value = xattr.getxattr(self.randomFile, key)
181 self.assertEqual(value, read_value.decode(enc))
184 xattr.removexattr(self.randomFile, key)
186 def test_xattr_remove(self):
192 xattr.setxattr(self.randomFile, key, bytes(value, enc))
195 xattr.removexattr(self.randomFile, key)
197 # list should be empty
198 attrs = xattr.listxattr(self.randomFile)
199 self.assertEqual(len(attrs), 0)
201 # should fail when trying to read it
202 with self.assertRaises(OSError) as ex:
203 xattr.getxattr(self.randomFile, key)
204 self.assertEqual(ex.exception.errno, 61)
205 self.assertEqual(ex.exception.strerror, "No data available")
207 # removing twice should fail
208 with self.assertRaises(OSError) as ex:
209 xattr.getxattr(self.randomFile, key)
210 self.assertEqual(ex.exception.errno, 61)
211 self.assertEqual(ex.exception.strerror, "No data available")
214 if __name__ == '__main__':