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