]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com> | |
7 | * | |
8 | * Author: Loic Dachary <loic@dachary.org> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU Library Public License as published by | |
12 | * the Free Software Foundation; either version 2, or (at your option) | |
13 | * any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU Library Public License for more details. | |
19 | * | |
20 | */ | |
21 | ||
22 | #include <stdio.h> | |
23 | #include <signal.h> | |
24 | #include "os/filestore/chain_xattr.h" | |
25 | #include "include/Context.h" | |
26 | #include "include/coredumpctl.h" | |
27 | #include "common/errno.h" | |
28 | #include "common/ceph_argparse.h" | |
29 | #include "global/global_init.h" | |
30 | #include <gtest/gtest.h> | |
31 | ||
32 | #define LARGE_BLOCK_LEN CHAIN_XATTR_MAX_BLOCK_LEN + 1024 | |
33 | #define FILENAME "chain_xattr" | |
34 | ||
20effc67 TL |
35 | using namespace std; |
36 | ||
7c673cae FG |
37 | TEST(chain_xattr, get_and_set) { |
38 | const char* file = FILENAME; | |
39 | ::unlink(file); | |
40 | int fd = ::open(file, O_CREAT|O_WRONLY|O_TRUNC, 0700); | |
41 | const string user("user."); | |
42 | ||
43 | { | |
44 | const string name = user + string(CHAIN_XATTR_MAX_NAME_LEN - user.size(), '@'); | |
45 | const string x(LARGE_BLOCK_LEN, 'X'); | |
46 | ||
47 | { | |
48 | char y[LARGE_BLOCK_LEN]; | |
49 | ASSERT_EQ(LARGE_BLOCK_LEN, chain_setxattr(file, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); | |
50 | ASSERT_EQ(LARGE_BLOCK_LEN, chain_getxattr(file, name.c_str(), 0, 0)); | |
51 | ASSERT_EQ(LARGE_BLOCK_LEN, chain_getxattr(file, name.c_str(), y, LARGE_BLOCK_LEN)); | |
52 | ASSERT_EQ(0, chain_removexattr(file, name.c_str())); | |
53 | ASSERT_EQ(0, memcmp(x.c_str(), y, LARGE_BLOCK_LEN)); | |
54 | } | |
55 | ||
56 | { | |
57 | char y[LARGE_BLOCK_LEN]; | |
58 | ASSERT_EQ(LARGE_BLOCK_LEN, chain_fsetxattr(fd, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); | |
59 | ASSERT_EQ(LARGE_BLOCK_LEN, chain_fgetxattr(fd, name.c_str(), 0, 0)); | |
60 | ASSERT_EQ(LARGE_BLOCK_LEN, chain_fgetxattr(fd, name.c_str(), y, LARGE_BLOCK_LEN)); | |
61 | ASSERT_EQ(0, chain_fremovexattr(fd, name.c_str())); | |
62 | ASSERT_EQ(0, memcmp(x.c_str(), y, LARGE_BLOCK_LEN)); | |
63 | } | |
64 | } | |
65 | ||
66 | // | |
67 | // when chain_setxattr is used to store value that is | |
68 | // CHAIN_XATTR_MAX_BLOCK_LEN * 2 + 10 bytes long it | |
69 | // | |
70 | // add user.foo => CHAIN_XATTR_MAX_BLOCK_LEN bytes | |
71 | // add user.foo@1 => CHAIN_XATTR_MAX_BLOCK_LEN bytes | |
72 | // add user.foo@2 => 10 bytes | |
73 | // | |
74 | // then ( no chain_removexattr in between ) when it is used to | |
75 | // override with a value that is exactly CHAIN_XATTR_MAX_BLOCK_LEN | |
76 | // bytes long it will | |
77 | // | |
78 | // replace user.foo => CHAIN_XATTR_MAX_BLOCK_LEN bytes | |
79 | // remove user.foo@1 => CHAIN_XATTR_MAX_BLOCK_LEN bytes | |
80 | // leak user.foo@2 => 10 bytes | |
81 | // | |
82 | // see http://marc.info/?l=ceph-devel&m=136027076615853&w=4 for the | |
83 | // discussion | |
84 | // | |
85 | { | |
86 | const string name = user + string(CHAIN_XATTR_MAX_NAME_LEN - user.size(), '@'); | |
87 | const string x(LARGE_BLOCK_LEN, 'X'); | |
88 | ||
89 | { | |
90 | char y[CHAIN_XATTR_MAX_BLOCK_LEN]; | |
91 | ASSERT_EQ(LARGE_BLOCK_LEN, chain_setxattr(file, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); | |
92 | ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_setxattr(file, name.c_str(), x.c_str(), CHAIN_XATTR_MAX_BLOCK_LEN)); | |
93 | ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_getxattr(file, name.c_str(), 0, 0)); | |
94 | ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_getxattr(file, name.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); | |
95 | ASSERT_EQ(0, chain_removexattr(file, name.c_str())); | |
96 | ASSERT_EQ(0, memcmp(x.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); | |
97 | } | |
98 | ||
99 | { | |
100 | char y[CHAIN_XATTR_MAX_BLOCK_LEN]; | |
101 | ASSERT_EQ(LARGE_BLOCK_LEN, chain_fsetxattr(fd, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); | |
102 | ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_fsetxattr(fd, name.c_str(), x.c_str(), CHAIN_XATTR_MAX_BLOCK_LEN)); | |
103 | ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_fgetxattr(fd, name.c_str(), 0, 0)); | |
104 | ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_fgetxattr(fd, name.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); | |
105 | ASSERT_EQ(0, chain_fremovexattr(fd, name.c_str())); | |
106 | ASSERT_EQ(0, memcmp(x.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); | |
107 | } | |
108 | } | |
109 | ||
110 | { | |
111 | int x = 0; | |
112 | ASSERT_EQ(-ENOENT, chain_setxattr("UNLIKELY_TO_EXIST", "NAME", &x, sizeof(x))); | |
113 | ASSERT_EQ(-ENOENT, chain_getxattr("UNLIKELY_TO_EXIST", "NAME", 0, 0)); | |
114 | ASSERT_EQ(-ENOENT, chain_getxattr("UNLIKELY_TO_EXIST", "NAME", &x, sizeof(x))); | |
115 | ASSERT_EQ(-ENOENT, chain_removexattr("UNLIKELY_TO_EXIST", "NAME")); | |
116 | int unlikely_to_be_a_valid_fd = 400; | |
117 | ASSERT_EQ(-EBADF, chain_fsetxattr(unlikely_to_be_a_valid_fd, "NAME", &x, sizeof(x))); | |
118 | ASSERT_EQ(-EBADF, chain_fgetxattr(unlikely_to_be_a_valid_fd, "NAME", 0, 0)); | |
119 | ASSERT_EQ(-EBADF, chain_fgetxattr(unlikely_to_be_a_valid_fd, "NAME", &x, sizeof(x))); | |
120 | ASSERT_EQ(-EBADF, chain_fremovexattr(unlikely_to_be_a_valid_fd, "NAME")); | |
121 | } | |
122 | ||
123 | { | |
124 | int x; | |
125 | const string name = user + string(CHAIN_XATTR_MAX_NAME_LEN * 2, '@'); | |
126 | PrCtl unset_dumpable; | |
f67539c2 | 127 | ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
7c673cae FG |
128 | ASSERT_DEATH(chain_setxattr(file, name.c_str(), &x, sizeof(x)), ""); |
129 | ASSERT_DEATH(chain_fsetxattr(fd, name.c_str(), &x, sizeof(x)), ""); | |
f67539c2 | 130 | ::testing::FLAGS_gtest_death_test_style = "fast"; |
7c673cae FG |
131 | } |
132 | ||
133 | { | |
134 | const string name = user + string(CHAIN_XATTR_MAX_NAME_LEN - user.size(), '@'); | |
135 | const string x(LARGE_BLOCK_LEN, 'X'); | |
136 | { | |
137 | char y[LARGE_BLOCK_LEN]; | |
138 | ASSERT_EQ(LARGE_BLOCK_LEN, chain_setxattr(file, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); | |
139 | ASSERT_EQ(-ERANGE, chain_getxattr(file, name.c_str(), y, LARGE_BLOCK_LEN - 1)); | |
140 | ASSERT_EQ(-ERANGE, chain_getxattr(file, name.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); | |
141 | ASSERT_EQ(0, chain_removexattr(file, name.c_str())); | |
142 | } | |
143 | ||
144 | { | |
145 | char y[LARGE_BLOCK_LEN]; | |
146 | ASSERT_EQ(LARGE_BLOCK_LEN, chain_fsetxattr(fd, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); | |
147 | ASSERT_EQ(-ERANGE, chain_fgetxattr(fd, name.c_str(), y, LARGE_BLOCK_LEN - 1)); | |
148 | ASSERT_EQ(-ERANGE, chain_fgetxattr(fd, name.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); | |
149 | ASSERT_EQ(0, chain_fremovexattr(fd, name.c_str())); | |
150 | } | |
151 | } | |
152 | ||
153 | ::close(fd); | |
154 | ::unlink(file); | |
155 | } | |
156 | ||
157 | TEST(chain_xattr, chunk_aligned) { | |
158 | const char* file = FILENAME; | |
159 | ::unlink(file); | |
160 | int fd = ::open(file, O_CREAT|O_WRONLY|O_TRUNC, 0700); | |
161 | const string user("user."); | |
162 | ||
163 | // set N* chunk size | |
164 | const string name = "user.foo"; | |
165 | const string name2 = "user.bar"; | |
166 | ||
167 | for (int len = CHAIN_XATTR_MAX_BLOCK_LEN - 10; | |
168 | len < CHAIN_XATTR_MAX_BLOCK_LEN + 10; | |
169 | ++len) { | |
170 | cout << len << std::endl; | |
171 | const string x(len, 'x'); | |
172 | char buf[len*2]; | |
173 | ASSERT_EQ(len, chain_setxattr(file, name.c_str(), x.c_str(), len)); | |
174 | char attrbuf[4096]; | |
175 | int l = ceph_os_listxattr(file, attrbuf, sizeof(attrbuf)); | |
176 | for (char *p = attrbuf; p - attrbuf < l; p += strlen(p) + 1) { | |
177 | cout << " attr " << p << std::endl; | |
178 | } | |
179 | ASSERT_EQ(len, chain_getxattr(file, name.c_str(), buf, len*2)); | |
180 | ASSERT_EQ(0, chain_removexattr(file, name.c_str())); | |
181 | ||
182 | ASSERT_EQ(len, chain_fsetxattr(fd, name2.c_str(), x.c_str(), len)); | |
183 | l = ceph_os_flistxattr(fd, attrbuf, sizeof(attrbuf)); | |
184 | for (char *p = attrbuf; p - attrbuf < l; p += strlen(p) + 1) { | |
185 | cout << " attr " << p << std::endl; | |
186 | } | |
187 | ASSERT_EQ(len, chain_fgetxattr(fd, name2.c_str(), buf, len*2)); | |
188 | ASSERT_EQ(0, chain_fremovexattr(fd, name2.c_str())); | |
189 | } | |
190 | ||
191 | for (int len = CHAIN_XATTR_SHORT_BLOCK_LEN - 10; | |
192 | len < CHAIN_XATTR_SHORT_BLOCK_LEN + 10; | |
193 | ++len) { | |
194 | cout << len << std::endl; | |
195 | const string x(len, 'x'); | |
196 | char buf[len*2]; | |
197 | ASSERT_EQ(len, chain_setxattr(file, name.c_str(), x.c_str(), len)); | |
198 | char attrbuf[4096]; | |
199 | int l = ceph_os_listxattr(file, attrbuf, sizeof(attrbuf)); | |
200 | for (char *p = attrbuf; p - attrbuf < l; p += strlen(p) + 1) { | |
201 | cout << " attr " << p << std::endl; | |
202 | } | |
203 | ASSERT_EQ(len, chain_getxattr(file, name.c_str(), buf, len*2)); | |
204 | } | |
205 | ||
206 | { | |
207 | // test tail path in chain_getxattr | |
208 | const char *aname = "user.baz"; | |
209 | char buf[CHAIN_XATTR_SHORT_BLOCK_LEN*3]; | |
210 | memset(buf, 'x', sizeof(buf)); | |
211 | ASSERT_EQ((int)sizeof(buf), chain_setxattr(file, aname, buf, sizeof(buf))); | |
212 | ASSERT_EQ(-ERANGE, chain_getxattr(file, aname, buf, | |
213 | CHAIN_XATTR_SHORT_BLOCK_LEN*2)); | |
214 | } | |
215 | { | |
216 | // test tail path in chain_fgetxattr | |
217 | const char *aname = "user.biz"; | |
218 | char buf[CHAIN_XATTR_SHORT_BLOCK_LEN*3]; | |
219 | memset(buf, 'x', sizeof(buf)); | |
220 | ASSERT_EQ((int)sizeof(buf), chain_fsetxattr(fd, aname, buf, sizeof(buf))); | |
221 | ASSERT_EQ(-ERANGE, chain_fgetxattr(fd, aname, buf, | |
222 | CHAIN_XATTR_SHORT_BLOCK_LEN*2)); | |
223 | } | |
224 | ||
225 | ::close(fd); | |
226 | ::unlink(file); | |
227 | } | |
228 | ||
229 | void get_vector_from_xattr(vector<string> &xattrs, char* xattr, int size) { | |
230 | char *end = xattr + size; | |
231 | while (xattr < end) { | |
232 | if (*xattr == '\0' ) | |
233 | break; | |
234 | xattrs.push_back(xattr); | |
235 | xattr += strlen(xattr) + 1; | |
236 | } | |
237 | } | |
238 | ||
239 | bool listxattr_cmp(char* xattr1, char* xattr2, int size) { | |
240 | vector<string> xattrs1; | |
241 | vector<string> xattrs2; | |
242 | get_vector_from_xattr(xattrs1, xattr1, size); | |
243 | get_vector_from_xattr(xattrs2, xattr2, size); | |
244 | ||
245 | if (xattrs1.size() != xattrs2.size()) | |
246 | return false; | |
247 | ||
248 | std::sort(xattrs1.begin(), xattrs1.end()); | |
249 | std::sort(xattrs2.begin(), xattrs2.end()); | |
250 | std::vector<string> diff; | |
251 | std::set_difference(xattrs1.begin(), xattrs1.end(), | |
252 | xattrs2.begin(), xattrs2.end(), | |
253 | diff.begin()); | |
254 | ||
255 | return diff.empty(); | |
256 | } | |
257 | ||
258 | TEST(chain_xattr, listxattr) { | |
259 | const char* file = FILENAME; | |
260 | ::unlink(file); | |
261 | int fd = ::open(file, O_CREAT|O_WRONLY|O_TRUNC, 0700); | |
262 | const string user("user."); | |
263 | const string name1 = user + string(CHAIN_XATTR_MAX_NAME_LEN - user.size(), '1'); | |
264 | const string name2 = user + string(CHAIN_XATTR_MAX_NAME_LEN - user.size(), '@'); | |
265 | const string x(LARGE_BLOCK_LEN, 'X'); | |
266 | const int y = 1234; | |
267 | ||
268 | int orig_size = chain_listxattr(file, NULL, 0); | |
269 | char *orig_buffer = NULL; | |
270 | string orig_str; | |
271 | if (orig_size) { | |
272 | orig_buffer = (char*)malloc(orig_size); | |
273 | chain_flistxattr(fd, orig_buffer, orig_size); | |
274 | orig_str = string(orig_buffer); | |
275 | orig_size = orig_str.size(); | |
276 | } | |
277 | ||
278 | ASSERT_EQ(LARGE_BLOCK_LEN, chain_setxattr(file, name1.c_str(), x.c_str(), LARGE_BLOCK_LEN)); | |
279 | ASSERT_EQ((int)sizeof(y), chain_setxattr(file, name2.c_str(), &y, sizeof(y))); | |
280 | ||
281 | int buffer_size = 0; | |
282 | if (orig_size) | |
283 | buffer_size += orig_size + sizeof(char); | |
284 | buffer_size += name1.size() + sizeof(char) + name2.size() + sizeof(char); | |
285 | ||
286 | int index = 0; | |
287 | char* expected = (char*)malloc(buffer_size); | |
288 | ::memset(expected, '\0', buffer_size); | |
289 | if (orig_size) { | |
290 | ::strcpy(expected, orig_str.c_str()); | |
291 | index = orig_size + 1; | |
292 | } | |
293 | ::strcpy(expected + index, name1.c_str()); | |
294 | ::strcpy(expected + index + name1.size() + 1, name2.c_str()); | |
295 | char* actual = (char*)malloc(buffer_size); | |
296 | ::memset(actual, '\0', buffer_size); | |
297 | ASSERT_LT(buffer_size, chain_listxattr(file, NULL, 0)); // size evaluation is conservative | |
298 | chain_listxattr(file, actual, buffer_size); | |
299 | ASSERT_TRUE(listxattr_cmp(expected, actual, buffer_size)); | |
300 | ::memset(actual, '\0', buffer_size); | |
301 | chain_flistxattr(fd, actual, buffer_size); | |
302 | ASSERT_TRUE(listxattr_cmp(expected, actual, buffer_size)); | |
303 | ||
304 | int unlikely_to_be_a_valid_fd = 400; | |
305 | ASSERT_GT(0, chain_listxattr("UNLIKELY_TO_EXIST", actual, 0)); | |
306 | ASSERT_GT(0, chain_listxattr("UNLIKELY_TO_EXIST", actual, buffer_size)); | |
307 | ASSERT_GT(0, chain_flistxattr(unlikely_to_be_a_valid_fd, actual, 0)); | |
308 | ASSERT_GT(0, chain_flistxattr(unlikely_to_be_a_valid_fd, actual, buffer_size)); | |
309 | ASSERT_EQ(-ERANGE, chain_listxattr(file, actual, 1)); | |
310 | ASSERT_EQ(-ERANGE, chain_flistxattr(fd, actual, 1)); | |
311 | ||
312 | ASSERT_EQ(0, chain_removexattr(file, name1.c_str())); | |
313 | ASSERT_EQ(0, chain_removexattr(file, name2.c_str())); | |
314 | ||
315 | free(orig_buffer); | |
316 | free(actual); | |
317 | free(expected); | |
318 | ::unlink(file); | |
319 | } | |
320 | ||
321 | list<string> get_xattrs(int fd) | |
322 | { | |
323 | char _buf[1024]; | |
324 | char *buf = _buf; | |
325 | int len = sys_flistxattr(fd, _buf, sizeof(_buf)); | |
326 | if (len < 0) | |
327 | return list<string>(); | |
328 | list<string> ret; | |
329 | while (len > 0) { | |
330 | size_t next_len = strlen(buf); | |
331 | ret.push_back(string(buf, buf + next_len)); | |
11fdf7f2 | 332 | ceph_assert(len >= (int)(next_len + 1)); |
7c673cae FG |
333 | buf += (next_len + 1); |
334 | len -= (next_len + 1); | |
335 | } | |
336 | return ret; | |
337 | } | |
338 | ||
339 | list<string> get_xattrs(string fn) | |
340 | { | |
341 | int fd = ::open(fn.c_str(), O_RDONLY); | |
342 | if (fd < 0) | |
343 | return list<string>(); | |
344 | auto ret = get_xattrs(fd); | |
345 | ::close(fd); | |
346 | return ret; | |
347 | } | |
348 | ||
349 | TEST(chain_xattr, fskip_chain_cleanup_and_ensure_single_attr) | |
350 | { | |
351 | const char *name = "user.foo"; | |
352 | const char *file = FILENAME; | |
353 | ::unlink(file); | |
354 | int fd = ::open(file, O_CREAT|O_RDWR|O_TRUNC, 0700); | |
11fdf7f2 | 355 | ceph_assert(fd >= 0); |
7c673cae FG |
356 | |
357 | std::size_t existing_xattrs = get_xattrs(fd).size(); | |
358 | char buf[800]; | |
359 | memset(buf, 0x1F, sizeof(buf)); | |
360 | // set chunked without either | |
361 | { | |
362 | std::size_t r = chain_fsetxattr(fd, name, buf, sizeof(buf)); | |
363 | ASSERT_EQ(sizeof(buf), r); | |
364 | ASSERT_GT(get_xattrs(fd).size(), existing_xattrs + 1UL); | |
365 | } | |
366 | ||
367 | // verify | |
368 | { | |
369 | char buf2[sizeof(buf)*2]; | |
370 | std::size_t r = chain_fgetxattr(fd, name, buf2, sizeof(buf2)); | |
371 | ASSERT_EQ(sizeof(buf), r); | |
372 | ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); | |
373 | } | |
374 | ||
375 | // overwrite | |
376 | { | |
377 | std::size_t r = chain_fsetxattr<false, true>(fd, name, buf, sizeof(buf)); | |
378 | ASSERT_EQ(sizeof(buf), r); | |
379 | ASSERT_EQ(existing_xattrs + 1UL, get_xattrs(fd).size()); | |
380 | } | |
381 | ||
382 | // verify | |
383 | { | |
384 | char buf2[sizeof(buf)*2]; | |
385 | std::size_t r = chain_fgetxattr(fd, name, buf2, sizeof(buf2)); | |
386 | ASSERT_EQ(sizeof(buf), r); | |
387 | ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); | |
388 | } | |
389 | ||
390 | ::close(fd); | |
391 | ::unlink(file); | |
392 | } | |
393 | ||
394 | TEST(chain_xattr, skip_chain_cleanup_and_ensure_single_attr) | |
395 | { | |
396 | const char *name = "user.foo"; | |
397 | const char *file = FILENAME; | |
398 | ::unlink(file); | |
399 | int fd = ::open(file, O_CREAT|O_RDWR|O_TRUNC, 0700); | |
11fdf7f2 | 400 | ceph_assert(fd >= 0); |
7c673cae FG |
401 | std::size_t existing_xattrs = get_xattrs(fd).size(); |
402 | ::close(fd); | |
403 | ||
404 | char buf[3000]; | |
405 | memset(buf, 0x1F, sizeof(buf)); | |
406 | // set chunked without either | |
407 | { | |
408 | std::size_t r = chain_setxattr(file, name, buf, sizeof(buf)); | |
409 | ASSERT_EQ(sizeof(buf), r); | |
410 | ASSERT_GT(get_xattrs(file).size(), existing_xattrs + 1UL); | |
411 | } | |
412 | ||
413 | // verify | |
414 | { | |
415 | char buf2[sizeof(buf)*2]; | |
416 | std::size_t r = chain_getxattr(file, name, buf2, sizeof(buf2)); | |
417 | ASSERT_EQ(sizeof(buf), r); | |
418 | ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); | |
419 | } | |
420 | ||
421 | // overwrite | |
422 | { | |
423 | std::size_t r = chain_setxattr<false, true>(file, name, buf, sizeof(buf)); | |
424 | ASSERT_EQ(sizeof(buf), r); | |
425 | ASSERT_EQ(existing_xattrs + 1UL, get_xattrs(file).size()); | |
426 | } | |
427 | ||
428 | // verify | |
429 | { | |
430 | char buf2[sizeof(buf)*2]; | |
431 | std::size_t r = chain_getxattr(file, name, buf2, sizeof(buf2)); | |
432 | ASSERT_EQ(sizeof(buf), r); | |
433 | ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); | |
434 | } | |
435 | ||
436 | ::unlink(file); | |
437 | } | |
438 | ||
439 | int main(int argc, char **argv) { | |
20effc67 | 440 | auto args = argv_to_vec(argc, argv); |
7c673cae | 441 | |
20effc67 | 442 | auto cct = global_init(nullptr, args, CEPH_ENTITY_TYPE_CLIENT, |
11fdf7f2 TL |
443 | CODE_ENVIRONMENT_UTILITY, |
444 | CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); | |
7c673cae | 445 | common_init_finish(g_ceph_context); |
11fdf7f2 TL |
446 | g_ceph_context->_conf.set_val("err_to_stderr", "false"); |
447 | g_ceph_context->_conf.set_val("log_to_stderr", "false"); | |
448 | g_ceph_context->_conf.apply_changes(nullptr); | |
7c673cae FG |
449 | |
450 | const char* file = FILENAME; | |
451 | int x = 1234; | |
452 | int y = 0; | |
453 | int tmpfd = ::open(file, O_CREAT|O_WRONLY|O_TRUNC, 0700); | |
454 | int ret = ::ceph_os_fsetxattr(tmpfd, "user.test", &x, sizeof(x)); | |
455 | if (ret >= 0) | |
456 | ret = ::ceph_os_fgetxattr(tmpfd, "user.test", &y, sizeof(y)); | |
457 | ::close(tmpfd); | |
458 | ::unlink(file); | |
459 | if ((ret < 0) || (x != y)) { | |
460 | cerr << "SKIP all tests because extended attributes don't appear to work in the file system in which the tests are run: " << cpp_strerror(ret) << std::endl; | |
461 | } else { | |
462 | ::testing::InitGoogleTest(&argc, argv); | |
463 | return RUN_ALL_TESTS(); | |
464 | } | |
465 | } | |
466 | ||
467 | // Local Variables: | |
468 | // compile-command: "cd ../.. ; make unittest_chain_xattr ; valgrind --tool=memcheck ./unittest_chain_xattr # --gtest_filter=chain_xattr.get_and_set" | |
469 | // End: |