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