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