1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2011 New Dream Network
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.
15 #include "gtest/gtest.h"
16 #include "include/cephfs/libcephfs.h"
17 #include "include/stat.h"
21 #include <sys/types.h>
24 #include <sys/xattr.h>
34 TEST(LibCephFS
, OpenEmptyComponent
) {
36 pid_t mypid
= getpid();
37 struct ceph_mount_info
*cmount
;
38 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
39 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
40 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
41 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
44 sprintf(c_dir
, "/open_test_%d", mypid
);
45 struct ceph_dir_result
*dirp
;
47 ASSERT_EQ(0, ceph_mkdirs(cmount
, c_dir
, 0777));
49 ASSERT_EQ(0, ceph_opendir(cmount
, c_dir
, &dirp
));
52 sprintf(c_path
, "/open_test_%d//created_file_%d", mypid
, mypid
);
53 int fd
= ceph_open(cmount
, c_path
, O_RDONLY
|O_CREAT
, 0666);
56 ASSERT_EQ(0, ceph_close(cmount
, fd
));
57 ASSERT_EQ(0, ceph_closedir(cmount
, dirp
));
58 ceph_shutdown(cmount
);
60 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
61 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
62 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
64 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
66 fd
= ceph_open(cmount
, c_path
, O_RDONLY
, 0666);
69 ASSERT_EQ(0, ceph_close(cmount
, fd
));
70 ceph_shutdown(cmount
);
73 TEST(LibCephFS
, OpenReadWrite
) {
74 struct ceph_mount_info
*cmount
;
75 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
76 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
77 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
78 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
81 sprintf(c_path
, "test_open_rdwr_%d", getpid());
82 int fd
= ceph_open(cmount
, c_path
, O_WRONLY
|O_CREAT
, 0666);
85 const char *out_buf
= "hello world";
86 size_t size
= strlen(out_buf
);
88 ASSERT_EQ(ceph_write(cmount
, fd
, out_buf
, size
, 0), (int)size
);
89 ASSERT_EQ(ceph_read(cmount
, fd
, in_buf
, sizeof(in_buf
), 0), -EBADF
);
90 ASSERT_EQ(0, ceph_close(cmount
, fd
));
92 fd
= ceph_open(cmount
, c_path
, O_RDONLY
, 0);
94 ASSERT_EQ(ceph_write(cmount
, fd
, out_buf
, size
, 0), -EBADF
);
95 ASSERT_EQ(ceph_read(cmount
, fd
, in_buf
, sizeof(in_buf
), 0), (int)size
);
96 ASSERT_EQ(0, ceph_close(cmount
, fd
));
98 fd
= ceph_open(cmount
, c_path
, O_RDWR
, 0);
100 ASSERT_EQ(ceph_write(cmount
, fd
, out_buf
, size
, 0), (int)size
);
101 ASSERT_EQ(ceph_read(cmount
, fd
, in_buf
, sizeof(in_buf
), 0), (int)size
);
102 ASSERT_EQ(0, ceph_close(cmount
, fd
));
104 ceph_shutdown(cmount
);
107 TEST(LibCephFS
, MountNonExist
) {
109 struct ceph_mount_info
*cmount
;
111 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
112 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
113 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
114 ASSERT_NE(0, ceph_mount(cmount
, "/non-exist"));
115 ceph_shutdown(cmount
);
118 TEST(LibCephFS
, MountDouble
) {
120 struct ceph_mount_info
*cmount
;
122 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
123 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
124 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
125 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
126 ASSERT_EQ(-EISCONN
, ceph_mount(cmount
, "/"));
127 ceph_shutdown(cmount
);
130 TEST(LibCephFS
, MountRemount
) {
132 struct ceph_mount_info
*cmount
;
134 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
135 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
136 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
138 CephContext
*cct
= ceph_get_mount_context(cmount
);
139 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
140 ASSERT_EQ(0, ceph_unmount(cmount
));
142 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
143 ASSERT_EQ(cct
, ceph_get_mount_context(cmount
));
145 ceph_shutdown(cmount
);
148 TEST(LibCephFS
, UnmountUnmounted
) {
150 struct ceph_mount_info
*cmount
;
152 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
153 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
154 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
155 ASSERT_EQ(-ENOTCONN
, ceph_unmount(cmount
));
156 ceph_shutdown(cmount
);
159 TEST(LibCephFS
, ReleaseUnmounted
) {
161 struct ceph_mount_info
*cmount
;
163 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
164 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
165 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
166 ASSERT_EQ(0, ceph_release(cmount
));
169 TEST(LibCephFS
, ReleaseMounted
) {
171 struct ceph_mount_info
*cmount
;
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_mount(cmount
, "/"));
177 ASSERT_EQ(-EISCONN
, ceph_release(cmount
));
178 ASSERT_EQ(0, ceph_unmount(cmount
));
179 ASSERT_EQ(0, ceph_release(cmount
));
182 TEST(LibCephFS
, UnmountRelease
) {
184 struct ceph_mount_info
*cmount
;
186 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
187 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
188 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
189 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
190 ASSERT_EQ(0, ceph_unmount(cmount
));
191 ASSERT_EQ(0, ceph_release(cmount
));
194 TEST(LibCephFS
, Mount
) {
195 struct ceph_mount_info
*cmount
;
196 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
197 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
198 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
199 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
200 ceph_shutdown(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
);
209 TEST(LibCephFS
, OpenLayout
) {
210 struct ceph_mount_info
*cmount
;
211 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
212 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
213 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
214 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
217 char test_layout_file
[256];
218 sprintf(test_layout_file
, "test_layout_%d_b", getpid());
219 int fd
= ceph_open_layout(cmount
, test_layout_file
, O_CREAT
|O_WRONLY
, 0666, (1<<20), 7, (1<<20), NULL
);
222 ASSERT_LT(0, ceph_get_file_pool_name(cmount
, fd
, poolname
, sizeof(poolname
)));
223 ASSERT_LT(0, ceph_get_file_pool_name(cmount
, fd
, poolname
, 0));
225 /* on already-written file (ENOTEMPTY) */
226 ceph_write(cmount
, fd
, "hello world", 11, 0);
227 ceph_close(cmount
, fd
);
231 sprintf(xattrk
, "ceph.file.layout.stripe_unit");
232 sprintf(xattrv
, "65536");
233 ASSERT_EQ(-ENOTEMPTY
, ceph_setxattr(cmount
, test_layout_file
, xattrk
, (void *)xattrv
, 5, 0));
236 sprintf(test_layout_file
, "test_layout_%d_c", getpid());
237 fd
= ceph_open_layout(cmount
, test_layout_file
, O_CREAT
, 0666, (1<<20), 1, 19, NULL
);
238 ASSERT_EQ(fd
, -EINVAL
);
241 sprintf(test_layout_file
, "test_layout_%d_d", getpid());
242 fd
= ceph_open_layout(cmount
, test_layout_file
, O_CREAT
, 0666, (1<<20), 7, (1<<20), poolname
);
244 ceph_close(cmount
, fd
);
246 /* with metadata pool (invalid) */
247 sprintf(test_layout_file
, "test_layout_%d_e", getpid());
248 fd
= ceph_open_layout(cmount
, test_layout_file
, O_CREAT
, 0666, (1<<20), 7, (1<<20), "metadata");
249 ASSERT_EQ(fd
, -EINVAL
);
251 /* with metadata pool (does not exist) */
252 sprintf(test_layout_file
, "test_layout_%d_f", getpid());
253 fd
= ceph_open_layout(cmount
, test_layout_file
, O_CREAT
, 0666, (1<<20), 7, (1<<20), "asdfjasdfjasdf");
254 ASSERT_EQ(fd
, -EINVAL
);
256 ceph_shutdown(cmount
);
259 TEST(LibCephFS
, DirLs
) {
261 pid_t mypid
= getpid();
263 struct ceph_mount_info
*cmount
;
264 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
265 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
266 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
267 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
269 struct ceph_dir_result
*ls_dir
= NULL
;
271 sprintf(foostr
, "dir_ls%d", mypid
);
272 ASSERT_EQ(ceph_opendir(cmount
, foostr
, &ls_dir
), -ENOENT
);
274 ASSERT_EQ(ceph_mkdir(cmount
, foostr
, 0777), 0);
275 struct ceph_statx stx
;
276 ASSERT_EQ(ceph_statx(cmount
, foostr
, &stx
, 0, 0), 0);
277 ASSERT_NE(S_ISDIR(stx
.stx_mode
), 0);
280 sprintf(barstr
, "dir_ls2%d", mypid
);
281 ASSERT_EQ(ceph_statx(cmount
, barstr
, &stx
, 0, AT_SYMLINK_NOFOLLOW
), -ENOENT
);
283 // insert files into directory and test open
285 int i
= 0, r
= rand() % 4096;
286 if (getenv("LIBCEPHFS_RAND")) {
287 r
= atoi(getenv("LIBCEPHFS_RAND"));
289 printf("rand: %d\n", r
);
292 sprintf(bazstr
, "dir_ls%d/dirf%d", mypid
, i
);
293 int fd
= ceph_open(cmount
, bazstr
, O_CREAT
|O_RDONLY
, 0666);
295 ASSERT_EQ(ceph_close(cmount
, fd
), 0);
297 // set file sizes for readdirplus
298 ceph_truncate(cmount
, bazstr
, i
);
301 ASSERT_EQ(ceph_opendir(cmount
, foostr
, &ls_dir
), 0);
303 // not guaranteed to get . and .. first, but its a safe assumption in this case
304 struct dirent
*result
= ceph_readdir(cmount
, ls_dir
);
305 ASSERT_TRUE(result
!= NULL
);
306 ASSERT_STREQ(result
->d_name
, ".");
307 result
= ceph_readdir(cmount
, ls_dir
);
308 ASSERT_TRUE(result
!= NULL
);
309 ASSERT_STREQ(result
->d_name
, "..");
311 std::vector
<std::string
> entries
;
312 std::map
<std::string
, int64_t> offset_map
;
313 int64_t offset
= ceph_telldir(cmount
, ls_dir
);
314 for(i
= 0; i
< r
; ++i
) {
315 result
= ceph_readdir(cmount
, ls_dir
);
316 ASSERT_TRUE(result
!= NULL
);
317 entries
.push_back(result
->d_name
);
318 offset_map
[result
->d_name
] = offset
;
319 offset
= ceph_telldir(cmount
, ls_dir
);
322 ASSERT_TRUE(ceph_readdir(cmount
, ls_dir
) == NULL
);
323 offset
= ceph_telldir(cmount
, ls_dir
);
325 ASSERT_EQ(offset_map
.size(), entries
.size());
326 for(i
= 0; i
< r
; ++i
) {
327 sprintf(bazstr
, "dirf%d", i
);
328 ASSERT_TRUE(offset_map
.count(bazstr
) == 1);
332 ceph_seekdir(cmount
, ls_dir
, offset
);
333 ASSERT_TRUE(ceph_readdir(cmount
, ls_dir
) == NULL
);
335 for (auto p
= offset_map
.begin(); p
!= offset_map
.end(); ++p
) {
336 ceph_seekdir(cmount
, ls_dir
, p
->second
);
337 result
= ceph_readdir(cmount
, ls_dir
);
338 ASSERT_TRUE(result
!= NULL
);
339 std::string
d_name(result
->d_name
);
340 ASSERT_EQ(p
->first
, d_name
);
344 ceph_rewinddir(cmount
, ls_dir
);
346 result
= ceph_readdir(cmount
, ls_dir
);
347 ASSERT_TRUE(result
!= NULL
);
348 ASSERT_STREQ(result
->d_name
, ".");
349 result
= ceph_readdir(cmount
, ls_dir
);
350 ASSERT_TRUE(result
!= NULL
);
351 ASSERT_STREQ(result
->d_name
, "..");
353 ceph_rewinddir(cmount
, ls_dir
);
355 int t
= ceph_telldir(cmount
, ls_dir
);
358 ASSERT_TRUE(ceph_readdir(cmount
, ls_dir
) != NULL
);
360 // test seekdir - move back to the beginning
361 ceph_seekdir(cmount
, ls_dir
, t
);
364 struct dirent
*getdents_entries
;
365 getdents_entries
= (struct dirent
*)malloc((r
+ 2) * sizeof(*getdents_entries
));
368 std::vector
<std::string
> found
;
370 int len
= ceph_getdents(cmount
, ls_dir
, (char *)getdents_entries
, r
* sizeof(*getdents_entries
));
374 ASSERT_TRUE((len
% sizeof(*getdents_entries
)) == 0);
375 int n
= len
/ sizeof(*getdents_entries
);
378 ASSERT_STREQ(getdents_entries
[0].d_name
, ".");
379 ASSERT_STREQ(getdents_entries
[1].d_name
, "..");
385 for(; j
< n
; ++i
, ++j
) {
386 const char *name
= getdents_entries
[j
].d_name
;
387 found
.push_back(name
);
390 ASSERT_EQ(found
, entries
);
391 free(getdents_entries
);
394 ceph_rewinddir(cmount
, ls_dir
);
396 result
= ceph_readdir(cmount
, ls_dir
);
397 ASSERT_TRUE(result
!= NULL
);
398 ASSERT_STREQ(result
->d_name
, ".");
399 result
= ceph_readdir(cmount
, ls_dir
);
400 ASSERT_TRUE(result
!= NULL
);
401 ASSERT_STREQ(result
->d_name
, "..");
406 int len
= ceph_readdir_r(cmount
, ls_dir
, &rdent
);
410 found
.push_back(rdent
.d_name
);
412 ASSERT_EQ(found
, entries
);
415 ceph_rewinddir(cmount
, ls_dir
);
417 result
= ceph_readdir(cmount
, ls_dir
);
418 ASSERT_TRUE(result
!= NULL
);
419 ASSERT_STREQ(result
->d_name
, ".");
420 result
= ceph_readdir(cmount
, ls_dir
);
421 ASSERT_TRUE(result
!= NULL
);
422 ASSERT_STREQ(result
->d_name
, "..");
427 struct ceph_statx stx
;
428 int len
= ceph_readdirplus_r(cmount
, ls_dir
, &rdent
, &stx
,
429 CEPH_STATX_SIZE
, AT_NO_ATTR_SYNC
, NULL
);
433 const char *name
= rdent
.d_name
;
434 found
.push_back(name
);
436 sscanf(name
, "dirf%d", &size
);
437 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_SIZE
);
438 ASSERT_EQ(stx
.stx_size
, (size_t)size
);
439 ASSERT_EQ(stx
.stx_ino
, rdent
.d_ino
);
440 //ASSERT_EQ(st.st_mode, (mode_t)0666);
442 ASSERT_EQ(found
, entries
);
444 ASSERT_EQ(ceph_closedir(cmount
, ls_dir
), 0);
446 ceph_shutdown(cmount
);
449 TEST(LibCephFS
, ManyNestedDirs
) {
450 struct ceph_mount_info
*cmount
;
451 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
452 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
453 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
454 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
456 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";
457 ASSERT_EQ(ceph_mkdirs(cmount
, many_path
, 0755), 0);
462 ASSERT_EQ(ceph_chdir(cmount
, "a"), 0);
464 struct ceph_dir_result
*dirp
;
465 ASSERT_EQ(ceph_opendir(cmount
, "a", &dirp
), 0);
466 struct dirent
*dent
= ceph_readdir(cmount
, dirp
);
467 ASSERT_TRUE(dent
!= NULL
);
468 ASSERT_STREQ(dent
->d_name
, ".");
469 dent
= ceph_readdir(cmount
, dirp
);
470 ASSERT_TRUE(dent
!= NULL
);
471 ASSERT_STREQ(dent
->d_name
, "..");
472 dent
= ceph_readdir(cmount
, dirp
);
473 ASSERT_TRUE(dent
!= NULL
);
474 ASSERT_STREQ(dent
->d_name
, "a");
475 ASSERT_EQ(ceph_closedir(cmount
, dirp
), 0);
478 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");
480 ASSERT_EQ(ceph_chdir(cmount
, "a/a/a"), 0);
482 for(i
= 0; i
< 39; ++i
) {
483 ASSERT_EQ(ceph_chdir(cmount
, ".."), 0);
484 ASSERT_EQ(ceph_rmdir(cmount
, "a"), 0);
487 ASSERT_EQ(ceph_chdir(cmount
, "/"), 0);
489 ASSERT_EQ(ceph_rmdir(cmount
, "a/a/a"), 0);
491 ceph_shutdown(cmount
);
494 TEST(LibCephFS
, Xattrs
) {
495 struct ceph_mount_info
*cmount
;
496 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
497 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
498 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
499 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
501 char test_xattr_file
[256];
502 sprintf(test_xattr_file
, "test_xattr_%d", getpid());
503 int fd
= ceph_open(cmount
, test_xattr_file
, O_CREAT
, 0666);
509 for(; i
< 'a'+26; ++i
) {
510 sprintf(xattrk
, "user.test_xattr_%c", i
);
511 int len
= sprintf(xattrv
, "testxattr%c", i
);
512 ASSERT_EQ(ceph_setxattr(cmount
, test_xattr_file
, xattrk
, (void *) xattrv
, len
, XATTR_CREATE
), 0);
515 char xattrlist
[128*26];
516 int len
= ceph_listxattr(cmount
, test_xattr_file
, xattrlist
, sizeof(xattrlist
));
521 // skip/ignore the dir layout
522 if (strcmp(p
, "ceph.dir.layout") == 0 ||
523 strcmp(p
, "ceph.file.layout") == 0) {
524 len
-= strlen(p
) + 1;
529 sprintf(xattrk
, "user.test_xattr_%c", i
);
530 ASSERT_STREQ(p
, xattrk
);
533 std::cout
<< "getting attr " << p
<< std::endl
;
534 int alen
= ceph_getxattr(cmount
, test_xattr_file
, p
, (void *) gxattrv
, 128);
536 sprintf(xattrv
, "testxattr%c", i
);
537 ASSERT_TRUE(!strncmp(xattrv
, gxattrv
, alen
));
547 for(i
= 'a'; i
< 'a'+26; ++i
) {
548 sprintf(xattrk
, "user.test_xattr_%c", i
);
549 ASSERT_EQ(ceph_removexattr(cmount
, test_xattr_file
, xattrk
), 0);
552 ceph_close(cmount
, fd
);
553 ceph_shutdown(cmount
);
557 TEST(LibCephFS
, Xattrs_ll
) {
558 struct ceph_mount_info
*cmount
;
559 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
560 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
561 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
562 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
564 char test_xattr_file
[256];
565 sprintf(test_xattr_file
, "test_xattr_%d", getpid());
566 int fd
= ceph_open(cmount
, test_xattr_file
, O_CREAT
, 0666);
568 ceph_close(cmount
, fd
);
571 Inode
*existent_file_handle
= NULL
;
573 int res
= ceph_ll_lookup_root(cmount
, &root
);
576 UserPerm
*perms
= ceph_mount_perms(cmount
);
577 struct ceph_statx stx
;
579 res
= ceph_ll_lookup(cmount
, root
, test_xattr_file
, &existent_file_handle
,
583 const char *valid_name
= "user.attrname";
584 const char *value
= "attrvalue";
585 char value_buf
[256] = { 0 };
587 res
= ceph_ll_setxattr(cmount
, existent_file_handle
, valid_name
, value
, strlen(value
), 0, perms
);
590 res
= ceph_ll_getxattr(cmount
, existent_file_handle
, valid_name
, value_buf
, 256, perms
);
591 ASSERT_EQ(res
, (int)strlen(value
));
593 value_buf
[res
] = '\0';
594 ASSERT_STREQ(value_buf
, value
);
596 ceph_shutdown(cmount
);
599 TEST(LibCephFS
, LstatSlashdot
) {
600 struct ceph_mount_info
*cmount
;
601 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
602 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
603 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
604 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
606 struct ceph_statx stx
;
607 ASSERT_EQ(ceph_statx(cmount
, "/.", &stx
, 0, AT_SYMLINK_NOFOLLOW
), 0);
608 ASSERT_EQ(ceph_statx(cmount
, ".", &stx
, 0, AT_SYMLINK_NOFOLLOW
), 0);
610 ceph_shutdown(cmount
);
613 TEST(LibCephFS
, DoubleChmod
) {
615 struct ceph_mount_info
*cmount
;
616 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
617 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
618 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
619 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
622 sprintf(test_file
, "test_perms_%d", getpid());
624 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
628 const char *bytes
= "foobarbaz";
629 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
631 ceph_close(cmount
, fd
);
633 // set perms to read but can't write
634 ASSERT_EQ(ceph_chmod(cmount
, test_file
, 0400), 0);
636 fd
= ceph_open(cmount
, test_file
, O_RDWR
, 0);
637 ASSERT_EQ(fd
, -EACCES
);
639 fd
= ceph_open(cmount
, test_file
, O_RDONLY
, 0);
643 int ret
= ceph_read(cmount
, fd
, buf
, 100, 0);
644 ASSERT_EQ(ret
, (int)strlen(bytes
));
646 ASSERT_STREQ(buf
, bytes
);
648 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), -EBADF
);
650 ceph_close(cmount
, fd
);
652 // reset back to writeable
653 ASSERT_EQ(ceph_chmod(cmount
, test_file
, 0600), 0);
655 // ensure perms are correct
656 struct ceph_statx stx
;
657 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx
, CEPH_STATX_MODE
, AT_SYMLINK_NOFOLLOW
), 0);
658 ASSERT_EQ(stx
.stx_mode
, 0100600U);
660 fd
= ceph_open(cmount
, test_file
, O_RDWR
, 0);
663 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
664 ceph_close(cmount
, fd
);
666 ceph_shutdown(cmount
);
669 TEST(LibCephFS
, Fchmod
) {
670 struct ceph_mount_info
*cmount
;
671 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
672 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
673 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
674 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
677 sprintf(test_file
, "test_perms_%d", getpid());
679 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
683 const char *bytes
= "foobarbaz";
684 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
686 // set perms to read but can't write
687 ASSERT_EQ(ceph_fchmod(cmount
, fd
, 0400), 0);
690 int ret
= ceph_read(cmount
, fd
, buf
, 100, 0);
691 ASSERT_EQ(ret
, (int)strlen(bytes
));
693 ASSERT_STREQ(buf
, bytes
);
695 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
697 ceph_close(cmount
, fd
);
699 ASSERT_EQ(ceph_open(cmount
, test_file
, O_RDWR
, 0), -EACCES
);
701 // reset back to writeable
702 ASSERT_EQ(ceph_chmod(cmount
, test_file
, 0600), 0);
704 fd
= ceph_open(cmount
, test_file
, O_RDWR
, 0);
707 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
708 ceph_close(cmount
, fd
);
710 ceph_shutdown(cmount
);
713 TEST(LibCephFS
, Fchown
) {
714 struct ceph_mount_info
*cmount
;
715 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
716 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
717 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
718 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
721 sprintf(test_file
, "test_fchown_%d", getpid());
723 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
726 // set perms to readable and writeable only by owner
727 ASSERT_EQ(ceph_fchmod(cmount
, fd
, 0600), 0);
729 // change ownership to nobody -- we assume nobody exists and id is always 65534
730 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "0"), 0);
731 ASSERT_EQ(ceph_fchown(cmount
, fd
, 65534, 65534), 0);
732 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "1"), 0);
734 ceph_close(cmount
, fd
);
736 fd
= ceph_open(cmount
, test_file
, O_RDWR
, 0);
737 ASSERT_EQ(fd
, -EACCES
);
739 ceph_shutdown(cmount
);
742 #if defined(__linux__) && defined(O_PATH)
743 TEST(LibCephFS
, FlagO_PATH
) {
744 struct ceph_mount_info
*cmount
;
746 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
747 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
748 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
749 ASSERT_EQ(0, ceph_mount(cmount
, NULL
));
751 char test_file
[PATH_MAX
];
752 sprintf(test_file
, "test_oflag_%d", getpid());
754 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
|O_PATH
, 0666);
755 ASSERT_EQ(-ENOENT
, fd
);
757 fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
759 ASSERT_EQ(0, ceph_close(cmount
, fd
));
761 // ok, the file has been created. perform real checks now
762 fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
|O_PATH
, 0666);
766 ASSERT_EQ(-EBADF
, ceph_read(cmount
, fd
, buf
, sizeof(buf
), 0));
767 ASSERT_EQ(-EBADF
, ceph_write(cmount
, fd
, buf
, sizeof(buf
), 0));
769 // set perms to readable and writeable only by owner
770 ASSERT_EQ(-EBADF
, ceph_fchmod(cmount
, fd
, 0600));
772 // change ownership to nobody -- we assume nobody exists and id is always 65534
773 ASSERT_EQ(-EBADF
, ceph_fchown(cmount
, fd
, 65534, 65534));
776 ASSERT_EQ(-EBADF
, ceph_fsync(cmount
, fd
, false));
778 struct ceph_statx stx
;
779 ASSERT_EQ(0, ceph_fstatx(cmount
, fd
, &stx
, 0, 0));
781 ASSERT_EQ(0, ceph_close(cmount
, fd
));
782 ceph_shutdown(cmount
);
786 TEST(LibCephFS
, Symlinks
) {
787 struct ceph_mount_info
*cmount
;
788 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
789 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
790 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
791 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
794 sprintf(test_file
, "test_symlinks_%d", getpid());
796 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
799 ceph_close(cmount
, fd
);
801 char test_symlink
[256];
802 sprintf(test_symlink
, "test_symlinks_sym_%d", getpid());
804 ASSERT_EQ(ceph_symlink(cmount
, test_file
, test_symlink
), 0);
806 // test the O_NOFOLLOW case
807 fd
= ceph_open(cmount
, test_symlink
, O_NOFOLLOW
, 0);
808 ASSERT_EQ(fd
, -ELOOP
);
810 // stat the original file
811 struct ceph_statx stx_orig
;
812 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx_orig
, CEPH_STATX_ALL_STATS
, 0), 0);
814 struct ceph_statx stx_symlink_orig
;
815 ASSERT_EQ(ceph_statx(cmount
, test_symlink
, &stx_symlink_orig
, CEPH_STATX_ALL_STATS
, 0), 0);
816 // ensure the statx bufs are equal
817 ASSERT_EQ(memcmp(&stx_orig
, &stx_symlink_orig
, sizeof(stx_orig
)), 0);
819 sprintf(test_file
, "/test_symlinks_abs_%d", getpid());
821 fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
824 ceph_close(cmount
, fd
);
826 sprintf(test_symlink
, "/test_symlinks_abs_sym_%d", getpid());
828 ASSERT_EQ(ceph_symlink(cmount
, test_file
, test_symlink
), 0);
830 // stat the original file
831 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx_orig
, CEPH_STATX_ALL_STATS
, 0), 0);
833 ASSERT_EQ(ceph_statx(cmount
, test_symlink
, &stx_symlink_orig
, CEPH_STATX_ALL_STATS
, 0), 0);
834 // ensure the statx bufs are equal
835 ASSERT_TRUE(!memcmp(&stx_orig
, &stx_symlink_orig
, sizeof(stx_orig
)));
838 ASSERT_EQ(ceph_statx(cmount
, test_symlink
, &stx_orig
, CEPH_STATX_ALL_STATS
, AT_SYMLINK_NOFOLLOW
), 0);
839 ASSERT_TRUE(S_ISLNK(stx_orig
.stx_mode
));
841 ceph_shutdown(cmount
);
844 TEST(LibCephFS
, DirSyms
) {
845 struct ceph_mount_info
*cmount
;
846 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
847 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
848 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
849 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
852 sprintf(test_dir1
, "dir1_symlinks_%d", getpid());
854 ASSERT_EQ(ceph_mkdir(cmount
, test_dir1
, 0700), 0);
856 char test_symdir
[256];
857 sprintf(test_symdir
, "symdir_symlinks_%d", getpid());
859 ASSERT_EQ(ceph_symlink(cmount
, test_dir1
, test_symdir
), 0);
862 sprintf(test_file
, "/symdir_symlinks_%d/test_symdir_file", getpid());
863 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0600);
865 ceph_close(cmount
, fd
);
867 struct ceph_statx stx
;
868 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx
, 0, AT_SYMLINK_NOFOLLOW
), 0);
870 // ensure that its a file not a directory we get back
871 ASSERT_TRUE(S_ISREG(stx
.stx_mode
));
873 ceph_shutdown(cmount
);
876 TEST(LibCephFS
, LoopSyms
) {
877 struct ceph_mount_info
*cmount
;
878 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
879 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
880 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
881 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
884 sprintf(test_dir1
, "dir1_loopsym_%d", getpid());
886 ASSERT_EQ(ceph_mkdir(cmount
, test_dir1
, 0700), 0);
889 sprintf(test_dir2
, "/dir1_loopsym_%d/loop_dir", getpid());
891 ASSERT_EQ(ceph_mkdir(cmount
, test_dir2
, 0700), 0);
893 // symlink it itself: /path/to/mysym -> /path/to/mysym
894 char test_symdir
[256];
895 sprintf(test_symdir
, "/dir1_loopsym_%d/loop_dir/symdir", getpid());
897 ASSERT_EQ(ceph_symlink(cmount
, test_symdir
, test_symdir
), 0);
900 sprintf(test_file
, "/dir1_loopsym_%d/loop_dir/symdir/test_loopsym_file", getpid());
901 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0600);
902 ASSERT_EQ(fd
, -ELOOP
);
904 // loop: /a -> /b, /b -> /c, /c -> /a
905 char a
[256], b
[256], c
[256];
906 sprintf(a
, "/%s/a", test_dir1
);
907 sprintf(b
, "/%s/b", test_dir1
);
908 sprintf(c
, "/%s/c", test_dir1
);
909 ASSERT_EQ(ceph_symlink(cmount
, a
, b
), 0);
910 ASSERT_EQ(ceph_symlink(cmount
, b
, c
), 0);
911 ASSERT_EQ(ceph_symlink(cmount
, c
, a
), 0);
912 ASSERT_EQ(ceph_open(cmount
, a
, O_RDWR
, 0), -ELOOP
);
914 ceph_shutdown(cmount
);
917 TEST(LibCephFS
, HardlinkNoOriginal
) {
919 int mypid
= getpid();
921 struct ceph_mount_info
*cmount
;
922 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
923 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
924 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
925 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
928 sprintf(dir
, "/test_rmdirfail%d", mypid
);
929 ASSERT_EQ(ceph_mkdir(cmount
, dir
, 0777), 0);
931 ASSERT_EQ(ceph_chdir(cmount
, dir
), 0);
933 int fd
= ceph_open(cmount
, "f1", O_CREAT
, 0644);
936 ceph_close(cmount
, fd
);
939 ASSERT_EQ(ceph_link(cmount
, "f1", "hardl1"), 0);
941 // remove file link points to
942 ASSERT_EQ(ceph_unlink(cmount
, "f1"), 0);
944 ceph_shutdown(cmount
);
947 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
948 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
949 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
950 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
951 ASSERT_EQ(ceph_chdir(cmount
, dir
), 0);
952 ASSERT_EQ(ceph_unlink(cmount
, "hardl1"), 0);
953 ASSERT_EQ(ceph_rmdir(cmount
, dir
), 0);
955 ceph_shutdown(cmount
);
958 TEST(LibCephFS
, BadArgument
) {
959 struct ceph_mount_info
*cmount
;
960 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
961 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
962 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
963 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
965 int fd
= ceph_open(cmount
, "test_file", O_CREAT
|O_RDWR
, 0666);
968 ASSERT_EQ(ceph_write(cmount
, fd
, buf
, sizeof(buf
), 0), (int)sizeof(buf
));
969 ASSERT_EQ(ceph_read(cmount
, fd
, buf
, 0, 5), 0);
970 ceph_close(cmount
, fd
);
971 ASSERT_EQ(ceph_unlink(cmount
, "test_file"), 0);
973 ceph_shutdown(cmount
);
976 TEST(LibCephFS
, BadFileDesc
) {
977 struct ceph_mount_info
*cmount
;
978 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
979 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
980 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
981 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
983 ASSERT_EQ(ceph_fchmod(cmount
, -1, 0655), -EBADF
);
984 ASSERT_EQ(ceph_close(cmount
, -1), -EBADF
);
985 ASSERT_EQ(ceph_lseek(cmount
, -1, 0, SEEK_SET
), -EBADF
);
988 ASSERT_EQ(ceph_read(cmount
, -1, buf
, 0, 0), -EBADF
);
989 ASSERT_EQ(ceph_write(cmount
, -1, buf
, 0, 0), -EBADF
);
991 ASSERT_EQ(ceph_ftruncate(cmount
, -1, 0), -EBADF
);
992 ASSERT_EQ(ceph_fsync(cmount
, -1, 0), -EBADF
);
994 struct ceph_statx stx
;
995 ASSERT_EQ(ceph_fstatx(cmount
, -1, &stx
, 0, 0), -EBADF
);
997 struct sockaddr_storage addr
;
998 ASSERT_EQ(ceph_get_file_stripe_address(cmount
, -1, 0, &addr
, 1), -EBADF
);
1000 ASSERT_EQ(ceph_get_file_stripe_unit(cmount
, -1), -EBADF
);
1001 ASSERT_EQ(ceph_get_file_pool(cmount
, -1), -EBADF
);
1003 ASSERT_EQ(ceph_get_file_pool_name(cmount
, -1, poolname
, sizeof(poolname
)), -EBADF
);
1004 ASSERT_EQ(ceph_get_file_replication(cmount
, -1), -EBADF
);
1005 ASSERT_EQ(ceph_get_file_object_size(cmount
, -1), -EBADF
);
1006 int stripe_unit
, stripe_count
, object_size
, pg_pool
;
1007 ASSERT_EQ(ceph_get_file_layout(cmount
, -1, &stripe_unit
, &stripe_count
, &object_size
, &pg_pool
), -EBADF
);
1008 ASSERT_EQ(ceph_get_file_stripe_count(cmount
, -1), -EBADF
);
1010 ceph_shutdown(cmount
);
1013 TEST(LibCephFS
, ReadEmptyFile
) {
1014 struct ceph_mount_info
*cmount
;
1015 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1016 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1017 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1018 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1020 // test the read_sync path in the client for zero files
1021 ASSERT_EQ(ceph_conf_set(cmount
, "client_debug_force_sync_read", "true"), 0);
1023 int mypid
= getpid();
1026 sprintf(testf
, "test_reademptyfile%d", mypid
);
1027 int fd
= ceph_open(cmount
, testf
, O_CREAT
|O_TRUNC
|O_WRONLY
, 0644);
1030 ceph_close(cmount
, fd
);
1032 fd
= ceph_open(cmount
, testf
, O_RDONLY
, 0);
1036 ASSERT_EQ(ceph_read(cmount
, fd
, buf
, 4096, 0), 0);
1038 ceph_close(cmount
, fd
);
1039 ceph_shutdown(cmount
);
1042 TEST(LibCephFS
, PreadvPwritev
) {
1043 struct ceph_mount_info
*cmount
;
1044 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1045 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1046 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1047 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1049 int mypid
= getpid();
1052 sprintf(testf
, "test_preadvpwritevfile%d", mypid
);
1053 int fd
= ceph_open(cmount
, testf
, O_CREAT
|O_RDWR
, 0666);
1056 char out0
[] = "hello ";
1057 char out1
[] = "world\n";
1058 struct iovec iov_out
[2] = {
1059 {out0
, sizeof(out0
)},
1060 {out1
, sizeof(out1
)},
1062 char in0
[sizeof(out0
)];
1063 char in1
[sizeof(out1
)];
1064 struct iovec iov_in
[2] = {
1068 ssize_t nwritten
= iov_out
[0].iov_len
+ iov_out
[1].iov_len
;
1069 ssize_t nread
= iov_in
[0].iov_len
+ iov_in
[1].iov_len
;
1071 ASSERT_EQ(ceph_pwritev(cmount
, fd
, iov_out
, 2, 0), nwritten
);
1072 ASSERT_EQ(ceph_preadv(cmount
, fd
, iov_in
, 2, 0), nread
);
1073 ASSERT_EQ(0, strncmp((const char*)iov_in
[0].iov_base
, (const char*)iov_out
[0].iov_base
, iov_out
[0].iov_len
));
1074 ASSERT_EQ(0, strncmp((const char*)iov_in
[1].iov_base
, (const char*)iov_out
[1].iov_base
, iov_out
[1].iov_len
));
1076 ceph_close(cmount
, fd
);
1077 ceph_shutdown(cmount
);
1080 TEST(LibCephFS
, StripeUnitGran
) {
1081 struct ceph_mount_info
*cmount
;
1082 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1083 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1084 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1085 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1086 ASSERT_GT(ceph_get_stripe_unit_granularity(cmount
), 0);
1087 ceph_shutdown(cmount
);
1090 TEST(LibCephFS
, Rename
) {
1091 struct ceph_mount_info
*cmount
;
1092 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1093 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1094 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1095 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1097 int mypid
= getpid();
1101 /* make a source file */
1102 sprintf(path_src
, "test_rename_src%d", mypid
);
1103 int fd
= ceph_open(cmount
, path_src
, O_CREAT
|O_TRUNC
|O_WRONLY
, 0777);
1105 ASSERT_EQ(0, ceph_close(cmount
, fd
));
1107 /* rename to a new dest path */
1108 sprintf(path_dst
, "test_rename_dst%d", mypid
);
1109 ASSERT_EQ(0, ceph_rename(cmount
, path_src
, path_dst
));
1111 /* test that dest path exists */
1112 struct ceph_statx stx
;
1113 ASSERT_EQ(0, ceph_statx(cmount
, path_dst
, &stx
, 0, 0));
1115 /* test that src path doesn't exist */
1116 ASSERT_EQ(-ENOENT
, ceph_statx(cmount
, path_src
, &stx
, 0, AT_SYMLINK_NOFOLLOW
));
1118 /* rename with non-existent source path */
1119 ASSERT_EQ(-ENOENT
, ceph_rename(cmount
, path_src
, path_dst
));
1121 ASSERT_EQ(0, ceph_unlink(cmount
, path_dst
));
1122 ceph_shutdown(cmount
);
1125 TEST(LibCephFS
, UseUnmounted
) {
1126 struct ceph_mount_info
*cmount
;
1127 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1128 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1129 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1131 struct statvfs stvfs
;
1132 EXPECT_EQ(-ENOTCONN
, ceph_statfs(cmount
, "/", &stvfs
));
1133 EXPECT_EQ(-ENOTCONN
, ceph_get_local_osd(cmount
));
1134 EXPECT_EQ(-ENOTCONN
, ceph_chdir(cmount
, "/"));
1136 struct ceph_dir_result
*dirp
;
1137 EXPECT_EQ(-ENOTCONN
, ceph_opendir(cmount
, "/", &dirp
));
1138 EXPECT_EQ(-ENOTCONN
, ceph_closedir(cmount
, dirp
));
1140 ceph_readdir(cmount
, dirp
);
1141 EXPECT_EQ(ENOTCONN
, errno
);
1143 struct dirent rdent
;
1144 EXPECT_EQ(-ENOTCONN
, ceph_readdir_r(cmount
, dirp
, &rdent
));
1146 struct ceph_statx stx
;
1147 EXPECT_EQ(-ENOTCONN
, ceph_readdirplus_r(cmount
, dirp
, &rdent
, &stx
, 0, 0, NULL
));
1148 EXPECT_EQ(-ENOTCONN
, ceph_getdents(cmount
, dirp
, NULL
, 0));
1149 EXPECT_EQ(-ENOTCONN
, ceph_getdnames(cmount
, dirp
, NULL
, 0));
1150 EXPECT_EQ(-ENOTCONN
, ceph_telldir(cmount
, dirp
));
1151 EXPECT_EQ(-ENOTCONN
, ceph_link(cmount
, "/", "/link"));
1152 EXPECT_EQ(-ENOTCONN
, ceph_unlink(cmount
, "/path"));
1153 EXPECT_EQ(-ENOTCONN
, ceph_rename(cmount
, "/path", "/path"));
1154 EXPECT_EQ(-ENOTCONN
, ceph_mkdir(cmount
, "/", 0655));
1155 EXPECT_EQ(-ENOTCONN
, ceph_mkdirs(cmount
, "/", 0655));
1156 EXPECT_EQ(-ENOTCONN
, ceph_rmdir(cmount
, "/path"));
1157 EXPECT_EQ(-ENOTCONN
, ceph_readlink(cmount
, "/path", NULL
, 0));
1158 EXPECT_EQ(-ENOTCONN
, ceph_symlink(cmount
, "/path", "/path"));
1159 EXPECT_EQ(-ENOTCONN
, ceph_statx(cmount
, "/path", &stx
, 0, 0));
1160 EXPECT_EQ(-ENOTCONN
, ceph_setattrx(cmount
, "/path", &stx
, 0, 0));
1161 EXPECT_EQ(-ENOTCONN
, ceph_getxattr(cmount
, "/path", "name", NULL
, 0));
1162 EXPECT_EQ(-ENOTCONN
, ceph_lgetxattr(cmount
, "/path", "name", NULL
, 0));
1163 EXPECT_EQ(-ENOTCONN
, ceph_listxattr(cmount
, "/path", NULL
, 0));
1164 EXPECT_EQ(-ENOTCONN
, ceph_llistxattr(cmount
, "/path", NULL
, 0));
1165 EXPECT_EQ(-ENOTCONN
, ceph_removexattr(cmount
, "/path", "name"));
1166 EXPECT_EQ(-ENOTCONN
, ceph_lremovexattr(cmount
, "/path", "name"));
1167 EXPECT_EQ(-ENOTCONN
, ceph_setxattr(cmount
, "/path", "name", NULL
, 0, 0));
1168 EXPECT_EQ(-ENOTCONN
, ceph_lsetxattr(cmount
, "/path", "name", NULL
, 0, 0));
1169 EXPECT_EQ(-ENOTCONN
, ceph_fsetattrx(cmount
, 0, &stx
, 0));
1170 EXPECT_EQ(-ENOTCONN
, ceph_chmod(cmount
, "/path", 0));
1171 EXPECT_EQ(-ENOTCONN
, ceph_fchmod(cmount
, 0, 0));
1172 EXPECT_EQ(-ENOTCONN
, ceph_chown(cmount
, "/path", 0, 0));
1173 EXPECT_EQ(-ENOTCONN
, ceph_lchown(cmount
, "/path", 0, 0));
1174 EXPECT_EQ(-ENOTCONN
, ceph_fchown(cmount
, 0, 0, 0));
1177 EXPECT_EQ(-ENOTCONN
, ceph_utime(cmount
, "/path", &utb
));
1178 EXPECT_EQ(-ENOTCONN
, ceph_truncate(cmount
, "/path", 0));
1179 EXPECT_EQ(-ENOTCONN
, ceph_mknod(cmount
, "/path", 0, 0));
1180 EXPECT_EQ(-ENOTCONN
, ceph_open(cmount
, "/path", 0, 0));
1181 EXPECT_EQ(-ENOTCONN
, ceph_open_layout(cmount
, "/path", 0, 0, 0, 0, 0, "pool"));
1182 EXPECT_EQ(-ENOTCONN
, ceph_close(cmount
, 0));
1183 EXPECT_EQ(-ENOTCONN
, ceph_lseek(cmount
, 0, 0, SEEK_SET
));
1184 EXPECT_EQ(-ENOTCONN
, ceph_read(cmount
, 0, NULL
, 0, 0));
1185 EXPECT_EQ(-ENOTCONN
, ceph_write(cmount
, 0, NULL
, 0, 0));
1186 EXPECT_EQ(-ENOTCONN
, ceph_ftruncate(cmount
, 0, 0));
1187 EXPECT_EQ(-ENOTCONN
, ceph_fsync(cmount
, 0, 0));
1188 EXPECT_EQ(-ENOTCONN
, ceph_fstatx(cmount
, 0, &stx
, 0, 0));
1189 EXPECT_EQ(-ENOTCONN
, ceph_sync_fs(cmount
));
1190 EXPECT_EQ(-ENOTCONN
, ceph_get_file_stripe_unit(cmount
, 0));
1191 EXPECT_EQ(-ENOTCONN
, ceph_get_file_stripe_count(cmount
, 0));
1192 EXPECT_EQ(-ENOTCONN
, ceph_get_file_layout(cmount
, 0, NULL
, NULL
,NULL
,NULL
));
1193 EXPECT_EQ(-ENOTCONN
, ceph_get_file_object_size(cmount
, 0));
1194 EXPECT_EQ(-ENOTCONN
, ceph_get_file_pool(cmount
, 0));
1195 EXPECT_EQ(-ENOTCONN
, ceph_get_file_pool_name(cmount
, 0, NULL
, 0));
1196 EXPECT_EQ(-ENOTCONN
, ceph_get_file_replication(cmount
, 0));
1197 EXPECT_EQ(-ENOTCONN
, ceph_get_path_replication(cmount
, "/path"));
1198 EXPECT_EQ(-ENOTCONN
, ceph_get_path_layout(cmount
, "/path", NULL
, NULL
, NULL
, NULL
));
1199 EXPECT_EQ(-ENOTCONN
, ceph_get_path_object_size(cmount
, "/path"));
1200 EXPECT_EQ(-ENOTCONN
, ceph_get_path_stripe_count(cmount
, "/path"));
1201 EXPECT_EQ(-ENOTCONN
, ceph_get_path_stripe_unit(cmount
, "/path"));
1202 EXPECT_EQ(-ENOTCONN
, ceph_get_path_pool(cmount
, "/path"));
1203 EXPECT_EQ(-ENOTCONN
, ceph_get_path_pool_name(cmount
, "/path", NULL
, 0));
1204 EXPECT_EQ(-ENOTCONN
, ceph_get_pool_name(cmount
, 0, NULL
, 0));
1205 EXPECT_EQ(-ENOTCONN
, ceph_get_file_stripe_address(cmount
, 0, 0, NULL
, 0));
1206 EXPECT_EQ(-ENOTCONN
, ceph_localize_reads(cmount
, 0));
1207 EXPECT_EQ(-ENOTCONN
, ceph_debug_get_fd_caps(cmount
, 0));
1208 EXPECT_EQ(-ENOTCONN
, ceph_debug_get_file_caps(cmount
, "/path"));
1209 EXPECT_EQ(-ENOTCONN
, ceph_get_stripe_unit_granularity(cmount
));
1210 EXPECT_EQ(-ENOTCONN
, ceph_get_pool_id(cmount
, "data"));
1211 EXPECT_EQ(-ENOTCONN
, ceph_get_pool_replication(cmount
, 1));
1213 ceph_release(cmount
);
1216 TEST(LibCephFS
, GetPoolId
) {
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);
1224 memset(name
, 0, sizeof(name
));
1225 ASSERT_LE(0, ceph_get_path_pool_name(cmount
, "/", name
, sizeof(name
)));
1226 ASSERT_GE(ceph_get_pool_id(cmount
, name
), 0);
1227 ASSERT_EQ(ceph_get_pool_id(cmount
, "weflkjwelfjwlkejf"), -ENOENT
);
1229 ceph_shutdown(cmount
);
1232 TEST(LibCephFS
, GetPoolReplication
) {
1233 struct ceph_mount_info
*cmount
;
1234 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1235 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1236 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1237 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1239 /* negative pools */
1240 ASSERT_EQ(ceph_get_pool_replication(cmount
, -10), -ENOENT
);
1244 int stripe_unit
, stripe_count
, object_size
;
1245 ASSERT_EQ(0, ceph_get_path_layout(cmount
, "/", &stripe_unit
, &stripe_count
,
1246 &object_size
, &pool_id
));
1247 ASSERT_GE(pool_id
, 0);
1248 ASSERT_GT(ceph_get_pool_replication(cmount
, pool_id
), 0);
1250 ceph_shutdown(cmount
);
1253 TEST(LibCephFS
, GetExtentOsds
) {
1254 struct ceph_mount_info
*cmount
;
1255 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1257 EXPECT_EQ(-ENOTCONN
, ceph_get_file_extent_osds(cmount
, 0, 0, NULL
, NULL
, 0));
1259 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1260 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1261 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1263 int stripe_unit
= (1<<18);
1266 char test_file
[256];
1267 sprintf(test_file
, "test_extent_osds_%d", getpid());
1268 int fd
= ceph_open_layout(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666,
1269 stripe_unit
, 2, stripe_unit
*2, NULL
);
1272 /* get back how many osds > 0 */
1273 int ret
= ceph_get_file_extent_osds(cmount
, fd
, 0, NULL
, NULL
, 0);
1279 /* full stripe extent */
1280 EXPECT_EQ(ret
, ceph_get_file_extent_osds(cmount
, fd
, 0, &len
, osds
, ret
));
1281 EXPECT_EQ(len
, (int64_t)stripe_unit
);
1283 /* half stripe extent */
1284 EXPECT_EQ(ret
, ceph_get_file_extent_osds(cmount
, fd
, stripe_unit
/2, &len
, osds
, ret
));
1285 EXPECT_EQ(len
, (int64_t)stripe_unit
/2);
1287 /* 1.5 stripe unit offset -1 byte */
1288 EXPECT_EQ(ret
, ceph_get_file_extent_osds(cmount
, fd
, 3*stripe_unit
/2-1, &len
, osds
, ret
));
1289 EXPECT_EQ(len
, (int64_t)stripe_unit
/2+1);
1291 /* 1.5 stripe unit offset +1 byte */
1292 EXPECT_EQ(ret
, ceph_get_file_extent_osds(cmount
, fd
, 3*stripe_unit
/2+1, &len
, osds
, ret
));
1293 EXPECT_EQ(len
, (int64_t)stripe_unit
/2-1);
1295 /* only when more than 1 osd */
1297 EXPECT_EQ(-ERANGE
, ceph_get_file_extent_osds(cmount
, fd
, 0, NULL
, osds
, 1));
1300 ceph_close(cmount
, fd
);
1302 ceph_shutdown(cmount
);
1305 TEST(LibCephFS
, GetOsdCrushLocation
) {
1306 struct ceph_mount_info
*cmount
;
1307 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1309 EXPECT_EQ(-ENOTCONN
, ceph_get_osd_crush_location(cmount
, 0, NULL
, 0));
1311 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1312 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1313 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1315 ASSERT_EQ(ceph_get_osd_crush_location(cmount
, 0, NULL
, 1), -EINVAL
);
1318 ASSERT_EQ(ceph_get_osd_crush_location(cmount
, 9999999, path
, 0), -ENOENT
);
1319 ASSERT_EQ(ceph_get_osd_crush_location(cmount
, -1, path
, 0), -EINVAL
);
1321 char test_file
[256];
1322 sprintf(test_file
, "test_osds_loc_%d", getpid());
1323 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
1326 /* get back how many osds > 0 */
1327 int ret
= ceph_get_file_extent_osds(cmount
, fd
, 0, NULL
, NULL
, 0);
1330 /* full stripe extent */
1332 EXPECT_EQ(ret
, ceph_get_file_extent_osds(cmount
, fd
, 0, NULL
, osds
, ret
));
1334 ASSERT_GT(ceph_get_osd_crush_location(cmount
, 0, path
, 0), 0);
1335 ASSERT_EQ(ceph_get_osd_crush_location(cmount
, 0, path
, 1), -ERANGE
);
1337 for (int i
= 0; i
< ret
; i
++) {
1338 int len
= ceph_get_osd_crush_location(cmount
, osds
[i
], path
, sizeof(path
));
1342 std::string
type(path
+ pos
);
1343 ASSERT_GT((int)type
.size(), 0);
1344 pos
+= type
.size() + 1;
1346 std::string
name(path
+ pos
);
1347 ASSERT_GT((int)name
.size(), 0);
1348 pos
+= name
.size() + 1;
1352 ceph_close(cmount
, fd
);
1353 ceph_shutdown(cmount
);
1356 TEST(LibCephFS
, GetOsdAddr
) {
1357 struct ceph_mount_info
*cmount
;
1358 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1360 EXPECT_EQ(-ENOTCONN
, ceph_get_osd_addr(cmount
, 0, NULL
));
1362 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1363 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1364 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1366 ASSERT_EQ(-EINVAL
, ceph_get_osd_addr(cmount
, 0, NULL
));
1368 struct sockaddr_storage addr
;
1369 ASSERT_EQ(-ENOENT
, ceph_get_osd_addr(cmount
, -1, &addr
));
1370 ASSERT_EQ(-ENOENT
, ceph_get_osd_addr(cmount
, 9999999, &addr
));
1372 ASSERT_EQ(0, ceph_get_osd_addr(cmount
, 0, &addr
));
1374 ceph_shutdown(cmount
);
1377 TEST(LibCephFS
, OpenNoClose
) {
1378 struct ceph_mount_info
*cmount
;
1379 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1380 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1381 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1382 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1384 pid_t mypid
= getpid();
1386 sprintf(str_buf
, "open_no_close_dir%d", mypid
);
1387 ASSERT_EQ(0, ceph_mkdirs(cmount
, str_buf
, 0777));
1389 struct ceph_dir_result
*ls_dir
= NULL
;
1390 ASSERT_EQ(ceph_opendir(cmount
, str_buf
, &ls_dir
), 0);
1392 sprintf(str_buf
, "open_no_close_file%d", mypid
);
1393 int fd
= ceph_open(cmount
, str_buf
, O_RDONLY
|O_CREAT
, 0666);
1396 // shutdown should force close opened file/dir
1397 ceph_shutdown(cmount
);
1400 TEST(LibCephFS
, Nlink
) {
1401 struct ceph_mount_info
*cmount
;
1402 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1403 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1404 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1405 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1407 Inode
*root
, *dir
, *file
;
1409 ASSERT_EQ(ceph_ll_lookup_root(cmount
, &root
), 0);
1411 char dirname
[32], filename
[32], linkname
[32];
1412 sprintf(dirname
, "nlinkdir%x", getpid());
1413 sprintf(filename
, "nlinkorig%x", getpid());
1414 sprintf(linkname
, "nlinklink%x", getpid());
1416 struct ceph_statx stx
;
1418 UserPerm
*perms
= ceph_mount_perms(cmount
);
1420 ASSERT_EQ(ceph_ll_mkdir(cmount
, root
, dirname
, 0755, &dir
, &stx
, 0, 0, perms
), 0);
1421 ASSERT_EQ(ceph_ll_create(cmount
, dir
, filename
, 0666, O_RDWR
|O_CREAT
|O_EXCL
,
1422 &file
, &fh
, &stx
, CEPH_STATX_NLINK
, 0, perms
), 0);
1423 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
1424 ASSERT_EQ(stx
.stx_nlink
, (nlink_t
)1);
1426 ASSERT_EQ(ceph_ll_link(cmount
, file
, dir
, linkname
, perms
), 0);
1427 ASSERT_EQ(ceph_ll_getattr(cmount
, file
, &stx
, CEPH_STATX_NLINK
, 0, perms
), 0);
1428 ASSERT_EQ(stx
.stx_nlink
, (nlink_t
)2);
1430 ASSERT_EQ(ceph_ll_unlink(cmount
, dir
, linkname
, perms
), 0);
1431 ASSERT_EQ(ceph_ll_lookup(cmount
, dir
, filename
, &file
, &stx
,
1432 CEPH_STATX_NLINK
, 0, perms
), 0);
1433 ASSERT_EQ(stx
.stx_nlink
, (nlink_t
)1);
1435 ceph_shutdown(cmount
);
1438 TEST(LibCephFS
, SlashDotDot
) {
1439 struct ceph_mount_info
*cmount
;
1440 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1441 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1442 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1443 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1445 struct ceph_statx stx
;
1446 ASSERT_EQ(ceph_statx(cmount
, "/.", &stx
, CEPH_STATX_INO
, 0), 0);
1448 ino_t ino
= stx
.stx_ino
;
1449 ASSERT_EQ(ceph_statx(cmount
, "/..", &stx
, CEPH_STATX_INO
, 0), 0);
1451 /* At root, "." and ".." should be the same inode */
1452 ASSERT_EQ(ino
, stx
.stx_ino
);
1454 /* Test accessing the parent of an unlinked directory */
1455 char dir1
[32], dir2
[32];
1456 sprintf(dir1
, "/sldotdot%x", getpid());
1457 sprintf(dir2
, "%s/sub%x", dir1
, getpid());
1459 ASSERT_EQ(ceph_mkdir(cmount
, dir1
, 0755), 0);
1460 ASSERT_EQ(ceph_mkdir(cmount
, dir2
, 0755), 0);
1462 ASSERT_EQ(ceph_chdir(cmount
, dir2
), 0);
1464 /* Test behavior when unlinking cwd */
1465 struct ceph_dir_result
*rdir
;
1466 ASSERT_EQ(ceph_opendir(cmount
, ".", &rdir
), 0);
1467 ASSERT_EQ(ceph_rmdir(cmount
, dir2
), 0);
1470 struct dirent
*result
= ceph_readdir(cmount
, rdir
);
1471 ino
= result
->d_ino
;
1473 /* get ".." entry */
1474 result
= ceph_readdir(cmount
, rdir
);
1475 ASSERT_EQ(ino
, result
->d_ino
);
1476 ceph_closedir(cmount
, rdir
);
1478 /* Make sure it works same way when mounting subtree */
1479 ASSERT_EQ(ceph_unmount(cmount
), 0);
1480 ASSERT_EQ(ceph_mount(cmount
, dir1
), 0);
1481 ASSERT_EQ(ceph_statx(cmount
, "/..", &stx
, CEPH_STATX_INO
, 0), 0);
1483 /* Test readdir behavior */
1484 ASSERT_EQ(ceph_opendir(cmount
, "/", &rdir
), 0);
1485 result
= ceph_readdir(cmount
, rdir
);
1486 ASSERT_TRUE(result
!= NULL
);
1487 ASSERT_STREQ(result
->d_name
, ".");
1488 ino
= result
->d_ino
;
1489 result
= ceph_readdir(cmount
, rdir
);
1490 ASSERT_TRUE(result
!= NULL
);
1491 ASSERT_STREQ(result
->d_name
, "..");
1492 ASSERT_EQ(ino
, result
->d_ino
);
1494 ceph_shutdown(cmount
);
1498 timespec_eq(timespec
const& lhs
, timespec
const& rhs
)
1500 return lhs
.tv_sec
== rhs
.tv_sec
&& lhs
.tv_nsec
== rhs
.tv_nsec
;
1503 TEST(LibCephFS
, Btime
) {
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);
1511 sprintf(filename
, "/getattrx%x", getpid());
1513 ceph_unlink(cmount
, filename
);
1514 int fd
= ceph_open(cmount
, filename
, O_RDWR
|O_CREAT
|O_EXCL
, 0666);
1517 /* make sure fstatx works */
1518 struct ceph_statx stx
;
1520 ASSERT_EQ(ceph_fstatx(cmount
, fd
, &stx
, CEPH_STATX_CTIME
|CEPH_STATX_BTIME
, 0), 0);
1521 ASSERT_TRUE(stx
.stx_mask
& (CEPH_STATX_CTIME
|CEPH_STATX_BTIME
));
1522 ASSERT_TRUE(timespec_eq(stx
.stx_ctime
, stx
.stx_btime
));
1523 ceph_close(cmount
, fd
);
1525 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_CTIME
|CEPH_STATX_BTIME
, 0), 0);
1526 ASSERT_TRUE(timespec_eq(stx
.stx_ctime
, stx
.stx_btime
));
1527 ASSERT_TRUE(stx
.stx_mask
& (CEPH_STATX_CTIME
|CEPH_STATX_BTIME
));
1529 struct timespec old_btime
= stx
.stx_btime
;
1531 /* Now sleep, do a chmod and verify that the ctime changed, but btime didn't */
1533 ASSERT_EQ(ceph_chmod(cmount
, filename
, 0644), 0);
1534 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_CTIME
|CEPH_STATX_BTIME
, 0), 0);
1535 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_BTIME
);
1536 ASSERT_TRUE(timespec_eq(stx
.stx_btime
, old_btime
));
1537 ASSERT_FALSE(timespec_eq(stx
.stx_ctime
, stx
.stx_btime
));
1539 ceph_shutdown(cmount
);
1542 TEST(LibCephFS
, SetBtime
) {
1543 struct ceph_mount_info
*cmount
;
1544 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1545 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1546 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1547 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1550 sprintf(filename
, "/setbtime%x", getpid());
1552 ceph_unlink(cmount
, filename
);
1553 int fd
= ceph_open(cmount
, filename
, O_RDWR
|O_CREAT
|O_EXCL
, 0666);
1555 ceph_close(cmount
, fd
);
1557 struct ceph_statx stx
;
1558 struct timespec old_btime
= { 1, 2 };
1560 stx
.stx_btime
= old_btime
;
1562 ASSERT_EQ(ceph_setattrx(cmount
, filename
, &stx
, CEPH_SETATTR_BTIME
, 0), 0);
1564 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_BTIME
, 0), 0);
1565 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_BTIME
);
1566 ASSERT_TRUE(timespec_eq(stx
.stx_btime
, old_btime
));
1568 ceph_shutdown(cmount
);
1571 TEST(LibCephFS
, LazyStatx
) {
1572 struct ceph_mount_info
*cmount1
, *cmount2
;
1573 ASSERT_EQ(ceph_create(&cmount1
, NULL
), 0);
1574 ASSERT_EQ(ceph_create(&cmount2
, NULL
), 0);
1575 ASSERT_EQ(ceph_conf_read_file(cmount1
, NULL
), 0);
1576 ASSERT_EQ(ceph_conf_read_file(cmount2
, NULL
), 0);
1577 ASSERT_EQ(0, ceph_conf_parse_env(cmount1
, NULL
));
1578 ASSERT_EQ(0, ceph_conf_parse_env(cmount2
, NULL
));
1579 ASSERT_EQ(ceph_mount(cmount1
, "/"), 0);
1580 ASSERT_EQ(ceph_mount(cmount2
, "/"), 0);
1583 sprintf(filename
, "lazystatx%x", getpid());
1585 Inode
*root1
, *file1
, *root2
, *file2
;
1586 struct ceph_statx stx
;
1588 UserPerm
*perms1
= ceph_mount_perms(cmount1
);
1589 UserPerm
*perms2
= ceph_mount_perms(cmount2
);
1591 ASSERT_EQ(ceph_ll_lookup_root(cmount1
, &root1
), 0);
1592 ceph_ll_unlink(cmount1
, root1
, filename
, perms1
);
1593 ASSERT_EQ(ceph_ll_create(cmount1
, root1
, filename
, 0666, O_RDWR
|O_CREAT
|O_EXCL
,
1594 &file1
, &fh
, &stx
, 0, 0, perms1
), 0);
1595 ASSERT_EQ(ceph_ll_close(cmount1
, fh
), 0);
1597 ASSERT_EQ(ceph_ll_lookup_root(cmount2
, &root2
), 0);
1599 ASSERT_EQ(ceph_ll_lookup(cmount2
, root2
, filename
, &file2
, &stx
, CEPH_STATX_CTIME
, 0, perms2
), 0);
1601 struct timespec old_ctime
= stx
.stx_ctime
;
1604 * Now sleep, do a chmod on the first client and the see whether we get a
1605 * different ctime with a statx that uses AT_NO_ATTR_SYNC
1608 stx
.stx_mode
= 0644;
1609 ASSERT_EQ(ceph_ll_setattr(cmount1
, file1
, &stx
, CEPH_SETATTR_MODE
, perms1
), 0);
1611 ASSERT_EQ(ceph_ll_getattr(cmount2
, file2
, &stx
, CEPH_STATX_CTIME
, AT_NO_ATTR_SYNC
, perms2
), 0);
1612 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_CTIME
);
1613 ASSERT_TRUE(stx
.stx_ctime
.tv_sec
== old_ctime
.tv_sec
&&
1614 stx
.stx_ctime
.tv_nsec
== old_ctime
.tv_nsec
);
1616 ceph_shutdown(cmount1
);
1617 ceph_shutdown(cmount2
);
1620 TEST(LibCephFS
, ChangeAttr
) {
1621 struct ceph_mount_info
*cmount
;
1622 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1623 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1624 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1625 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1628 sprintf(filename
, "/changeattr%x", getpid());
1630 ceph_unlink(cmount
, filename
);
1631 int fd
= ceph_open(cmount
, filename
, O_RDWR
|O_CREAT
|O_EXCL
, 0666);
1634 struct ceph_statx stx
;
1635 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1636 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1638 uint64_t old_change_attr
= stx
.stx_version
;
1640 /* do chmod, and check whether change_attr changed */
1641 ASSERT_EQ(ceph_chmod(cmount
, filename
, 0644), 0);
1642 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1643 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1644 ASSERT_NE(stx
.stx_version
, old_change_attr
);
1645 old_change_attr
= stx
.stx_version
;
1647 /* now do a write and see if it changed again */
1648 ASSERT_EQ(3, ceph_write(cmount
, fd
, "foo", 3, 0));
1649 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1650 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1651 ASSERT_NE(stx
.stx_version
, old_change_attr
);
1652 old_change_attr
= stx
.stx_version
;
1654 /* Now truncate and check again */
1655 ASSERT_EQ(0, ceph_ftruncate(cmount
, fd
, 0));
1656 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1657 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1658 ASSERT_NE(stx
.stx_version
, old_change_attr
);
1660 ceph_close(cmount
, fd
);
1661 ceph_shutdown(cmount
);
1664 TEST(LibCephFS
, DirChangeAttr
) {
1665 struct ceph_mount_info
*cmount
;
1666 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1667 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1668 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1669 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1671 char dirname
[32], filename
[32];
1672 sprintf(dirname
, "/dirchange%x", getpid());
1673 sprintf(filename
, "%s/foo", dirname
);
1675 ASSERT_EQ(ceph_mkdir(cmount
, dirname
, 0755), 0);
1677 struct ceph_statx stx
;
1678 ASSERT_EQ(ceph_statx(cmount
, dirname
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1679 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1681 uint64_t old_change_attr
= stx
.stx_version
;
1683 int fd
= ceph_open(cmount
, filename
, O_RDWR
|O_CREAT
|O_EXCL
, 0666);
1685 ceph_close(cmount
, fd
);
1687 ASSERT_EQ(ceph_statx(cmount
, dirname
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1688 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1689 ASSERT_NE(stx
.stx_version
, old_change_attr
);
1691 old_change_attr
= stx
.stx_version
;
1693 ASSERT_EQ(ceph_unlink(cmount
, filename
), 0);
1694 ASSERT_EQ(ceph_statx(cmount
, dirname
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1695 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1696 ASSERT_NE(stx
.stx_version
, old_change_attr
);
1698 ceph_shutdown(cmount
);
1701 TEST(LibCephFS
, SetSize
) {
1702 struct ceph_mount_info
*cmount
;
1703 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1704 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1705 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1706 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1709 sprintf(filename
, "/setsize%x", getpid());
1711 ceph_unlink(cmount
, filename
);
1712 int fd
= ceph_open(cmount
, filename
, O_RDWR
|O_CREAT
|O_EXCL
, 0666);
1715 struct ceph_statx stx
;
1716 uint64_t size
= 8388608;
1717 stx
.stx_size
= size
;
1718 ASSERT_EQ(ceph_fsetattrx(cmount
, fd
, &stx
, CEPH_SETATTR_SIZE
), 0);
1719 ASSERT_EQ(ceph_fstatx(cmount
, fd
, &stx
, CEPH_STATX_SIZE
, 0), 0);
1720 ASSERT_EQ(stx
.stx_size
, size
);
1722 ceph_close(cmount
, fd
);
1723 ceph_shutdown(cmount
);
1726 TEST(LibCephFS
, ClearSetuid
) {
1727 struct ceph_mount_info
*cmount
;
1728 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1729 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1730 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1731 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1734 ASSERT_EQ(ceph_ll_lookup_root(cmount
, &root
), 0);
1737 sprintf(filename
, "clearsetuid%x", getpid());
1741 struct ceph_statx stx
;
1742 const mode_t after_mode
= S_IRWXU
;
1743 const mode_t before_mode
= S_IRWXU
| S_ISUID
| S_ISGID
;
1744 const unsigned want
= CEPH_STATX_UID
|CEPH_STATX_GID
|CEPH_STATX_MODE
;
1745 UserPerm
*usercred
= ceph_mount_perms(cmount
);
1747 ceph_ll_unlink(cmount
, root
, filename
, usercred
);
1748 ASSERT_EQ(ceph_ll_create(cmount
, root
, filename
, before_mode
,
1749 O_RDWR
|O_CREAT
|O_EXCL
, &in
, &fh
, &stx
, want
, 0,
1752 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, before_mode
);
1755 ASSERT_EQ(ceph_ll_write(cmount
, fh
, 0, 3, "foo"), 3);
1756 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, usercred
), 0);
1757 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_MODE
);
1758 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, after_mode
);
1761 stx
.stx_mode
= before_mode
;
1762 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, usercred
), 0);
1763 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, usercred
), 0);
1764 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_MODE
);
1765 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, before_mode
);
1769 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_SETATTR_SIZE
, usercred
), 0);
1770 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, usercred
), 0);
1771 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_MODE
);
1772 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, after_mode
);
1775 stx
.stx_mode
= before_mode
;
1776 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, usercred
), 0);
1777 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, usercred
), 0);
1778 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_MODE
);
1779 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, before_mode
);
1781 // chown -- for this we need to be "root"
1782 UserPerm
*rootcred
= ceph_userperm_new(0, 0, 0, NULL
);
1783 ASSERT_TRUE(rootcred
);
1786 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_SETATTR_UID
|CEPH_SETATTR_GID
, rootcred
), 0);
1787 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, usercred
), 0);
1788 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_MODE
);
1789 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, after_mode
);
1791 /* test chown with supplementary groups, and chown with/without exe bit */
1794 gid_t gids
[] = {65533,65532};
1795 UserPerm
*altcred
= ceph_userperm_new(u
, g
, sizeof gids
/ sizeof gids
[0], gids
);
1798 mode_t m
= S_ISGID
|S_ISUID
|S_IRUSR
|S_IWUSR
;
1800 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_STATX_MODE
|CEPH_SETATTR_UID
|CEPH_SETATTR_GID
, rootcred
), 0);
1801 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, altcred
), 0);
1802 ASSERT_EQ(stx
.stx_mode
&(mode_t
)ALLPERMS
, m
);
1803 /* not dropped without exe bit */
1804 stx
.stx_gid
= gids
[0];
1805 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_SETATTR_GID
, altcred
), 0);
1806 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, altcred
), 0);
1807 ASSERT_EQ(stx
.stx_mode
&(mode_t
)ALLPERMS
, m
);
1808 /* now check dropped with exe bit */
1809 m
= S_ISGID
|S_ISUID
|S_IRWXU
;
1811 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, altcred
), 0);
1812 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, altcred
), 0);
1813 ASSERT_EQ(stx
.stx_mode
&(mode_t
)ALLPERMS
, m
);
1814 stx
.stx_gid
= gids
[1];
1815 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_SETATTR_GID
, altcred
), 0);
1816 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, altcred
), 0);
1817 ASSERT_EQ(stx
.stx_mode
&(mode_t
)ALLPERMS
, m
&(S_IRWXU
|S_IRWXG
|S_IRWXO
));
1818 ceph_userperm_destroy(altcred
);
1820 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
1821 ceph_shutdown(cmount
);
1824 TEST(LibCephFS
, OperationsOnRoot
)
1826 struct ceph_mount_info
*cmount
;
1827 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1828 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1829 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1830 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1833 sprintf(dirname
, "/somedir%x", getpid());
1835 ASSERT_EQ(ceph_mkdir(cmount
, dirname
, 0755), 0);
1837 ASSERT_EQ(ceph_rmdir(cmount
, "/"), -EBUSY
);
1839 ASSERT_EQ(ceph_link(cmount
, "/", "/"), -EEXIST
);
1840 ASSERT_EQ(ceph_link(cmount
, dirname
, "/"), -EEXIST
);
1841 ASSERT_EQ(ceph_link(cmount
, "nonExisitingDir", "/"), -ENOENT
);
1843 ASSERT_EQ(ceph_unlink(cmount
, "/"), -EISDIR
);
1845 ASSERT_EQ(ceph_rename(cmount
, "/", "/"), -EBUSY
);
1846 ASSERT_EQ(ceph_rename(cmount
, dirname
, "/"), -EBUSY
);
1847 ASSERT_EQ(ceph_rename(cmount
, "nonExistingDir", "/"), -EBUSY
);
1848 ASSERT_EQ(ceph_rename(cmount
, "/", dirname
), -EBUSY
);
1849 ASSERT_EQ(ceph_rename(cmount
, "/", "nonExistingDir"), -EBUSY
);
1851 ASSERT_EQ(ceph_mkdir(cmount
, "/", 0777), -EEXIST
);
1853 ASSERT_EQ(ceph_mknod(cmount
, "/", 0, 0), -EEXIST
);
1855 ASSERT_EQ(ceph_symlink(cmount
, "/", "/"), -EEXIST
);
1856 ASSERT_EQ(ceph_symlink(cmount
, dirname
, "/"), -EEXIST
);
1857 ASSERT_EQ(ceph_symlink(cmount
, "nonExistingDir", "/"), -EEXIST
);
1859 ceph_shutdown(cmount
);