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