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/tmp/foo.txt"
26 self.randomFileSidecar = "./mount/tmp/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)
37 def test_xattr_set(self):
38 xattr.setxattr(self.randomFile, "user.foo", bytes("bar", "utf-8"))
40 def test_xattr_set_name_max_length(self):
42 key = "user." + "x" * 250
44 self.assertEqual(len(key), 255)
45 xattr.setxattr(self.randomFile, key, bytes(value, enc))
47 key = "user." + "x" * 251
48 self.assertEqual(len(key), 256)
49 with self.assertRaises(OSError) as ex:
50 xattr.setxattr(self.randomFile, key, bytes(value, enc))
51 self.assertEqual(ex.exception.errno, 34)
52 self.assertEqual(ex.exception.strerror, "Numerical result out of range")
54 @unittest.expectedFailure
55 def test_xattr_set_value_max_size(self):
58 value = "x" * (64 * 1024 + 1) # we want max 64KiB of data
59 with self.assertRaises(OSError) as ex:
60 xattr.setxattr(self.randomFile, key, bytes(value, enc))
62 # on btrfs we get "no space left on device"
63 self.assertEqual(ex.exception.errno, 28)
64 self.assertEqual(ex.exception.strerror, "No space left on device")
66 # on fuse_xattr we get "Argument list too long"
67 # the error is thrown by fuse, not by fuse_xattr code
69 def test_xattr_set_namespaces(self):
70 with self.assertRaises(OSError) as ex:
71 xattr.setxattr(self.randomFile, "system.foo", bytes("bar", "utf-8"))
72 self.assertEqual(ex.exception.errno, 95)
73 self.assertEqual(ex.exception.strerror, "Operation not supported")
75 with self.assertRaises(OSError) as ex:
76 xattr.setxattr(self.randomFile, "trust.foo", bytes("bar", "utf-8"))
77 self.assertEqual(ex.exception.errno, 95)
78 self.assertEqual(ex.exception.strerror, "Operation not supported")
80 with self.assertRaises(OSError) as ex:
81 xattr.setxattr(self.randomFile, "foo.foo", bytes("bar", "utf-8"))
82 self.assertEqual(ex.exception.errno, 95)
83 self.assertEqual(ex.exception.strerror, "Operation not supported")
85 with self.assertRaises(PermissionError) as ex:
86 xattr.setxattr(self.randomFile, "security.foo", bytes("bar", "utf-8"))
87 self.assertEqual(ex.exception.errno, 1)
88 self.assertEqual(ex.exception.strerror, "Operation not permitted")
90 def test_xattr_get_non_existent(self):
92 with self.assertRaises(OSError) as ex:
93 xattr.getxattr(self.randomFile, key)
94 self.assertEqual(ex.exception.errno, 61)
95 self.assertEqual(ex.exception.strerror, "No data available")
97 def test_xattr_get(self):
101 xattr.setxattr(self.randomFile, key, bytes(value, enc))
102 read_value = xattr.getxattr(self.randomFile, key)
103 self.assertEqual(value, read_value.decode(enc))
105 def test_xattr_set_override(self):
110 xattr.setxattr(self.randomFile, key, bytes(value1, enc))
111 xattr.setxattr(self.randomFile, key, bytes(value2, enc))
112 read_value = xattr.getxattr(self.randomFile, key)
113 self.assertEqual(value2, read_value.decode(enc))
115 def test_xattr_set_create(self):
120 xattr.setxattr(self.randomFile, key, bytes(value1, enc), xattr.XATTR_CREATE)
121 with self.assertRaises(FileExistsError) as ex:
122 xattr.setxattr(self.randomFile, key, bytes(value2, enc), xattr.XATTR_CREATE)
123 self.assertEqual(ex.exception.errno, 17)
124 self.assertEqual(ex.exception.strerror, "File exists")
126 read_value = xattr.getxattr(self.randomFile, key)
127 self.assertEqual(value1, read_value.decode(enc))
129 def test_xattr_set_replace(self):
133 with self.assertRaises(OSError) as ex:
134 xattr.setxattr(self.randomFile, key, bytes(value, enc), xattr.XATTR_REPLACE)
135 self.assertEqual(ex.exception.errno, 61)
136 self.assertEqual(ex.exception.strerror, "No data available")
138 with self.assertRaises(OSError) as ex:
139 xattr.getxattr(self.randomFile, key)
140 self.assertEqual(ex.exception.errno, 61)
141 self.assertEqual(ex.exception.strerror, "No data available")
143 def test_xattr_list_empty(self):
144 attrs = xattr.listxattr(self.randomFile)
145 self.assertEqual(len(attrs), 0)
147 def test_xattr_list(self):
155 xattr.setxattr(self.randomFile, key1, bytes(value, enc))
156 xattr.setxattr(self.randomFile, key2, bytes(value, enc))
157 xattr.setxattr(self.randomFile, key3, bytes(value, enc))
159 # get and check the list
160 attrs = xattr.listxattr(self.randomFile)
162 self.assertEqual(len(attrs), 3)
163 self.assertTrue(key1 in attrs)
164 self.assertTrue(key2 in attrs)
165 self.assertTrue(key3 in attrs)
167 def test_xattr_unicode(self):
169 key = "user.fooシüßてЙĘ𝄠✠"
173 xattr.setxattr(self.randomFile, key, bytes(value, enc))
176 attrs = xattr.listxattr(self.randomFile)
177 self.assertEqual(len(attrs), 1)
178 self.assertTrue(key in attrs)
181 read_value = xattr.getxattr(self.randomFile, key)
182 self.assertEqual(value, read_value.decode(enc))
185 xattr.removexattr(self.randomFile, key)
187 def test_xattr_remove(self):
193 xattr.setxattr(self.randomFile, key, bytes(value, enc))
196 xattr.removexattr(self.randomFile, key)
198 # list should be empty
199 attrs = xattr.listxattr(self.randomFile)
200 self.assertEqual(len(attrs), 0)
202 # should fail when trying to read it
203 with self.assertRaises(OSError) as ex:
204 xattr.getxattr(self.randomFile, key)
205 self.assertEqual(ex.exception.errno, 61)
206 self.assertEqual(ex.exception.strerror, "No data available")
208 # removing twice should fail
209 with self.assertRaises(OSError) as ex:
210 xattr.getxattr(self.randomFile, key)
211 self.assertEqual(ex.exception.errno, 61)
212 self.assertEqual(ex.exception.strerror, "No data available")
215 if __name__ == '__main__':