]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/libcephfs/test.cc
a7a6ffc7e1556d7ad81caa05960ecb1322364d10
[ceph.git] / ceph / src / test / libcephfs / test.cc
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) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include "include/compat.h"
16 #include "gtest/gtest.h"
17 #include "include/cephfs/libcephfs.h"
18 #include "include/stat.h"
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <dirent.h>
25 #include <sys/uio.h>
26 #include <sys/time.h>
27 #include <sys/resource.h>
28
29 #include "common/Clock.h"
30
31 #ifdef __linux__
32 #include <limits.h>
33 #include <sys/xattr.h>
34 #endif
35
36 #include <map>
37 #include <vector>
38 #include <thread>
39
40 #ifndef ALLPERMS
41 #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
42 #endif
43
44 TEST(LibCephFS, OpenEmptyComponent) {
45
46 pid_t mypid = getpid();
47 struct ceph_mount_info *cmount;
48 ASSERT_EQ(0, ceph_create(&cmount, NULL));
49 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
50 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
51 ASSERT_EQ(0, ceph_mount(cmount, "/"));
52
53 char c_dir[1024];
54 sprintf(c_dir, "/open_test_%d", mypid);
55 struct ceph_dir_result *dirp;
56
57 ASSERT_EQ(0, ceph_mkdirs(cmount, c_dir, 0777));
58
59 ASSERT_EQ(0, ceph_opendir(cmount, c_dir, &dirp));
60
61 char c_path[1024];
62 sprintf(c_path, "/open_test_%d//created_file_%d", mypid, mypid);
63 int fd = ceph_open(cmount, c_path, O_RDONLY|O_CREAT, 0666);
64 ASSERT_LT(0, fd);
65
66 ASSERT_EQ(0, ceph_close(cmount, fd));
67 ASSERT_EQ(0, ceph_closedir(cmount, dirp));
68 ceph_shutdown(cmount);
69
70 ASSERT_EQ(0, ceph_create(&cmount, NULL));
71 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
72 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
73
74 ASSERT_EQ(0, ceph_mount(cmount, "/"));
75
76 fd = ceph_open(cmount, c_path, O_RDONLY, 0666);
77 ASSERT_LT(0, fd);
78
79 ASSERT_EQ(0, ceph_close(cmount, fd));
80 ceph_shutdown(cmount);
81 }
82
83 TEST(LibCephFS, OpenReadWrite) {
84 struct ceph_mount_info *cmount;
85 ASSERT_EQ(0, ceph_create(&cmount, NULL));
86 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
87 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
88 ASSERT_EQ(0, ceph_mount(cmount, "/"));
89
90 char c_path[1024];
91 sprintf(c_path, "test_open_rdwr_%d", getpid());
92 int fd = ceph_open(cmount, c_path, O_WRONLY|O_CREAT, 0666);
93 ASSERT_LT(0, fd);
94
95 const char *out_buf = "hello world";
96 size_t size = strlen(out_buf);
97 char in_buf[100];
98 ASSERT_EQ(ceph_write(cmount, fd, out_buf, size, 0), (int)size);
99 ASSERT_EQ(ceph_read(cmount, fd, in_buf, sizeof(in_buf), 0), -EBADF);
100 ASSERT_EQ(0, ceph_close(cmount, fd));
101
102 fd = ceph_open(cmount, c_path, O_RDONLY, 0);
103 ASSERT_LT(0, fd);
104 ASSERT_EQ(ceph_write(cmount, fd, out_buf, size, 0), -EBADF);
105 ASSERT_EQ(ceph_read(cmount, fd, in_buf, sizeof(in_buf), 0), (int)size);
106 ASSERT_EQ(0, ceph_close(cmount, fd));
107
108 fd = ceph_open(cmount, c_path, O_RDWR, 0);
109 ASSERT_LT(0, fd);
110 ASSERT_EQ(ceph_write(cmount, fd, out_buf, size, 0), (int)size);
111 ASSERT_EQ(ceph_read(cmount, fd, in_buf, sizeof(in_buf), 0), (int)size);
112 ASSERT_EQ(0, ceph_close(cmount, fd));
113
114 ceph_shutdown(cmount);
115 }
116
117 TEST(LibCephFS, MountNonExist) {
118
119 struct ceph_mount_info *cmount;
120
121 ASSERT_EQ(0, ceph_create(&cmount, NULL));
122 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
123 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
124 ASSERT_NE(0, ceph_mount(cmount, "/non-exist"));
125 ceph_shutdown(cmount);
126 }
127
128 TEST(LibCephFS, MountDouble) {
129
130 struct ceph_mount_info *cmount;
131
132 ASSERT_EQ(0, ceph_create(&cmount, NULL));
133 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
134 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
135 ASSERT_EQ(0, ceph_mount(cmount, "/"));
136 ASSERT_EQ(-EISCONN, ceph_mount(cmount, "/"));
137 ceph_shutdown(cmount);
138 }
139
140 TEST(LibCephFS, MountRemount) {
141
142 struct ceph_mount_info *cmount;
143
144 ASSERT_EQ(0, ceph_create(&cmount, NULL));
145 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
146 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
147
148 CephContext *cct = ceph_get_mount_context(cmount);
149 ASSERT_EQ(0, ceph_mount(cmount, "/"));
150 ASSERT_EQ(0, ceph_unmount(cmount));
151
152 ASSERT_EQ(0, ceph_mount(cmount, "/"));
153 ASSERT_EQ(cct, ceph_get_mount_context(cmount));
154
155 ceph_shutdown(cmount);
156 }
157
158 TEST(LibCephFS, UnmountUnmounted) {
159
160 struct ceph_mount_info *cmount;
161
162 ASSERT_EQ(0, ceph_create(&cmount, NULL));
163 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
164 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
165 ASSERT_EQ(-ENOTCONN, ceph_unmount(cmount));
166 ceph_shutdown(cmount);
167 }
168
169 TEST(LibCephFS, ReleaseUnmounted) {
170
171 struct ceph_mount_info *cmount;
172
173 ASSERT_EQ(0, ceph_create(&cmount, NULL));
174 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
175 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
176 ASSERT_EQ(0, ceph_release(cmount));
177 }
178
179 TEST(LibCephFS, ReleaseMounted) {
180
181 struct ceph_mount_info *cmount;
182
183 ASSERT_EQ(0, ceph_create(&cmount, NULL));
184 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
185 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
186 ASSERT_EQ(0, ceph_mount(cmount, "/"));
187 ASSERT_EQ(-EISCONN, ceph_release(cmount));
188 ASSERT_EQ(0, ceph_unmount(cmount));
189 ASSERT_EQ(0, ceph_release(cmount));
190 }
191
192 TEST(LibCephFS, UnmountRelease) {
193
194 struct ceph_mount_info *cmount;
195
196 ASSERT_EQ(0, ceph_create(&cmount, NULL));
197 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
198 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
199 ASSERT_EQ(0, ceph_mount(cmount, "/"));
200 ASSERT_EQ(0, ceph_unmount(cmount));
201 ASSERT_EQ(0, ceph_release(cmount));
202 }
203
204 TEST(LibCephFS, Mount) {
205 struct ceph_mount_info *cmount;
206 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
207 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
208 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
209 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
210 ceph_shutdown(cmount);
211
212 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
213 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
214 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
215 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
216 ceph_shutdown(cmount);
217 }
218
219 TEST(LibCephFS, OpenLayout) {
220 struct ceph_mount_info *cmount;
221 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
222 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
223 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
224 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
225
226 /* valid layout */
227 char test_layout_file[256];
228 sprintf(test_layout_file, "test_layout_%d_b", getpid());
229 int fd = ceph_open_layout(cmount, test_layout_file, O_CREAT|O_WRONLY, 0666, (1<<20), 7, (1<<20), NULL);
230 ASSERT_GT(fd, 0);
231 char poolname[80];
232 ASSERT_LT(0, ceph_get_file_pool_name(cmount, fd, poolname, sizeof(poolname)));
233 ASSERT_LT(0, ceph_get_file_pool_name(cmount, fd, poolname, 0));
234
235 /* on already-written file (ENOTEMPTY) */
236 ceph_write(cmount, fd, "hello world", 11, 0);
237 ceph_close(cmount, fd);
238
239 char xattrk[128];
240 char xattrv[128];
241 sprintf(xattrk, "ceph.file.layout.stripe_unit");
242 sprintf(xattrv, "65536");
243 ASSERT_EQ(-ENOTEMPTY, ceph_setxattr(cmount, test_layout_file, xattrk, (void *)xattrv, 5, 0));
244
245 /* invalid layout */
246 sprintf(test_layout_file, "test_layout_%d_c", getpid());
247 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 1, 19, NULL);
248 ASSERT_EQ(fd, -EINVAL);
249
250 /* with data pool */
251 sprintf(test_layout_file, "test_layout_%d_d", getpid());
252 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 7, (1<<20), poolname);
253 ASSERT_GT(fd, 0);
254 ceph_close(cmount, fd);
255
256 /* with metadata pool (invalid) */
257 sprintf(test_layout_file, "test_layout_%d_e", getpid());
258 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 7, (1<<20), "metadata");
259 ASSERT_EQ(fd, -EINVAL);
260
261 /* with metadata pool (does not exist) */
262 sprintf(test_layout_file, "test_layout_%d_f", getpid());
263 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 7, (1<<20), "asdfjasdfjasdf");
264 ASSERT_EQ(fd, -EINVAL);
265
266 ceph_shutdown(cmount);
267 }
268
269 TEST(LibCephFS, DirLs) {
270
271 pid_t mypid = getpid();
272
273 struct ceph_mount_info *cmount;
274 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
275 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
276 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
277 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
278
279 struct ceph_dir_result *ls_dir = NULL;
280 char foostr[256];
281 sprintf(foostr, "dir_ls%d", mypid);
282 ASSERT_EQ(ceph_opendir(cmount, foostr, &ls_dir), -ENOENT);
283
284 ASSERT_EQ(ceph_mkdir(cmount, foostr, 0777), 0);
285 struct ceph_statx stx;
286 ASSERT_EQ(ceph_statx(cmount, foostr, &stx, 0, 0), 0);
287 ASSERT_NE(S_ISDIR(stx.stx_mode), 0);
288
289 char barstr[256];
290 sprintf(barstr, "dir_ls2%d", mypid);
291 ASSERT_EQ(ceph_statx(cmount, barstr, &stx, 0, AT_SYMLINK_NOFOLLOW), -ENOENT);
292
293 // insert files into directory and test open
294 char bazstr[256];
295 int i = 0, r = rand() % 4096;
296 if (getenv("LIBCEPHFS_RAND")) {
297 r = atoi(getenv("LIBCEPHFS_RAND"));
298 }
299 printf("rand: %d\n", r);
300 for(; i < r; ++i) {
301
302 sprintf(bazstr, "dir_ls%d/dirf%d", mypid, i);
303 int fd = ceph_open(cmount, bazstr, O_CREAT|O_RDONLY, 0666);
304 ASSERT_GT(fd, 0);
305 ASSERT_EQ(ceph_close(cmount, fd), 0);
306
307 // set file sizes for readdirplus
308 ceph_truncate(cmount, bazstr, i);
309 }
310
311 ASSERT_EQ(ceph_opendir(cmount, foostr, &ls_dir), 0);
312
313 // not guaranteed to get . and .. first, but its a safe assumption in this case
314 struct dirent *result = ceph_readdir(cmount, ls_dir);
315 ASSERT_TRUE(result != NULL);
316 ASSERT_STREQ(result->d_name, ".");
317 result = ceph_readdir(cmount, ls_dir);
318 ASSERT_TRUE(result != NULL);
319 ASSERT_STREQ(result->d_name, "..");
320
321 std::vector<std::string> entries;
322 std::map<std::string, int64_t> offset_map;
323 int64_t offset = ceph_telldir(cmount, ls_dir);
324 for(i = 0; i < r; ++i) {
325 result = ceph_readdir(cmount, ls_dir);
326 ASSERT_TRUE(result != NULL);
327 entries.push_back(result->d_name);
328 offset_map[result->d_name] = offset;
329 offset = ceph_telldir(cmount, ls_dir);
330 }
331
332 ASSERT_TRUE(ceph_readdir(cmount, ls_dir) == NULL);
333 offset = ceph_telldir(cmount, ls_dir);
334
335 ASSERT_EQ(offset_map.size(), entries.size());
336 for(i = 0; i < r; ++i) {
337 sprintf(bazstr, "dirf%d", i);
338 ASSERT_TRUE(offset_map.count(bazstr) == 1);
339 }
340
341 // test seekdir
342 ceph_seekdir(cmount, ls_dir, offset);
343 ASSERT_TRUE(ceph_readdir(cmount, ls_dir) == NULL);
344
345 for (auto p = offset_map.begin(); p != offset_map.end(); ++p) {
346 ceph_seekdir(cmount, ls_dir, p->second);
347 result = ceph_readdir(cmount, ls_dir);
348 ASSERT_TRUE(result != NULL);
349 std::string d_name(result->d_name);
350 ASSERT_EQ(p->first, d_name);
351 }
352
353 // test rewinddir
354 ceph_rewinddir(cmount, ls_dir);
355
356 result = ceph_readdir(cmount, ls_dir);
357 ASSERT_TRUE(result != NULL);
358 ASSERT_STREQ(result->d_name, ".");
359 result = ceph_readdir(cmount, ls_dir);
360 ASSERT_TRUE(result != NULL);
361 ASSERT_STREQ(result->d_name, "..");
362
363 ceph_rewinddir(cmount, ls_dir);
364
365 int t = ceph_telldir(cmount, ls_dir);
366 ASSERT_GT(t, -1);
367
368 ASSERT_TRUE(ceph_readdir(cmount, ls_dir) != NULL);
369
370 // test seekdir - move back to the beginning
371 ceph_seekdir(cmount, ls_dir, t);
372
373 // test getdents
374 struct dirent *getdents_entries;
375 size_t getdents_entries_len = (r + 2) * sizeof(*getdents_entries);
376 getdents_entries = (struct dirent *)malloc(getdents_entries_len);
377
378 int count = 0;
379 std::vector<std::string> found;
380 while (true) {
381 int len = ceph_getdents(cmount, ls_dir, (char *)getdents_entries, getdents_entries_len);
382 if (len == 0)
383 break;
384 ASSERT_GT(len, 0);
385 ASSERT_TRUE((len % sizeof(*getdents_entries)) == 0);
386 int n = len / sizeof(*getdents_entries);
387 int j;
388 if (count == 0) {
389 ASSERT_STREQ(getdents_entries[0].d_name, ".");
390 ASSERT_STREQ(getdents_entries[1].d_name, "..");
391 j = 2;
392 } else {
393 j = 0;
394 }
395 count += n;
396 for(; j < n; ++i, ++j) {
397 const char *name = getdents_entries[j].d_name;
398 found.push_back(name);
399 }
400 }
401 ASSERT_EQ(found, entries);
402 free(getdents_entries);
403
404 // test readdir_r
405 ceph_rewinddir(cmount, ls_dir);
406
407 result = ceph_readdir(cmount, ls_dir);
408 ASSERT_TRUE(result != NULL);
409 ASSERT_STREQ(result->d_name, ".");
410 result = ceph_readdir(cmount, ls_dir);
411 ASSERT_TRUE(result != NULL);
412 ASSERT_STREQ(result->d_name, "..");
413
414 found.clear();
415 while (true) {
416 struct dirent rdent;
417 int len = ceph_readdir_r(cmount, ls_dir, &rdent);
418 if (len == 0)
419 break;
420 ASSERT_EQ(len, 1);
421 found.push_back(rdent.d_name);
422 }
423 ASSERT_EQ(found, entries);
424
425 // test readdirplus
426 ceph_rewinddir(cmount, ls_dir);
427
428 result = ceph_readdir(cmount, ls_dir);
429 ASSERT_TRUE(result != NULL);
430 ASSERT_STREQ(result->d_name, ".");
431 result = ceph_readdir(cmount, ls_dir);
432 ASSERT_TRUE(result != NULL);
433 ASSERT_STREQ(result->d_name, "..");
434
435 found.clear();
436 while (true) {
437 struct dirent rdent;
438 struct ceph_statx stx;
439 int len = ceph_readdirplus_r(cmount, ls_dir, &rdent, &stx,
440 CEPH_STATX_SIZE, AT_NO_ATTR_SYNC, NULL);
441 if (len == 0)
442 break;
443 ASSERT_EQ(len, 1);
444 const char *name = rdent.d_name;
445 found.push_back(name);
446 int size;
447 sscanf(name, "dirf%d", &size);
448 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_SIZE);
449 ASSERT_EQ(stx.stx_size, (size_t)size);
450 ASSERT_EQ(stx.stx_ino, rdent.d_ino);
451 //ASSERT_EQ(st.st_mode, (mode_t)0666);
452 }
453 ASSERT_EQ(found, entries);
454
455 ASSERT_EQ(ceph_closedir(cmount, ls_dir), 0);
456
457 ceph_shutdown(cmount);
458 }
459
460 TEST(LibCephFS, ManyNestedDirs) {
461 struct ceph_mount_info *cmount;
462 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
463 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
464 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
465 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
466
467 const char *many_path = "a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a";
468 ASSERT_EQ(ceph_mkdirs(cmount, many_path, 0755), 0);
469
470 int i = 0;
471
472 for(; i < 39; ++i) {
473 ASSERT_EQ(ceph_chdir(cmount, "a"), 0);
474
475 struct ceph_dir_result *dirp;
476 ASSERT_EQ(ceph_opendir(cmount, "a", &dirp), 0);
477 struct dirent *dent = ceph_readdir(cmount, dirp);
478 ASSERT_TRUE(dent != NULL);
479 ASSERT_STREQ(dent->d_name, ".");
480 dent = ceph_readdir(cmount, dirp);
481 ASSERT_TRUE(dent != NULL);
482 ASSERT_STREQ(dent->d_name, "..");
483 dent = ceph_readdir(cmount, dirp);
484 ASSERT_TRUE(dent != NULL);
485 ASSERT_STREQ(dent->d_name, "a");
486 ASSERT_EQ(ceph_closedir(cmount, dirp), 0);
487 }
488
489 ASSERT_STREQ(ceph_getcwd(cmount), "/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a");
490
491 ASSERT_EQ(ceph_chdir(cmount, "a/a/a"), 0);
492
493 for(i = 0; i < 39; ++i) {
494 ASSERT_EQ(ceph_chdir(cmount, ".."), 0);
495 ASSERT_EQ(ceph_rmdir(cmount, "a"), 0);
496 }
497
498 ASSERT_EQ(ceph_chdir(cmount, "/"), 0);
499
500 ASSERT_EQ(ceph_rmdir(cmount, "a/a/a"), 0);
501
502 ceph_shutdown(cmount);
503 }
504
505 TEST(LibCephFS, Xattrs) {
506 struct ceph_mount_info *cmount;
507 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
508 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
509 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
510 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
511
512 char test_xattr_file[256];
513 sprintf(test_xattr_file, "test_xattr_%d", getpid());
514 int fd = ceph_open(cmount, test_xattr_file, O_CREAT, 0666);
515 ASSERT_GT(fd, 0);
516
517 char i = 'a';
518 char xattrk[128];
519 char xattrv[128];
520 for(; i < 'a'+26; ++i) {
521 sprintf(xattrk, "user.test_xattr_%c", i);
522 int len = sprintf(xattrv, "testxattr%c", i);
523 ASSERT_EQ(ceph_setxattr(cmount, test_xattr_file, xattrk, (void *) xattrv, len, XATTR_CREATE), 0);
524 }
525
526 // zero size should return required buffer length
527 int len_needed = ceph_listxattr(cmount, test_xattr_file, NULL, 0);
528 ASSERT_GT(len_needed, 0);
529
530 // buffer size smaller than needed should fail
531 char xattrlist[128*26];
532 ASSERT_GT(sizeof(xattrlist), (size_t)len_needed);
533 int len = ceph_listxattr(cmount, test_xattr_file, xattrlist, len_needed - 1);
534 ASSERT_EQ(-ERANGE, len);
535
536 len = ceph_listxattr(cmount, test_xattr_file, xattrlist, sizeof(xattrlist));
537 ASSERT_EQ(len, len_needed);
538 char *p = xattrlist;
539 char *n;
540 i = 'a';
541 while (len > 0) {
542 // ceph.* xattrs should not be listed
543 ASSERT_NE(strncmp(p, "ceph.", 5), 0);
544
545 sprintf(xattrk, "user.test_xattr_%c", i);
546 ASSERT_STREQ(p, xattrk);
547
548 char gxattrv[128];
549 std::cout << "getting attr " << p << std::endl;
550 int alen = ceph_getxattr(cmount, test_xattr_file, p, (void *) gxattrv, 128);
551 ASSERT_GT(alen, 0);
552 sprintf(xattrv, "testxattr%c", i);
553 ASSERT_TRUE(!strncmp(xattrv, gxattrv, alen));
554
555 n = index(p, '\0');
556 n++;
557 len -= (n - p);
558 p = n;
559 ++i;
560 }
561
562 i = 'a';
563 for(i = 'a'; i < 'a'+26; ++i) {
564 sprintf(xattrk, "user.test_xattr_%c", i);
565 ASSERT_EQ(ceph_removexattr(cmount, test_xattr_file, xattrk), 0);
566 }
567
568 ceph_close(cmount, fd);
569 ceph_shutdown(cmount);
570
571 }
572
573 TEST(LibCephFS, Xattrs_ll) {
574 struct ceph_mount_info *cmount;
575 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
576 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
577 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
578 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
579
580 char test_xattr_file[256];
581 sprintf(test_xattr_file, "test_xattr_%d", getpid());
582 int fd = ceph_open(cmount, test_xattr_file, O_CREAT, 0666);
583 ASSERT_GT(fd, 0);
584 ceph_close(cmount, fd);
585
586 Inode *root = NULL;
587 Inode *existent_file_handle = NULL;
588
589 int res = ceph_ll_lookup_root(cmount, &root);
590 ASSERT_EQ(res, 0);
591
592 UserPerm *perms = ceph_mount_perms(cmount);
593 struct ceph_statx stx;
594
595 res = ceph_ll_lookup(cmount, root, test_xattr_file, &existent_file_handle,
596 &stx, 0, 0, perms);
597 ASSERT_EQ(res, 0);
598
599 const char *valid_name = "user.attrname";
600 const char *value = "attrvalue";
601 char value_buf[256] = { 0 };
602
603 res = ceph_ll_setxattr(cmount, existent_file_handle, valid_name, value, strlen(value), 0, perms);
604 ASSERT_EQ(res, 0);
605
606 res = ceph_ll_getxattr(cmount, existent_file_handle, valid_name, value_buf, 256, perms);
607 ASSERT_EQ(res, (int)strlen(value));
608
609 value_buf[res] = '\0';
610 ASSERT_STREQ(value_buf, value);
611
612 ceph_shutdown(cmount);
613 }
614
615 TEST(LibCephFS, LstatSlashdot) {
616 struct ceph_mount_info *cmount;
617 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
618 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
619 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
620 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
621
622 struct ceph_statx stx;
623 ASSERT_EQ(ceph_statx(cmount, "/.", &stx, 0, AT_SYMLINK_NOFOLLOW), 0);
624 ASSERT_EQ(ceph_statx(cmount, ".", &stx, 0, AT_SYMLINK_NOFOLLOW), 0);
625
626 ceph_shutdown(cmount);
627 }
628
629 TEST(LibCephFS, StatDirNlink) {
630 struct ceph_mount_info *cmount;
631 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
632 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
633 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
634 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
635
636 char test_dir1[256];
637 sprintf(test_dir1, "dir1_symlinks_%d", getpid());
638 ASSERT_EQ(ceph_mkdir(cmount, test_dir1, 0700), 0);
639
640 int fd = ceph_open(cmount, test_dir1, O_DIRECTORY|O_RDONLY, 0);
641 ASSERT_GT(fd, 0);
642 struct ceph_statx stx;
643 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
644 ASSERT_EQ(stx.stx_nlink, 2u);
645
646 {
647 char test_dir2[296];
648 sprintf(test_dir2, "%s/.", test_dir1);
649 ASSERT_EQ(ceph_statx(cmount, test_dir2, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
650 ASSERT_EQ(stx.stx_nlink, 2u);
651 }
652
653 {
654 char test_dir2[296];
655 sprintf(test_dir2, "%s/1", test_dir1);
656 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0700), 0);
657 ASSERT_EQ(ceph_statx(cmount, test_dir2, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
658 ASSERT_EQ(stx.stx_nlink, 2u);
659 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
660 ASSERT_EQ(stx.stx_nlink, 3u);
661 sprintf(test_dir2, "%s/2", test_dir1);
662 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0700), 0);
663 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
664 ASSERT_EQ(stx.stx_nlink, 4u);
665 sprintf(test_dir2, "%s/1/1", test_dir1);
666 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0700), 0);
667 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
668 ASSERT_EQ(stx.stx_nlink, 4u);
669 ASSERT_EQ(ceph_rmdir(cmount, test_dir2), 0);
670 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
671 ASSERT_EQ(stx.stx_nlink, 4u);
672 sprintf(test_dir2, "%s/1", test_dir1);
673 ASSERT_EQ(ceph_rmdir(cmount, test_dir2), 0);
674 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
675 ASSERT_EQ(stx.stx_nlink, 3u);
676 sprintf(test_dir2, "%s/2", test_dir1);
677 ASSERT_EQ(ceph_rmdir(cmount, test_dir2), 0);
678 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
679 ASSERT_EQ(stx.stx_nlink, 2u);
680 }
681
682 ASSERT_EQ(ceph_rmdir(cmount, test_dir1), 0);
683 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
684 ASSERT_EQ(stx.stx_nlink, 0u);
685
686 ceph_close(cmount, fd);
687
688 ceph_shutdown(cmount);
689 }
690
691 TEST(LibCephFS, DoubleChmod) {
692
693 struct ceph_mount_info *cmount;
694 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
695 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
696 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
697 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
698
699 char test_file[256];
700 sprintf(test_file, "test_perms_%d", getpid());
701
702 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
703 ASSERT_GT(fd, 0);
704
705 // write some stuff
706 const char *bytes = "foobarbaz";
707 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
708
709 ceph_close(cmount, fd);
710
711 // set perms to read but can't write
712 ASSERT_EQ(ceph_chmod(cmount, test_file, 0400), 0);
713
714 fd = ceph_open(cmount, test_file, O_RDWR, 0);
715 ASSERT_EQ(fd, -EACCES);
716
717 fd = ceph_open(cmount, test_file, O_RDONLY, 0);
718 ASSERT_GT(fd, -1);
719
720 char buf[100];
721 int ret = ceph_read(cmount, fd, buf, 100, 0);
722 ASSERT_EQ(ret, (int)strlen(bytes));
723 buf[ret] = '\0';
724 ASSERT_STREQ(buf, bytes);
725
726 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), -EBADF);
727
728 ceph_close(cmount, fd);
729
730 // reset back to writeable
731 ASSERT_EQ(ceph_chmod(cmount, test_file, 0600), 0);
732
733 // ensure perms are correct
734 struct ceph_statx stx;
735 ASSERT_EQ(ceph_statx(cmount, test_file, &stx, CEPH_STATX_MODE, AT_SYMLINK_NOFOLLOW), 0);
736 ASSERT_EQ(stx.stx_mode, 0100600U);
737
738 fd = ceph_open(cmount, test_file, O_RDWR, 0);
739 ASSERT_GT(fd, 0);
740
741 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
742 ceph_close(cmount, fd);
743
744 ceph_shutdown(cmount);
745 }
746
747 TEST(LibCephFS, Fchmod) {
748 struct ceph_mount_info *cmount;
749 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
750 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
751 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
752 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
753
754 char test_file[256];
755 sprintf(test_file, "test_perms_%d", getpid());
756
757 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
758 ASSERT_GT(fd, 0);
759
760 // write some stuff
761 const char *bytes = "foobarbaz";
762 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
763
764 // set perms to read but can't write
765 ASSERT_EQ(ceph_fchmod(cmount, fd, 0400), 0);
766
767 char buf[100];
768 int ret = ceph_read(cmount, fd, buf, 100, 0);
769 ASSERT_EQ(ret, (int)strlen(bytes));
770 buf[ret] = '\0';
771 ASSERT_STREQ(buf, bytes);
772
773 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
774
775 ceph_close(cmount, fd);
776
777 ASSERT_EQ(ceph_open(cmount, test_file, O_RDWR, 0), -EACCES);
778
779 // reset back to writeable
780 ASSERT_EQ(ceph_chmod(cmount, test_file, 0600), 0);
781
782 fd = ceph_open(cmount, test_file, O_RDWR, 0);
783 ASSERT_GT(fd, 0);
784
785 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
786 ceph_close(cmount, fd);
787
788 ceph_shutdown(cmount);
789 }
790
791 TEST(LibCephFS, Fchown) {
792 struct ceph_mount_info *cmount;
793 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
794 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
795 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
796 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
797
798 char test_file[256];
799 sprintf(test_file, "test_fchown_%d", getpid());
800
801 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
802 ASSERT_GT(fd, 0);
803
804 // set perms to readable and writeable only by owner
805 ASSERT_EQ(ceph_fchmod(cmount, fd, 0600), 0);
806
807 // change ownership to nobody -- we assume nobody exists and id is always 65534
808 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "0"), 0);
809 ASSERT_EQ(ceph_fchown(cmount, fd, 65534, 65534), 0);
810 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "1"), 0);
811
812 ceph_close(cmount, fd);
813
814 fd = ceph_open(cmount, test_file, O_RDWR, 0);
815 ASSERT_EQ(fd, -EACCES);
816
817 ceph_shutdown(cmount);
818 }
819
820 #if defined(__linux__) && defined(O_PATH)
821 TEST(LibCephFS, FlagO_PATH) {
822 struct ceph_mount_info *cmount;
823
824 ASSERT_EQ(0, ceph_create(&cmount, NULL));
825 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
826 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
827 ASSERT_EQ(0, ceph_mount(cmount, NULL));
828
829 char test_file[PATH_MAX];
830 sprintf(test_file, "test_oflag_%d", getpid());
831
832 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR|O_PATH, 0666);
833 ASSERT_EQ(-ENOENT, fd);
834
835 fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
836 ASSERT_GT(fd, 0);
837 ASSERT_EQ(0, ceph_close(cmount, fd));
838
839 // ok, the file has been created. perform real checks now
840 fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR|O_PATH, 0666);
841 ASSERT_GT(fd, 0);
842
843 char buf[128];
844 ASSERT_EQ(-EBADF, ceph_read(cmount, fd, buf, sizeof(buf), 0));
845 ASSERT_EQ(-EBADF, ceph_write(cmount, fd, buf, sizeof(buf), 0));
846
847 // set perms to readable and writeable only by owner
848 ASSERT_EQ(-EBADF, ceph_fchmod(cmount, fd, 0600));
849
850 // change ownership to nobody -- we assume nobody exists and id is always 65534
851 ASSERT_EQ(-EBADF, ceph_fchown(cmount, fd, 65534, 65534));
852
853 // try to sync
854 ASSERT_EQ(-EBADF, ceph_fsync(cmount, fd, false));
855
856 struct ceph_statx stx;
857 ASSERT_EQ(0, ceph_fstatx(cmount, fd, &stx, 0, 0));
858
859 ASSERT_EQ(0, ceph_close(cmount, fd));
860 ceph_shutdown(cmount);
861 }
862 #endif /* __linux */
863
864 TEST(LibCephFS, Symlinks) {
865 struct ceph_mount_info *cmount;
866 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
867 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
868 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
869 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
870
871 char test_file[256];
872 sprintf(test_file, "test_symlinks_%d", getpid());
873
874 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
875 ASSERT_GT(fd, 0);
876
877 ceph_close(cmount, fd);
878
879 char test_symlink[256];
880 sprintf(test_symlink, "test_symlinks_sym_%d", getpid());
881
882 ASSERT_EQ(ceph_symlink(cmount, test_file, test_symlink), 0);
883
884 // test the O_NOFOLLOW case
885 fd = ceph_open(cmount, test_symlink, O_NOFOLLOW, 0);
886 ASSERT_EQ(fd, -ELOOP);
887
888 // stat the original file
889 struct ceph_statx stx_orig;
890 ASSERT_EQ(ceph_statx(cmount, test_file, &stx_orig, CEPH_STATX_ALL_STATS, 0), 0);
891 // stat the symlink
892 struct ceph_statx stx_symlink_orig;
893 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx_symlink_orig, CEPH_STATX_ALL_STATS, 0), 0);
894 // ensure the statx bufs are equal
895 ASSERT_EQ(memcmp(&stx_orig, &stx_symlink_orig, sizeof(stx_orig)), 0);
896
897 sprintf(test_file, "/test_symlinks_abs_%d", getpid());
898
899 fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
900 ASSERT_GT(fd, 0);
901
902 ceph_close(cmount, fd);
903
904 sprintf(test_symlink, "/test_symlinks_abs_sym_%d", getpid());
905
906 ASSERT_EQ(ceph_symlink(cmount, test_file, test_symlink), 0);
907
908 // stat the original file
909 ASSERT_EQ(ceph_statx(cmount, test_file, &stx_orig, CEPH_STATX_ALL_STATS, 0), 0);
910 // stat the symlink
911 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx_symlink_orig, CEPH_STATX_ALL_STATS, 0), 0);
912 // ensure the statx bufs are equal
913 ASSERT_TRUE(!memcmp(&stx_orig, &stx_symlink_orig, sizeof(stx_orig)));
914
915 // test lstat
916 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx_orig, CEPH_STATX_ALL_STATS, AT_SYMLINK_NOFOLLOW), 0);
917 ASSERT_TRUE(S_ISLNK(stx_orig.stx_mode));
918
919 ceph_shutdown(cmount);
920 }
921
922 TEST(LibCephFS, DirSyms) {
923 struct ceph_mount_info *cmount;
924 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
925 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
926 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
927 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
928
929 char test_dir1[256];
930 sprintf(test_dir1, "dir1_symlinks_%d", getpid());
931
932 ASSERT_EQ(ceph_mkdir(cmount, test_dir1, 0700), 0);
933
934 char test_symdir[256];
935 sprintf(test_symdir, "symdir_symlinks_%d", getpid());
936
937 ASSERT_EQ(ceph_symlink(cmount, test_dir1, test_symdir), 0);
938
939 char test_file[256];
940 sprintf(test_file, "/symdir_symlinks_%d/test_symdir_file", getpid());
941 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0600);
942 ASSERT_GT(fd, 0);
943 ceph_close(cmount, fd);
944
945 struct ceph_statx stx;
946 ASSERT_EQ(ceph_statx(cmount, test_file, &stx, 0, AT_SYMLINK_NOFOLLOW), 0);
947
948 // ensure that its a file not a directory we get back
949 ASSERT_TRUE(S_ISREG(stx.stx_mode));
950
951 ceph_shutdown(cmount);
952 }
953
954 TEST(LibCephFS, LoopSyms) {
955 struct ceph_mount_info *cmount;
956 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
957 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
958 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
959 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
960
961 char test_dir1[256];
962 sprintf(test_dir1, "dir1_loopsym_%d", getpid());
963
964 ASSERT_EQ(ceph_mkdir(cmount, test_dir1, 0700), 0);
965
966 char test_dir2[256];
967 sprintf(test_dir2, "/dir1_loopsym_%d/loop_dir", getpid());
968
969 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0700), 0);
970
971 // symlink it itself: /path/to/mysym -> /path/to/mysym
972 char test_symdir[256];
973 sprintf(test_symdir, "/dir1_loopsym_%d/loop_dir/symdir", getpid());
974
975 ASSERT_EQ(ceph_symlink(cmount, test_symdir, test_symdir), 0);
976
977 char test_file[256];
978 sprintf(test_file, "/dir1_loopsym_%d/loop_dir/symdir/test_loopsym_file", getpid());
979 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0600);
980 ASSERT_EQ(fd, -ELOOP);
981
982 // loop: /a -> /b, /b -> /c, /c -> /a
983 char a[264], b[264], c[264];
984 sprintf(a, "/%s/a", test_dir1);
985 sprintf(b, "/%s/b", test_dir1);
986 sprintf(c, "/%s/c", test_dir1);
987 ASSERT_EQ(ceph_symlink(cmount, a, b), 0);
988 ASSERT_EQ(ceph_symlink(cmount, b, c), 0);
989 ASSERT_EQ(ceph_symlink(cmount, c, a), 0);
990 ASSERT_EQ(ceph_open(cmount, a, O_RDWR, 0), -ELOOP);
991
992 ceph_shutdown(cmount);
993 }
994
995 TEST(LibCephFS, HardlinkNoOriginal) {
996
997 int mypid = getpid();
998
999 struct ceph_mount_info *cmount;
1000 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1001 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1002 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1003 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1004
1005 char dir[256];
1006 sprintf(dir, "/test_rmdirfail%d", mypid);
1007 ASSERT_EQ(ceph_mkdir(cmount, dir, 0777), 0);
1008
1009 ASSERT_EQ(ceph_chdir(cmount, dir), 0);
1010
1011 int fd = ceph_open(cmount, "f1", O_CREAT, 0644);
1012 ASSERT_GT(fd, 0);
1013
1014 ceph_close(cmount, fd);
1015
1016 // create hard link
1017 ASSERT_EQ(ceph_link(cmount, "f1", "hardl1"), 0);
1018
1019 // remove file link points to
1020 ASSERT_EQ(ceph_unlink(cmount, "f1"), 0);
1021
1022 ceph_shutdown(cmount);
1023
1024 // now cleanup
1025 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1026 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1027 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1028 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1029 ASSERT_EQ(ceph_chdir(cmount, dir), 0);
1030 ASSERT_EQ(ceph_unlink(cmount, "hardl1"), 0);
1031 ASSERT_EQ(ceph_rmdir(cmount, dir), 0);
1032
1033 ceph_shutdown(cmount);
1034 }
1035
1036 TEST(LibCephFS, BadArgument) {
1037 struct ceph_mount_info *cmount;
1038 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1039 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1040 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1041 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1042
1043 int fd = ceph_open(cmount, "test_file", O_CREAT|O_RDWR, 0666);
1044 ASSERT_GT(fd, 0);
1045 char buf[100];
1046 ASSERT_EQ(ceph_write(cmount, fd, buf, sizeof(buf), 0), (int)sizeof(buf));
1047 ASSERT_EQ(ceph_read(cmount, fd, buf, 0, 5), 0);
1048 ceph_close(cmount, fd);
1049 ASSERT_EQ(ceph_unlink(cmount, "test_file"), 0);
1050
1051 ceph_shutdown(cmount);
1052 }
1053
1054 TEST(LibCephFS, BadFileDesc) {
1055 struct ceph_mount_info *cmount;
1056 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1057 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1058 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1059 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1060
1061 ASSERT_EQ(ceph_fchmod(cmount, -1, 0655), -EBADF);
1062 ASSERT_EQ(ceph_close(cmount, -1), -EBADF);
1063 ASSERT_EQ(ceph_lseek(cmount, -1, 0, SEEK_SET), -EBADF);
1064
1065 char buf[0];
1066 ASSERT_EQ(ceph_read(cmount, -1, buf, 0, 0), -EBADF);
1067 ASSERT_EQ(ceph_write(cmount, -1, buf, 0, 0), -EBADF);
1068
1069 ASSERT_EQ(ceph_ftruncate(cmount, -1, 0), -EBADF);
1070 ASSERT_EQ(ceph_fsync(cmount, -1, 0), -EBADF);
1071
1072 struct ceph_statx stx;
1073 ASSERT_EQ(ceph_fstatx(cmount, -1, &stx, 0, 0), -EBADF);
1074
1075 struct sockaddr_storage addr;
1076 ASSERT_EQ(ceph_get_file_stripe_address(cmount, -1, 0, &addr, 1), -EBADF);
1077
1078 ASSERT_EQ(ceph_get_file_stripe_unit(cmount, -1), -EBADF);
1079 ASSERT_EQ(ceph_get_file_pool(cmount, -1), -EBADF);
1080 char poolname[80];
1081 ASSERT_EQ(ceph_get_file_pool_name(cmount, -1, poolname, sizeof(poolname)), -EBADF);
1082 ASSERT_EQ(ceph_get_file_replication(cmount, -1), -EBADF);
1083 ASSERT_EQ(ceph_get_file_object_size(cmount, -1), -EBADF);
1084 int stripe_unit, stripe_count, object_size, pg_pool;
1085 ASSERT_EQ(ceph_get_file_layout(cmount, -1, &stripe_unit, &stripe_count, &object_size, &pg_pool), -EBADF);
1086 ASSERT_EQ(ceph_get_file_stripe_count(cmount, -1), -EBADF);
1087
1088 ceph_shutdown(cmount);
1089 }
1090
1091 TEST(LibCephFS, ReadEmptyFile) {
1092 struct ceph_mount_info *cmount;
1093 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1094 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1095 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1096 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1097
1098 // test the read_sync path in the client for zero files
1099 ASSERT_EQ(ceph_conf_set(cmount, "client_debug_force_sync_read", "true"), 0);
1100
1101 int mypid = getpid();
1102 char testf[256];
1103
1104 sprintf(testf, "test_reademptyfile%d", mypid);
1105 int fd = ceph_open(cmount, testf, O_CREAT|O_TRUNC|O_WRONLY, 0644);
1106 ASSERT_GT(fd, 0);
1107
1108 ceph_close(cmount, fd);
1109
1110 fd = ceph_open(cmount, testf, O_RDONLY, 0);
1111 ASSERT_GT(fd, 0);
1112
1113 char buf[4096];
1114 ASSERT_EQ(ceph_read(cmount, fd, buf, 4096, 0), 0);
1115
1116 ceph_close(cmount, fd);
1117 ceph_shutdown(cmount);
1118 }
1119
1120 TEST(LibCephFS, PreadvPwritev) {
1121 struct ceph_mount_info *cmount;
1122 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1123 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1124 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1125 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1126
1127 int mypid = getpid();
1128 char testf[256];
1129
1130 sprintf(testf, "test_preadvpwritevfile%d", mypid);
1131 int fd = ceph_open(cmount, testf, O_CREAT|O_RDWR, 0666);
1132 ASSERT_GT(fd, 0);
1133
1134 char out0[] = "hello ";
1135 char out1[] = "world\n";
1136 struct iovec iov_out[2] = {
1137 {out0, sizeof(out0)},
1138 {out1, sizeof(out1)},
1139 };
1140 char in0[sizeof(out0)];
1141 char in1[sizeof(out1)];
1142 struct iovec iov_in[2] = {
1143 {in0, sizeof(in0)},
1144 {in1, sizeof(in1)},
1145 };
1146 ssize_t nwritten = iov_out[0].iov_len + iov_out[1].iov_len;
1147 ssize_t nread = iov_in[0].iov_len + iov_in[1].iov_len;
1148
1149 ASSERT_EQ(ceph_pwritev(cmount, fd, iov_out, 2, 0), nwritten);
1150 ASSERT_EQ(ceph_preadv(cmount, fd, iov_in, 2, 0), nread);
1151 ASSERT_EQ(0, strncmp((const char*)iov_in[0].iov_base, (const char*)iov_out[0].iov_base, iov_out[0].iov_len));
1152 ASSERT_EQ(0, strncmp((const char*)iov_in[1].iov_base, (const char*)iov_out[1].iov_base, iov_out[1].iov_len));
1153
1154 ceph_close(cmount, fd);
1155 ceph_shutdown(cmount);
1156 }
1157
1158 TEST(LibCephFS, LlreadvLlwritev) {
1159 struct ceph_mount_info *cmount;
1160 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1161 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1162 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1163 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1164
1165 int mypid = getpid();
1166 char filename[256];
1167
1168 sprintf(filename, "test_llreadvllwritevfile%u", mypid);
1169
1170 Inode *root, *file;
1171 ASSERT_EQ(ceph_ll_lookup_root(cmount, &root), 0);
1172
1173 Fh *fh;
1174 struct ceph_statx stx;
1175 UserPerm *perms = ceph_mount_perms(cmount);
1176
1177 ASSERT_EQ(ceph_ll_create(cmount, root, filename, 0666,
1178 O_RDWR|O_CREAT|O_TRUNC, &file, &fh, &stx, 0, 0, perms), 0);
1179
1180 /* Reopen read-only */
1181 char out0[] = "hello ";
1182 char out1[] = "world\n";
1183 struct iovec iov_out[2] = {
1184 {out0, sizeof(out0)},
1185 {out1, sizeof(out1)},
1186 };
1187 char in0[sizeof(out0)];
1188 char in1[sizeof(out1)];
1189 struct iovec iov_in[2] = {
1190 {in0, sizeof(in0)},
1191 {in1, sizeof(in1)},
1192 };
1193 ssize_t nwritten = iov_out[0].iov_len + iov_out[1].iov_len;
1194 ssize_t nread = iov_in[0].iov_len + iov_in[1].iov_len;
1195
1196 ASSERT_EQ(ceph_ll_writev(cmount, fh, iov_out, 2, 0), nwritten);
1197 ASSERT_EQ(ceph_ll_readv(cmount, fh, iov_in, 2, 0), nread);
1198 ASSERT_EQ(0, strncmp((const char*)iov_in[0].iov_base, (const char*)iov_out[0].iov_base, iov_out[0].iov_len));
1199 ASSERT_EQ(0, strncmp((const char*)iov_in[1].iov_base, (const char*)iov_out[1].iov_base, iov_out[1].iov_len));
1200
1201 ceph_ll_close(cmount, fh);
1202 ceph_shutdown(cmount);
1203 }
1204
1205 TEST(LibCephFS, StripeUnitGran) {
1206 struct ceph_mount_info *cmount;
1207 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1208 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1209 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1210 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1211 ASSERT_GT(ceph_get_stripe_unit_granularity(cmount), 0);
1212 ceph_shutdown(cmount);
1213 }
1214
1215 TEST(LibCephFS, Rename) {
1216 struct ceph_mount_info *cmount;
1217 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1218 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1219 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1220 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1221
1222 int mypid = getpid();
1223 char path_src[256];
1224 char path_dst[256];
1225
1226 /* make a source file */
1227 sprintf(path_src, "test_rename_src%d", mypid);
1228 int fd = ceph_open(cmount, path_src, O_CREAT|O_TRUNC|O_WRONLY, 0777);
1229 ASSERT_GT(fd, 0);
1230 ASSERT_EQ(0, ceph_close(cmount, fd));
1231
1232 /* rename to a new dest path */
1233 sprintf(path_dst, "test_rename_dst%d", mypid);
1234 ASSERT_EQ(0, ceph_rename(cmount, path_src, path_dst));
1235
1236 /* test that dest path exists */
1237 struct ceph_statx stx;
1238 ASSERT_EQ(0, ceph_statx(cmount, path_dst, &stx, 0, 0));
1239
1240 /* test that src path doesn't exist */
1241 ASSERT_EQ(-ENOENT, ceph_statx(cmount, path_src, &stx, 0, AT_SYMLINK_NOFOLLOW));
1242
1243 /* rename with non-existent source path */
1244 ASSERT_EQ(-ENOENT, ceph_rename(cmount, path_src, path_dst));
1245
1246 ASSERT_EQ(0, ceph_unlink(cmount, path_dst));
1247 ceph_shutdown(cmount);
1248 }
1249
1250 TEST(LibCephFS, UseUnmounted) {
1251 struct ceph_mount_info *cmount;
1252 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1253 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1254 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1255
1256 struct statvfs stvfs;
1257 EXPECT_EQ(-ENOTCONN, ceph_statfs(cmount, "/", &stvfs));
1258 EXPECT_EQ(-ENOTCONN, ceph_get_local_osd(cmount));
1259 EXPECT_EQ(-ENOTCONN, ceph_chdir(cmount, "/"));
1260
1261 struct ceph_dir_result *dirp;
1262 EXPECT_EQ(-ENOTCONN, ceph_opendir(cmount, "/", &dirp));
1263 EXPECT_EQ(-ENOTCONN, ceph_closedir(cmount, dirp));
1264
1265 ceph_readdir(cmount, dirp);
1266 EXPECT_EQ(ENOTCONN, errno);
1267
1268 struct dirent rdent;
1269 EXPECT_EQ(-ENOTCONN, ceph_readdir_r(cmount, dirp, &rdent));
1270
1271 struct ceph_statx stx;
1272 EXPECT_EQ(-ENOTCONN, ceph_readdirplus_r(cmount, dirp, &rdent, &stx, 0, 0, NULL));
1273 EXPECT_EQ(-ENOTCONN, ceph_getdents(cmount, dirp, NULL, 0));
1274 EXPECT_EQ(-ENOTCONN, ceph_getdnames(cmount, dirp, NULL, 0));
1275 EXPECT_EQ(-ENOTCONN, ceph_telldir(cmount, dirp));
1276 EXPECT_EQ(-ENOTCONN, ceph_link(cmount, "/", "/link"));
1277 EXPECT_EQ(-ENOTCONN, ceph_unlink(cmount, "/path"));
1278 EXPECT_EQ(-ENOTCONN, ceph_rename(cmount, "/path", "/path"));
1279 EXPECT_EQ(-ENOTCONN, ceph_mkdir(cmount, "/", 0655));
1280 EXPECT_EQ(-ENOTCONN, ceph_mkdirs(cmount, "/", 0655));
1281 EXPECT_EQ(-ENOTCONN, ceph_rmdir(cmount, "/path"));
1282 EXPECT_EQ(-ENOTCONN, ceph_readlink(cmount, "/path", NULL, 0));
1283 EXPECT_EQ(-ENOTCONN, ceph_symlink(cmount, "/path", "/path"));
1284 EXPECT_EQ(-ENOTCONN, ceph_statx(cmount, "/path", &stx, 0, 0));
1285 EXPECT_EQ(-ENOTCONN, ceph_setattrx(cmount, "/path", &stx, 0, 0));
1286 EXPECT_EQ(-ENOTCONN, ceph_getxattr(cmount, "/path", "name", NULL, 0));
1287 EXPECT_EQ(-ENOTCONN, ceph_lgetxattr(cmount, "/path", "name", NULL, 0));
1288 EXPECT_EQ(-ENOTCONN, ceph_listxattr(cmount, "/path", NULL, 0));
1289 EXPECT_EQ(-ENOTCONN, ceph_llistxattr(cmount, "/path", NULL, 0));
1290 EXPECT_EQ(-ENOTCONN, ceph_removexattr(cmount, "/path", "name"));
1291 EXPECT_EQ(-ENOTCONN, ceph_lremovexattr(cmount, "/path", "name"));
1292 EXPECT_EQ(-ENOTCONN, ceph_setxattr(cmount, "/path", "name", NULL, 0, 0));
1293 EXPECT_EQ(-ENOTCONN, ceph_lsetxattr(cmount, "/path", "name", NULL, 0, 0));
1294 EXPECT_EQ(-ENOTCONN, ceph_fsetattrx(cmount, 0, &stx, 0));
1295 EXPECT_EQ(-ENOTCONN, ceph_chmod(cmount, "/path", 0));
1296 EXPECT_EQ(-ENOTCONN, ceph_fchmod(cmount, 0, 0));
1297 EXPECT_EQ(-ENOTCONN, ceph_chown(cmount, "/path", 0, 0));
1298 EXPECT_EQ(-ENOTCONN, ceph_lchown(cmount, "/path", 0, 0));
1299 EXPECT_EQ(-ENOTCONN, ceph_fchown(cmount, 0, 0, 0));
1300
1301 struct utimbuf utb;
1302 EXPECT_EQ(-ENOTCONN, ceph_utime(cmount, "/path", &utb));
1303 EXPECT_EQ(-ENOTCONN, ceph_truncate(cmount, "/path", 0));
1304 EXPECT_EQ(-ENOTCONN, ceph_mknod(cmount, "/path", 0, 0));
1305 EXPECT_EQ(-ENOTCONN, ceph_open(cmount, "/path", 0, 0));
1306 EXPECT_EQ(-ENOTCONN, ceph_open_layout(cmount, "/path", 0, 0, 0, 0, 0, "pool"));
1307 EXPECT_EQ(-ENOTCONN, ceph_close(cmount, 0));
1308 EXPECT_EQ(-ENOTCONN, ceph_lseek(cmount, 0, 0, SEEK_SET));
1309 EXPECT_EQ(-ENOTCONN, ceph_read(cmount, 0, NULL, 0, 0));
1310 EXPECT_EQ(-ENOTCONN, ceph_write(cmount, 0, NULL, 0, 0));
1311 EXPECT_EQ(-ENOTCONN, ceph_ftruncate(cmount, 0, 0));
1312 EXPECT_EQ(-ENOTCONN, ceph_fsync(cmount, 0, 0));
1313 EXPECT_EQ(-ENOTCONN, ceph_fstatx(cmount, 0, &stx, 0, 0));
1314 EXPECT_EQ(-ENOTCONN, ceph_sync_fs(cmount));
1315 EXPECT_EQ(-ENOTCONN, ceph_get_file_stripe_unit(cmount, 0));
1316 EXPECT_EQ(-ENOTCONN, ceph_get_file_stripe_count(cmount, 0));
1317 EXPECT_EQ(-ENOTCONN, ceph_get_file_layout(cmount, 0, NULL, NULL ,NULL ,NULL));
1318 EXPECT_EQ(-ENOTCONN, ceph_get_file_object_size(cmount, 0));
1319 EXPECT_EQ(-ENOTCONN, ceph_get_file_pool(cmount, 0));
1320 EXPECT_EQ(-ENOTCONN, ceph_get_file_pool_name(cmount, 0, NULL, 0));
1321 EXPECT_EQ(-ENOTCONN, ceph_get_file_replication(cmount, 0));
1322 EXPECT_EQ(-ENOTCONN, ceph_get_path_replication(cmount, "/path"));
1323 EXPECT_EQ(-ENOTCONN, ceph_get_path_layout(cmount, "/path", NULL, NULL, NULL, NULL));
1324 EXPECT_EQ(-ENOTCONN, ceph_get_path_object_size(cmount, "/path"));
1325 EXPECT_EQ(-ENOTCONN, ceph_get_path_stripe_count(cmount, "/path"));
1326 EXPECT_EQ(-ENOTCONN, ceph_get_path_stripe_unit(cmount, "/path"));
1327 EXPECT_EQ(-ENOTCONN, ceph_get_path_pool(cmount, "/path"));
1328 EXPECT_EQ(-ENOTCONN, ceph_get_path_pool_name(cmount, "/path", NULL, 0));
1329 EXPECT_EQ(-ENOTCONN, ceph_get_pool_name(cmount, 0, NULL, 0));
1330 EXPECT_EQ(-ENOTCONN, ceph_get_file_stripe_address(cmount, 0, 0, NULL, 0));
1331 EXPECT_EQ(-ENOTCONN, ceph_localize_reads(cmount, 0));
1332 EXPECT_EQ(-ENOTCONN, ceph_debug_get_fd_caps(cmount, 0));
1333 EXPECT_EQ(-ENOTCONN, ceph_debug_get_file_caps(cmount, "/path"));
1334 EXPECT_EQ(-ENOTCONN, ceph_get_stripe_unit_granularity(cmount));
1335 EXPECT_EQ(-ENOTCONN, ceph_get_pool_id(cmount, "data"));
1336 EXPECT_EQ(-ENOTCONN, ceph_get_pool_replication(cmount, 1));
1337
1338 ceph_release(cmount);
1339 }
1340
1341 TEST(LibCephFS, GetPoolId) {
1342 struct ceph_mount_info *cmount;
1343 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1344 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1345 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1346 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1347
1348 char name[80];
1349 memset(name, 0, sizeof(name));
1350 ASSERT_LE(0, ceph_get_path_pool_name(cmount, "/", name, sizeof(name)));
1351 ASSERT_GE(ceph_get_pool_id(cmount, name), 0);
1352 ASSERT_EQ(ceph_get_pool_id(cmount, "weflkjwelfjwlkejf"), -ENOENT);
1353
1354 ceph_shutdown(cmount);
1355 }
1356
1357 TEST(LibCephFS, GetPoolReplication) {
1358 struct ceph_mount_info *cmount;
1359 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1360 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1361 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1362 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1363
1364 /* negative pools */
1365 ASSERT_EQ(ceph_get_pool_replication(cmount, -10), -ENOENT);
1366
1367 /* valid pool */
1368 int pool_id;
1369 int stripe_unit, stripe_count, object_size;
1370 ASSERT_EQ(0, ceph_get_path_layout(cmount, "/", &stripe_unit, &stripe_count,
1371 &object_size, &pool_id));
1372 ASSERT_GE(pool_id, 0);
1373 ASSERT_GT(ceph_get_pool_replication(cmount, pool_id), 0);
1374
1375 ceph_shutdown(cmount);
1376 }
1377
1378 TEST(LibCephFS, GetExtentOsds) {
1379 struct ceph_mount_info *cmount;
1380 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1381
1382 EXPECT_EQ(-ENOTCONN, ceph_get_file_extent_osds(cmount, 0, 0, NULL, NULL, 0));
1383
1384 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1385 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1386 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1387
1388 int stripe_unit = (1<<18);
1389
1390 /* make a file! */
1391 char test_file[256];
1392 sprintf(test_file, "test_extent_osds_%d", getpid());
1393 int fd = ceph_open_layout(cmount, test_file, O_CREAT|O_RDWR, 0666,
1394 stripe_unit, 2, stripe_unit*2, NULL);
1395 ASSERT_GT(fd, 0);
1396
1397 /* get back how many osds > 0 */
1398 int ret = ceph_get_file_extent_osds(cmount, fd, 0, NULL, NULL, 0);
1399 EXPECT_GT(ret, 0);
1400
1401 int64_t len;
1402 int osds[ret];
1403
1404 /* full stripe extent */
1405 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 0, &len, osds, ret));
1406 EXPECT_EQ(len, (int64_t)stripe_unit);
1407
1408 /* half stripe extent */
1409 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, stripe_unit/2, &len, osds, ret));
1410 EXPECT_EQ(len, (int64_t)stripe_unit/2);
1411
1412 /* 1.5 stripe unit offset -1 byte */
1413 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 3*stripe_unit/2-1, &len, osds, ret));
1414 EXPECT_EQ(len, (int64_t)stripe_unit/2+1);
1415
1416 /* 1.5 stripe unit offset +1 byte */
1417 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 3*stripe_unit/2+1, &len, osds, ret));
1418 EXPECT_EQ(len, (int64_t)stripe_unit/2-1);
1419
1420 /* only when more than 1 osd */
1421 if (ret > 1) {
1422 EXPECT_EQ(-ERANGE, ceph_get_file_extent_osds(cmount, fd, 0, NULL, osds, 1));
1423 }
1424
1425 ceph_close(cmount, fd);
1426
1427 ceph_shutdown(cmount);
1428 }
1429
1430 TEST(LibCephFS, GetOsdCrushLocation) {
1431 struct ceph_mount_info *cmount;
1432 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1433
1434 EXPECT_EQ(-ENOTCONN, ceph_get_osd_crush_location(cmount, 0, NULL, 0));
1435
1436 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1437 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1438 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1439
1440 ASSERT_EQ(ceph_get_osd_crush_location(cmount, 0, NULL, 1), -EINVAL);
1441
1442 char path[256];
1443 ASSERT_EQ(ceph_get_osd_crush_location(cmount, 9999999, path, 0), -ENOENT);
1444 ASSERT_EQ(ceph_get_osd_crush_location(cmount, -1, path, 0), -EINVAL);
1445
1446 char test_file[256];
1447 sprintf(test_file, "test_osds_loc_%d", getpid());
1448 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
1449 ASSERT_GT(fd, 0);
1450
1451 /* get back how many osds > 0 */
1452 int ret = ceph_get_file_extent_osds(cmount, fd, 0, NULL, NULL, 0);
1453 EXPECT_GT(ret, 0);
1454
1455 /* full stripe extent */
1456 int osds[ret];
1457 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 0, NULL, osds, ret));
1458
1459 ASSERT_GT(ceph_get_osd_crush_location(cmount, 0, path, 0), 0);
1460 ASSERT_EQ(ceph_get_osd_crush_location(cmount, 0, path, 1), -ERANGE);
1461
1462 for (int i = 0; i < ret; i++) {
1463 int len = ceph_get_osd_crush_location(cmount, osds[i], path, sizeof(path));
1464 ASSERT_GT(len, 0);
1465 int pos = 0;
1466 while (pos < len) {
1467 std::string type(path + pos);
1468 ASSERT_GT((int)type.size(), 0);
1469 pos += type.size() + 1;
1470
1471 std::string name(path + pos);
1472 ASSERT_GT((int)name.size(), 0);
1473 pos += name.size() + 1;
1474 }
1475 }
1476
1477 ceph_close(cmount, fd);
1478 ceph_shutdown(cmount);
1479 }
1480
1481 TEST(LibCephFS, GetOsdAddr) {
1482 struct ceph_mount_info *cmount;
1483 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1484
1485 EXPECT_EQ(-ENOTCONN, ceph_get_osd_addr(cmount, 0, NULL));
1486
1487 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1488 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1489 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1490
1491 ASSERT_EQ(-EINVAL, ceph_get_osd_addr(cmount, 0, NULL));
1492
1493 struct sockaddr_storage addr;
1494 ASSERT_EQ(-ENOENT, ceph_get_osd_addr(cmount, -1, &addr));
1495 ASSERT_EQ(-ENOENT, ceph_get_osd_addr(cmount, 9999999, &addr));
1496
1497 ASSERT_EQ(0, ceph_get_osd_addr(cmount, 0, &addr));
1498
1499 ceph_shutdown(cmount);
1500 }
1501
1502 TEST(LibCephFS, OpenNoClose) {
1503 struct ceph_mount_info *cmount;
1504 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1505 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1506 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1507 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1508
1509 pid_t mypid = getpid();
1510 char str_buf[256];
1511 sprintf(str_buf, "open_no_close_dir%d", mypid);
1512 ASSERT_EQ(0, ceph_mkdirs(cmount, str_buf, 0777));
1513
1514 struct ceph_dir_result *ls_dir = NULL;
1515 ASSERT_EQ(ceph_opendir(cmount, str_buf, &ls_dir), 0);
1516
1517 sprintf(str_buf, "open_no_close_file%d", mypid);
1518 int fd = ceph_open(cmount, str_buf, O_RDONLY|O_CREAT, 0666);
1519 ASSERT_LT(0, fd);
1520
1521 // shutdown should force close opened file/dir
1522 ceph_shutdown(cmount);
1523 }
1524
1525 TEST(LibCephFS, Nlink) {
1526 struct ceph_mount_info *cmount;
1527 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1528 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1529 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1530 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1531
1532 Inode *root, *dir, *file;
1533
1534 ASSERT_EQ(ceph_ll_lookup_root(cmount, &root), 0);
1535
1536 char dirname[32], filename[32], linkname[32];
1537 sprintf(dirname, "nlinkdir%x", getpid());
1538 sprintf(filename, "nlinkorig%x", getpid());
1539 sprintf(linkname, "nlinklink%x", getpid());
1540
1541 struct ceph_statx stx;
1542 Fh *fh;
1543 UserPerm *perms = ceph_mount_perms(cmount);
1544
1545 ASSERT_EQ(ceph_ll_mkdir(cmount, root, dirname, 0755, &dir, &stx, 0, 0, perms), 0);
1546 ASSERT_EQ(ceph_ll_create(cmount, dir, filename, 0666, O_RDWR|O_CREAT|O_EXCL,
1547 &file, &fh, &stx, CEPH_STATX_NLINK, 0, perms), 0);
1548 ASSERT_EQ(ceph_ll_close(cmount, fh), 0);
1549 ASSERT_EQ(stx.stx_nlink, (nlink_t)1);
1550
1551 ASSERT_EQ(ceph_ll_link(cmount, file, dir, linkname, perms), 0);
1552 ASSERT_EQ(ceph_ll_getattr(cmount, file, &stx, CEPH_STATX_NLINK, 0, perms), 0);
1553 ASSERT_EQ(stx.stx_nlink, (nlink_t)2);
1554
1555 ASSERT_EQ(ceph_ll_unlink(cmount, dir, linkname, perms), 0);
1556 ASSERT_EQ(ceph_ll_lookup(cmount, dir, filename, &file, &stx,
1557 CEPH_STATX_NLINK, 0, perms), 0);
1558 ASSERT_EQ(stx.stx_nlink, (nlink_t)1);
1559
1560 ceph_shutdown(cmount);
1561 }
1562
1563 TEST(LibCephFS, SlashDotDot) {
1564 struct ceph_mount_info *cmount;
1565 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1566 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1567 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1568 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1569
1570 struct ceph_statx stx;
1571 ASSERT_EQ(ceph_statx(cmount, "/.", &stx, CEPH_STATX_INO, 0), 0);
1572
1573 ino_t ino = stx.stx_ino;
1574 ASSERT_EQ(ceph_statx(cmount, "/..", &stx, CEPH_STATX_INO, 0), 0);
1575
1576 /* At root, "." and ".." should be the same inode */
1577 ASSERT_EQ(ino, stx.stx_ino);
1578
1579 /* Test accessing the parent of an unlinked directory */
1580 char dir1[32], dir2[56];
1581 sprintf(dir1, "/sldotdot%x", getpid());
1582 sprintf(dir2, "%s/sub%x", dir1, getpid());
1583
1584 ASSERT_EQ(ceph_mkdir(cmount, dir1, 0755), 0);
1585 ASSERT_EQ(ceph_mkdir(cmount, dir2, 0755), 0);
1586
1587 ASSERT_EQ(ceph_chdir(cmount, dir2), 0);
1588
1589 /* Test behavior when unlinking cwd */
1590 struct ceph_dir_result *rdir;
1591 ASSERT_EQ(ceph_opendir(cmount, ".", &rdir), 0);
1592 ASSERT_EQ(ceph_rmdir(cmount, dir2), 0);
1593
1594 /* get "." entry */
1595 struct dirent *result = ceph_readdir(cmount, rdir);
1596 ino = result->d_ino;
1597
1598 /* get ".." entry */
1599 result = ceph_readdir(cmount, rdir);
1600 ASSERT_EQ(ino, result->d_ino);
1601 ceph_closedir(cmount, rdir);
1602
1603 /* Make sure it works same way when mounting subtree */
1604 ASSERT_EQ(ceph_unmount(cmount), 0);
1605 ASSERT_EQ(ceph_mount(cmount, dir1), 0);
1606 ASSERT_EQ(ceph_statx(cmount, "/..", &stx, CEPH_STATX_INO, 0), 0);
1607
1608 /* Test readdir behavior */
1609 ASSERT_EQ(ceph_opendir(cmount, "/", &rdir), 0);
1610 result = ceph_readdir(cmount, rdir);
1611 ASSERT_TRUE(result != NULL);
1612 ASSERT_STREQ(result->d_name, ".");
1613 ino = result->d_ino;
1614 result = ceph_readdir(cmount, rdir);
1615 ASSERT_TRUE(result != NULL);
1616 ASSERT_STREQ(result->d_name, "..");
1617 ASSERT_EQ(ino, result->d_ino);
1618
1619 ceph_shutdown(cmount);
1620 }
1621
1622 static inline bool
1623 timespec_eq(timespec const& lhs, timespec const& rhs)
1624 {
1625 return lhs.tv_sec == rhs.tv_sec && lhs.tv_nsec == rhs.tv_nsec;
1626 }
1627
1628 TEST(LibCephFS, Btime) {
1629 struct ceph_mount_info *cmount;
1630 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1631 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1632 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1633 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1634
1635 char filename[32];
1636 sprintf(filename, "/getattrx%x", getpid());
1637
1638 ceph_unlink(cmount, filename);
1639 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1640 ASSERT_LT(0, fd);
1641
1642 /* make sure fstatx works */
1643 struct ceph_statx stx;
1644
1645 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_CTIME|CEPH_STATX_BTIME, 0), 0);
1646 ASSERT_TRUE(stx.stx_mask & (CEPH_STATX_CTIME|CEPH_STATX_BTIME));
1647 ASSERT_TRUE(timespec_eq(stx.stx_ctime, stx.stx_btime));
1648 ceph_close(cmount, fd);
1649
1650 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_CTIME|CEPH_STATX_BTIME, 0), 0);
1651 ASSERT_TRUE(timespec_eq(stx.stx_ctime, stx.stx_btime));
1652 ASSERT_TRUE(stx.stx_mask & (CEPH_STATX_CTIME|CEPH_STATX_BTIME));
1653
1654 struct timespec old_btime = stx.stx_btime;
1655
1656 /* Now sleep, do a chmod and verify that the ctime changed, but btime didn't */
1657 sleep(1);
1658 ASSERT_EQ(ceph_chmod(cmount, filename, 0644), 0);
1659 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_CTIME|CEPH_STATX_BTIME, 0), 0);
1660 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_BTIME);
1661 ASSERT_TRUE(timespec_eq(stx.stx_btime, old_btime));
1662 ASSERT_FALSE(timespec_eq(stx.stx_ctime, stx.stx_btime));
1663
1664 ceph_shutdown(cmount);
1665 }
1666
1667 TEST(LibCephFS, SetBtime) {
1668 struct ceph_mount_info *cmount;
1669 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1670 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1671 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1672 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1673
1674 char filename[32];
1675 sprintf(filename, "/setbtime%x", getpid());
1676
1677 ceph_unlink(cmount, filename);
1678 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1679 ASSERT_LT(0, fd);
1680 ceph_close(cmount, fd);
1681
1682 struct ceph_statx stx;
1683 struct timespec old_btime = { 1, 2 };
1684
1685 stx.stx_btime = old_btime;
1686
1687 ASSERT_EQ(ceph_setattrx(cmount, filename, &stx, CEPH_SETATTR_BTIME, 0), 0);
1688
1689 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_BTIME, 0), 0);
1690 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_BTIME);
1691 ASSERT_TRUE(timespec_eq(stx.stx_btime, old_btime));
1692
1693 ceph_shutdown(cmount);
1694 }
1695
1696 TEST(LibCephFS, LazyStatx) {
1697 struct ceph_mount_info *cmount1, *cmount2;
1698 ASSERT_EQ(ceph_create(&cmount1, NULL), 0);
1699 ASSERT_EQ(ceph_create(&cmount2, NULL), 0);
1700 ASSERT_EQ(ceph_conf_read_file(cmount1, NULL), 0);
1701 ASSERT_EQ(ceph_conf_read_file(cmount2, NULL), 0);
1702 ASSERT_EQ(0, ceph_conf_parse_env(cmount1, NULL));
1703 ASSERT_EQ(0, ceph_conf_parse_env(cmount2, NULL));
1704 ASSERT_EQ(ceph_mount(cmount1, "/"), 0);
1705 ASSERT_EQ(ceph_mount(cmount2, "/"), 0);
1706
1707 char filename[32];
1708 sprintf(filename, "lazystatx%x", getpid());
1709
1710 Inode *root1, *file1, *root2, *file2;
1711 struct ceph_statx stx;
1712 Fh *fh;
1713 UserPerm *perms1 = ceph_mount_perms(cmount1);
1714 UserPerm *perms2 = ceph_mount_perms(cmount2);
1715
1716 ASSERT_EQ(ceph_ll_lookup_root(cmount1, &root1), 0);
1717 ceph_ll_unlink(cmount1, root1, filename, perms1);
1718 ASSERT_EQ(ceph_ll_create(cmount1, root1, filename, 0666, O_RDWR|O_CREAT|O_EXCL,
1719 &file1, &fh, &stx, 0, 0, perms1), 0);
1720 ASSERT_EQ(ceph_ll_close(cmount1, fh), 0);
1721
1722 ASSERT_EQ(ceph_ll_lookup_root(cmount2, &root2), 0);
1723
1724 ASSERT_EQ(ceph_ll_lookup(cmount2, root2, filename, &file2, &stx, CEPH_STATX_CTIME, 0, perms2), 0);
1725
1726 struct timespec old_ctime = stx.stx_ctime;
1727
1728 /*
1729 * Now sleep, do a chmod on the first client and the see whether we get a
1730 * different ctime with a statx that uses AT_NO_ATTR_SYNC
1731 */
1732 sleep(1);
1733 stx.stx_mode = 0644;
1734 ASSERT_EQ(ceph_ll_setattr(cmount1, file1, &stx, CEPH_SETATTR_MODE, perms1), 0);
1735
1736 ASSERT_EQ(ceph_ll_getattr(cmount2, file2, &stx, CEPH_STATX_CTIME, AT_NO_ATTR_SYNC, perms2), 0);
1737 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_CTIME);
1738 ASSERT_TRUE(stx.stx_ctime.tv_sec == old_ctime.tv_sec &&
1739 stx.stx_ctime.tv_nsec == old_ctime.tv_nsec);
1740
1741 ceph_shutdown(cmount1);
1742 ceph_shutdown(cmount2);
1743 }
1744
1745 TEST(LibCephFS, ChangeAttr) {
1746 struct ceph_mount_info *cmount;
1747 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1748 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1749 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1750 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1751
1752 char filename[32];
1753 sprintf(filename, "/changeattr%x", getpid());
1754
1755 ceph_unlink(cmount, filename);
1756 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1757 ASSERT_LT(0, fd);
1758
1759 struct ceph_statx stx;
1760 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1761 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1762
1763 uint64_t old_change_attr = stx.stx_version;
1764
1765 /* do chmod, and check whether change_attr changed */
1766 ASSERT_EQ(ceph_chmod(cmount, filename, 0644), 0);
1767 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1768 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1769 ASSERT_NE(stx.stx_version, old_change_attr);
1770 old_change_attr = stx.stx_version;
1771
1772 /* now do a write and see if it changed again */
1773 ASSERT_EQ(3, ceph_write(cmount, fd, "foo", 3, 0));
1774 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1775 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1776 ASSERT_NE(stx.stx_version, old_change_attr);
1777 old_change_attr = stx.stx_version;
1778
1779 /* Now truncate and check again */
1780 ASSERT_EQ(0, ceph_ftruncate(cmount, fd, 0));
1781 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1782 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1783 ASSERT_NE(stx.stx_version, old_change_attr);
1784
1785 ceph_close(cmount, fd);
1786 ceph_shutdown(cmount);
1787 }
1788
1789 TEST(LibCephFS, DirChangeAttr) {
1790 struct ceph_mount_info *cmount;
1791 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1792 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1793 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1794 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1795
1796 char dirname[32], filename[56];
1797 sprintf(dirname, "/dirchange%x", getpid());
1798 sprintf(filename, "%s/foo", dirname);
1799
1800 ASSERT_EQ(ceph_mkdir(cmount, dirname, 0755), 0);
1801
1802 struct ceph_statx stx;
1803 ASSERT_EQ(ceph_statx(cmount, dirname, &stx, CEPH_STATX_VERSION, 0), 0);
1804 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1805
1806 uint64_t old_change_attr = stx.stx_version;
1807
1808 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1809 ASSERT_LT(0, fd);
1810 ceph_close(cmount, fd);
1811
1812 ASSERT_EQ(ceph_statx(cmount, dirname, &stx, CEPH_STATX_VERSION, 0), 0);
1813 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1814 ASSERT_NE(stx.stx_version, old_change_attr);
1815
1816 old_change_attr = stx.stx_version;
1817
1818 ASSERT_EQ(ceph_unlink(cmount, filename), 0);
1819 ASSERT_EQ(ceph_statx(cmount, dirname, &stx, CEPH_STATX_VERSION, 0), 0);
1820 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1821 ASSERT_NE(stx.stx_version, old_change_attr);
1822
1823 ceph_shutdown(cmount);
1824 }
1825
1826 TEST(LibCephFS, SetSize) {
1827 struct ceph_mount_info *cmount;
1828 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1829 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1830 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1831 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1832
1833 char filename[32];
1834 sprintf(filename, "/setsize%x", getpid());
1835
1836 ceph_unlink(cmount, filename);
1837 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1838 ASSERT_LT(0, fd);
1839
1840 struct ceph_statx stx;
1841 uint64_t size = 8388608;
1842 stx.stx_size = size;
1843 ASSERT_EQ(ceph_fsetattrx(cmount, fd, &stx, CEPH_SETATTR_SIZE), 0);
1844 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_SIZE, 0), 0);
1845 ASSERT_EQ(stx.stx_size, size);
1846
1847 ceph_close(cmount, fd);
1848 ceph_shutdown(cmount);
1849 }
1850
1851 TEST(LibCephFS, ClearSetuid) {
1852 struct ceph_mount_info *cmount;
1853 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1854 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1855 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1856 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1857
1858 Inode *root;
1859 ASSERT_EQ(ceph_ll_lookup_root(cmount, &root), 0);
1860
1861 char filename[32];
1862 sprintf(filename, "clearsetuid%x", getpid());
1863
1864 Fh *fh;
1865 Inode *in;
1866 struct ceph_statx stx;
1867 const mode_t after_mode = S_IRWXU;
1868 const mode_t before_mode = S_IRWXU | S_ISUID | S_ISGID;
1869 const unsigned want = CEPH_STATX_UID|CEPH_STATX_GID|CEPH_STATX_MODE;
1870 UserPerm *usercred = ceph_mount_perms(cmount);
1871
1872 ceph_ll_unlink(cmount, root, filename, usercred);
1873 ASSERT_EQ(ceph_ll_create(cmount, root, filename, before_mode,
1874 O_RDWR|O_CREAT|O_EXCL, &in, &fh, &stx, want, 0,
1875 usercred), 0);
1876
1877 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, before_mode);
1878
1879 // write
1880 ASSERT_EQ(ceph_ll_write(cmount, fh, 0, 3, "foo"), 3);
1881 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1882 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1883 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, after_mode);
1884
1885 // reset mode
1886 stx.stx_mode = before_mode;
1887 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE, usercred), 0);
1888 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1889 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1890 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, before_mode);
1891
1892 // truncate
1893 stx.stx_size = 1;
1894 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_SIZE, usercred), 0);
1895 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1896 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1897 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, after_mode);
1898
1899 // reset mode
1900 stx.stx_mode = before_mode;
1901 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE, usercred), 0);
1902 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1903 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1904 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, before_mode);
1905
1906 // chown -- for this we need to be "root"
1907 UserPerm *rootcred = ceph_userperm_new(0, 0, 0, NULL);
1908 ASSERT_TRUE(rootcred);
1909 stx.stx_uid++;
1910 stx.stx_gid++;
1911 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_UID|CEPH_SETATTR_GID, rootcred), 0);
1912 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1913 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1914 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, after_mode);
1915
1916 /* test chown with supplementary groups, and chown with/without exe bit */
1917 uid_t u = 65534;
1918 gid_t g = 65534;
1919 gid_t gids[] = {65533,65532};
1920 UserPerm *altcred = ceph_userperm_new(u, g, sizeof gids / sizeof gids[0], gids);
1921 stx.stx_uid = u;
1922 stx.stx_gid = g;
1923 mode_t m = S_ISGID|S_ISUID|S_IRUSR|S_IWUSR;
1924 stx.stx_mode = m;
1925 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE|CEPH_SETATTR_UID|CEPH_SETATTR_GID, rootcred), 0);
1926 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
1927 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m);
1928 /* not dropped without exe bit */
1929 stx.stx_gid = gids[0];
1930 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_GID, altcred), 0);
1931 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
1932 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m);
1933 /* now check dropped with exe bit */
1934 m = S_ISGID|S_ISUID|S_IRWXU;
1935 stx.stx_mode = m;
1936 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE, altcred), 0);
1937 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
1938 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m);
1939 stx.stx_gid = gids[1];
1940 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_GID, altcred), 0);
1941 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
1942 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m&(S_IRWXU|S_IRWXG|S_IRWXO));
1943 ceph_userperm_destroy(altcred);
1944
1945 ASSERT_EQ(ceph_ll_close(cmount, fh), 0);
1946 ceph_shutdown(cmount);
1947 }
1948
1949 TEST(LibCephFS, OperationsOnRoot)
1950 {
1951 struct ceph_mount_info *cmount;
1952 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1953 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1954 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1955 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1956
1957 char dirname[32];
1958 sprintf(dirname, "/somedir%x", getpid());
1959
1960 ASSERT_EQ(ceph_mkdir(cmount, dirname, 0755), 0);
1961
1962 ASSERT_EQ(ceph_rmdir(cmount, "/"), -EBUSY);
1963
1964 ASSERT_EQ(ceph_link(cmount, "/", "/"), -EEXIST);
1965 ASSERT_EQ(ceph_link(cmount, dirname, "/"), -EEXIST);
1966 ASSERT_EQ(ceph_link(cmount, "nonExisitingDir", "/"), -ENOENT);
1967
1968 ASSERT_EQ(ceph_unlink(cmount, "/"), -EISDIR);
1969
1970 ASSERT_EQ(ceph_rename(cmount, "/", "/"), -EBUSY);
1971 ASSERT_EQ(ceph_rename(cmount, dirname, "/"), -EBUSY);
1972 ASSERT_EQ(ceph_rename(cmount, "nonExistingDir", "/"), -EBUSY);
1973 ASSERT_EQ(ceph_rename(cmount, "/", dirname), -EBUSY);
1974 ASSERT_EQ(ceph_rename(cmount, "/", "nonExistingDir"), -EBUSY);
1975
1976 ASSERT_EQ(ceph_mkdir(cmount, "/", 0777), -EEXIST);
1977
1978 ASSERT_EQ(ceph_mknod(cmount, "/", 0, 0), -EEXIST);
1979
1980 ASSERT_EQ(ceph_symlink(cmount, "/", "/"), -EEXIST);
1981 ASSERT_EQ(ceph_symlink(cmount, dirname, "/"), -EEXIST);
1982 ASSERT_EQ(ceph_symlink(cmount, "nonExistingDir", "/"), -EEXIST);
1983
1984 ceph_shutdown(cmount);
1985 }
1986
1987 static void shutdown_racer_func()
1988 {
1989 const int niter = 32;
1990 struct ceph_mount_info *cmount;
1991 int i;
1992
1993 for (i = 0; i < niter; ++i) {
1994 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1995 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1996 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1997 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1998 ceph_shutdown(cmount);
1999 }
2000 }
2001
2002 // See tracker #20988
2003 TEST(LibCephFS, ShutdownRace)
2004 {
2005 const int nthreads = 128;
2006 std::thread threads[nthreads];
2007
2008 // Need a bunch of fd's for this test
2009 struct rlimit rold, rnew;
2010 ASSERT_EQ(getrlimit(RLIMIT_NOFILE, &rold), 0);
2011 rnew = rold;
2012 rnew.rlim_cur = rnew.rlim_max;
2013 ASSERT_EQ(setrlimit(RLIMIT_NOFILE, &rnew), 0);
2014
2015 for (int i = 0; i < nthreads; ++i)
2016 threads[i] = std::thread(shutdown_racer_func);
2017
2018 for (int i = 0; i < nthreads; ++i)
2019 threads[i].join();
2020 ASSERT_EQ(setrlimit(RLIMIT_NOFILE, &rold), 0);
2021 }
2022
2023 static void get_current_time_utimbuf(struct utimbuf *utb)
2024 {
2025 utime_t t = ceph_clock_now();
2026 utb->actime = t.sec();
2027 utb->modtime = t.sec();
2028 }
2029
2030 static void get_current_time_timeval(struct timeval tv[2])
2031 {
2032 utime_t t = ceph_clock_now();
2033 t.copy_to_timeval(&tv[0]);
2034 t.copy_to_timeval(&tv[1]);
2035 }
2036
2037 static void get_current_time_timespec(struct timespec ts[2])
2038 {
2039 utime_t t = ceph_clock_now();
2040 t.to_timespec(&ts[0]);
2041 t.to_timespec(&ts[1]);
2042 }
2043
2044 TEST(LibCephFS, TestUtime) {
2045 struct ceph_mount_info *cmount;
2046 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2047 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2048 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2049 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2050
2051 char test_file[256];
2052 sprintf(test_file, "test_utime_file_%d", getpid());
2053 int fd = ceph_open(cmount, test_file, O_CREAT, 0666);
2054 ASSERT_GT(fd, 0);
2055
2056 struct utimbuf utb;
2057 struct ceph_statx stx;
2058
2059 get_current_time_utimbuf(&utb);
2060
2061 // ceph_utime()
2062 EXPECT_EQ(0, ceph_utime(cmount, test_file, &utb));
2063 ASSERT_EQ(ceph_statx(cmount, test_file, &stx,
2064 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
2065 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(utb.actime, 0));
2066 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(utb.modtime, 0));
2067
2068 get_current_time_utimbuf(&utb);
2069
2070 // ceph_futime()
2071 EXPECT_EQ(0, ceph_futime(cmount, fd, &utb));
2072 ASSERT_EQ(ceph_statx(cmount, test_file, &stx,
2073 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
2074 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(utb.actime, 0));
2075 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(utb.modtime, 0));
2076
2077 ceph_close(cmount, fd);
2078 ceph_shutdown(cmount);
2079 }
2080
2081 TEST(LibCephFS, TestUtimes) {
2082 struct ceph_mount_info *cmount;
2083 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2084 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2085 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2086 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2087
2088 char test_file[256];
2089 char test_symlink[256];
2090
2091 sprintf(test_file, "test_utimes_file_%d", getpid());
2092 sprintf(test_symlink, "test_utimes_symlink_%d", getpid());
2093 int fd = ceph_open(cmount, test_file, O_CREAT, 0666);
2094 ASSERT_GT(fd, 0);
2095
2096 ASSERT_EQ(ceph_symlink(cmount, test_file, test_symlink), 0);
2097
2098 struct timeval times[2];
2099 struct ceph_statx stx;
2100
2101 get_current_time_timeval(times);
2102
2103 // ceph_utimes() on symlink, validate target file time
2104 EXPECT_EQ(0, ceph_utimes(cmount, test_symlink, times));
2105 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx,
2106 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
2107 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(times[0]));
2108 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(times[1]));
2109
2110 get_current_time_timeval(times);
2111
2112 // ceph_lutimes() on symlink, validate symlink time
2113 EXPECT_EQ(0, ceph_lutimes(cmount, test_symlink, times));
2114 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx,
2115 CEPH_STATX_MTIME|CEPH_STATX_ATIME, AT_SYMLINK_NOFOLLOW), 0);
2116 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(times[0]));
2117 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(times[1]));
2118
2119 get_current_time_timeval(times);
2120
2121 // ceph_futimes()
2122 EXPECT_EQ(0, ceph_futimes(cmount, fd, times));
2123 ASSERT_EQ(ceph_statx(cmount, test_file, &stx,
2124 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
2125 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(times[0]));
2126 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(times[1]));
2127
2128 ceph_close(cmount, fd);
2129 ceph_shutdown(cmount);
2130 }
2131
2132 TEST(LibCephFS, TestFutimens) {
2133 struct ceph_mount_info *cmount;
2134 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2135 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2136 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2137 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2138
2139 char test_file[256];
2140
2141 sprintf(test_file, "test_futimens_file_%d", getpid());
2142 int fd = ceph_open(cmount, test_file, O_CREAT, 0666);
2143 ASSERT_GT(fd, 0);
2144
2145 struct timespec times[2];
2146 struct ceph_statx stx;
2147
2148 get_current_time_timespec(times);
2149
2150 // ceph_futimens()
2151 EXPECT_EQ(0, ceph_futimens(cmount, fd, times));
2152 ASSERT_EQ(ceph_statx(cmount, test_file, &stx,
2153 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
2154 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(times[0]));
2155 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(times[1]));
2156
2157 ceph_close(cmount, fd);
2158 ceph_shutdown(cmount);
2159 }
2160
2161 TEST(LibCephFS, OperationsOnDotDot) {
2162 struct ceph_mount_info *cmount;
2163 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2164 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2165 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2166 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2167
2168 char c_dir[512], c_dir_dot[1024], c_dir_dotdot[1024];
2169 char c_non_existent_dir[1024], c_non_existent_dirs[1024];
2170 char c_temp[1024];
2171
2172 pid_t mypid = getpid();
2173 sprintf(c_dir, "/oodd_dir_%d", mypid);
2174 sprintf(c_dir_dot, "/%s/.", c_dir);
2175 sprintf(c_dir_dotdot, "/%s/..", c_dir);
2176 sprintf(c_non_existent_dir, "/%s/../oodd_nonexistent/..", c_dir);
2177 sprintf(c_non_existent_dirs,
2178 "/%s/../ood_nonexistent1_%d/oodd_nonexistent2_%d", c_dir, mypid, mypid);
2179 sprintf(c_temp, "/oodd_temp_%d", mypid);
2180
2181 ASSERT_EQ(0, ceph_mkdir(cmount, c_dir, 0777));
2182 ASSERT_EQ(-EEXIST, ceph_mkdir(cmount, c_dir_dot, 0777));
2183 ASSERT_EQ(-EEXIST, ceph_mkdir(cmount, c_dir_dotdot, 0777));
2184 ASSERT_EQ(0, ceph_mkdirs(cmount, c_non_existent_dirs, 0777));
2185
2186 ASSERT_EQ(-ENOTEMPTY, ceph_rmdir(cmount, c_dir_dot));
2187 ASSERT_EQ(-ENOTEMPTY, ceph_rmdir(cmount, c_dir_dotdot));
2188 // non existent directory should return -ENOENT
2189 ASSERT_EQ(-ENOENT, ceph_rmdir(cmount, c_non_existent_dir));
2190
2191 ASSERT_EQ(-EBUSY, ceph_rename(cmount, c_dir_dot, c_temp));
2192 ASSERT_EQ(0, ceph_chdir(cmount, c_dir));
2193 ASSERT_EQ(0, ceph_mkdir(cmount, c_temp, 0777));
2194 ASSERT_EQ(-EBUSY, ceph_rename(cmount, c_temp, ".."));
2195
2196 ceph_shutdown(cmount);
2197 }
2198
2199 TEST(LibCephFS, SnapXattrs) {
2200 struct ceph_mount_info *cmount;
2201 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2202 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2203 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2204 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2205
2206 char test_snap_xattr_file[256];
2207 char c_temp[PATH_MAX];
2208 char gxattrv[128];
2209 char gxattrv2[128];
2210 int xbuflen = sizeof(gxattrv);
2211 pid_t mypid = getpid();
2212
2213 sprintf(test_snap_xattr_file, "test_snap_xattr_%d", mypid);
2214 int fd = ceph_open(cmount, test_snap_xattr_file, O_CREAT, 0666);
2215 ASSERT_GT(fd, 0);
2216 ceph_close(cmount, fd);
2217
2218 sprintf(c_temp, "/.snap/test_snap_xattr_snap_%d", mypid);
2219 ASSERT_EQ(0, ceph_mkdir(cmount, c_temp, 0777));
2220
2221 int alen = ceph_getxattr(cmount, c_temp, "ceph.snap.btime", (void *)gxattrv, xbuflen);
2222 // xattr value is secs.nsecs (don't assume zero-term)
2223 ASSERT_LT(0, alen);
2224 ASSERT_LT(alen, xbuflen);
2225 gxattrv[alen] = '\0';
2226 char *s = strchrnul(gxattrv, '.');
2227 ASSERT_LT(s, gxattrv + alen);
2228 ASSERT_EQ('.', *s);
2229 *s = '\0';
2230 utime_t btime = utime_t(strtoull(gxattrv, NULL, 10), strtoull(s + 1, NULL, 10));
2231 *s = '.'; // restore for later strcmp
2232
2233 // file within the snapshot should carry the same btime
2234 sprintf(c_temp, "/.snap/test_snap_xattr_snap_%d/%s", mypid, test_snap_xattr_file);
2235
2236 int alen2 = ceph_getxattr(cmount, c_temp, "ceph.snap.btime", (void *)gxattrv2, xbuflen);
2237 ASSERT_EQ(alen, alen2);
2238 ASSERT_EQ(0, strncmp(gxattrv, gxattrv2, alen));
2239
2240 // non-snap file shouldn't carry the xattr
2241 alen = ceph_getxattr(cmount, test_snap_xattr_file, "ceph.snap.btime", (void *)gxattrv2, xbuflen);
2242 ASSERT_EQ(-ENODATA, alen);
2243
2244 // create a second snapshot
2245 sprintf(c_temp, "/.snap/test_snap_xattr_snap2_%d", mypid);
2246 ASSERT_EQ(0, ceph_mkdir(cmount, c_temp, 0777));
2247
2248 // check that the btime for the newer snapshot is > older
2249 alen = ceph_getxattr(cmount, c_temp, "ceph.snap.btime", (void *)gxattrv2, xbuflen);
2250 ASSERT_LT(0, alen);
2251 ASSERT_LT(alen, xbuflen);
2252 gxattrv2[alen] = '\0';
2253 s = strchrnul(gxattrv2, '.');
2254 ASSERT_LT(s, gxattrv2 + alen);
2255 ASSERT_EQ('.', *s);
2256 *s = '\0';
2257 utime_t new_btime = utime_t(strtoull(gxattrv2, NULL, 10), strtoull(s + 1, NULL, 10));
2258 ASSERT_LT(btime, new_btime);
2259
2260 // listxattr() shouldn't return snap.btime vxattr
2261 char xattrlist[512];
2262 int len = ceph_listxattr(cmount, test_snap_xattr_file, xattrlist, sizeof(xattrlist));
2263 ASSERT_GE(sizeof(xattrlist), (size_t)len);
2264 char *p = xattrlist;
2265 int found = 0;
2266 while (len > 0) {
2267 if (strcmp(p, "ceph.snap.btime") == 0)
2268 found++;
2269 len -= strlen(p) + 1;
2270 p += strlen(p) + 1;
2271 }
2272 ASSERT_EQ(found, 0);
2273
2274 ceph_shutdown(cmount);
2275 }
2276
2277 TEST(LibCephFS, SnapQuota) {
2278 struct ceph_mount_info *cmount;
2279 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2280 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2281 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2282 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2283
2284 char test_snap_dir_quota_xattr[256];
2285 char test_snap_subdir_quota_xattr[256];
2286 char test_snap_subdir_noquota_xattr[256];
2287 char xattrk[128];
2288 char xattrv[128];
2289 char c_temp[PATH_MAX];
2290 char gxattrv[128];
2291 int xbuflen = sizeof(gxattrv);
2292 pid_t mypid = getpid();
2293
2294 // create dir and set quota
2295 sprintf(test_snap_dir_quota_xattr, "test_snap_dir_quota_xattr_%d", mypid);
2296 ASSERT_EQ(0, ceph_mkdir(cmount, test_snap_dir_quota_xattr, 0777));
2297
2298 sprintf(xattrk, "ceph.quota.max_bytes");
2299 sprintf(xattrv, "65536");
2300 ASSERT_EQ(0, ceph_setxattr(cmount, test_snap_dir_quota_xattr, xattrk, (void *)xattrv, 5, XATTR_CREATE));
2301
2302 // create subdir and set quota
2303 sprintf(test_snap_subdir_quota_xattr, "test_snap_dir_quota_xattr_%d/subdir_quota", mypid);
2304 ASSERT_EQ(0, ceph_mkdirs(cmount, test_snap_subdir_quota_xattr, 0777));
2305
2306 sprintf(xattrk, "ceph.quota.max_bytes");
2307 sprintf(xattrv, "32768");
2308 ASSERT_EQ(0, ceph_setxattr(cmount, test_snap_subdir_quota_xattr, xattrk, (void *)xattrv, 5, XATTR_CREATE));
2309
2310 // create subdir with no quota
2311 sprintf(test_snap_subdir_noquota_xattr, "test_snap_dir_quota_xattr_%d/subdir_noquota", mypid);
2312 ASSERT_EQ(0, ceph_mkdirs(cmount, test_snap_subdir_noquota_xattr, 0777));
2313
2314 // snapshot dir
2315 sprintf(c_temp, "/.snap/test_snap_dir_quota_xattr_snap_%d", mypid);
2316 ASSERT_EQ(0, ceph_mkdirs(cmount, c_temp, 0777));
2317
2318 // check dir quota under snap
2319 sprintf(c_temp, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d", mypid, mypid);
2320 int alen = ceph_getxattr(cmount, c_temp, "ceph.quota.max_bytes", (void *)gxattrv, xbuflen);
2321 ASSERT_LT(0, alen);
2322 ASSERT_LT(alen, xbuflen);
2323 gxattrv[alen] = '\0';
2324 ASSERT_STREQ(gxattrv, "65536");
2325
2326 // check subdir quota under snap
2327 sprintf(c_temp, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d/subdir_quota", mypid, mypid);
2328 alen = ceph_getxattr(cmount, c_temp, "ceph.quota.max_bytes", (void *)gxattrv, xbuflen);
2329 ASSERT_LT(0, alen);
2330 ASSERT_LT(alen, xbuflen);
2331 gxattrv[alen] = '\0';
2332 ASSERT_STREQ(gxattrv, "32768");
2333
2334 // ensure subdir noquota xattr under snap
2335 sprintf(c_temp, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d/subdir_noquota", mypid, mypid);
2336 EXPECT_EQ(-ENODATA, ceph_getxattr(cmount, c_temp, "ceph.quota.max_bytes", (void *)gxattrv, xbuflen));
2337
2338 // listxattr() shouldn't return ceph.quota.max_bytes vxattr
2339 sprintf(c_temp, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d", mypid, mypid);
2340 char xattrlist[512];
2341 int len = ceph_listxattr(cmount, c_temp, xattrlist, sizeof(xattrlist));
2342 ASSERT_GE(sizeof(xattrlist), (size_t)len);
2343 char *p = xattrlist;
2344 int found = 0;
2345 while (len > 0) {
2346 if (strcmp(p, "ceph.quota.max_bytes") == 0)
2347 found++;
2348 len -= strlen(p) + 1;
2349 p += strlen(p) + 1;
2350 }
2351 ASSERT_EQ(found, 0);
2352
2353 ceph_shutdown(cmount);
2354 }
2355
2356 TEST(LibCephFS, Lseek) {
2357 struct ceph_mount_info *cmount;
2358 ASSERT_EQ(0, ceph_create(&cmount, NULL));
2359 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
2360 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2361 ASSERT_EQ(0, ceph_mount(cmount, "/"));
2362
2363 char c_path[1024];
2364 sprintf(c_path, "test_lseek_%d", getpid());
2365 int fd = ceph_open(cmount, c_path, O_RDWR|O_CREAT|O_TRUNC, 0666);
2366 ASSERT_LT(0, fd);
2367
2368 const char *out_buf = "hello world";
2369 size_t size = strlen(out_buf);
2370 ASSERT_EQ(ceph_write(cmount, fd, out_buf, size, 0), (int)size);
2371
2372 /* basic SEEK_SET/END/CUR tests */
2373 ASSERT_EQ(0, ceph_lseek(cmount, fd, 0, SEEK_SET));
2374 ASSERT_EQ(size, ceph_lseek(cmount, fd, 0, SEEK_END));
2375 ASSERT_EQ(0, ceph_lseek(cmount, fd, -size, SEEK_CUR));
2376
2377 /* Test basic functionality and out of bounds conditions for SEEK_HOLE/DATA */
2378 #ifdef SEEK_HOLE
2379 ASSERT_EQ(size, ceph_lseek(cmount, fd, 0, SEEK_HOLE));
2380 ASSERT_EQ(-ENXIO, ceph_lseek(cmount, fd, -1, SEEK_HOLE));
2381 ASSERT_EQ(-ENXIO, ceph_lseek(cmount, fd, size + 1, SEEK_HOLE));
2382 #endif
2383 #ifdef SEEK_DATA
2384 ASSERT_EQ(0, ceph_lseek(cmount, fd, 0, SEEK_DATA));
2385 ASSERT_EQ(-ENXIO, ceph_lseek(cmount, fd, -1, SEEK_DATA));
2386 ASSERT_EQ(-ENXIO, ceph_lseek(cmount, fd, size + 1, SEEK_DATA));
2387 #endif
2388
2389 ASSERT_EQ(0, ceph_close(cmount, fd));
2390 ceph_shutdown(cmount);
2391 }