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