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 "include/compat.h"
16 #include "gtest/gtest.h"
17 #include "include/cephfs/libcephfs.h"
18 #include "mds/mdstypes.h"
19 #include "include/stat.h"
23 #include <sys/types.h>
28 #include <sys/resource.h>
30 #include "common/Clock.h"
34 #include <sys/xattr.h>
37 #include <fmt/format.h>
44 #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
49 TEST(LibCephFS
, OpenEmptyComponent
) {
51 pid_t mypid
= getpid();
52 struct ceph_mount_info
*cmount
;
53 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
54 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
55 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
56 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
59 sprintf(c_dir
, "/open_test_%d", mypid
);
60 struct ceph_dir_result
*dirp
;
62 ASSERT_EQ(0, ceph_mkdirs(cmount
, c_dir
, 0777));
64 ASSERT_EQ(0, ceph_opendir(cmount
, c_dir
, &dirp
));
67 sprintf(c_path
, "/open_test_%d//created_file_%d", mypid
, mypid
);
68 int fd
= ceph_open(cmount
, c_path
, O_RDONLY
|O_CREAT
, 0666);
71 ASSERT_EQ(0, ceph_close(cmount
, fd
));
72 ASSERT_EQ(0, ceph_closedir(cmount
, dirp
));
73 ceph_shutdown(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
));
79 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
81 fd
= ceph_open(cmount
, c_path
, O_RDONLY
, 0666);
83 ASSERT_EQ(0, ceph_close(cmount
, fd
));
86 ASSERT_EQ(0, ceph_unlink(cmount
, c_path
));
87 ASSERT_EQ(0, ceph_rmdir(cmount
, c_dir
));
89 ceph_shutdown(cmount
);
92 TEST(LibCephFS
, OpenReadTruncate
) {
93 struct ceph_mount_info
*cmount
;
94 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
95 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
96 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
97 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
99 auto path
= fmt::format("test_open_rdt_{}", getpid());
100 int fd
= ceph_open(cmount
, path
.c_str(), O_WRONLY
|O_CREAT
, 0666);
103 auto data
= std::string("hello world");
104 ASSERT_EQ(ceph_write(cmount
, fd
, data
.c_str(), data
.size(), 0), (int)data
.size());
105 ASSERT_EQ(0, ceph_close(cmount
, fd
));
107 fd
= ceph_open(cmount
, path
.c_str(), O_RDONLY
, 0);
109 ASSERT_EQ(ceph_ftruncate(cmount
, fd
, 0), -EBADF
);
110 ASSERT_EQ(ceph_ftruncate(cmount
, fd
, 1), -EBADF
);
111 ASSERT_EQ(0, ceph_close(cmount
, fd
));
113 ceph_shutdown(cmount
);
116 TEST(LibCephFS
, OpenReadWrite
) {
117 struct ceph_mount_info
*cmount
;
118 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
119 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
120 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
121 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
124 sprintf(c_path
, "test_open_rdwr_%d", getpid());
125 int fd
= ceph_open(cmount
, c_path
, O_WRONLY
|O_CREAT
, 0666);
128 const char *out_buf
= "hello world";
129 size_t size
= strlen(out_buf
);
131 ASSERT_EQ(ceph_write(cmount
, fd
, out_buf
, size
, 0), (int)size
);
132 ASSERT_EQ(ceph_read(cmount
, fd
, in_buf
, sizeof(in_buf
), 0), -EBADF
);
133 ASSERT_EQ(0, ceph_close(cmount
, fd
));
135 fd
= ceph_open(cmount
, c_path
, O_RDONLY
, 0);
137 ASSERT_EQ(ceph_write(cmount
, fd
, out_buf
, size
, 0), -EBADF
);
138 ASSERT_EQ(ceph_read(cmount
, fd
, in_buf
, sizeof(in_buf
), 0), (int)size
);
139 ASSERT_EQ(0, ceph_close(cmount
, fd
));
141 fd
= ceph_open(cmount
, c_path
, O_RDWR
, 0);
143 ASSERT_EQ(ceph_write(cmount
, fd
, out_buf
, size
, 0), (int)size
);
144 ASSERT_EQ(ceph_read(cmount
, fd
, in_buf
, sizeof(in_buf
), 0), (int)size
);
145 ASSERT_EQ(0, ceph_close(cmount
, fd
));
147 ceph_shutdown(cmount
);
150 TEST(LibCephFS
, MountNonExist
) {
152 struct ceph_mount_info
*cmount
;
154 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
155 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
156 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
157 ASSERT_NE(0, ceph_mount(cmount
, "/non-exist"));
158 ceph_shutdown(cmount
);
161 TEST(LibCephFS
, MountDouble
) {
163 struct ceph_mount_info
*cmount
;
165 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
166 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
167 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
168 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
169 ASSERT_EQ(-EISCONN
, ceph_mount(cmount
, "/"));
170 ceph_shutdown(cmount
);
173 TEST(LibCephFS
, MountRemount
) {
175 struct ceph_mount_info
*cmount
;
177 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
178 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
179 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
181 CephContext
*cct
= ceph_get_mount_context(cmount
);
182 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
183 ASSERT_EQ(0, ceph_unmount(cmount
));
185 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
186 ASSERT_EQ(cct
, ceph_get_mount_context(cmount
));
188 ceph_shutdown(cmount
);
191 TEST(LibCephFS
, UnmountUnmounted
) {
193 struct ceph_mount_info
*cmount
;
195 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
196 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
197 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
198 ASSERT_EQ(-ENOTCONN
, ceph_unmount(cmount
));
199 ceph_shutdown(cmount
);
202 TEST(LibCephFS
, ReleaseUnmounted
) {
204 struct ceph_mount_info
*cmount
;
206 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
207 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
208 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
209 ASSERT_EQ(0, ceph_release(cmount
));
212 TEST(LibCephFS
, ReleaseMounted
) {
214 struct ceph_mount_info
*cmount
;
216 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
217 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
218 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
219 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
220 ASSERT_EQ(-EISCONN
, ceph_release(cmount
));
221 ASSERT_EQ(0, ceph_unmount(cmount
));
222 ASSERT_EQ(0, ceph_release(cmount
));
225 TEST(LibCephFS
, UnmountRelease
) {
227 struct ceph_mount_info
*cmount
;
229 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
230 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
231 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
232 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
233 ASSERT_EQ(0, ceph_unmount(cmount
));
234 ASSERT_EQ(0, ceph_release(cmount
));
237 TEST(LibCephFS
, Mount
) {
238 struct ceph_mount_info
*cmount
;
239 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
240 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
241 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
242 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
243 ceph_shutdown(cmount
);
245 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
246 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
247 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
248 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
249 ceph_shutdown(cmount
);
252 TEST(LibCephFS
, OpenLayout
) {
253 struct ceph_mount_info
*cmount
;
254 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
255 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
256 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
257 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
260 char test_layout_file
[256];
261 sprintf(test_layout_file
, "test_layout_%d_b", getpid());
262 int fd
= ceph_open_layout(cmount
, test_layout_file
, O_CREAT
|O_WRONLY
, 0666, (1<<20), 7, (1<<20), NULL
);
265 ASSERT_LT(0, ceph_get_file_pool_name(cmount
, fd
, poolname
, sizeof(poolname
)));
266 ASSERT_LT(0, ceph_get_file_pool_name(cmount
, fd
, poolname
, 0));
268 /* on already-written file (ENOTEMPTY) */
269 ceph_write(cmount
, fd
, "hello world", 11, 0);
270 ceph_close(cmount
, fd
);
274 sprintf(xattrk
, "ceph.file.layout.stripe_unit");
275 sprintf(xattrv
, "65536");
276 ASSERT_EQ(-ENOTEMPTY
, ceph_setxattr(cmount
, test_layout_file
, xattrk
, (void *)xattrv
, 5, 0));
279 sprintf(test_layout_file
, "test_layout_%d_c", getpid());
280 fd
= ceph_open_layout(cmount
, test_layout_file
, O_CREAT
, 0666, (1<<20), 1, 19, NULL
);
281 ASSERT_EQ(fd
, -EINVAL
);
284 sprintf(test_layout_file
, "test_layout_%d_d", getpid());
285 fd
= ceph_open_layout(cmount
, test_layout_file
, O_CREAT
, 0666, (1<<20), 7, (1<<20), poolname
);
287 ceph_close(cmount
, fd
);
289 /* with metadata pool (invalid) */
290 sprintf(test_layout_file
, "test_layout_%d_e", getpid());
291 fd
= ceph_open_layout(cmount
, test_layout_file
, O_CREAT
, 0666, (1<<20), 7, (1<<20), "metadata");
292 ASSERT_EQ(fd
, -EINVAL
);
294 /* with metadata pool (does not exist) */
295 sprintf(test_layout_file
, "test_layout_%d_f", getpid());
296 fd
= ceph_open_layout(cmount
, test_layout_file
, O_CREAT
, 0666, (1<<20), 7, (1<<20), "asdfjasdfjasdf");
297 ASSERT_EQ(fd
, -EINVAL
);
299 ceph_shutdown(cmount
);
302 TEST(LibCephFS
, DirLs
) {
304 pid_t mypid
= getpid();
306 struct ceph_mount_info
*cmount
;
307 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
308 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
309 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
310 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
312 struct ceph_dir_result
*ls_dir
= NULL
;
314 sprintf(foostr
, "dir_ls%d", mypid
);
315 ASSERT_EQ(ceph_opendir(cmount
, foostr
, &ls_dir
), -ENOENT
);
317 ASSERT_EQ(ceph_mkdir(cmount
, foostr
, 0777), 0);
318 struct ceph_statx stx
;
319 ASSERT_EQ(ceph_statx(cmount
, foostr
, &stx
, 0, 0), 0);
320 ASSERT_NE(S_ISDIR(stx
.stx_mode
), 0);
323 sprintf(barstr
, "dir_ls2%d", mypid
);
324 ASSERT_EQ(ceph_statx(cmount
, barstr
, &stx
, 0, AT_SYMLINK_NOFOLLOW
), -ENOENT
);
326 // insert files into directory and test open
328 int i
= 0, r
= rand() % 4096;
329 if (getenv("LIBCEPHFS_RAND")) {
330 r
= atoi(getenv("LIBCEPHFS_RAND"));
332 printf("rand: %d\n", r
);
335 sprintf(bazstr
, "dir_ls%d/dirf%d", mypid
, i
);
336 int fd
= ceph_open(cmount
, bazstr
, O_CREAT
|O_RDONLY
, 0666);
338 ASSERT_EQ(ceph_close(cmount
, fd
), 0);
340 // set file sizes for readdirplus
341 ceph_truncate(cmount
, bazstr
, i
);
344 ASSERT_EQ(ceph_opendir(cmount
, foostr
, &ls_dir
), 0);
346 // not guaranteed to get . and .. first, but its a safe assumption in this case
347 struct dirent
*result
= ceph_readdir(cmount
, ls_dir
);
348 ASSERT_TRUE(result
!= NULL
);
349 ASSERT_STREQ(result
->d_name
, ".");
350 result
= ceph_readdir(cmount
, ls_dir
);
351 ASSERT_TRUE(result
!= NULL
);
352 ASSERT_STREQ(result
->d_name
, "..");
354 std::vector
<std::string
> entries
;
355 std::map
<std::string
, int64_t> offset_map
;
356 int64_t offset
= ceph_telldir(cmount
, ls_dir
);
357 for(i
= 0; i
< r
; ++i
) {
358 result
= ceph_readdir(cmount
, ls_dir
);
359 ASSERT_TRUE(result
!= NULL
);
360 entries
.push_back(result
->d_name
);
361 offset_map
[result
->d_name
] = offset
;
362 offset
= ceph_telldir(cmount
, ls_dir
);
365 ASSERT_TRUE(ceph_readdir(cmount
, ls_dir
) == NULL
);
366 offset
= ceph_telldir(cmount
, ls_dir
);
368 ASSERT_EQ(offset_map
.size(), entries
.size());
369 for(i
= 0; i
< r
; ++i
) {
370 sprintf(bazstr
, "dirf%d", i
);
371 ASSERT_TRUE(offset_map
.count(bazstr
) == 1);
375 ceph_seekdir(cmount
, ls_dir
, offset
);
376 ASSERT_TRUE(ceph_readdir(cmount
, ls_dir
) == NULL
);
378 for (auto p
= offset_map
.begin(); p
!= offset_map
.end(); ++p
) {
379 ceph_seekdir(cmount
, ls_dir
, p
->second
);
380 result
= ceph_readdir(cmount
, ls_dir
);
381 ASSERT_TRUE(result
!= NULL
);
382 std::string
d_name(result
->d_name
);
383 ASSERT_EQ(p
->first
, d_name
);
387 ceph_rewinddir(cmount
, ls_dir
);
389 result
= ceph_readdir(cmount
, ls_dir
);
390 ASSERT_TRUE(result
!= NULL
);
391 ASSERT_STREQ(result
->d_name
, ".");
392 result
= ceph_readdir(cmount
, ls_dir
);
393 ASSERT_TRUE(result
!= NULL
);
394 ASSERT_STREQ(result
->d_name
, "..");
396 ceph_rewinddir(cmount
, ls_dir
);
398 int t
= ceph_telldir(cmount
, ls_dir
);
401 ASSERT_TRUE(ceph_readdir(cmount
, ls_dir
) != NULL
);
403 // test seekdir - move back to the beginning
404 ceph_seekdir(cmount
, ls_dir
, t
);
407 struct dirent
*getdents_entries
;
408 size_t getdents_entries_len
= (r
+ 2) * sizeof(*getdents_entries
);
409 getdents_entries
= (struct dirent
*)malloc(getdents_entries_len
);
412 std::vector
<std::string
> found
;
414 int len
= ceph_getdents(cmount
, ls_dir
, (char *)getdents_entries
, getdents_entries_len
);
418 ASSERT_TRUE((len
% sizeof(*getdents_entries
)) == 0);
419 int n
= len
/ sizeof(*getdents_entries
);
422 ASSERT_STREQ(getdents_entries
[0].d_name
, ".");
423 ASSERT_STREQ(getdents_entries
[1].d_name
, "..");
429 for(; j
< n
; ++i
, ++j
) {
430 const char *name
= getdents_entries
[j
].d_name
;
431 found
.push_back(name
);
434 ASSERT_EQ(found
, entries
);
435 free(getdents_entries
);
438 ceph_rewinddir(cmount
, ls_dir
);
440 result
= ceph_readdir(cmount
, ls_dir
);
441 ASSERT_TRUE(result
!= NULL
);
442 ASSERT_STREQ(result
->d_name
, ".");
443 result
= ceph_readdir(cmount
, ls_dir
);
444 ASSERT_TRUE(result
!= NULL
);
445 ASSERT_STREQ(result
->d_name
, "..");
450 int len
= ceph_readdir_r(cmount
, ls_dir
, &rdent
);
454 found
.push_back(rdent
.d_name
);
456 ASSERT_EQ(found
, entries
);
459 ceph_rewinddir(cmount
, ls_dir
);
461 result
= ceph_readdir(cmount
, ls_dir
);
462 ASSERT_TRUE(result
!= NULL
);
463 ASSERT_STREQ(result
->d_name
, ".");
464 result
= ceph_readdir(cmount
, ls_dir
);
465 ASSERT_TRUE(result
!= NULL
);
466 ASSERT_STREQ(result
->d_name
, "..");
471 struct ceph_statx stx
;
472 int len
= ceph_readdirplus_r(cmount
, ls_dir
, &rdent
, &stx
,
473 CEPH_STATX_SIZE
, AT_STATX_DONT_SYNC
, NULL
);
477 const char *name
= rdent
.d_name
;
478 found
.push_back(name
);
480 sscanf(name
, "dirf%d", &size
);
481 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_SIZE
);
482 ASSERT_EQ(stx
.stx_size
, (size_t)size
);
483 ASSERT_EQ(stx
.stx_ino
, rdent
.d_ino
);
484 //ASSERT_EQ(st.st_mode, (mode_t)0666);
486 ASSERT_EQ(found
, entries
);
488 ASSERT_EQ(ceph_closedir(cmount
, ls_dir
), 0);
491 for(i
= 0; i
< r
; ++i
) {
492 sprintf(bazstr
, "dir_ls%d/dirf%d", mypid
, i
);
493 ASSERT_EQ(0, ceph_unlink(cmount
, bazstr
));
495 ASSERT_EQ(0, ceph_rmdir(cmount
, foostr
));
497 ceph_shutdown(cmount
);
500 TEST(LibCephFS
, ManyNestedDirs
) {
501 struct ceph_mount_info
*cmount
;
502 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
503 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
504 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
505 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
507 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";
508 ASSERT_EQ(ceph_mkdirs(cmount
, many_path
, 0755), 0);
513 ASSERT_EQ(ceph_chdir(cmount
, "a"), 0);
515 struct ceph_dir_result
*dirp
;
516 ASSERT_EQ(ceph_opendir(cmount
, "a", &dirp
), 0);
517 struct dirent
*dent
= ceph_readdir(cmount
, dirp
);
518 ASSERT_TRUE(dent
!= NULL
);
519 ASSERT_STREQ(dent
->d_name
, ".");
520 dent
= ceph_readdir(cmount
, dirp
);
521 ASSERT_TRUE(dent
!= NULL
);
522 ASSERT_STREQ(dent
->d_name
, "..");
523 dent
= ceph_readdir(cmount
, dirp
);
524 ASSERT_TRUE(dent
!= NULL
);
525 ASSERT_STREQ(dent
->d_name
, "a");
526 ASSERT_EQ(ceph_closedir(cmount
, dirp
), 0);
529 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");
531 ASSERT_EQ(ceph_chdir(cmount
, "a/a/a"), 0);
533 for(i
= 0; i
< 39; ++i
) {
534 ASSERT_EQ(ceph_chdir(cmount
, ".."), 0);
535 ASSERT_EQ(ceph_rmdir(cmount
, "a"), 0);
538 ASSERT_EQ(ceph_chdir(cmount
, "/"), 0);
540 ASSERT_EQ(ceph_rmdir(cmount
, "a/a/a"), 0);
542 ceph_shutdown(cmount
);
545 TEST(LibCephFS
, Xattrs
) {
546 struct ceph_mount_info
*cmount
;
547 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
548 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
549 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
550 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
552 char test_xattr_file
[256];
553 sprintf(test_xattr_file
, "test_xattr_%d", getpid());
554 int fd
= ceph_open(cmount
, test_xattr_file
, O_CREAT
, 0666);
557 // test removing non-existent xattr
558 ASSERT_EQ(-ENODATA
, ceph_removexattr(cmount
, test_xattr_file
, "user.nosuchxattr"));
563 for(; i
< 'a'+26; ++i
) {
564 sprintf(xattrk
, "user.test_xattr_%c", i
);
565 int len
= sprintf(xattrv
, "testxattr%c", i
);
566 ASSERT_EQ(ceph_setxattr(cmount
, test_xattr_file
, xattrk
, (void *) xattrv
, len
, XATTR_CREATE
), 0);
569 // zero size should return required buffer length
570 int len_needed
= ceph_listxattr(cmount
, test_xattr_file
, NULL
, 0);
571 ASSERT_GT(len_needed
, 0);
573 // buffer size smaller than needed should fail
574 char xattrlist
[128*26];
575 ASSERT_GT(sizeof(xattrlist
), (size_t)len_needed
);
576 int len
= ceph_listxattr(cmount
, test_xattr_file
, xattrlist
, len_needed
- 1);
577 ASSERT_EQ(-ERANGE
, len
);
579 len
= ceph_listxattr(cmount
, test_xattr_file
, xattrlist
, sizeof(xattrlist
));
580 ASSERT_EQ(len
, len_needed
);
585 // ceph.* xattrs should not be listed
586 ASSERT_NE(strncmp(p
, "ceph.", 5), 0);
588 sprintf(xattrk
, "user.test_xattr_%c", i
);
589 ASSERT_STREQ(p
, xattrk
);
592 std::cout
<< "getting attr " << p
<< std::endl
;
593 int alen
= ceph_getxattr(cmount
, test_xattr_file
, p
, (void *) gxattrv
, 128);
595 sprintf(xattrv
, "testxattr%c", i
);
596 ASSERT_TRUE(!strncmp(xattrv
, gxattrv
, alen
));
606 for(i
= 'a'; i
< 'a'+26; ++i
) {
607 sprintf(xattrk
, "user.test_xattr_%c", i
);
608 ASSERT_EQ(ceph_removexattr(cmount
, test_xattr_file
, xattrk
), 0);
611 ceph_close(cmount
, fd
);
612 ceph_shutdown(cmount
);
616 TEST(LibCephFS
, Xattrs_ll
) {
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);
623 char test_xattr_file
[256];
624 sprintf(test_xattr_file
, "test_xattr_%d", getpid());
625 int fd
= ceph_open(cmount
, test_xattr_file
, O_CREAT
, 0666);
627 ceph_close(cmount
, fd
);
630 Inode
*existent_file_handle
= NULL
;
632 int res
= ceph_ll_lookup_root(cmount
, &root
);
635 UserPerm
*perms
= ceph_mount_perms(cmount
);
636 struct ceph_statx stx
;
638 res
= ceph_ll_lookup(cmount
, root
, test_xattr_file
, &existent_file_handle
,
642 const char *valid_name
= "user.attrname";
643 const char *value
= "attrvalue";
644 char value_buf
[256] = { 0 };
646 res
= ceph_ll_setxattr(cmount
, existent_file_handle
, valid_name
, value
, strlen(value
), 0, perms
);
649 res
= ceph_ll_getxattr(cmount
, existent_file_handle
, valid_name
, value_buf
, 256, perms
);
650 ASSERT_EQ(res
, (int)strlen(value
));
652 value_buf
[res
] = '\0';
653 ASSERT_STREQ(value_buf
, value
);
655 ceph_shutdown(cmount
);
658 TEST(LibCephFS
, LstatSlashdot
) {
659 struct ceph_mount_info
*cmount
;
660 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
661 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
662 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
663 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
665 struct ceph_statx stx
;
666 ASSERT_EQ(ceph_statx(cmount
, "/.", &stx
, 0, AT_SYMLINK_NOFOLLOW
), 0);
667 ASSERT_EQ(ceph_statx(cmount
, ".", &stx
, 0, AT_SYMLINK_NOFOLLOW
), 0);
669 ceph_shutdown(cmount
);
672 TEST(LibCephFS
, StatDirNlink
) {
673 struct ceph_mount_info
*cmount
;
674 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
675 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
676 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
677 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
680 sprintf(test_dir1
, "dir1_symlinks_%d", getpid());
681 ASSERT_EQ(ceph_mkdir(cmount
, test_dir1
, 0700), 0);
683 int fd
= ceph_open(cmount
, test_dir1
, O_DIRECTORY
|O_RDONLY
, 0);
685 struct ceph_statx stx
;
686 ASSERT_EQ(ceph_fstatx(cmount
, fd
, &stx
, CEPH_STATX_NLINK
, AT_SYMLINK_NOFOLLOW
), 0);
687 ASSERT_EQ(stx
.stx_nlink
, 2u);
691 sprintf(test_dir2
, "%s/.", test_dir1
);
692 ASSERT_EQ(ceph_statx(cmount
, test_dir2
, &stx
, CEPH_STATX_NLINK
, AT_SYMLINK_NOFOLLOW
), 0);
693 ASSERT_EQ(stx
.stx_nlink
, 2u);
698 sprintf(test_dir2
, "%s/1", test_dir1
);
699 ASSERT_EQ(ceph_mkdir(cmount
, test_dir2
, 0700), 0);
700 ASSERT_EQ(ceph_statx(cmount
, test_dir2
, &stx
, CEPH_STATX_NLINK
, AT_SYMLINK_NOFOLLOW
), 0);
701 ASSERT_EQ(stx
.stx_nlink
, 2u);
702 ASSERT_EQ(ceph_statx(cmount
, test_dir1
, &stx
, CEPH_STATX_NLINK
, AT_SYMLINK_NOFOLLOW
), 0);
703 ASSERT_EQ(stx
.stx_nlink
, 3u);
704 sprintf(test_dir2
, "%s/2", test_dir1
);
705 ASSERT_EQ(ceph_mkdir(cmount
, test_dir2
, 0700), 0);
706 ASSERT_EQ(ceph_statx(cmount
, test_dir1
, &stx
, CEPH_STATX_NLINK
, AT_SYMLINK_NOFOLLOW
), 0);
707 ASSERT_EQ(stx
.stx_nlink
, 4u);
708 sprintf(test_dir2
, "%s/1/1", test_dir1
);
709 ASSERT_EQ(ceph_mkdir(cmount
, test_dir2
, 0700), 0);
710 ASSERT_EQ(ceph_statx(cmount
, test_dir1
, &stx
, CEPH_STATX_NLINK
, AT_SYMLINK_NOFOLLOW
), 0);
711 ASSERT_EQ(stx
.stx_nlink
, 4u);
712 ASSERT_EQ(ceph_rmdir(cmount
, test_dir2
), 0);
713 ASSERT_EQ(ceph_statx(cmount
, test_dir1
, &stx
, CEPH_STATX_NLINK
, AT_SYMLINK_NOFOLLOW
), 0);
714 ASSERT_EQ(stx
.stx_nlink
, 4u);
715 sprintf(test_dir2
, "%s/1", test_dir1
);
716 ASSERT_EQ(ceph_rmdir(cmount
, test_dir2
), 0);
717 ASSERT_EQ(ceph_statx(cmount
, test_dir1
, &stx
, CEPH_STATX_NLINK
, AT_SYMLINK_NOFOLLOW
), 0);
718 ASSERT_EQ(stx
.stx_nlink
, 3u);
719 sprintf(test_dir2
, "%s/2", test_dir1
);
720 ASSERT_EQ(ceph_rmdir(cmount
, test_dir2
), 0);
721 ASSERT_EQ(ceph_statx(cmount
, test_dir1
, &stx
, CEPH_STATX_NLINK
, AT_SYMLINK_NOFOLLOW
), 0);
722 ASSERT_EQ(stx
.stx_nlink
, 2u);
725 ASSERT_EQ(ceph_rmdir(cmount
, test_dir1
), 0);
726 ASSERT_EQ(ceph_fstatx(cmount
, fd
, &stx
, CEPH_STATX_NLINK
, AT_SYMLINK_NOFOLLOW
), 0);
727 ASSERT_EQ(stx
.stx_nlink
, 0u);
729 ceph_close(cmount
, fd
);
731 ceph_shutdown(cmount
);
734 TEST(LibCephFS
, DoubleChmod
) {
736 struct ceph_mount_info
*cmount
;
737 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
738 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
739 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
740 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
743 sprintf(test_file
, "test_perms_%d", getpid());
745 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
749 const char *bytes
= "foobarbaz";
750 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
752 ceph_close(cmount
, fd
);
754 // set perms to read but can't write
755 ASSERT_EQ(ceph_chmod(cmount
, test_file
, 0400), 0);
757 fd
= ceph_open(cmount
, test_file
, O_RDWR
, 0);
758 ASSERT_EQ(fd
, -EACCES
);
760 fd
= ceph_open(cmount
, test_file
, O_RDONLY
, 0);
764 int ret
= ceph_read(cmount
, fd
, buf
, 100, 0);
765 ASSERT_EQ(ret
, (int)strlen(bytes
));
767 ASSERT_STREQ(buf
, bytes
);
769 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), -EBADF
);
771 ceph_close(cmount
, fd
);
773 // reset back to writeable
774 ASSERT_EQ(ceph_chmod(cmount
, test_file
, 0600), 0);
776 // ensure perms are correct
777 struct ceph_statx stx
;
778 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx
, CEPH_STATX_MODE
, AT_SYMLINK_NOFOLLOW
), 0);
779 ASSERT_EQ(stx
.stx_mode
, 0100600U);
781 fd
= ceph_open(cmount
, test_file
, O_RDWR
, 0);
784 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
785 ceph_close(cmount
, fd
);
787 ceph_shutdown(cmount
);
790 TEST(LibCephFS
, Fchmod
) {
791 struct ceph_mount_info
*cmount
;
792 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
793 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
794 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
795 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
798 sprintf(test_file
, "test_perms_%d", getpid());
800 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
804 const char *bytes
= "foobarbaz";
805 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
807 // set perms to read but can't write
808 ASSERT_EQ(ceph_fchmod(cmount
, fd
, 0400), 0);
811 int ret
= ceph_read(cmount
, fd
, buf
, 100, 0);
812 ASSERT_EQ(ret
, (int)strlen(bytes
));
814 ASSERT_STREQ(buf
, bytes
);
816 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
818 ceph_close(cmount
, fd
);
820 ASSERT_EQ(ceph_open(cmount
, test_file
, O_RDWR
, 0), -EACCES
);
822 // reset back to writeable
823 ASSERT_EQ(ceph_chmod(cmount
, test_file
, 0600), 0);
825 fd
= ceph_open(cmount
, test_file
, O_RDWR
, 0);
828 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
829 ceph_close(cmount
, fd
);
831 ceph_shutdown(cmount
);
834 TEST(LibCephFS
, Lchmod
) {
835 struct ceph_mount_info
*cmount
;
836 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
837 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
838 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
839 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
842 sprintf(test_file
, "test_perms_lchmod_%d", getpid());
844 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
848 const char *bytes
= "foobarbaz";
849 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
850 ceph_close(cmount
, fd
);
853 char test_symlink
[256];
854 sprintf(test_symlink
, "test_lchmod_sym_%d", getpid());
855 ASSERT_EQ(ceph_symlink(cmount
, test_file
, test_symlink
), 0);
857 // get symlink stat - lstat
858 struct ceph_statx stx_orig1
;
859 ASSERT_EQ(ceph_statx(cmount
, test_symlink
, &stx_orig1
, CEPH_STATX_ALL_STATS
, AT_SYMLINK_NOFOLLOW
), 0);
861 // Change mode on symlink file
862 ASSERT_EQ(ceph_lchmod(cmount
, test_symlink
, 0400), 0);
863 struct ceph_statx stx_orig2
;
864 ASSERT_EQ(ceph_statx(cmount
, test_symlink
, &stx_orig2
, CEPH_STATX_ALL_STATS
, AT_SYMLINK_NOFOLLOW
), 0);
867 ASSERT_NE(stx_orig1
.stx_mode
, stx_orig2
.stx_mode
);
868 static const int permbits
= S_IRWXU
|S_IRWXG
|S_IRWXO
;
869 ASSERT_EQ(permbits
&stx_orig1
.stx_mode
, 0777);
870 ASSERT_EQ(permbits
&stx_orig2
.stx_mode
, 0400);
872 ceph_shutdown(cmount
);
875 TEST(LibCephFS
, Fchown
) {
876 struct ceph_mount_info
*cmount
;
877 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
878 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
879 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
880 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
883 sprintf(test_file
, "test_fchown_%d", getpid());
885 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
888 // set perms to readable and writeable only by owner
889 ASSERT_EQ(ceph_fchmod(cmount
, fd
, 0600), 0);
891 // change ownership to nobody -- we assume nobody exists and id is always 65534
892 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "0"), 0);
893 ASSERT_EQ(ceph_fchown(cmount
, fd
, 65534, 65534), 0);
894 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "1"), 0);
896 ceph_close(cmount
, fd
);
898 fd
= ceph_open(cmount
, test_file
, O_RDWR
, 0);
899 ASSERT_EQ(fd
, -EACCES
);
901 ceph_shutdown(cmount
);
904 #if defined(__linux__) && defined(O_PATH)
905 TEST(LibCephFS
, FlagO_PATH
) {
906 struct ceph_mount_info
*cmount
;
908 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
909 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
910 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
911 ASSERT_EQ(0, ceph_mount(cmount
, NULL
));
913 char test_file
[PATH_MAX
];
914 sprintf(test_file
, "test_oflag_%d", getpid());
916 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
|O_PATH
, 0666);
917 ASSERT_EQ(-ENOENT
, fd
);
919 fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
921 ASSERT_EQ(0, ceph_close(cmount
, fd
));
923 // ok, the file has been created. perform real checks now
924 fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
|O_PATH
, 0666);
928 ASSERT_EQ(-EBADF
, ceph_read(cmount
, fd
, buf
, sizeof(buf
), 0));
929 ASSERT_EQ(-EBADF
, ceph_write(cmount
, fd
, buf
, sizeof(buf
), 0));
931 // set perms to readable and writeable only by owner
932 ASSERT_EQ(-EBADF
, ceph_fchmod(cmount
, fd
, 0600));
934 // change ownership to nobody -- we assume nobody exists and id is always 65534
935 ASSERT_EQ(-EBADF
, ceph_fchown(cmount
, fd
, 65534, 65534));
938 ASSERT_EQ(-EBADF
, ceph_fsync(cmount
, fd
, false));
940 struct ceph_statx stx
;
941 ASSERT_EQ(0, ceph_fstatx(cmount
, fd
, &stx
, 0, 0));
943 ASSERT_EQ(0, ceph_close(cmount
, fd
));
944 ceph_shutdown(cmount
);
948 TEST(LibCephFS
, Symlinks
) {
949 struct ceph_mount_info
*cmount
;
950 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
951 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
952 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
953 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
956 sprintf(test_file
, "test_symlinks_%d", getpid());
958 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
961 ceph_close(cmount
, fd
);
963 char test_symlink
[256];
964 sprintf(test_symlink
, "test_symlinks_sym_%d", getpid());
966 ASSERT_EQ(ceph_symlink(cmount
, test_file
, test_symlink
), 0);
968 // test the O_NOFOLLOW case
969 fd
= ceph_open(cmount
, test_symlink
, O_NOFOLLOW
, 0);
970 ASSERT_EQ(fd
, -ELOOP
);
972 // stat the original file
973 struct ceph_statx stx_orig
;
974 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx_orig
, CEPH_STATX_ALL_STATS
, 0), 0);
976 struct ceph_statx stx_symlink_orig
;
977 ASSERT_EQ(ceph_statx(cmount
, test_symlink
, &stx_symlink_orig
, CEPH_STATX_ALL_STATS
, 0), 0);
978 // ensure the statx bufs are equal
979 ASSERT_EQ(memcmp(&stx_orig
, &stx_symlink_orig
, sizeof(stx_orig
)), 0);
981 sprintf(test_file
, "/test_symlinks_abs_%d", getpid());
983 fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
986 ceph_close(cmount
, fd
);
988 sprintf(test_symlink
, "/test_symlinks_abs_sym_%d", getpid());
990 ASSERT_EQ(ceph_symlink(cmount
, test_file
, test_symlink
), 0);
992 // stat the original file
993 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx_orig
, CEPH_STATX_ALL_STATS
, 0), 0);
995 ASSERT_EQ(ceph_statx(cmount
, test_symlink
, &stx_symlink_orig
, CEPH_STATX_ALL_STATS
, 0), 0);
996 // ensure the statx bufs are equal
997 ASSERT_TRUE(!memcmp(&stx_orig
, &stx_symlink_orig
, sizeof(stx_orig
)));
1000 ASSERT_EQ(ceph_statx(cmount
, test_symlink
, &stx_orig
, CEPH_STATX_ALL_STATS
, AT_SYMLINK_NOFOLLOW
), 0);
1001 ASSERT_TRUE(S_ISLNK(stx_orig
.stx_mode
));
1003 ceph_shutdown(cmount
);
1006 TEST(LibCephFS
, DirSyms
) {
1007 struct ceph_mount_info
*cmount
;
1008 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1009 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1010 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1011 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1013 char test_dir1
[256];
1014 sprintf(test_dir1
, "dir1_symlinks_%d", getpid());
1016 ASSERT_EQ(ceph_mkdir(cmount
, test_dir1
, 0700), 0);
1018 char test_symdir
[256];
1019 sprintf(test_symdir
, "symdir_symlinks_%d", getpid());
1021 ASSERT_EQ(ceph_symlink(cmount
, test_dir1
, test_symdir
), 0);
1023 char test_file
[256];
1024 sprintf(test_file
, "/symdir_symlinks_%d/test_symdir_file", getpid());
1025 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0600);
1027 ceph_close(cmount
, fd
);
1029 struct ceph_statx stx
;
1030 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx
, 0, AT_SYMLINK_NOFOLLOW
), 0);
1032 // ensure that its a file not a directory we get back
1033 ASSERT_TRUE(S_ISREG(stx
.stx_mode
));
1035 ceph_shutdown(cmount
);
1038 TEST(LibCephFS
, LoopSyms
) {
1039 struct ceph_mount_info
*cmount
;
1040 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1041 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1042 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1043 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1045 char test_dir1
[256];
1046 sprintf(test_dir1
, "dir1_loopsym_%d", getpid());
1048 ASSERT_EQ(ceph_mkdir(cmount
, test_dir1
, 0700), 0);
1050 char test_dir2
[256];
1051 sprintf(test_dir2
, "/dir1_loopsym_%d/loop_dir", getpid());
1053 ASSERT_EQ(ceph_mkdir(cmount
, test_dir2
, 0700), 0);
1055 // symlink it itself: /path/to/mysym -> /path/to/mysym
1056 char test_symdir
[256];
1057 sprintf(test_symdir
, "/dir1_loopsym_%d/loop_dir/symdir", getpid());
1059 ASSERT_EQ(ceph_symlink(cmount
, test_symdir
, test_symdir
), 0);
1061 char test_file
[256];
1062 sprintf(test_file
, "/dir1_loopsym_%d/loop_dir/symdir/test_loopsym_file", getpid());
1063 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0600);
1064 ASSERT_EQ(fd
, -ELOOP
);
1066 // loop: /a -> /b, /b -> /c, /c -> /a
1067 char a
[264], b
[264], c
[264];
1068 sprintf(a
, "/%s/a", test_dir1
);
1069 sprintf(b
, "/%s/b", test_dir1
);
1070 sprintf(c
, "/%s/c", test_dir1
);
1071 ASSERT_EQ(ceph_symlink(cmount
, a
, b
), 0);
1072 ASSERT_EQ(ceph_symlink(cmount
, b
, c
), 0);
1073 ASSERT_EQ(ceph_symlink(cmount
, c
, a
), 0);
1074 ASSERT_EQ(ceph_open(cmount
, a
, O_RDWR
, 0), -ELOOP
);
1076 ceph_shutdown(cmount
);
1079 TEST(LibCephFS
, HardlinkNoOriginal
) {
1081 int mypid
= getpid();
1083 struct ceph_mount_info
*cmount
;
1084 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1085 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1086 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1087 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1090 sprintf(dir
, "/test_rmdirfail%d", mypid
);
1091 ASSERT_EQ(ceph_mkdir(cmount
, dir
, 0777), 0);
1093 ASSERT_EQ(ceph_chdir(cmount
, dir
), 0);
1095 int fd
= ceph_open(cmount
, "f1", O_CREAT
, 0644);
1098 ceph_close(cmount
, fd
);
1101 ASSERT_EQ(ceph_link(cmount
, "f1", "hardl1"), 0);
1103 // remove file link points to
1104 ASSERT_EQ(ceph_unlink(cmount
, "f1"), 0);
1106 ceph_shutdown(cmount
);
1109 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1110 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1111 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1112 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1113 ASSERT_EQ(ceph_chdir(cmount
, dir
), 0);
1114 ASSERT_EQ(ceph_unlink(cmount
, "hardl1"), 0);
1115 ASSERT_EQ(ceph_rmdir(cmount
, dir
), 0);
1117 ceph_shutdown(cmount
);
1120 TEST(LibCephFS
, BadArgument
) {
1121 struct ceph_mount_info
*cmount
;
1122 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1123 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1124 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1125 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1127 int fd
= ceph_open(cmount
, "test_file", O_CREAT
|O_RDWR
, 0666);
1130 ASSERT_EQ(ceph_write(cmount
, fd
, buf
, sizeof(buf
), 0), (int)sizeof(buf
));
1131 ASSERT_EQ(ceph_read(cmount
, fd
, buf
, 0, 5), 0);
1132 ceph_close(cmount
, fd
);
1133 ASSERT_EQ(ceph_unlink(cmount
, "test_file"), 0);
1135 ceph_shutdown(cmount
);
1138 TEST(LibCephFS
, BadFileDesc
) {
1139 struct ceph_mount_info
*cmount
;
1140 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1141 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1142 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1143 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1145 ASSERT_EQ(ceph_fchmod(cmount
, -1, 0655), -EBADF
);
1146 ASSERT_EQ(ceph_close(cmount
, -1), -EBADF
);
1147 ASSERT_EQ(ceph_lseek(cmount
, -1, 0, SEEK_SET
), -EBADF
);
1150 ASSERT_EQ(ceph_read(cmount
, -1, buf
, 0, 0), -EBADF
);
1151 ASSERT_EQ(ceph_write(cmount
, -1, buf
, 0, 0), -EBADF
);
1153 ASSERT_EQ(ceph_ftruncate(cmount
, -1, 0), -EBADF
);
1154 ASSERT_EQ(ceph_fsync(cmount
, -1, 0), -EBADF
);
1156 struct ceph_statx stx
;
1157 ASSERT_EQ(ceph_fstatx(cmount
, -1, &stx
, 0, 0), -EBADF
);
1159 struct sockaddr_storage addr
;
1160 ASSERT_EQ(ceph_get_file_stripe_address(cmount
, -1, 0, &addr
, 1), -EBADF
);
1162 ASSERT_EQ(ceph_get_file_stripe_unit(cmount
, -1), -EBADF
);
1163 ASSERT_EQ(ceph_get_file_pool(cmount
, -1), -EBADF
);
1165 ASSERT_EQ(ceph_get_file_pool_name(cmount
, -1, poolname
, sizeof(poolname
)), -EBADF
);
1166 ASSERT_EQ(ceph_get_file_replication(cmount
, -1), -EBADF
);
1167 ASSERT_EQ(ceph_get_file_object_size(cmount
, -1), -EBADF
);
1168 int stripe_unit
, stripe_count
, object_size
, pg_pool
;
1169 ASSERT_EQ(ceph_get_file_layout(cmount
, -1, &stripe_unit
, &stripe_count
, &object_size
, &pg_pool
), -EBADF
);
1170 ASSERT_EQ(ceph_get_file_stripe_count(cmount
, -1), -EBADF
);
1172 ceph_shutdown(cmount
);
1175 TEST(LibCephFS
, ReadEmptyFile
) {
1176 struct ceph_mount_info
*cmount
;
1177 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1178 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1179 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1180 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1182 // test the read_sync path in the client for zero files
1183 ASSERT_EQ(ceph_conf_set(cmount
, "client_debug_force_sync_read", "true"), 0);
1185 int mypid
= getpid();
1188 sprintf(testf
, "test_reademptyfile%d", mypid
);
1189 int fd
= ceph_open(cmount
, testf
, O_CREAT
|O_TRUNC
|O_WRONLY
, 0644);
1192 ceph_close(cmount
, fd
);
1194 fd
= ceph_open(cmount
, testf
, O_RDONLY
, 0);
1198 ASSERT_EQ(ceph_read(cmount
, fd
, buf
, 4096, 0), 0);
1200 ceph_close(cmount
, fd
);
1201 ceph_shutdown(cmount
);
1204 TEST(LibCephFS
, PreadvPwritev
) {
1205 struct ceph_mount_info
*cmount
;
1206 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1207 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1208 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1209 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1211 int mypid
= getpid();
1214 sprintf(testf
, "test_preadvpwritevfile%d", mypid
);
1215 int fd
= ceph_open(cmount
, testf
, O_CREAT
|O_RDWR
, 0666);
1218 char out0
[] = "hello ";
1219 char out1
[] = "world\n";
1220 struct iovec iov_out
[2] = {
1221 {out0
, sizeof(out0
)},
1222 {out1
, sizeof(out1
)},
1224 char in0
[sizeof(out0
)];
1225 char in1
[sizeof(out1
)];
1226 struct iovec iov_in
[2] = {
1230 ssize_t nwritten
= iov_out
[0].iov_len
+ iov_out
[1].iov_len
;
1231 ssize_t nread
= iov_in
[0].iov_len
+ iov_in
[1].iov_len
;
1233 ASSERT_EQ(ceph_pwritev(cmount
, fd
, iov_out
, 2, 0), nwritten
);
1234 ASSERT_EQ(ceph_preadv(cmount
, fd
, iov_in
, 2, 0), nread
);
1235 ASSERT_EQ(0, strncmp((const char*)iov_in
[0].iov_base
, (const char*)iov_out
[0].iov_base
, iov_out
[0].iov_len
));
1236 ASSERT_EQ(0, strncmp((const char*)iov_in
[1].iov_base
, (const char*)iov_out
[1].iov_base
, iov_out
[1].iov_len
));
1238 ceph_close(cmount
, fd
);
1239 ceph_shutdown(cmount
);
1242 TEST(LibCephFS
, LlreadvLlwritev
) {
1243 struct ceph_mount_info
*cmount
;
1244 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1245 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1246 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1247 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1249 int mypid
= getpid();
1252 sprintf(filename
, "test_llreadvllwritevfile%u", mypid
);
1255 ASSERT_EQ(ceph_ll_lookup_root(cmount
, &root
), 0);
1258 struct ceph_statx stx
;
1259 UserPerm
*perms
= ceph_mount_perms(cmount
);
1261 ASSERT_EQ(ceph_ll_create(cmount
, root
, filename
, 0666,
1262 O_RDWR
|O_CREAT
|O_TRUNC
, &file
, &fh
, &stx
, 0, 0, perms
), 0);
1264 /* Reopen read-only */
1265 char out0
[] = "hello ";
1266 char out1
[] = "world\n";
1267 struct iovec iov_out
[2] = {
1268 {out0
, sizeof(out0
)},
1269 {out1
, sizeof(out1
)},
1271 char in0
[sizeof(out0
)];
1272 char in1
[sizeof(out1
)];
1273 struct iovec iov_in
[2] = {
1277 ssize_t nwritten
= iov_out
[0].iov_len
+ iov_out
[1].iov_len
;
1278 ssize_t nread
= iov_in
[0].iov_len
+ iov_in
[1].iov_len
;
1280 ASSERT_EQ(ceph_ll_writev(cmount
, fh
, iov_out
, 2, 0), nwritten
);
1281 ASSERT_EQ(ceph_ll_readv(cmount
, fh
, iov_in
, 2, 0), nread
);
1282 ASSERT_EQ(0, strncmp((const char*)iov_in
[0].iov_base
, (const char*)iov_out
[0].iov_base
, iov_out
[0].iov_len
));
1283 ASSERT_EQ(0, strncmp((const char*)iov_in
[1].iov_base
, (const char*)iov_out
[1].iov_base
, iov_out
[1].iov_len
));
1285 ceph_ll_close(cmount
, fh
);
1286 ceph_shutdown(cmount
);
1289 TEST(LibCephFS
, StripeUnitGran
) {
1290 struct ceph_mount_info
*cmount
;
1291 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1292 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1293 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1294 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1295 ASSERT_GT(ceph_get_stripe_unit_granularity(cmount
), 0);
1296 ceph_shutdown(cmount
);
1299 TEST(LibCephFS
, Rename
) {
1300 struct ceph_mount_info
*cmount
;
1301 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1302 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1303 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1304 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1306 int mypid
= getpid();
1310 /* make a source file */
1311 sprintf(path_src
, "test_rename_src%d", mypid
);
1312 int fd
= ceph_open(cmount
, path_src
, O_CREAT
|O_TRUNC
|O_WRONLY
, 0777);
1314 ASSERT_EQ(0, ceph_close(cmount
, fd
));
1316 /* rename to a new dest path */
1317 sprintf(path_dst
, "test_rename_dst%d", mypid
);
1318 ASSERT_EQ(0, ceph_rename(cmount
, path_src
, path_dst
));
1320 /* test that dest path exists */
1321 struct ceph_statx stx
;
1322 ASSERT_EQ(0, ceph_statx(cmount
, path_dst
, &stx
, 0, 0));
1324 /* test that src path doesn't exist */
1325 ASSERT_EQ(-ENOENT
, ceph_statx(cmount
, path_src
, &stx
, 0, AT_SYMLINK_NOFOLLOW
));
1327 /* rename with non-existent source path */
1328 ASSERT_EQ(-ENOENT
, ceph_rename(cmount
, path_src
, path_dst
));
1330 ASSERT_EQ(0, ceph_unlink(cmount
, path_dst
));
1331 ceph_shutdown(cmount
);
1334 TEST(LibCephFS
, UseUnmounted
) {
1335 struct ceph_mount_info
*cmount
;
1336 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1337 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1338 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1340 struct statvfs stvfs
;
1341 EXPECT_EQ(-ENOTCONN
, ceph_statfs(cmount
, "/", &stvfs
));
1342 EXPECT_EQ(-ENOTCONN
, ceph_get_local_osd(cmount
));
1343 EXPECT_EQ(-ENOTCONN
, ceph_chdir(cmount
, "/"));
1345 struct ceph_dir_result
*dirp
;
1346 EXPECT_EQ(-ENOTCONN
, ceph_opendir(cmount
, "/", &dirp
));
1347 EXPECT_EQ(-ENOTCONN
, ceph_closedir(cmount
, dirp
));
1349 ceph_readdir(cmount
, dirp
);
1350 EXPECT_EQ(ENOTCONN
, errno
);
1352 struct dirent rdent
;
1353 EXPECT_EQ(-ENOTCONN
, ceph_readdir_r(cmount
, dirp
, &rdent
));
1355 struct ceph_statx stx
;
1356 EXPECT_EQ(-ENOTCONN
, ceph_readdirplus_r(cmount
, dirp
, &rdent
, &stx
, 0, 0, NULL
));
1357 EXPECT_EQ(-ENOTCONN
, ceph_getdents(cmount
, dirp
, NULL
, 0));
1358 EXPECT_EQ(-ENOTCONN
, ceph_getdnames(cmount
, dirp
, NULL
, 0));
1359 EXPECT_EQ(-ENOTCONN
, ceph_telldir(cmount
, dirp
));
1360 EXPECT_EQ(-ENOTCONN
, ceph_link(cmount
, "/", "/link"));
1361 EXPECT_EQ(-ENOTCONN
, ceph_unlink(cmount
, "/path"));
1362 EXPECT_EQ(-ENOTCONN
, ceph_rename(cmount
, "/path", "/path"));
1363 EXPECT_EQ(-ENOTCONN
, ceph_mkdir(cmount
, "/", 0655));
1364 EXPECT_EQ(-ENOTCONN
, ceph_mkdirs(cmount
, "/", 0655));
1365 EXPECT_EQ(-ENOTCONN
, ceph_rmdir(cmount
, "/path"));
1366 EXPECT_EQ(-ENOTCONN
, ceph_readlink(cmount
, "/path", NULL
, 0));
1367 EXPECT_EQ(-ENOTCONN
, ceph_symlink(cmount
, "/path", "/path"));
1368 EXPECT_EQ(-ENOTCONN
, ceph_statx(cmount
, "/path", &stx
, 0, 0));
1369 EXPECT_EQ(-ENOTCONN
, ceph_setattrx(cmount
, "/path", &stx
, 0, 0));
1370 EXPECT_EQ(-ENOTCONN
, ceph_getxattr(cmount
, "/path", "name", NULL
, 0));
1371 EXPECT_EQ(-ENOTCONN
, ceph_lgetxattr(cmount
, "/path", "name", NULL
, 0));
1372 EXPECT_EQ(-ENOTCONN
, ceph_listxattr(cmount
, "/path", NULL
, 0));
1373 EXPECT_EQ(-ENOTCONN
, ceph_llistxattr(cmount
, "/path", NULL
, 0));
1374 EXPECT_EQ(-ENOTCONN
, ceph_removexattr(cmount
, "/path", "name"));
1375 EXPECT_EQ(-ENOTCONN
, ceph_lremovexattr(cmount
, "/path", "name"));
1376 EXPECT_EQ(-ENOTCONN
, ceph_setxattr(cmount
, "/path", "name", NULL
, 0, 0));
1377 EXPECT_EQ(-ENOTCONN
, ceph_lsetxattr(cmount
, "/path", "name", NULL
, 0, 0));
1378 EXPECT_EQ(-ENOTCONN
, ceph_fsetattrx(cmount
, 0, &stx
, 0));
1379 EXPECT_EQ(-ENOTCONN
, ceph_chmod(cmount
, "/path", 0));
1380 EXPECT_EQ(-ENOTCONN
, ceph_fchmod(cmount
, 0, 0));
1381 EXPECT_EQ(-ENOTCONN
, ceph_chown(cmount
, "/path", 0, 0));
1382 EXPECT_EQ(-ENOTCONN
, ceph_lchown(cmount
, "/path", 0, 0));
1383 EXPECT_EQ(-ENOTCONN
, ceph_fchown(cmount
, 0, 0, 0));
1386 EXPECT_EQ(-ENOTCONN
, ceph_utime(cmount
, "/path", &utb
));
1387 EXPECT_EQ(-ENOTCONN
, ceph_truncate(cmount
, "/path", 0));
1388 EXPECT_EQ(-ENOTCONN
, ceph_mknod(cmount
, "/path", 0, 0));
1389 EXPECT_EQ(-ENOTCONN
, ceph_open(cmount
, "/path", 0, 0));
1390 EXPECT_EQ(-ENOTCONN
, ceph_open_layout(cmount
, "/path", 0, 0, 0, 0, 0, "pool"));
1391 EXPECT_EQ(-ENOTCONN
, ceph_close(cmount
, 0));
1392 EXPECT_EQ(-ENOTCONN
, ceph_lseek(cmount
, 0, 0, SEEK_SET
));
1393 EXPECT_EQ(-ENOTCONN
, ceph_read(cmount
, 0, NULL
, 0, 0));
1394 EXPECT_EQ(-ENOTCONN
, ceph_write(cmount
, 0, NULL
, 0, 0));
1395 EXPECT_EQ(-ENOTCONN
, ceph_ftruncate(cmount
, 0, 0));
1396 EXPECT_EQ(-ENOTCONN
, ceph_fsync(cmount
, 0, 0));
1397 EXPECT_EQ(-ENOTCONN
, ceph_fstatx(cmount
, 0, &stx
, 0, 0));
1398 EXPECT_EQ(-ENOTCONN
, ceph_sync_fs(cmount
));
1399 EXPECT_EQ(-ENOTCONN
, ceph_get_file_stripe_unit(cmount
, 0));
1400 EXPECT_EQ(-ENOTCONN
, ceph_get_file_stripe_count(cmount
, 0));
1401 EXPECT_EQ(-ENOTCONN
, ceph_get_file_layout(cmount
, 0, NULL
, NULL
,NULL
,NULL
));
1402 EXPECT_EQ(-ENOTCONN
, ceph_get_file_object_size(cmount
, 0));
1403 EXPECT_EQ(-ENOTCONN
, ceph_get_file_pool(cmount
, 0));
1404 EXPECT_EQ(-ENOTCONN
, ceph_get_file_pool_name(cmount
, 0, NULL
, 0));
1405 EXPECT_EQ(-ENOTCONN
, ceph_get_file_replication(cmount
, 0));
1406 EXPECT_EQ(-ENOTCONN
, ceph_get_path_replication(cmount
, "/path"));
1407 EXPECT_EQ(-ENOTCONN
, ceph_get_path_layout(cmount
, "/path", NULL
, NULL
, NULL
, NULL
));
1408 EXPECT_EQ(-ENOTCONN
, ceph_get_path_object_size(cmount
, "/path"));
1409 EXPECT_EQ(-ENOTCONN
, ceph_get_path_stripe_count(cmount
, "/path"));
1410 EXPECT_EQ(-ENOTCONN
, ceph_get_path_stripe_unit(cmount
, "/path"));
1411 EXPECT_EQ(-ENOTCONN
, ceph_get_path_pool(cmount
, "/path"));
1412 EXPECT_EQ(-ENOTCONN
, ceph_get_path_pool_name(cmount
, "/path", NULL
, 0));
1413 EXPECT_EQ(-ENOTCONN
, ceph_get_pool_name(cmount
, 0, NULL
, 0));
1414 EXPECT_EQ(-ENOTCONN
, ceph_get_file_stripe_address(cmount
, 0, 0, NULL
, 0));
1415 EXPECT_EQ(-ENOTCONN
, ceph_localize_reads(cmount
, 0));
1416 EXPECT_EQ(-ENOTCONN
, ceph_debug_get_fd_caps(cmount
, 0));
1417 EXPECT_EQ(-ENOTCONN
, ceph_debug_get_file_caps(cmount
, "/path"));
1418 EXPECT_EQ(-ENOTCONN
, ceph_get_stripe_unit_granularity(cmount
));
1419 EXPECT_EQ(-ENOTCONN
, ceph_get_pool_id(cmount
, "data"));
1420 EXPECT_EQ(-ENOTCONN
, ceph_get_pool_replication(cmount
, 1));
1422 ceph_release(cmount
);
1425 TEST(LibCephFS
, GetPoolId
) {
1426 struct ceph_mount_info
*cmount
;
1427 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1428 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1429 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1430 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1433 memset(name
, 0, sizeof(name
));
1434 ASSERT_LE(0, ceph_get_path_pool_name(cmount
, "/", name
, sizeof(name
)));
1435 ASSERT_GE(ceph_get_pool_id(cmount
, name
), 0);
1436 ASSERT_EQ(ceph_get_pool_id(cmount
, "weflkjwelfjwlkejf"), -ENOENT
);
1438 ceph_shutdown(cmount
);
1441 TEST(LibCephFS
, GetPoolReplication
) {
1442 struct ceph_mount_info
*cmount
;
1443 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1444 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1445 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1446 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1448 /* negative pools */
1449 ASSERT_EQ(ceph_get_pool_replication(cmount
, -10), -ENOENT
);
1453 int stripe_unit
, stripe_count
, object_size
;
1454 ASSERT_EQ(0, ceph_get_path_layout(cmount
, "/", &stripe_unit
, &stripe_count
,
1455 &object_size
, &pool_id
));
1456 ASSERT_GE(pool_id
, 0);
1457 ASSERT_GT(ceph_get_pool_replication(cmount
, pool_id
), 0);
1459 ceph_shutdown(cmount
);
1462 TEST(LibCephFS
, GetExtentOsds
) {
1463 struct ceph_mount_info
*cmount
;
1464 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1466 EXPECT_EQ(-ENOTCONN
, ceph_get_file_extent_osds(cmount
, 0, 0, NULL
, NULL
, 0));
1468 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1469 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1470 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1472 int stripe_unit
= (1<<18);
1475 char test_file
[256];
1476 sprintf(test_file
, "test_extent_osds_%d", getpid());
1477 int fd
= ceph_open_layout(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666,
1478 stripe_unit
, 2, stripe_unit
*2, NULL
);
1481 /* get back how many osds > 0 */
1482 int ret
= ceph_get_file_extent_osds(cmount
, fd
, 0, NULL
, NULL
, 0);
1488 /* full stripe extent */
1489 EXPECT_EQ(ret
, ceph_get_file_extent_osds(cmount
, fd
, 0, &len
, osds
, ret
));
1490 EXPECT_EQ(len
, (int64_t)stripe_unit
);
1492 /* half stripe extent */
1493 EXPECT_EQ(ret
, ceph_get_file_extent_osds(cmount
, fd
, stripe_unit
/2, &len
, osds
, ret
));
1494 EXPECT_EQ(len
, (int64_t)stripe_unit
/2);
1496 /* 1.5 stripe unit offset -1 byte */
1497 EXPECT_EQ(ret
, ceph_get_file_extent_osds(cmount
, fd
, 3*stripe_unit
/2-1, &len
, osds
, ret
));
1498 EXPECT_EQ(len
, (int64_t)stripe_unit
/2+1);
1500 /* 1.5 stripe unit offset +1 byte */
1501 EXPECT_EQ(ret
, ceph_get_file_extent_osds(cmount
, fd
, 3*stripe_unit
/2+1, &len
, osds
, ret
));
1502 EXPECT_EQ(len
, (int64_t)stripe_unit
/2-1);
1504 /* only when more than 1 osd */
1506 EXPECT_EQ(-ERANGE
, ceph_get_file_extent_osds(cmount
, fd
, 0, NULL
, osds
, 1));
1509 ceph_close(cmount
, fd
);
1511 ceph_shutdown(cmount
);
1514 TEST(LibCephFS
, GetOsdCrushLocation
) {
1515 struct ceph_mount_info
*cmount
;
1516 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1518 EXPECT_EQ(-ENOTCONN
, ceph_get_osd_crush_location(cmount
, 0, NULL
, 0));
1520 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1521 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1522 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1524 ASSERT_EQ(ceph_get_osd_crush_location(cmount
, 0, NULL
, 1), -EINVAL
);
1527 ASSERT_EQ(ceph_get_osd_crush_location(cmount
, 9999999, path
, 0), -ENOENT
);
1528 ASSERT_EQ(ceph_get_osd_crush_location(cmount
, -1, path
, 0), -EINVAL
);
1530 char test_file
[256];
1531 sprintf(test_file
, "test_osds_loc_%d", getpid());
1532 int fd
= ceph_open(cmount
, test_file
, O_CREAT
|O_RDWR
, 0666);
1535 /* get back how many osds > 0 */
1536 int ret
= ceph_get_file_extent_osds(cmount
, fd
, 0, NULL
, NULL
, 0);
1539 /* full stripe extent */
1541 EXPECT_EQ(ret
, ceph_get_file_extent_osds(cmount
, fd
, 0, NULL
, osds
, ret
));
1543 ASSERT_GT(ceph_get_osd_crush_location(cmount
, 0, path
, 0), 0);
1544 ASSERT_EQ(ceph_get_osd_crush_location(cmount
, 0, path
, 1), -ERANGE
);
1546 for (int i
= 0; i
< ret
; i
++) {
1547 int len
= ceph_get_osd_crush_location(cmount
, osds
[i
], path
, sizeof(path
));
1551 std::string
type(path
+ pos
);
1552 ASSERT_GT((int)type
.size(), 0);
1553 pos
+= type
.size() + 1;
1555 std::string
name(path
+ pos
);
1556 ASSERT_GT((int)name
.size(), 0);
1557 pos
+= name
.size() + 1;
1561 ceph_close(cmount
, fd
);
1562 ceph_shutdown(cmount
);
1565 TEST(LibCephFS
, GetOsdAddr
) {
1566 struct ceph_mount_info
*cmount
;
1567 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1569 EXPECT_EQ(-ENOTCONN
, ceph_get_osd_addr(cmount
, 0, NULL
));
1571 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1572 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1573 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
1575 ASSERT_EQ(-EINVAL
, ceph_get_osd_addr(cmount
, 0, NULL
));
1577 struct sockaddr_storage addr
;
1578 ASSERT_EQ(-ENOENT
, ceph_get_osd_addr(cmount
, -1, &addr
));
1579 ASSERT_EQ(-ENOENT
, ceph_get_osd_addr(cmount
, 9999999, &addr
));
1581 ASSERT_EQ(0, ceph_get_osd_addr(cmount
, 0, &addr
));
1583 ceph_shutdown(cmount
);
1586 TEST(LibCephFS
, OpenNoClose
) {
1587 struct ceph_mount_info
*cmount
;
1588 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1589 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1590 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1591 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1593 pid_t mypid
= getpid();
1595 sprintf(str_buf
, "open_no_close_dir%d", mypid
);
1596 ASSERT_EQ(0, ceph_mkdirs(cmount
, str_buf
, 0777));
1598 struct ceph_dir_result
*ls_dir
= NULL
;
1599 ASSERT_EQ(ceph_opendir(cmount
, str_buf
, &ls_dir
), 0);
1601 sprintf(str_buf
, "open_no_close_file%d", mypid
);
1602 int fd
= ceph_open(cmount
, str_buf
, O_RDONLY
|O_CREAT
, 0666);
1605 // shutdown should force close opened file/dir
1606 ceph_shutdown(cmount
);
1609 TEST(LibCephFS
, Nlink
) {
1610 struct ceph_mount_info
*cmount
;
1611 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1612 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1613 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1614 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1616 Inode
*root
, *dir
, *file
;
1618 ASSERT_EQ(ceph_ll_lookup_root(cmount
, &root
), 0);
1620 char dirname
[32], filename
[32], linkname
[32];
1621 sprintf(dirname
, "nlinkdir%x", getpid());
1622 sprintf(filename
, "nlinkorig%x", getpid());
1623 sprintf(linkname
, "nlinklink%x", getpid());
1625 struct ceph_statx stx
;
1627 UserPerm
*perms
= ceph_mount_perms(cmount
);
1629 ASSERT_EQ(ceph_ll_mkdir(cmount
, root
, dirname
, 0755, &dir
, &stx
, 0, 0, perms
), 0);
1630 ASSERT_EQ(ceph_ll_create(cmount
, dir
, filename
, 0666, O_RDWR
|O_CREAT
|O_EXCL
,
1631 &file
, &fh
, &stx
, CEPH_STATX_NLINK
, 0, perms
), 0);
1632 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
1633 ASSERT_EQ(stx
.stx_nlink
, (nlink_t
)1);
1635 ASSERT_EQ(ceph_ll_link(cmount
, file
, dir
, linkname
, perms
), 0);
1636 ASSERT_EQ(ceph_ll_getattr(cmount
, file
, &stx
, CEPH_STATX_NLINK
, 0, perms
), 0);
1637 ASSERT_EQ(stx
.stx_nlink
, (nlink_t
)2);
1639 ASSERT_EQ(ceph_ll_unlink(cmount
, dir
, linkname
, perms
), 0);
1640 ASSERT_EQ(ceph_ll_lookup(cmount
, dir
, filename
, &file
, &stx
,
1641 CEPH_STATX_NLINK
, 0, perms
), 0);
1642 ASSERT_EQ(stx
.stx_nlink
, (nlink_t
)1);
1644 ceph_shutdown(cmount
);
1647 TEST(LibCephFS
, SlashDotDot
) {
1648 struct ceph_mount_info
*cmount
;
1649 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1650 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1651 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1652 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1654 struct ceph_statx stx
;
1655 ASSERT_EQ(ceph_statx(cmount
, "/.", &stx
, CEPH_STATX_INO
, 0), 0);
1657 ino_t ino
= stx
.stx_ino
;
1658 ASSERT_EQ(ceph_statx(cmount
, "/..", &stx
, CEPH_STATX_INO
, 0), 0);
1660 /* At root, "." and ".." should be the same inode */
1661 ASSERT_EQ(ino
, stx
.stx_ino
);
1663 /* Test accessing the parent of an unlinked directory */
1664 char dir1
[32], dir2
[56];
1665 sprintf(dir1
, "/sldotdot%x", getpid());
1666 sprintf(dir2
, "%s/sub%x", dir1
, getpid());
1668 ASSERT_EQ(ceph_mkdir(cmount
, dir1
, 0755), 0);
1669 ASSERT_EQ(ceph_mkdir(cmount
, dir2
, 0755), 0);
1671 ASSERT_EQ(ceph_chdir(cmount
, dir2
), 0);
1673 /* Test behavior when unlinking cwd */
1674 struct ceph_dir_result
*rdir
;
1675 ASSERT_EQ(ceph_opendir(cmount
, ".", &rdir
), 0);
1676 ASSERT_EQ(ceph_rmdir(cmount
, dir2
), 0);
1679 struct dirent
*result
= ceph_readdir(cmount
, rdir
);
1680 ino
= result
->d_ino
;
1682 /* get ".." entry */
1683 result
= ceph_readdir(cmount
, rdir
);
1684 ASSERT_EQ(ino
, result
->d_ino
);
1685 ceph_closedir(cmount
, rdir
);
1687 /* Make sure it works same way when mounting subtree */
1688 ASSERT_EQ(ceph_unmount(cmount
), 0);
1689 ASSERT_EQ(ceph_mount(cmount
, dir1
), 0);
1690 ASSERT_EQ(ceph_statx(cmount
, "/..", &stx
, CEPH_STATX_INO
, 0), 0);
1692 /* Test readdir behavior */
1693 ASSERT_EQ(ceph_opendir(cmount
, "/", &rdir
), 0);
1694 result
= ceph_readdir(cmount
, rdir
);
1695 ASSERT_TRUE(result
!= NULL
);
1696 ASSERT_STREQ(result
->d_name
, ".");
1697 ino
= result
->d_ino
;
1698 result
= ceph_readdir(cmount
, rdir
);
1699 ASSERT_TRUE(result
!= NULL
);
1700 ASSERT_STREQ(result
->d_name
, "..");
1701 ASSERT_EQ(ino
, result
->d_ino
);
1703 ceph_shutdown(cmount
);
1707 timespec_eq(timespec
const& lhs
, timespec
const& rhs
)
1709 return lhs
.tv_sec
== rhs
.tv_sec
&& lhs
.tv_nsec
== rhs
.tv_nsec
;
1712 TEST(LibCephFS
, Btime
) {
1713 struct ceph_mount_info
*cmount
;
1714 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1715 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1716 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1717 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1720 sprintf(filename
, "/getattrx%x", getpid());
1722 ceph_unlink(cmount
, filename
);
1723 int fd
= ceph_open(cmount
, filename
, O_RDWR
|O_CREAT
|O_EXCL
, 0666);
1726 /* make sure fstatx works */
1727 struct ceph_statx stx
;
1729 ASSERT_EQ(ceph_fstatx(cmount
, fd
, &stx
, CEPH_STATX_CTIME
|CEPH_STATX_BTIME
, 0), 0);
1730 ASSERT_TRUE(stx
.stx_mask
& (CEPH_STATX_CTIME
|CEPH_STATX_BTIME
));
1731 ASSERT_TRUE(timespec_eq(stx
.stx_ctime
, stx
.stx_btime
));
1732 ceph_close(cmount
, fd
);
1734 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_CTIME
|CEPH_STATX_BTIME
, 0), 0);
1735 ASSERT_TRUE(timespec_eq(stx
.stx_ctime
, stx
.stx_btime
));
1736 ASSERT_TRUE(stx
.stx_mask
& (CEPH_STATX_CTIME
|CEPH_STATX_BTIME
));
1738 struct timespec old_btime
= stx
.stx_btime
;
1740 /* Now sleep, do a chmod and verify that the ctime changed, but btime didn't */
1742 ASSERT_EQ(ceph_chmod(cmount
, filename
, 0644), 0);
1743 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_CTIME
|CEPH_STATX_BTIME
, 0), 0);
1744 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_BTIME
);
1745 ASSERT_TRUE(timespec_eq(stx
.stx_btime
, old_btime
));
1746 ASSERT_FALSE(timespec_eq(stx
.stx_ctime
, stx
.stx_btime
));
1748 ceph_shutdown(cmount
);
1751 TEST(LibCephFS
, SetBtime
) {
1752 struct ceph_mount_info
*cmount
;
1753 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1754 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1755 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1756 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1759 sprintf(filename
, "/setbtime%x", getpid());
1761 ceph_unlink(cmount
, filename
);
1762 int fd
= ceph_open(cmount
, filename
, O_RDWR
|O_CREAT
|O_EXCL
, 0666);
1764 ceph_close(cmount
, fd
);
1766 struct ceph_statx stx
;
1767 struct timespec old_btime
= { 1, 2 };
1769 stx
.stx_btime
= old_btime
;
1771 ASSERT_EQ(ceph_setattrx(cmount
, filename
, &stx
, CEPH_SETATTR_BTIME
, 0), 0);
1773 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_BTIME
, 0), 0);
1774 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_BTIME
);
1775 ASSERT_TRUE(timespec_eq(stx
.stx_btime
, old_btime
));
1777 ceph_shutdown(cmount
);
1780 TEST(LibCephFS
, LazyStatx
) {
1781 struct ceph_mount_info
*cmount1
, *cmount2
;
1782 ASSERT_EQ(ceph_create(&cmount1
, NULL
), 0);
1783 ASSERT_EQ(ceph_create(&cmount2
, NULL
), 0);
1784 ASSERT_EQ(ceph_conf_read_file(cmount1
, NULL
), 0);
1785 ASSERT_EQ(ceph_conf_read_file(cmount2
, NULL
), 0);
1786 ASSERT_EQ(0, ceph_conf_parse_env(cmount1
, NULL
));
1787 ASSERT_EQ(0, ceph_conf_parse_env(cmount2
, NULL
));
1788 ASSERT_EQ(ceph_mount(cmount1
, "/"), 0);
1789 ASSERT_EQ(ceph_mount(cmount2
, "/"), 0);
1792 sprintf(filename
, "lazystatx%x", getpid());
1794 Inode
*root1
, *file1
, *root2
, *file2
;
1795 struct ceph_statx stx
;
1797 UserPerm
*perms1
= ceph_mount_perms(cmount1
);
1798 UserPerm
*perms2
= ceph_mount_perms(cmount2
);
1800 ASSERT_EQ(ceph_ll_lookup_root(cmount1
, &root1
), 0);
1801 ceph_ll_unlink(cmount1
, root1
, filename
, perms1
);
1802 ASSERT_EQ(ceph_ll_create(cmount1
, root1
, filename
, 0666, O_RDWR
|O_CREAT
|O_EXCL
,
1803 &file1
, &fh
, &stx
, 0, 0, perms1
), 0);
1804 ASSERT_EQ(ceph_ll_close(cmount1
, fh
), 0);
1806 ASSERT_EQ(ceph_ll_lookup_root(cmount2
, &root2
), 0);
1808 ASSERT_EQ(ceph_ll_lookup(cmount2
, root2
, filename
, &file2
, &stx
, CEPH_STATX_CTIME
, 0, perms2
), 0);
1810 struct timespec old_ctime
= stx
.stx_ctime
;
1813 * Now sleep, do a chmod on the first client and the see whether we get a
1814 * different ctime with a statx that uses AT_STATX_DONT_SYNC
1817 stx
.stx_mode
= 0644;
1818 ASSERT_EQ(ceph_ll_setattr(cmount1
, file1
, &stx
, CEPH_SETATTR_MODE
, perms1
), 0);
1820 ASSERT_EQ(ceph_ll_getattr(cmount2
, file2
, &stx
, CEPH_STATX_CTIME
, AT_STATX_DONT_SYNC
, perms2
), 0);
1821 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_CTIME
);
1822 ASSERT_TRUE(stx
.stx_ctime
.tv_sec
== old_ctime
.tv_sec
&&
1823 stx
.stx_ctime
.tv_nsec
== old_ctime
.tv_nsec
);
1825 ceph_shutdown(cmount1
);
1826 ceph_shutdown(cmount2
);
1829 TEST(LibCephFS
, ChangeAttr
) {
1830 struct ceph_mount_info
*cmount
;
1831 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1832 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1833 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1834 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1837 sprintf(filename
, "/changeattr%x", getpid());
1839 ceph_unlink(cmount
, filename
);
1840 int fd
= ceph_open(cmount
, filename
, O_RDWR
|O_CREAT
|O_EXCL
, 0666);
1843 struct ceph_statx stx
;
1844 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1845 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1847 uint64_t old_change_attr
= stx
.stx_version
;
1849 /* do chmod, and check whether change_attr changed */
1850 ASSERT_EQ(ceph_chmod(cmount
, filename
, 0644), 0);
1851 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1852 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1853 ASSERT_NE(stx
.stx_version
, old_change_attr
);
1854 old_change_attr
= stx
.stx_version
;
1856 /* now do a write and see if it changed again */
1857 ASSERT_EQ(3, ceph_write(cmount
, fd
, "foo", 3, 0));
1858 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1859 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1860 ASSERT_NE(stx
.stx_version
, old_change_attr
);
1861 old_change_attr
= stx
.stx_version
;
1863 /* Now truncate and check again */
1864 ASSERT_EQ(0, ceph_ftruncate(cmount
, fd
, 0));
1865 ASSERT_EQ(ceph_statx(cmount
, filename
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1866 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1867 ASSERT_NE(stx
.stx_version
, old_change_attr
);
1869 ceph_close(cmount
, fd
);
1870 ceph_shutdown(cmount
);
1873 TEST(LibCephFS
, DirChangeAttr
) {
1874 struct ceph_mount_info
*cmount
;
1875 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1876 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1877 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1878 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1880 char dirname
[32], filename
[56];
1881 sprintf(dirname
, "/dirchange%x", getpid());
1882 sprintf(filename
, "%s/foo", dirname
);
1884 ASSERT_EQ(ceph_mkdir(cmount
, dirname
, 0755), 0);
1886 struct ceph_statx stx
;
1887 ASSERT_EQ(ceph_statx(cmount
, dirname
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1888 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1890 uint64_t old_change_attr
= stx
.stx_version
;
1892 int fd
= ceph_open(cmount
, filename
, O_RDWR
|O_CREAT
|O_EXCL
, 0666);
1894 ceph_close(cmount
, fd
);
1896 ASSERT_EQ(ceph_statx(cmount
, dirname
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1897 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1898 ASSERT_NE(stx
.stx_version
, old_change_attr
);
1900 old_change_attr
= stx
.stx_version
;
1902 ASSERT_EQ(ceph_unlink(cmount
, filename
), 0);
1903 ASSERT_EQ(ceph_statx(cmount
, dirname
, &stx
, CEPH_STATX_VERSION
, 0), 0);
1904 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_VERSION
);
1905 ASSERT_NE(stx
.stx_version
, old_change_attr
);
1907 ceph_shutdown(cmount
);
1910 TEST(LibCephFS
, SetSize
) {
1911 struct ceph_mount_info
*cmount
;
1912 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1913 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1914 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1915 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1918 sprintf(filename
, "/setsize%x", getpid());
1920 ceph_unlink(cmount
, filename
);
1921 int fd
= ceph_open(cmount
, filename
, O_RDWR
|O_CREAT
|O_EXCL
, 0666);
1924 struct ceph_statx stx
;
1925 uint64_t size
= 8388608;
1926 stx
.stx_size
= size
;
1927 ASSERT_EQ(ceph_fsetattrx(cmount
, fd
, &stx
, CEPH_SETATTR_SIZE
), 0);
1928 ASSERT_EQ(ceph_fstatx(cmount
, fd
, &stx
, CEPH_STATX_SIZE
, 0), 0);
1929 ASSERT_EQ(stx
.stx_size
, size
);
1931 ceph_close(cmount
, fd
);
1932 ceph_shutdown(cmount
);
1935 TEST(LibCephFS
, ClearSetuid
) {
1936 struct ceph_mount_info
*cmount
;
1937 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
1938 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
1939 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
1940 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
1943 ASSERT_EQ(ceph_ll_lookup_root(cmount
, &root
), 0);
1946 sprintf(filename
, "clearsetuid%x", getpid());
1950 struct ceph_statx stx
;
1951 const mode_t after_mode
= S_IRWXU
;
1952 const mode_t before_mode
= S_IRWXU
| S_ISUID
| S_ISGID
;
1953 const unsigned want
= CEPH_STATX_UID
|CEPH_STATX_GID
|CEPH_STATX_MODE
;
1954 UserPerm
*usercred
= ceph_mount_perms(cmount
);
1956 ceph_ll_unlink(cmount
, root
, filename
, usercred
);
1957 ASSERT_EQ(ceph_ll_create(cmount
, root
, filename
, before_mode
,
1958 O_RDWR
|O_CREAT
|O_EXCL
, &in
, &fh
, &stx
, want
, 0,
1961 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, before_mode
);
1964 ASSERT_EQ(ceph_ll_write(cmount
, fh
, 0, 3, "foo"), 3);
1965 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, usercred
), 0);
1966 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_MODE
);
1967 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, after_mode
);
1970 stx
.stx_mode
= before_mode
;
1971 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, usercred
), 0);
1972 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, usercred
), 0);
1973 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_MODE
);
1974 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, before_mode
);
1978 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_SETATTR_SIZE
, usercred
), 0);
1979 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, usercred
), 0);
1980 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_MODE
);
1981 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, after_mode
);
1984 stx
.stx_mode
= before_mode
;
1985 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, usercred
), 0);
1986 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, usercred
), 0);
1987 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_MODE
);
1988 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, before_mode
);
1990 // chown -- for this we need to be "root"
1991 UserPerm
*rootcred
= ceph_userperm_new(0, 0, 0, NULL
);
1992 ASSERT_TRUE(rootcred
);
1995 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_SETATTR_UID
|CEPH_SETATTR_GID
, rootcred
), 0);
1996 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, usercred
), 0);
1997 ASSERT_TRUE(stx
.stx_mask
& CEPH_STATX_MODE
);
1998 ASSERT_EQ(stx
.stx_mode
& (mode_t
)ALLPERMS
, after_mode
);
2000 /* test chown with supplementary groups, and chown with/without exe bit */
2003 gid_t gids
[] = {65533,65532};
2004 UserPerm
*altcred
= ceph_userperm_new(u
, g
, sizeof gids
/ sizeof gids
[0], gids
);
2007 mode_t m
= S_ISGID
|S_ISUID
|S_IRUSR
|S_IWUSR
;
2009 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_STATX_MODE
|CEPH_SETATTR_UID
|CEPH_SETATTR_GID
, rootcred
), 0);
2010 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, altcred
), 0);
2011 ASSERT_EQ(stx
.stx_mode
&(mode_t
)ALLPERMS
, m
);
2012 /* not dropped without exe bit */
2013 stx
.stx_gid
= gids
[0];
2014 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_SETATTR_GID
, altcred
), 0);
2015 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, altcred
), 0);
2016 ASSERT_EQ(stx
.stx_mode
&(mode_t
)ALLPERMS
, m
);
2017 /* now check dropped with exe bit */
2018 m
= S_ISGID
|S_ISUID
|S_IRWXU
;
2020 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, altcred
), 0);
2021 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, altcred
), 0);
2022 ASSERT_EQ(stx
.stx_mode
&(mode_t
)ALLPERMS
, m
);
2023 stx
.stx_gid
= gids
[1];
2024 ASSERT_EQ(ceph_ll_setattr(cmount
, in
, &stx
, CEPH_SETATTR_GID
, altcred
), 0);
2025 ASSERT_EQ(ceph_ll_getattr(cmount
, in
, &stx
, CEPH_STATX_MODE
, 0, altcred
), 0);
2026 ASSERT_EQ(stx
.stx_mode
&(mode_t
)ALLPERMS
, m
&(S_IRWXU
|S_IRWXG
|S_IRWXO
));
2027 ceph_userperm_destroy(altcred
);
2029 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
2030 ceph_shutdown(cmount
);
2033 TEST(LibCephFS
, OperationsOnRoot
)
2035 struct ceph_mount_info
*cmount
;
2036 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2037 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2038 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2039 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
2042 sprintf(dirname
, "/somedir%x", getpid());
2044 ASSERT_EQ(ceph_mkdir(cmount
, dirname
, 0755), 0);
2046 ASSERT_EQ(ceph_rmdir(cmount
, "/"), -EBUSY
);
2048 ASSERT_EQ(ceph_link(cmount
, "/", "/"), -EEXIST
);
2049 ASSERT_EQ(ceph_link(cmount
, dirname
, "/"), -EEXIST
);
2050 ASSERT_EQ(ceph_link(cmount
, "nonExisitingDir", "/"), -ENOENT
);
2052 ASSERT_EQ(ceph_unlink(cmount
, "/"), -EISDIR
);
2054 ASSERT_EQ(ceph_rename(cmount
, "/", "/"), -EBUSY
);
2055 ASSERT_EQ(ceph_rename(cmount
, dirname
, "/"), -EBUSY
);
2056 ASSERT_EQ(ceph_rename(cmount
, "nonExistingDir", "/"), -EBUSY
);
2057 ASSERT_EQ(ceph_rename(cmount
, "/", dirname
), -EBUSY
);
2058 ASSERT_EQ(ceph_rename(cmount
, "/", "nonExistingDir"), -EBUSY
);
2060 ASSERT_EQ(ceph_mkdir(cmount
, "/", 0777), -EEXIST
);
2062 ASSERT_EQ(ceph_mknod(cmount
, "/", 0, 0), -EEXIST
);
2064 ASSERT_EQ(ceph_symlink(cmount
, "/", "/"), -EEXIST
);
2065 ASSERT_EQ(ceph_symlink(cmount
, dirname
, "/"), -EEXIST
);
2066 ASSERT_EQ(ceph_symlink(cmount
, "nonExistingDir", "/"), -EEXIST
);
2068 ceph_shutdown(cmount
);
2071 static void shutdown_racer_func()
2073 const int niter
= 32;
2074 struct ceph_mount_info
*cmount
;
2077 for (i
= 0; i
< niter
; ++i
) {
2078 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2079 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2080 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2081 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
2082 ceph_shutdown(cmount
);
2086 // See tracker #20988
2087 TEST(LibCephFS
, ShutdownRace
)
2089 const int nthreads
= 32;
2090 std::thread threads
[nthreads
];
2092 // Need a bunch of fd's for this test
2093 struct rlimit rold
, rnew
;
2094 ASSERT_EQ(getrlimit(RLIMIT_NOFILE
, &rold
), 0);
2096 rnew
.rlim_cur
= rnew
.rlim_max
;
2098 cout
<< "Setting RLIMIT_NOFILE from " << rold
.rlim_cur
<<
2099 " to " << rnew
.rlim_cur
<< std::endl
;
2101 ASSERT_EQ(setrlimit(RLIMIT_NOFILE
, &rnew
), 0);
2103 for (int i
= 0; i
< nthreads
; ++i
)
2104 threads
[i
] = std::thread(shutdown_racer_func
);
2106 for (int i
= 0; i
< nthreads
; ++i
)
2109 * Let's just ignore restoring the open files limit,
2110 * the kernel will defer releasing the file descriptors
2111 * and then the process will be possibly reachthe open
2112 * files limit. More detail, please see tracer#43039
2114 // ASSERT_EQ(setrlimit(RLIMIT_NOFILE, &rold), 0);
2117 static void get_current_time_utimbuf(struct utimbuf
*utb
)
2119 utime_t t
= ceph_clock_now();
2120 utb
->actime
= t
.sec();
2121 utb
->modtime
= t
.sec();
2124 static void get_current_time_timeval(struct timeval tv
[2])
2126 utime_t t
= ceph_clock_now();
2127 t
.copy_to_timeval(&tv
[0]);
2128 t
.copy_to_timeval(&tv
[1]);
2131 static void get_current_time_timespec(struct timespec ts
[2])
2133 utime_t t
= ceph_clock_now();
2134 t
.to_timespec(&ts
[0]);
2135 t
.to_timespec(&ts
[1]);
2138 TEST(LibCephFS
, TestUtime
) {
2139 struct ceph_mount_info
*cmount
;
2140 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2141 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2142 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2143 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2145 char test_file
[256];
2146 sprintf(test_file
, "test_utime_file_%d", getpid());
2147 int fd
= ceph_open(cmount
, test_file
, O_CREAT
, 0666);
2151 struct ceph_statx stx
;
2153 get_current_time_utimbuf(&utb
);
2156 EXPECT_EQ(0, ceph_utime(cmount
, test_file
, &utb
));
2157 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx
,
2158 CEPH_STATX_MTIME
|CEPH_STATX_ATIME
, 0), 0);
2159 ASSERT_EQ(utime_t(stx
.stx_atime
), utime_t(utb
.actime
, 0));
2160 ASSERT_EQ(utime_t(stx
.stx_mtime
), utime_t(utb
.modtime
, 0));
2162 get_current_time_utimbuf(&utb
);
2165 EXPECT_EQ(0, ceph_futime(cmount
, fd
, &utb
));
2166 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx
,
2167 CEPH_STATX_MTIME
|CEPH_STATX_ATIME
, 0), 0);
2168 ASSERT_EQ(utime_t(stx
.stx_atime
), utime_t(utb
.actime
, 0));
2169 ASSERT_EQ(utime_t(stx
.stx_mtime
), utime_t(utb
.modtime
, 0));
2171 ceph_close(cmount
, fd
);
2172 ceph_shutdown(cmount
);
2175 TEST(LibCephFS
, TestUtimes
) {
2176 struct ceph_mount_info
*cmount
;
2177 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2178 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2179 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2180 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2182 char test_file
[256];
2183 char test_symlink
[256];
2185 sprintf(test_file
, "test_utimes_file_%d", getpid());
2186 sprintf(test_symlink
, "test_utimes_symlink_%d", getpid());
2187 int fd
= ceph_open(cmount
, test_file
, O_CREAT
, 0666);
2190 ASSERT_EQ(ceph_symlink(cmount
, test_file
, test_symlink
), 0);
2192 struct timeval times
[2];
2193 struct ceph_statx stx
;
2195 get_current_time_timeval(times
);
2197 // ceph_utimes() on symlink, validate target file time
2198 EXPECT_EQ(0, ceph_utimes(cmount
, test_symlink
, times
));
2199 ASSERT_EQ(ceph_statx(cmount
, test_symlink
, &stx
,
2200 CEPH_STATX_MTIME
|CEPH_STATX_ATIME
, 0), 0);
2201 ASSERT_EQ(utime_t(stx
.stx_atime
), utime_t(times
[0]));
2202 ASSERT_EQ(utime_t(stx
.stx_mtime
), utime_t(times
[1]));
2204 get_current_time_timeval(times
);
2206 // ceph_lutimes() on symlink, validate symlink time
2207 EXPECT_EQ(0, ceph_lutimes(cmount
, test_symlink
, times
));
2208 ASSERT_EQ(ceph_statx(cmount
, test_symlink
, &stx
,
2209 CEPH_STATX_MTIME
|CEPH_STATX_ATIME
, AT_SYMLINK_NOFOLLOW
), 0);
2210 ASSERT_EQ(utime_t(stx
.stx_atime
), utime_t(times
[0]));
2211 ASSERT_EQ(utime_t(stx
.stx_mtime
), utime_t(times
[1]));
2213 get_current_time_timeval(times
);
2216 EXPECT_EQ(0, ceph_futimes(cmount
, fd
, times
));
2217 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx
,
2218 CEPH_STATX_MTIME
|CEPH_STATX_ATIME
, 0), 0);
2219 ASSERT_EQ(utime_t(stx
.stx_atime
), utime_t(times
[0]));
2220 ASSERT_EQ(utime_t(stx
.stx_mtime
), utime_t(times
[1]));
2222 ceph_close(cmount
, fd
);
2223 ceph_shutdown(cmount
);
2226 TEST(LibCephFS
, TestFutimens
) {
2227 struct ceph_mount_info
*cmount
;
2228 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2229 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2230 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2231 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2233 char test_file
[256];
2235 sprintf(test_file
, "test_futimens_file_%d", getpid());
2236 int fd
= ceph_open(cmount
, test_file
, O_CREAT
, 0666);
2239 struct timespec times
[2];
2240 struct ceph_statx stx
;
2242 get_current_time_timespec(times
);
2245 EXPECT_EQ(0, ceph_futimens(cmount
, fd
, times
));
2246 ASSERT_EQ(ceph_statx(cmount
, test_file
, &stx
,
2247 CEPH_STATX_MTIME
|CEPH_STATX_ATIME
, 0), 0);
2248 ASSERT_EQ(utime_t(stx
.stx_atime
), utime_t(times
[0]));
2249 ASSERT_EQ(utime_t(stx
.stx_mtime
), utime_t(times
[1]));
2251 ceph_close(cmount
, fd
);
2252 ceph_shutdown(cmount
);
2255 TEST(LibCephFS
, OperationsOnDotDot
) {
2256 struct ceph_mount_info
*cmount
;
2257 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2258 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2259 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2260 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2262 char c_dir
[512], c_dir_dot
[1024], c_dir_dotdot
[1024];
2263 char c_non_existent_dir
[1024], c_non_existent_dirs
[1024];
2266 pid_t mypid
= getpid();
2267 sprintf(c_dir
, "/oodd_dir_%d", mypid
);
2268 sprintf(c_dir_dot
, "/%s/.", c_dir
);
2269 sprintf(c_dir_dotdot
, "/%s/..", c_dir
);
2270 sprintf(c_non_existent_dir
, "/%s/../oodd_nonexistent/..", c_dir
);
2271 sprintf(c_non_existent_dirs
,
2272 "/%s/../ood_nonexistent1_%d/oodd_nonexistent2_%d", c_dir
, mypid
, mypid
);
2273 sprintf(c_temp
, "/oodd_temp_%d", mypid
);
2275 ASSERT_EQ(0, ceph_mkdir(cmount
, c_dir
, 0777));
2276 ASSERT_EQ(-EEXIST
, ceph_mkdir(cmount
, c_dir_dot
, 0777));
2277 ASSERT_EQ(-EEXIST
, ceph_mkdir(cmount
, c_dir_dotdot
, 0777));
2278 ASSERT_EQ(0, ceph_mkdirs(cmount
, c_non_existent_dirs
, 0777));
2280 ASSERT_EQ(-ENOTEMPTY
, ceph_rmdir(cmount
, c_dir_dot
));
2281 ASSERT_EQ(-ENOTEMPTY
, ceph_rmdir(cmount
, c_dir_dotdot
));
2282 // non existent directory should return -ENOENT
2283 ASSERT_EQ(-ENOENT
, ceph_rmdir(cmount
, c_non_existent_dir
));
2285 ASSERT_EQ(-EBUSY
, ceph_rename(cmount
, c_dir_dot
, c_temp
));
2286 ASSERT_EQ(0, ceph_chdir(cmount
, c_dir
));
2287 ASSERT_EQ(0, ceph_mkdir(cmount
, c_temp
, 0777));
2288 ASSERT_EQ(-EBUSY
, ceph_rename(cmount
, c_temp
, ".."));
2290 ceph_shutdown(cmount
);
2293 TEST(LibCephFS
, Caps_vxattr
) {
2294 struct ceph_mount_info
*cmount
;
2295 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2296 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2297 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2298 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2300 char test_caps_vxattr_file
[256];
2302 int xbuflen
= sizeof(gxattrv
);
2303 pid_t mypid
= getpid();
2305 sprintf(test_caps_vxattr_file
, "test_caps_vxattr_%d", mypid
);
2306 int fd
= ceph_open(cmount
, test_caps_vxattr_file
, O_CREAT
, 0666);
2308 ceph_close(cmount
, fd
);
2310 int alen
= ceph_getxattr(cmount
, test_caps_vxattr_file
, "ceph.caps", (void *)gxattrv
, xbuflen
);
2312 gxattrv
[alen
] = '\0';
2314 char caps_regex
[] = "pA[sx]*L[sx]*X[sx]*F[sxcrwbal]*/0x[0-9a-fA-f]+";
2315 ASSERT_TRUE(regex_match(gxattrv
, regex(caps_regex
)) == 1);
2316 ceph_shutdown(cmount
);
2319 TEST(LibCephFS
, SnapXattrs
) {
2320 struct ceph_mount_info
*cmount
;
2321 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2322 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2323 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2324 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2326 char test_snap_xattr_file
[256];
2327 char c_temp
[PATH_MAX
];
2330 int xbuflen
= sizeof(gxattrv
);
2331 pid_t mypid
= getpid();
2333 sprintf(test_snap_xattr_file
, "test_snap_xattr_%d", mypid
);
2334 int fd
= ceph_open(cmount
, test_snap_xattr_file
, O_CREAT
, 0666);
2336 ceph_close(cmount
, fd
);
2338 sprintf(c_temp
, "/.snap/test_snap_xattr_snap_%d", mypid
);
2339 ASSERT_EQ(0, ceph_mkdir(cmount
, c_temp
, 0777));
2341 int alen
= ceph_getxattr(cmount
, c_temp
, "ceph.snap.btime", (void *)gxattrv
, xbuflen
);
2342 // xattr value is secs.nsecs (don't assume zero-term)
2344 ASSERT_LT(alen
, xbuflen
);
2345 gxattrv
[alen
] = '\0';
2346 char *s
= strchrnul(gxattrv
, '.');
2347 ASSERT_LT(s
, gxattrv
+ alen
);
2350 utime_t btime
= utime_t(strtoull(gxattrv
, NULL
, 10), strtoull(s
+ 1, NULL
, 10));
2351 *s
= '.'; // restore for later strcmp
2353 // file within the snapshot should carry the same btime
2354 sprintf(c_temp
, "/.snap/test_snap_xattr_snap_%d/%s", mypid
, test_snap_xattr_file
);
2356 int alen2
= ceph_getxattr(cmount
, c_temp
, "ceph.snap.btime", (void *)gxattrv2
, xbuflen
);
2357 ASSERT_EQ(alen
, alen2
);
2358 ASSERT_EQ(0, strncmp(gxattrv
, gxattrv2
, alen
));
2360 // non-snap file shouldn't carry the xattr
2361 alen
= ceph_getxattr(cmount
, test_snap_xattr_file
, "ceph.snap.btime", (void *)gxattrv2
, xbuflen
);
2362 ASSERT_EQ(-ENODATA
, alen
);
2364 // create a second snapshot
2365 sprintf(c_temp
, "/.snap/test_snap_xattr_snap2_%d", mypid
);
2366 ASSERT_EQ(0, ceph_mkdir(cmount
, c_temp
, 0777));
2368 // check that the btime for the newer snapshot is > older
2369 alen
= ceph_getxattr(cmount
, c_temp
, "ceph.snap.btime", (void *)gxattrv2
, xbuflen
);
2371 ASSERT_LT(alen
, xbuflen
);
2372 gxattrv2
[alen
] = '\0';
2373 s
= strchrnul(gxattrv2
, '.');
2374 ASSERT_LT(s
, gxattrv2
+ alen
);
2377 utime_t new_btime
= utime_t(strtoull(gxattrv2
, NULL
, 10), strtoull(s
+ 1, NULL
, 10));
2378 ASSERT_LT(btime
, new_btime
);
2380 // listxattr() shouldn't return snap.btime vxattr
2381 char xattrlist
[512];
2382 int len
= ceph_listxattr(cmount
, test_snap_xattr_file
, xattrlist
, sizeof(xattrlist
));
2383 ASSERT_GE(sizeof(xattrlist
), (size_t)len
);
2384 char *p
= xattrlist
;
2387 if (strcmp(p
, "ceph.snap.btime") == 0)
2389 len
-= strlen(p
) + 1;
2392 ASSERT_EQ(found
, 0);
2394 ceph_shutdown(cmount
);
2397 TEST(LibCephFS
, SnapQuota
) {
2398 struct ceph_mount_info
*cmount
;
2399 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2400 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2401 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2402 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2404 char test_snap_dir_quota_xattr
[256];
2405 char test_snap_subdir_quota_xattr
[256];
2406 char test_snap_subdir_noquota_xattr
[256];
2409 char c_temp
[PATH_MAX
];
2411 int xbuflen
= sizeof(gxattrv
);
2412 pid_t mypid
= getpid();
2414 // create dir and set quota
2415 sprintf(test_snap_dir_quota_xattr
, "test_snap_dir_quota_xattr_%d", mypid
);
2416 ASSERT_EQ(0, ceph_mkdir(cmount
, test_snap_dir_quota_xattr
, 0777));
2418 sprintf(xattrk
, "ceph.quota.max_bytes");
2419 sprintf(xattrv
, "65536");
2420 ASSERT_EQ(0, ceph_setxattr(cmount
, test_snap_dir_quota_xattr
, xattrk
, (void *)xattrv
, 5, XATTR_CREATE
));
2422 // create subdir and set quota
2423 sprintf(test_snap_subdir_quota_xattr
, "test_snap_dir_quota_xattr_%d/subdir_quota", mypid
);
2424 ASSERT_EQ(0, ceph_mkdirs(cmount
, test_snap_subdir_quota_xattr
, 0777));
2426 sprintf(xattrk
, "ceph.quota.max_bytes");
2427 sprintf(xattrv
, "32768");
2428 ASSERT_EQ(0, ceph_setxattr(cmount
, test_snap_subdir_quota_xattr
, xattrk
, (void *)xattrv
, 5, XATTR_CREATE
));
2430 // create subdir with no quota
2431 sprintf(test_snap_subdir_noquota_xattr
, "test_snap_dir_quota_xattr_%d/subdir_noquota", mypid
);
2432 ASSERT_EQ(0, ceph_mkdirs(cmount
, test_snap_subdir_noquota_xattr
, 0777));
2435 sprintf(c_temp
, "/.snap/test_snap_dir_quota_xattr_snap_%d", mypid
);
2436 ASSERT_EQ(0, ceph_mkdirs(cmount
, c_temp
, 0777));
2438 // check dir quota under snap
2439 sprintf(c_temp
, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d", mypid
, mypid
);
2440 int alen
= ceph_getxattr(cmount
, c_temp
, "ceph.quota.max_bytes", (void *)gxattrv
, xbuflen
);
2442 ASSERT_LT(alen
, xbuflen
);
2443 gxattrv
[alen
] = '\0';
2444 ASSERT_STREQ(gxattrv
, "65536");
2446 // check subdir quota under snap
2447 sprintf(c_temp
, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d/subdir_quota", mypid
, mypid
);
2448 alen
= ceph_getxattr(cmount
, c_temp
, "ceph.quota.max_bytes", (void *)gxattrv
, xbuflen
);
2450 ASSERT_LT(alen
, xbuflen
);
2451 gxattrv
[alen
] = '\0';
2452 ASSERT_STREQ(gxattrv
, "32768");
2454 // ensure subdir noquota xattr under snap
2455 sprintf(c_temp
, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d/subdir_noquota", mypid
, mypid
);
2456 EXPECT_EQ(-ENODATA
, ceph_getxattr(cmount
, c_temp
, "ceph.quota.max_bytes", (void *)gxattrv
, xbuflen
));
2458 // listxattr() shouldn't return ceph.quota.max_bytes vxattr
2459 sprintf(c_temp
, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d", mypid
, mypid
);
2460 char xattrlist
[512];
2461 int len
= ceph_listxattr(cmount
, c_temp
, xattrlist
, sizeof(xattrlist
));
2462 ASSERT_GE(sizeof(xattrlist
), (size_t)len
);
2463 char *p
= xattrlist
;
2466 if (strcmp(p
, "ceph.quota.max_bytes") == 0)
2468 len
-= strlen(p
) + 1;
2471 ASSERT_EQ(found
, 0);
2473 ceph_shutdown(cmount
);
2476 TEST(LibCephFS
, Lseek
) {
2477 struct ceph_mount_info
*cmount
;
2478 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
2479 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
2480 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2481 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
2484 sprintf(c_path
, "test_lseek_%d", getpid());
2485 int fd
= ceph_open(cmount
, c_path
, O_RDWR
|O_CREAT
|O_TRUNC
, 0666);
2488 const char *out_buf
= "hello world";
2489 size_t size
= strlen(out_buf
);
2490 ASSERT_EQ(ceph_write(cmount
, fd
, out_buf
, size
, 0), (int)size
);
2492 /* basic SEEK_SET/END/CUR tests */
2493 ASSERT_EQ(0, ceph_lseek(cmount
, fd
, 0, SEEK_SET
));
2494 ASSERT_EQ(size
, ceph_lseek(cmount
, fd
, 0, SEEK_END
));
2495 ASSERT_EQ(0, ceph_lseek(cmount
, fd
, -size
, SEEK_CUR
));
2497 /* Test basic functionality and out of bounds conditions for SEEK_HOLE/DATA */
2499 ASSERT_EQ(size
, ceph_lseek(cmount
, fd
, 0, SEEK_HOLE
));
2500 ASSERT_EQ(-ENXIO
, ceph_lseek(cmount
, fd
, -1, SEEK_HOLE
));
2501 ASSERT_EQ(-ENXIO
, ceph_lseek(cmount
, fd
, size
+ 1, SEEK_HOLE
));
2504 ASSERT_EQ(0, ceph_lseek(cmount
, fd
, 0, SEEK_DATA
));
2505 ASSERT_EQ(-ENXIO
, ceph_lseek(cmount
, fd
, -1, SEEK_DATA
));
2506 ASSERT_EQ(-ENXIO
, ceph_lseek(cmount
, fd
, size
+ 1, SEEK_DATA
));
2509 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2510 ceph_shutdown(cmount
);
2513 TEST(LibCephFS
, SnapInfoOnNonSnapshot
) {
2514 struct ceph_mount_info
*cmount
;
2515 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2516 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2517 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2518 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2520 struct snap_info info
;
2521 ASSERT_EQ(-EINVAL
, ceph_get_snap_info(cmount
, "/", &info
));
2523 ceph_shutdown(cmount
);
2526 TEST(LibCephFS
, EmptySnapInfo
) {
2527 struct ceph_mount_info
*cmount
;
2528 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2529 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2530 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2531 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2534 char snap_path
[PATH_MAX
];
2535 sprintf(dir_path
, "/dir0_%d", getpid());
2536 sprintf(snap_path
, "%s/.snap/snap0_%d", dir_path
, getpid());
2538 ASSERT_EQ(0, ceph_mkdir(cmount
, dir_path
, 0755));
2539 // snapshot without custom metadata
2540 ASSERT_EQ(0, ceph_mkdir(cmount
, snap_path
, 0755));
2542 struct snap_info info
;
2543 ASSERT_EQ(0, ceph_get_snap_info(cmount
, snap_path
, &info
));
2544 ASSERT_GT(info
.id
, 0);
2545 ASSERT_EQ(info
.nr_snap_metadata
, 0);
2547 ASSERT_EQ(0, ceph_rmdir(cmount
, snap_path
));
2548 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
2549 ceph_shutdown(cmount
);
2552 TEST(LibCephFS
, SnapInfo
) {
2553 struct ceph_mount_info
*cmount
;
2554 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2555 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2556 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2557 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2561 char snap_path
[PATH_MAX
];
2562 sprintf(dir_path
, "/dir0_%d", getpid());
2563 sprintf(snap_name
, "snap0_%d", getpid());
2564 sprintf(snap_path
, "%s/.snap/%s", dir_path
, snap_name
);
2566 ASSERT_EQ(0, ceph_mkdir(cmount
, dir_path
, 0755));
2567 // snapshot with custom metadata
2568 struct snap_metadata snap_meta
[] = {{"foo", "bar"},{"this", "that"},{"abcdefg", "12345"}};
2569 ASSERT_EQ(0, ceph_mksnap(cmount
, dir_path
, snap_name
, 0755, snap_meta
, std::size(snap_meta
)));
2571 struct snap_info info
;
2572 ASSERT_EQ(0, ceph_get_snap_info(cmount
, snap_path
, &info
));
2573 ASSERT_GT(info
.id
, 0);
2574 ASSERT_EQ(info
.nr_snap_metadata
, std::size(snap_meta
));
2575 for (size_t i
= 0; i
< info
.nr_snap_metadata
; ++i
) {
2576 auto &k1
= info
.snap_metadata
[i
].key
;
2577 auto &v1
= info
.snap_metadata
[i
].value
;
2579 for (size_t j
= 0; j
< info
.nr_snap_metadata
; ++j
) {
2580 auto &k2
= snap_meta
[j
].key
;
2581 auto &v2
= snap_meta
[j
].value
;
2582 if (strncmp(k1
, k2
, strlen(k1
)) == 0 && strncmp(v1
, v2
, strlen(v1
)) == 0) {
2589 ceph_free_snap_info_buffer(&info
);
2591 ASSERT_EQ(0, ceph_rmsnap(cmount
, dir_path
, snap_name
));
2592 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
2594 ceph_shutdown(cmount
);
2597 TEST(LibCephFS
, LookupInoMDSDir
) {
2598 struct ceph_mount_info
*cmount
;
2599 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2600 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2601 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2602 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2605 auto ino
= inodeno_t(0x100); /* rank 0 ~mdsdir */
2606 ASSERT_EQ(-ESTALE
, ceph_ll_lookup_inode(cmount
, ino
, &inode
));
2607 ino
= inodeno_t(0x600); /* rank 0 first stray dir */
2608 ASSERT_EQ(-ESTALE
, ceph_ll_lookup_inode(cmount
, ino
, &inode
));
2610 ceph_shutdown(cmount
);
2613 TEST(LibCephFS
, LookupVino
) {
2614 struct ceph_mount_info
*cmount
;
2615 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2616 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2617 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2618 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2622 char snapdir_path
[128];
2623 char snap_path
[256];
2624 char file_path
[PATH_MAX
];
2625 char snap_file
[PATH_MAX
];
2626 sprintf(dir_path
, "/dir0_%d", getpid());
2627 sprintf(snap_name
, "snap0_%d", getpid());
2628 sprintf(file_path
, "%s/file_%d", dir_path
, getpid());
2629 sprintf(snapdir_path
, "%s/.snap", dir_path
);
2630 sprintf(snap_path
, "%s/%s", snapdir_path
, snap_name
);
2631 sprintf(snap_file
, "%s/file_%d", snap_path
, getpid());
2633 ASSERT_EQ(0, ceph_mkdir(cmount
, dir_path
, 0755));
2634 int fd
= ceph_open(cmount
, file_path
, O_WRONLY
|O_CREAT
, 0666);
2636 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2637 ASSERT_EQ(0, ceph_mksnap(cmount
, dir_path
, snap_name
, 0755, nullptr, 0));
2639 // record vinos for all of them
2640 struct ceph_statx stx
;
2641 ASSERT_EQ(0, ceph_statx(cmount
, dir_path
, &stx
, CEPH_STATX_INO
, 0));
2642 vinodeno_t
dir_vino(stx
.stx_ino
, stx
.stx_dev
);
2644 ASSERT_EQ(0, ceph_statx(cmount
, file_path
, &stx
, CEPH_STATX_INO
, 0));
2645 vinodeno_t
file_vino(stx
.stx_ino
, stx
.stx_dev
);
2647 ASSERT_EQ(0, ceph_statx(cmount
, snapdir_path
, &stx
, CEPH_STATX_INO
, 0));
2648 vinodeno_t
snapdir_vino(stx
.stx_ino
, stx
.stx_dev
);
2650 ASSERT_EQ(0, ceph_statx(cmount
, snap_path
, &stx
, CEPH_STATX_INO
, 0));
2651 vinodeno_t
snap_vino(stx
.stx_ino
, stx
.stx_dev
);
2653 ASSERT_EQ(0, ceph_statx(cmount
, snap_file
, &stx
, CEPH_STATX_INO
, 0));
2654 vinodeno_t
snap_file_vino(stx
.stx_ino
, stx
.stx_dev
);
2657 ASSERT_EQ(0, ceph_unmount(cmount
));
2658 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
2659 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
2660 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2661 ASSERT_EQ(0, ceph_mount(cmount
, NULL
));
2665 ASSERT_EQ(0, ceph_ll_lookup_vino(cmount
, dir_vino
, &inode
));
2666 ceph_ll_put(cmount
, inode
);
2667 ASSERT_EQ(0, ceph_ll_lookup_vino(cmount
, file_vino
, &inode
));
2668 ceph_ll_put(cmount
, inode
);
2669 ASSERT_EQ(0, ceph_ll_lookup_vino(cmount
, snapdir_vino
, &inode
));
2670 ceph_ll_put(cmount
, inode
);
2671 ASSERT_EQ(0, ceph_ll_lookup_vino(cmount
, snap_vino
, &inode
));
2672 ceph_ll_put(cmount
, inode
);
2673 ASSERT_EQ(0, ceph_ll_lookup_vino(cmount
, snap_file_vino
, &inode
));
2674 ceph_ll_put(cmount
, inode
);
2677 ASSERT_EQ(0, ceph_rmsnap(cmount
, dir_path
, snap_name
));
2678 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
2679 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
2681 ceph_shutdown(cmount
);
2684 TEST(LibCephFS
, Openat
) {
2685 pid_t mypid
= getpid();
2686 struct ceph_mount_info
*cmount
;
2687 ASSERT_EQ(0, ceph_create(&cmount
, NULL
));
2688 ASSERT_EQ(0, ceph_conf_read_file(cmount
, NULL
));
2689 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2690 ASSERT_EQ(0, ceph_mount(cmount
, "/"));
2694 sprintf(c_rel_dir
, "open_test_%d", mypid
);
2695 sprintf(c_dir
, "/%s", c_rel_dir
);
2696 ASSERT_EQ(0, ceph_mkdir(cmount
, c_dir
, 0777));
2698 int root_fd
= ceph_open(cmount
, "/", O_DIRECTORY
| O_RDONLY
, 0);
2699 ASSERT_LE(0, root_fd
);
2701 int dir_fd
= ceph_openat(cmount
, root_fd
, c_rel_dir
, O_DIRECTORY
| O_RDONLY
, 0);
2702 ASSERT_LE(0, dir_fd
);
2704 struct ceph_statx stx
;
2705 ASSERT_EQ(ceph_statxat(cmount
, root_fd
, c_rel_dir
, &stx
, 0, 0), 0);
2706 ASSERT_EQ(stx
.stx_mode
& S_IFMT
, S_IFDIR
);
2708 char c_rel_path
[64];
2710 sprintf(c_rel_path
, "created_file_%d", mypid
);
2711 sprintf(c_path
, "%s/created_file_%d", c_dir
, mypid
);
2712 int file_fd
= ceph_openat(cmount
, dir_fd
, c_rel_path
, O_RDONLY
| O_CREAT
, 0666);
2713 ASSERT_LE(0, file_fd
);
2715 ASSERT_EQ(ceph_statxat(cmount
, dir_fd
, c_rel_path
, &stx
, 0, 0), 0);
2716 ASSERT_EQ(stx
.stx_mode
& S_IFMT
, S_IFREG
);
2718 ASSERT_EQ(0, ceph_close(cmount
, file_fd
));
2719 ASSERT_EQ(0, ceph_close(cmount
, dir_fd
));
2720 ASSERT_EQ(0, ceph_close(cmount
, root_fd
));
2722 ASSERT_EQ(0, ceph_unlink(cmount
, c_path
));
2723 ASSERT_EQ(0, ceph_rmdir(cmount
, c_dir
));
2725 ceph_shutdown(cmount
);
2728 TEST(LibCephFS
, Statxat
) {
2729 struct ceph_mount_info
*cmount
;
2730 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2731 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2732 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2733 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2736 char rel_file_name_1
[128];
2737 char rel_file_name_2
[256];
2740 char file_path
[1024];
2742 // relative paths for *at() calls
2743 sprintf(dir_name
, "dir0_%d", getpid());
2744 sprintf(rel_file_name_1
, "file_%d", getpid());
2745 sprintf(rel_file_name_2
, "%s/%s", dir_name
, rel_file_name_1
);
2747 sprintf(dir_path
, "/%s", dir_name
);
2748 sprintf(file_path
, "%s/%s", dir_path
, rel_file_name_1
);
2750 ASSERT_EQ(0, ceph_mkdir(cmount
, dir_path
, 0755));
2751 int fd
= ceph_open(cmount
, file_path
, O_WRONLY
|O_CREAT
, 0666);
2753 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2755 struct ceph_statx stx
;
2757 // test relative to root
2758 fd
= ceph_open(cmount
, "/", O_DIRECTORY
| O_RDONLY
, 0);
2760 ASSERT_EQ(ceph_statxat(cmount
, fd
, dir_name
, &stx
, 0, 0), 0);
2761 ASSERT_EQ(stx
.stx_mode
& S_IFMT
, S_IFDIR
);
2762 ASSERT_EQ(ceph_statxat(cmount
, fd
, rel_file_name_2
, &stx
, 0, 0), 0);
2763 ASSERT_EQ(stx
.stx_mode
& S_IFMT
, S_IFREG
);
2764 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2766 // test relative to dir
2767 fd
= ceph_open(cmount
, dir_path
, O_DIRECTORY
| O_RDONLY
, 0);
2769 ASSERT_EQ(ceph_statxat(cmount
, fd
, rel_file_name_1
, &stx
, 0, 0), 0);
2770 ASSERT_EQ(stx
.stx_mode
& S_IFMT
, S_IFREG
);
2772 // delete the dirtree, recreate and verify
2773 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
2774 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
2775 ASSERT_EQ(0, ceph_mkdir(cmount
, dir_path
, 0755));
2776 int fd1
= ceph_open(cmount
, file_path
, O_WRONLY
|O_CREAT
, 0666);
2778 ASSERT_EQ(0, ceph_close(cmount
, fd1
));
2779 ASSERT_EQ(ceph_statxat(cmount
, fd
, rel_file_name_1
, &stx
, 0, 0), -ENOENT
);
2780 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2782 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
2783 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
2785 ceph_shutdown(cmount
);
2788 TEST(LibCephFS
, StatxatATFDCWD
) {
2789 struct ceph_mount_info
*cmount
;
2790 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2791 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2792 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2793 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
2796 char rel_file_name_1
[128];
2799 char file_path
[1024];
2801 // relative paths for *at() calls
2802 sprintf(dir_name
, "dir0_%d", getpid());
2803 sprintf(rel_file_name_1
, "file_%d", getpid());
2805 sprintf(dir_path
, "/%s", dir_name
);
2806 sprintf(file_path
, "%s/%s", dir_path
, rel_file_name_1
);
2808 ASSERT_EQ(0, ceph_mkdir(cmount
, dir_path
, 0755));
2809 int fd
= ceph_open(cmount
, file_path
, O_WRONLY
|O_CREAT
, 0666);
2811 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2813 struct ceph_statx stx
;
2814 // chdir and test with CEPHFS_AT_FDCWD
2815 ASSERT_EQ(0, ceph_chdir(cmount
, dir_path
));
2816 ASSERT_EQ(ceph_statxat(cmount
, CEPHFS_AT_FDCWD
, rel_file_name_1
, &stx
, 0, 0), 0);
2817 ASSERT_EQ(stx
.stx_mode
& S_IFMT
, S_IFREG
);
2819 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
2820 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
2822 ceph_shutdown(cmount
);
2825 TEST(LibCephFS
, Fdopendir
) {
2826 pid_t mypid
= getpid();
2828 struct ceph_mount_info
*cmount
;
2829 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2830 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2831 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2832 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
2835 sprintf(foostr
, "/dir_ls%d", mypid
);
2836 ASSERT_EQ(ceph_mkdir(cmount
, foostr
, 0777), 0);
2839 sprintf(bazstr
, "%s/elif", foostr
);
2840 int fd
= ceph_open(cmount
, bazstr
, O_CREAT
|O_RDONLY
, 0666);
2842 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2844 fd
= ceph_open(cmount
, foostr
, O_DIRECTORY
| O_RDONLY
, 0);
2846 struct ceph_dir_result
*ls_dir
= NULL
;
2847 ASSERT_EQ(ceph_fdopendir(cmount
, fd
, &ls_dir
), 0);
2849 // not guaranteed to get . and .. first, but its a safe assumption in this case
2850 struct dirent
*result
= ceph_readdir(cmount
, ls_dir
);
2851 ASSERT_TRUE(result
!= NULL
);
2852 ASSERT_STREQ(result
->d_name
, ".");
2853 result
= ceph_readdir(cmount
, ls_dir
);
2854 ASSERT_TRUE(result
!= NULL
);
2855 ASSERT_STREQ(result
->d_name
, "..");
2856 result
= ceph_readdir(cmount
, ls_dir
);
2857 ASSERT_TRUE(result
!= NULL
);
2858 ASSERT_STREQ(result
->d_name
, "elif");
2860 ASSERT_TRUE(ceph_readdir(cmount
, ls_dir
) == NULL
);
2862 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2863 ASSERT_EQ(0, ceph_closedir(cmount
, ls_dir
));
2864 ASSERT_EQ(0, ceph_unlink(cmount
, bazstr
));
2865 ASSERT_EQ(0, ceph_rmdir(cmount
, foostr
));
2866 ceph_shutdown(cmount
);
2869 TEST(LibCephFS
, FdopendirATFDCWD
) {
2870 pid_t mypid
= getpid();
2872 struct ceph_mount_info
*cmount
;
2873 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2874 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2875 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2876 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
2879 sprintf(foostr
, "/dir_ls%d", mypid
);
2880 ASSERT_EQ(ceph_mkdir(cmount
, foostr
, 0777), 0);
2883 sprintf(bazstr
, "%s/elif", foostr
);
2884 int fd
= ceph_open(cmount
, bazstr
, O_CREAT
|O_RDONLY
, 0666);
2886 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2888 ASSERT_EQ(0, ceph_chdir(cmount
, foostr
));
2889 struct ceph_dir_result
*ls_dir
= NULL
;
2890 ASSERT_EQ(ceph_fdopendir(cmount
, CEPHFS_AT_FDCWD
, &ls_dir
), 0);
2892 // not guaranteed to get . and .. first, but its a safe assumption in this case
2893 struct dirent
*result
= ceph_readdir(cmount
, ls_dir
);
2894 ASSERT_TRUE(result
!= NULL
);
2895 ASSERT_STREQ(result
->d_name
, ".");
2896 result
= ceph_readdir(cmount
, ls_dir
);
2897 ASSERT_TRUE(result
!= NULL
);
2898 ASSERT_STREQ(result
->d_name
, "..");
2899 result
= ceph_readdir(cmount
, ls_dir
);
2900 ASSERT_TRUE(result
!= NULL
);
2901 ASSERT_STREQ(result
->d_name
, "elif");
2903 ASSERT_TRUE(ceph_readdir(cmount
, ls_dir
) == NULL
);
2905 ASSERT_EQ(0, ceph_closedir(cmount
, ls_dir
));
2906 ASSERT_EQ(0, ceph_unlink(cmount
, bazstr
));
2907 ASSERT_EQ(0, ceph_rmdir(cmount
, foostr
));
2908 ceph_shutdown(cmount
);
2911 TEST(LibCephFS
, FdopendirReaddirTestWithDelete
) {
2912 pid_t mypid
= getpid();
2914 struct ceph_mount_info
*cmount
;
2915 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2916 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2917 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2918 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
2921 sprintf(foostr
, "/dir_ls%d", mypid
);
2922 ASSERT_EQ(ceph_mkdir(cmount
, foostr
, 0777), 0);
2925 sprintf(bazstr
, "%s/elif", foostr
);
2926 int fd
= ceph_open(cmount
, bazstr
, O_CREAT
|O_RDONLY
, 0666);
2928 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2930 fd
= ceph_open(cmount
, foostr
, O_DIRECTORY
| O_RDONLY
, 0);
2932 struct ceph_dir_result
*ls_dir
= NULL
;
2933 ASSERT_EQ(ceph_fdopendir(cmount
, fd
, &ls_dir
), 0);
2935 ASSERT_EQ(0, ceph_unlink(cmount
, bazstr
));
2936 ASSERT_EQ(0, ceph_rmdir(cmount
, foostr
));
2938 // not guaranteed to get . and .. first, but its a safe assumption
2939 // in this case. also, note that we may or may not get other
2941 struct dirent
*result
= ceph_readdir(cmount
, ls_dir
);
2942 ASSERT_TRUE(result
!= NULL
);
2943 ASSERT_STREQ(result
->d_name
, ".");
2944 result
= ceph_readdir(cmount
, ls_dir
);
2945 ASSERT_TRUE(result
!= NULL
);
2946 ASSERT_STREQ(result
->d_name
, "..");
2948 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2949 ASSERT_EQ(0, ceph_closedir(cmount
, ls_dir
));
2950 ceph_shutdown(cmount
);
2953 TEST(LibCephFS
, FdopendirOnNonDir
) {
2954 pid_t mypid
= getpid();
2956 struct ceph_mount_info
*cmount
;
2957 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2958 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2959 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2960 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
2963 sprintf(foostr
, "/dir_ls%d", mypid
);
2964 ASSERT_EQ(ceph_mkdir(cmount
, foostr
, 0777), 0);
2967 sprintf(bazstr
, "%s/file", foostr
);
2968 int fd
= ceph_open(cmount
, bazstr
, O_CREAT
|O_RDONLY
, 0666);
2971 struct ceph_dir_result
*ls_dir
= NULL
;
2972 ASSERT_EQ(ceph_fdopendir(cmount
, fd
, &ls_dir
), -ENOTDIR
);
2973 ASSERT_EQ(0, ceph_close(cmount
, fd
));
2975 ASSERT_EQ(0, ceph_unlink(cmount
, bazstr
));
2976 ASSERT_EQ(0, ceph_rmdir(cmount
, foostr
));
2978 ceph_shutdown(cmount
);
2981 TEST(LibCephFS
, Mkdirat
) {
2982 pid_t mypid
= getpid();
2984 struct ceph_mount_info
*cmount
;
2985 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
2986 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
2987 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
2988 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
2991 char dir_path1
[256];
2992 sprintf(dir_name
, "dir_%d", mypid
);
2993 sprintf(dir_path1
, "/%s", dir_name
);
2995 char dir_path2
[512];
2996 char rel_dir_path2
[512];
2997 sprintf(dir_path2
, "%s/dir_%d", dir_path1
, mypid
);
2998 sprintf(rel_dir_path2
, "%s/dir_%d", dir_name
, mypid
);
3000 int fd
= ceph_open(cmount
, "/", O_DIRECTORY
| O_RDONLY
, 0);
3003 ASSERT_EQ(0, ceph_mkdirat(cmount
, fd
, dir_name
, 0777));
3004 ASSERT_EQ(0, ceph_mkdirat(cmount
, fd
, rel_dir_path2
, 0666));
3006 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3007 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path2
));
3008 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path1
));
3009 ceph_shutdown(cmount
);
3012 TEST(LibCephFS
, MkdiratATFDCWD
) {
3013 pid_t mypid
= getpid();
3015 struct ceph_mount_info
*cmount
;
3016 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3017 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3018 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3019 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
3022 char dir_path1
[256];
3023 sprintf(dir_name
, "dir_%d", mypid
);
3024 sprintf(dir_path1
, "/%s", dir_name
);
3026 char dir_path2
[512];
3027 sprintf(dir_path2
, "%s/dir_%d", dir_path1
, mypid
);
3029 ASSERT_EQ(0, ceph_mkdirat(cmount
, CEPHFS_AT_FDCWD
, dir_name
, 0777));
3031 ASSERT_EQ(0, ceph_chdir(cmount
, dir_path1
));
3032 ASSERT_EQ(0, ceph_mkdirat(cmount
, CEPHFS_AT_FDCWD
, dir_name
, 0666));
3034 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path2
));
3035 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path1
));
3036 ceph_shutdown(cmount
);
3039 TEST(LibCephFS
, Readlinkat
) {
3040 pid_t mypid
= getpid();
3042 struct ceph_mount_info
*cmount
;
3043 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3044 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3045 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3046 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
3050 sprintf(dir_name
, "dir_%d", mypid
);
3051 sprintf(dir_path
, "/%s", dir_name
);
3052 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3054 char file_path
[512];
3055 char rel_file_path
[512];
3056 sprintf(rel_file_path
, "%s/elif", dir_name
);
3057 sprintf(file_path
, "%s/elif", dir_path
);
3058 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDONLY
, 0666);
3060 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3062 char link_path
[128];
3063 char rel_link_path
[64];
3064 sprintf(rel_link_path
, "linkfile_%d", mypid
);
3065 sprintf(link_path
, "/%s", rel_link_path
);
3066 ASSERT_EQ(0, ceph_symlink(cmount
, rel_file_path
, link_path
));
3068 fd
= ceph_open(cmount
, "/", O_DIRECTORY
| O_RDONLY
, 0);
3070 size_t target_len
= strlen(rel_file_path
);
3071 char target
[target_len
+1];
3072 ASSERT_EQ(target_len
, ceph_readlinkat(cmount
, fd
, rel_link_path
, target
, target_len
));
3073 target
[target_len
] = '\0';
3074 ASSERT_EQ(0, memcmp(target
, rel_file_path
, target_len
));
3076 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3077 ASSERT_EQ(0, ceph_unlink(cmount
, link_path
));
3078 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
3079 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
3080 ceph_shutdown(cmount
);
3083 TEST(LibCephFS
, ReadlinkatATFDCWD
) {
3084 pid_t mypid
= getpid();
3086 struct ceph_mount_info
*cmount
;
3087 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3088 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3089 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3090 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
3094 sprintf(dir_name
, "dir_%d", mypid
);
3095 sprintf(dir_path
, "/%s", dir_name
);
3096 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3098 char file_path
[512];
3099 char rel_file_path
[512] = "./elif";
3100 sprintf(file_path
, "%s/elif", dir_path
);
3101 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDONLY
, 0666);
3103 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3105 char link_path
[PATH_MAX
];
3106 char rel_link_path
[1024];
3107 sprintf(rel_link_path
, "./linkfile_%d", mypid
);
3108 sprintf(link_path
, "%s/%s", dir_path
, rel_link_path
);
3109 ASSERT_EQ(0, ceph_symlink(cmount
, rel_file_path
, link_path
));
3111 ASSERT_EQ(0, ceph_chdir(cmount
, dir_path
));
3112 size_t target_len
= strlen(rel_file_path
);
3113 char target
[target_len
+1];
3114 ASSERT_EQ(target_len
, ceph_readlinkat(cmount
, CEPHFS_AT_FDCWD
, rel_link_path
, target
, target_len
));
3115 target
[target_len
] = '\0';
3116 ASSERT_EQ(0, memcmp(target
, rel_file_path
, target_len
));
3118 ASSERT_EQ(0, ceph_unlink(cmount
, link_path
));
3119 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
3120 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
3121 ceph_shutdown(cmount
);
3124 TEST(LibCephFS
, Symlinkat
) {
3125 pid_t mypid
= getpid();
3127 struct ceph_mount_info
*cmount
;
3128 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3129 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3130 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3131 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
3135 sprintf(dir_name
, "dir_%d", mypid
);
3136 sprintf(dir_path
, "/%s", dir_name
);
3137 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3139 char file_path
[512];
3140 char rel_file_path
[512];
3141 sprintf(rel_file_path
, "%s/elif", dir_name
);
3142 sprintf(file_path
, "%s/elif", dir_path
);
3144 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDONLY
, 0666);
3146 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3148 char link_path
[128];
3149 char rel_link_path
[64];
3150 sprintf(rel_link_path
, "linkfile_%d", mypid
);
3151 sprintf(link_path
, "/%s", rel_link_path
);
3153 fd
= ceph_open(cmount
, "/", O_DIRECTORY
| O_RDONLY
, 0);
3155 ASSERT_EQ(0, ceph_symlinkat(cmount
, rel_file_path
, fd
, rel_link_path
));
3157 size_t target_len
= strlen(rel_file_path
);
3158 char target
[target_len
+1];
3159 ASSERT_EQ(target_len
, ceph_readlinkat(cmount
, fd
, rel_link_path
, target
, target_len
));
3160 target
[target_len
] = '\0';
3161 ASSERT_EQ(0, memcmp(target
, rel_file_path
, target_len
));
3163 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3164 ASSERT_EQ(0, ceph_unlink(cmount
, link_path
));
3165 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
3166 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
3167 ceph_shutdown(cmount
);
3170 TEST(LibCephFS
, SymlinkatATFDCWD
) {
3171 pid_t mypid
= getpid();
3173 struct ceph_mount_info
*cmount
;
3174 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3175 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3176 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3177 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
3181 sprintf(dir_name
, "dir_%d", mypid
);
3182 sprintf(dir_path
, "/%s", dir_name
);
3183 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3185 char file_path
[512];
3186 char rel_file_path
[512] = "./elif";
3187 sprintf(file_path
, "%s/elif", dir_path
);
3188 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDONLY
, 0666);
3190 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3192 char link_path
[PATH_MAX
];
3193 char rel_link_path
[1024];
3194 sprintf(rel_link_path
, "./linkfile_%d", mypid
);
3195 sprintf(link_path
, "%s/%s", dir_path
, rel_link_path
);
3196 ASSERT_EQ(0, ceph_chdir(cmount
, dir_path
));
3197 ASSERT_EQ(0, ceph_symlinkat(cmount
, rel_file_path
, CEPHFS_AT_FDCWD
, rel_link_path
));
3199 size_t target_len
= strlen(rel_file_path
);
3200 char target
[target_len
+1];
3201 ASSERT_EQ(target_len
, ceph_readlinkat(cmount
, CEPHFS_AT_FDCWD
, rel_link_path
, target
, target_len
));
3202 target
[target_len
] = '\0';
3203 ASSERT_EQ(0, memcmp(target
, rel_file_path
, target_len
));
3205 ASSERT_EQ(0, ceph_unlink(cmount
, link_path
));
3206 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
3207 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
3208 ceph_shutdown(cmount
);
3211 TEST(LibCephFS
, Unlinkat
) {
3212 pid_t mypid
= getpid();
3214 struct ceph_mount_info
*cmount
;
3215 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3216 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3217 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3218 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
3222 sprintf(dir_name
, "dir_%d", mypid
);
3223 sprintf(dir_path
, "/%s", dir_name
);
3224 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3226 char file_path
[512];
3227 char rel_file_path
[512] = "elif";
3228 sprintf(file_path
, "%s/elif", dir_path
);
3230 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDONLY
, 0666);
3232 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3234 fd
= ceph_open(cmount
, dir_path
, O_DIRECTORY
| O_RDONLY
, 0);
3236 ASSERT_EQ(-ENOTDIR
, ceph_unlinkat(cmount
, fd
, rel_file_path
, AT_REMOVEDIR
));
3237 ASSERT_EQ(0, ceph_unlinkat(cmount
, fd
, rel_file_path
, 0));
3238 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3240 fd
= ceph_open(cmount
, "/", O_DIRECTORY
| O_RDONLY
, 0);
3241 ASSERT_EQ(-EISDIR
, ceph_unlinkat(cmount
, fd
, dir_name
, 0));
3242 ASSERT_EQ(0, ceph_unlinkat(cmount
, fd
, dir_name
, AT_REMOVEDIR
));
3245 ceph_shutdown(cmount
);
3248 TEST(LibCephFS
, UnlinkatATFDCWD
) {
3249 pid_t mypid
= getpid();
3251 struct ceph_mount_info
*cmount
;
3252 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3253 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3254 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3255 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
3259 sprintf(dir_name
, "dir_%d", mypid
);
3260 sprintf(dir_path
, "/%s", dir_name
);
3261 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3263 char file_path
[512];
3264 char rel_file_path
[512] = "elif";
3265 sprintf(file_path
, "%s/elif", dir_path
);
3267 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDONLY
, 0666);
3269 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3271 ASSERT_EQ(0, ceph_chdir(cmount
, dir_path
));
3272 ASSERT_EQ(-ENOTDIR
, ceph_unlinkat(cmount
, CEPHFS_AT_FDCWD
, rel_file_path
, AT_REMOVEDIR
));
3273 ASSERT_EQ(0, ceph_unlinkat(cmount
, CEPHFS_AT_FDCWD
, rel_file_path
, 0));
3275 ASSERT_EQ(0, ceph_chdir(cmount
, "/"));
3276 ASSERT_EQ(-EISDIR
, ceph_unlinkat(cmount
, CEPHFS_AT_FDCWD
, dir_name
, 0));
3277 ASSERT_EQ(0, ceph_unlinkat(cmount
, CEPHFS_AT_FDCWD
, dir_name
, AT_REMOVEDIR
));
3279 ceph_shutdown(cmount
);
3282 TEST(LibCephFS
, Chownat
) {
3283 pid_t mypid
= getpid();
3285 struct ceph_mount_info
*cmount
;
3286 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3287 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3288 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3289 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
3293 sprintf(dir_name
, "dir_%d", mypid
);
3294 sprintf(dir_path
, "/%s", dir_name
);
3295 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3297 char file_path
[512];
3298 char rel_file_path
[512] = "elif";
3299 sprintf(file_path
, "%s/elif", dir_path
);
3300 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDWR
, 0666);
3303 // set perms to readable and writeable only by owner
3304 ASSERT_EQ(ceph_fchmod(cmount
, fd
, 0600), 0);
3305 ceph_close(cmount
, fd
);
3307 fd
= ceph_open(cmount
, dir_path
, O_DIRECTORY
| O_RDONLY
, 0);
3308 // change ownership to nobody -- we assume nobody exists and id is always 65534
3309 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "0"), 0);
3310 ASSERT_EQ(ceph_chownat(cmount
, fd
, rel_file_path
, 65534, 65534, 0), 0);
3311 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "1"), 0);
3312 ceph_close(cmount
, fd
);
3314 fd
= ceph_open(cmount
, file_path
, O_RDWR
, 0);
3315 ASSERT_EQ(fd
, -EACCES
);
3317 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "0"), 0);
3318 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
3319 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "1"), 0);
3320 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
3321 ceph_shutdown(cmount
);
3324 TEST(LibCephFS
, ChownatATFDCWD
) {
3325 pid_t mypid
= getpid();
3327 struct ceph_mount_info
*cmount
;
3328 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3329 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3330 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3331 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
3335 sprintf(dir_name
, "dir_%d", mypid
);
3336 sprintf(dir_path
, "/%s", dir_name
);
3337 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3339 char file_path
[512];
3340 char rel_file_path
[512] = "elif";
3341 sprintf(file_path
, "%s/elif", dir_path
);
3342 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDWR
, 0666);
3345 // set perms to readable and writeable only by owner
3346 ASSERT_EQ(ceph_fchmod(cmount
, fd
, 0600), 0);
3347 ceph_close(cmount
, fd
);
3349 ASSERT_EQ(0, ceph_chdir(cmount
, dir_path
));
3350 // change ownership to nobody -- we assume nobody exists and id is always 65534
3351 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "0"), 0);
3352 ASSERT_EQ(ceph_chownat(cmount
, CEPHFS_AT_FDCWD
, rel_file_path
, 65534, 65534, 0), 0);
3353 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "1"), 0);
3355 fd
= ceph_open(cmount
, file_path
, O_RDWR
, 0);
3356 ASSERT_EQ(fd
, -EACCES
);
3358 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "0"), 0);
3359 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
3360 ASSERT_EQ(ceph_conf_set(cmount
, "client_permissions", "1"), 0);
3361 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
3362 ceph_shutdown(cmount
);
3365 TEST(LibCephFS
, Chmodat
) {
3366 pid_t mypid
= getpid();
3368 struct ceph_mount_info
*cmount
;
3369 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3370 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3371 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3372 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
3376 sprintf(dir_name
, "dir_%d", mypid
);
3377 sprintf(dir_path
, "/%s", dir_name
);
3378 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3380 char file_path
[512];
3381 char rel_file_path
[512] = "elif";
3382 sprintf(file_path
, "%s/elif", dir_path
);
3383 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDWR
, 0666);
3385 const char *bytes
= "foobarbaz";
3386 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
3387 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3389 fd
= ceph_open(cmount
, dir_path
, O_DIRECTORY
| O_RDONLY
, 0);
3391 // set perms to read but can't write
3392 ASSERT_EQ(ceph_chmodat(cmount
, fd
, rel_file_path
, 0400, 0), 0);
3393 ASSERT_EQ(ceph_open(cmount
, file_path
, O_RDWR
, 0), -EACCES
);
3395 // reset back to writeable
3396 ASSERT_EQ(ceph_chmodat(cmount
, fd
, rel_file_path
, 0600, 0), 0);
3397 int fd2
= ceph_open(cmount
, file_path
, O_RDWR
, 0);
3400 ASSERT_EQ(0, ceph_close(cmount
, fd2
));
3401 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3403 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
3404 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
3405 ceph_shutdown(cmount
);
3408 TEST(LibCephFS
, ChmodatATFDCWD
) {
3409 pid_t mypid
= getpid();
3411 struct ceph_mount_info
*cmount
;
3412 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3413 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3414 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3415 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
3419 sprintf(dir_name
, "dir_%d", mypid
);
3420 sprintf(dir_path
, "/%s", dir_name
);
3421 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3423 char file_path
[512];
3424 char rel_file_path
[512] = "elif";
3425 sprintf(file_path
, "%s/elif", dir_path
);
3426 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDWR
, 0666);
3428 const char *bytes
= "foobarbaz";
3429 ASSERT_EQ(ceph_write(cmount
, fd
, bytes
, strlen(bytes
), 0), (int)strlen(bytes
));
3430 ASSERT_EQ(0, ceph_close(cmount
, fd
));
3432 // set perms to read but can't write
3433 ASSERT_EQ(0, ceph_chdir(cmount
, dir_path
));
3434 ASSERT_EQ(ceph_chmodat(cmount
, CEPHFS_AT_FDCWD
, rel_file_path
, 0400, 0), 0);
3435 ASSERT_EQ(ceph_open(cmount
, file_path
, O_RDWR
, 0), -EACCES
);
3437 // reset back to writeable
3438 ASSERT_EQ(ceph_chmodat(cmount
, CEPHFS_AT_FDCWD
, rel_file_path
, 0600, 0), 0);
3439 int fd2
= ceph_open(cmount
, file_path
, O_RDWR
, 0);
3441 ASSERT_EQ(0, ceph_close(cmount
, fd2
));
3443 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
3444 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
3445 ceph_shutdown(cmount
);
3448 TEST(LibCephFS
, Utimensat
) {
3449 pid_t mypid
= getpid();
3451 struct ceph_mount_info
*cmount
;
3452 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3453 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3454 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3455 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
3459 sprintf(dir_name
, "dir_%d", mypid
);
3460 sprintf(dir_path
, "/%s", dir_name
);
3461 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3463 char file_path
[512];
3464 char rel_file_path
[512] = "elif";
3465 sprintf(file_path
, "%s/elif", dir_path
);
3466 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDWR
, 0666);
3469 struct timespec times
[2];
3470 get_current_time_timespec(times
);
3472 fd
= ceph_open(cmount
, dir_path
, O_DIRECTORY
| O_RDONLY
, 0);
3474 EXPECT_EQ(0, ceph_utimensat(cmount
, fd
, rel_file_path
, times
, 0));
3475 ceph_close(cmount
, fd
);
3477 struct ceph_statx stx
;
3478 ASSERT_EQ(ceph_statx(cmount
, file_path
, &stx
,
3479 CEPH_STATX_MTIME
|CEPH_STATX_ATIME
, 0), 0);
3480 ASSERT_EQ(utime_t(stx
.stx_atime
), utime_t(times
[0]));
3481 ASSERT_EQ(utime_t(stx
.stx_mtime
), utime_t(times
[1]));
3483 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
3484 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
3485 ceph_shutdown(cmount
);
3488 TEST(LibCephFS
, UtimensatATFDCWD
) {
3489 pid_t mypid
= getpid();
3491 struct ceph_mount_info
*cmount
;
3492 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3493 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3494 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3495 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
3499 sprintf(dir_name
, "dir_%d", mypid
);
3500 sprintf(dir_path
, "/%s", dir_name
);
3501 ASSERT_EQ(ceph_mkdir(cmount
, dir_path
, 0777), 0);
3503 char file_path
[512];
3504 char rel_file_path
[512] = "elif";
3505 sprintf(file_path
, "%s/elif", dir_path
);
3506 int fd
= ceph_open(cmount
, file_path
, O_CREAT
|O_RDWR
, 0666);
3509 struct timespec times
[2];
3510 get_current_time_timespec(times
);
3512 ASSERT_EQ(0, ceph_chdir(cmount
, dir_path
));
3513 EXPECT_EQ(0, ceph_utimensat(cmount
, CEPHFS_AT_FDCWD
, rel_file_path
, times
, 0));
3515 struct ceph_statx stx
;
3516 ASSERT_EQ(ceph_statx(cmount
, file_path
, &stx
,
3517 CEPH_STATX_MTIME
|CEPH_STATX_ATIME
, 0), 0);
3518 ASSERT_EQ(utime_t(stx
.stx_atime
), utime_t(times
[0]));
3519 ASSERT_EQ(utime_t(stx
.stx_mtime
), utime_t(times
[1]));
3521 ASSERT_EQ(0, ceph_unlink(cmount
, file_path
));
3522 ASSERT_EQ(0, ceph_rmdir(cmount
, dir_path
));
3523 ceph_shutdown(cmount
);
3526 TEST(LibCephFS
, LookupMdsPrivateInos
) {
3527 struct ceph_mount_info
*cmount
;
3528 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3529 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3530 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3531 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
3534 for (int ino
= 0; ino
< MDS_INO_SYSTEM_BASE
; ino
++) {
3535 if (MDS_IS_PRIVATE_INO(ino
)) {
3536 ASSERT_EQ(-ESTALE
, ceph_ll_lookup_inode(cmount
, ino
, &inode
));
3537 } else if (ino
== CEPH_INO_ROOT
|| ino
== CEPH_INO_GLOBAL_SNAPREALM
) {
3538 ASSERT_EQ(0, ceph_ll_lookup_inode(cmount
, ino
, &inode
));
3539 ceph_ll_put(cmount
, inode
);
3540 } else if (ino
== CEPH_INO_LOST_AND_FOUND
) {
3541 // the ino 3 will only exists after the recovery tool ran, so
3542 // it may return -ESTALE with a fresh fs cluster
3543 int r
= ceph_ll_lookup_inode(cmount
, ino
, &inode
);
3545 ceph_ll_put(cmount
, inode
);
3547 ASSERT_TRUE(r
== -ESTALE
);
3550 // currently the ino 0 and 4~99 is not useded yet.
3551 ASSERT_EQ(-ESTALE
, ceph_ll_lookup_inode(cmount
, ino
, &inode
));
3555 ceph_shutdown(cmount
);
3558 TEST(LibCephFS
, SetMountTimeoutPostMount
) {
3559 struct ceph_mount_info
*cmount
;
3560 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3561 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3562 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3563 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
3565 ASSERT_EQ(-EINVAL
, ceph_set_mount_timeout(cmount
, 5));
3566 ceph_shutdown(cmount
);
3569 TEST(LibCephFS
, SetMountTimeout
) {
3570 struct ceph_mount_info
*cmount
;
3571 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
3572 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
3573 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
3574 ASSERT_EQ(0, ceph_set_mount_timeout(cmount
, 5));
3575 ASSERT_EQ(ceph_mount(cmount
, NULL
), 0);
3577 ceph_shutdown(cmount
);