]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/libcephfs/test.cc
585fae104dea452f3572331e66bb77f9b8f8ebff
[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 "include/compat.h"
16 #include "gtest/gtest.h"
17 #include "include/cephfs/libcephfs.h"
18 #include "mds/mdstypes.h"
19 #include "include/stat.h"
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <dirent.h>
26 #include <sys/uio.h>
27 #include <sys/time.h>
28 #include <sys/resource.h>
29
30 #include "common/Clock.h"
31
32 #ifdef __linux__
33 #include <limits.h>
34 #include <sys/xattr.h>
35 #endif
36
37 #include <fmt/format.h>
38 #include <map>
39 #include <vector>
40 #include <thread>
41 #include <regex>
42
43 #ifndef ALLPERMS
44 #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
45 #endif
46
47 using namespace std;
48
49 TEST(LibCephFS, OpenEmptyComponent) {
50
51 pid_t mypid = getpid();
52 struct ceph_mount_info *cmount;
53 ASSERT_EQ(0, ceph_create(&cmount, NULL));
54 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
55 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
56 ASSERT_EQ(0, ceph_mount(cmount, "/"));
57
58 char c_dir[1024];
59 sprintf(c_dir, "/open_test_%d", mypid);
60 struct ceph_dir_result *dirp;
61
62 ASSERT_EQ(0, ceph_mkdirs(cmount, c_dir, 0777));
63
64 ASSERT_EQ(0, ceph_opendir(cmount, c_dir, &dirp));
65
66 char c_path[1024];
67 sprintf(c_path, "/open_test_%d//created_file_%d", mypid, mypid);
68 int fd = ceph_open(cmount, c_path, O_RDONLY|O_CREAT, 0666);
69 ASSERT_LT(0, fd);
70
71 ASSERT_EQ(0, ceph_close(cmount, fd));
72 ASSERT_EQ(0, ceph_closedir(cmount, dirp));
73 ceph_shutdown(cmount);
74
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
79 ASSERT_EQ(0, ceph_mount(cmount, "/"));
80
81 fd = ceph_open(cmount, c_path, O_RDONLY, 0666);
82 ASSERT_LT(0, fd);
83 ASSERT_EQ(0, ceph_close(cmount, fd));
84
85 // cleanup
86 ASSERT_EQ(0, ceph_unlink(cmount, c_path));
87 ASSERT_EQ(0, ceph_rmdir(cmount, c_dir));
88
89 ceph_shutdown(cmount);
90 }
91
92 TEST(LibCephFS, OpenReadTruncate) {
93 struct ceph_mount_info *cmount;
94 ASSERT_EQ(0, ceph_create(&cmount, NULL));
95 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
96 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
97 ASSERT_EQ(0, ceph_mount(cmount, "/"));
98
99 auto path = fmt::format("test_open_rdt_{}", getpid());
100 int fd = ceph_open(cmount, path.c_str(), O_WRONLY|O_CREAT, 0666);
101 ASSERT_LE(0, fd);
102
103 auto data = std::string("hello world");
104 ASSERT_EQ(ceph_write(cmount, fd, data.c_str(), data.size(), 0), (int)data.size());
105 ASSERT_EQ(0, ceph_close(cmount, fd));
106
107 fd = ceph_open(cmount, path.c_str(), O_RDONLY, 0);
108 ASSERT_LE(0, fd);
109 ASSERT_EQ(ceph_ftruncate(cmount, fd, 0), -EBADF);
110 ASSERT_EQ(ceph_ftruncate(cmount, fd, 1), -EBADF);
111 ASSERT_EQ(0, ceph_close(cmount, fd));
112
113 ceph_shutdown(cmount);
114 }
115
116 TEST(LibCephFS, OpenReadWrite) {
117 struct ceph_mount_info *cmount;
118 ASSERT_EQ(0, ceph_create(&cmount, NULL));
119 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
120 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
121 ASSERT_EQ(0, ceph_mount(cmount, "/"));
122
123 char c_path[1024];
124 sprintf(c_path, "test_open_rdwr_%d", getpid());
125 int fd = ceph_open(cmount, c_path, O_WRONLY|O_CREAT, 0666);
126 ASSERT_LT(0, fd);
127
128 const char *out_buf = "hello world";
129 size_t size = strlen(out_buf);
130 char in_buf[100];
131 ASSERT_EQ(ceph_write(cmount, fd, out_buf, size, 0), (int)size);
132 ASSERT_EQ(ceph_read(cmount, fd, in_buf, sizeof(in_buf), 0), -EBADF);
133 ASSERT_EQ(0, ceph_close(cmount, fd));
134
135 fd = ceph_open(cmount, c_path, O_RDONLY, 0);
136 ASSERT_LT(0, fd);
137 ASSERT_EQ(ceph_write(cmount, fd, out_buf, size, 0), -EBADF);
138 ASSERT_EQ(ceph_read(cmount, fd, in_buf, sizeof(in_buf), 0), (int)size);
139 ASSERT_EQ(0, ceph_close(cmount, fd));
140
141 fd = ceph_open(cmount, c_path, O_RDWR, 0);
142 ASSERT_LT(0, fd);
143 ASSERT_EQ(ceph_write(cmount, fd, out_buf, size, 0), (int)size);
144 ASSERT_EQ(ceph_read(cmount, fd, in_buf, sizeof(in_buf), 0), (int)size);
145 ASSERT_EQ(0, ceph_close(cmount, fd));
146
147 ceph_shutdown(cmount);
148 }
149
150 TEST(LibCephFS, MountNonExist) {
151
152 struct ceph_mount_info *cmount;
153
154 ASSERT_EQ(0, ceph_create(&cmount, NULL));
155 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
156 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
157 ASSERT_NE(0, ceph_mount(cmount, "/non-exist"));
158 ceph_shutdown(cmount);
159 }
160
161 TEST(LibCephFS, MountDouble) {
162
163 struct ceph_mount_info *cmount;
164
165 ASSERT_EQ(0, ceph_create(&cmount, NULL));
166 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
167 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
168 ASSERT_EQ(0, ceph_mount(cmount, "/"));
169 ASSERT_EQ(-EISCONN, ceph_mount(cmount, "/"));
170 ceph_shutdown(cmount);
171 }
172
173 TEST(LibCephFS, MountRemount) {
174
175 struct ceph_mount_info *cmount;
176
177 ASSERT_EQ(0, ceph_create(&cmount, NULL));
178 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
179 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
180
181 CephContext *cct = ceph_get_mount_context(cmount);
182 ASSERT_EQ(0, ceph_mount(cmount, "/"));
183 ASSERT_EQ(0, ceph_unmount(cmount));
184
185 ASSERT_EQ(0, ceph_mount(cmount, "/"));
186 ASSERT_EQ(cct, ceph_get_mount_context(cmount));
187
188 ceph_shutdown(cmount);
189 }
190
191 TEST(LibCephFS, UnmountUnmounted) {
192
193 struct ceph_mount_info *cmount;
194
195 ASSERT_EQ(0, ceph_create(&cmount, NULL));
196 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
197 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
198 ASSERT_EQ(-ENOTCONN, ceph_unmount(cmount));
199 ceph_shutdown(cmount);
200 }
201
202 TEST(LibCephFS, ReleaseUnmounted) {
203
204 struct ceph_mount_info *cmount;
205
206 ASSERT_EQ(0, ceph_create(&cmount, NULL));
207 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
208 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
209 ASSERT_EQ(0, ceph_release(cmount));
210 }
211
212 TEST(LibCephFS, ReleaseMounted) {
213
214 struct ceph_mount_info *cmount;
215
216 ASSERT_EQ(0, ceph_create(&cmount, NULL));
217 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
218 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
219 ASSERT_EQ(0, ceph_mount(cmount, "/"));
220 ASSERT_EQ(-EISCONN, ceph_release(cmount));
221 ASSERT_EQ(0, ceph_unmount(cmount));
222 ASSERT_EQ(0, ceph_release(cmount));
223 }
224
225 TEST(LibCephFS, UnmountRelease) {
226
227 struct ceph_mount_info *cmount;
228
229 ASSERT_EQ(0, ceph_create(&cmount, NULL));
230 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
231 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
232 ASSERT_EQ(0, ceph_mount(cmount, "/"));
233 ASSERT_EQ(0, ceph_unmount(cmount));
234 ASSERT_EQ(0, ceph_release(cmount));
235 }
236
237 TEST(LibCephFS, Mount) {
238 struct ceph_mount_info *cmount;
239 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
240 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
241 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
242 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
243 ceph_shutdown(cmount);
244
245 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
246 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
247 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
248 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
249 ceph_shutdown(cmount);
250 }
251
252 TEST(LibCephFS, OpenLayout) {
253 struct ceph_mount_info *cmount;
254 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
255 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
256 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
257 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
258
259 /* valid layout */
260 char test_layout_file[256];
261 sprintf(test_layout_file, "test_layout_%d_b", getpid());
262 int fd = ceph_open_layout(cmount, test_layout_file, O_CREAT|O_WRONLY, 0666, (1<<20), 7, (1<<20), NULL);
263 ASSERT_GT(fd, 0);
264 char poolname[80];
265 ASSERT_LT(0, ceph_get_file_pool_name(cmount, fd, poolname, sizeof(poolname)));
266 ASSERT_LT(0, ceph_get_file_pool_name(cmount, fd, poolname, 0));
267
268 /* on already-written file (ENOTEMPTY) */
269 ceph_write(cmount, fd, "hello world", 11, 0);
270 ceph_close(cmount, fd);
271
272 char xattrk[128];
273 char xattrv[128];
274 sprintf(xattrk, "ceph.file.layout.stripe_unit");
275 sprintf(xattrv, "65536");
276 ASSERT_EQ(-ENOTEMPTY, ceph_setxattr(cmount, test_layout_file, xattrk, (void *)xattrv, 5, 0));
277
278 /* invalid layout */
279 sprintf(test_layout_file, "test_layout_%d_c", getpid());
280 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 1, 19, NULL);
281 ASSERT_EQ(fd, -EINVAL);
282
283 /* with data pool */
284 sprintf(test_layout_file, "test_layout_%d_d", getpid());
285 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 7, (1<<20), poolname);
286 ASSERT_GT(fd, 0);
287 ceph_close(cmount, fd);
288
289 /* with metadata pool (invalid) */
290 sprintf(test_layout_file, "test_layout_%d_e", getpid());
291 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 7, (1<<20), "metadata");
292 ASSERT_EQ(fd, -EINVAL);
293
294 /* with metadata pool (does not exist) */
295 sprintf(test_layout_file, "test_layout_%d_f", getpid());
296 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 7, (1<<20), "asdfjasdfjasdf");
297 ASSERT_EQ(fd, -EINVAL);
298
299 ceph_shutdown(cmount);
300 }
301
302 TEST(LibCephFS, DirLs) {
303
304 pid_t mypid = getpid();
305
306 struct ceph_mount_info *cmount;
307 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
308 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
309 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
310 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
311
312 struct ceph_dir_result *ls_dir = NULL;
313 char foostr[256];
314 sprintf(foostr, "dir_ls%d", mypid);
315 ASSERT_EQ(ceph_opendir(cmount, foostr, &ls_dir), -ENOENT);
316
317 ASSERT_EQ(ceph_mkdir(cmount, foostr, 0777), 0);
318 struct ceph_statx stx;
319 ASSERT_EQ(ceph_statx(cmount, foostr, &stx, 0, 0), 0);
320 ASSERT_NE(S_ISDIR(stx.stx_mode), 0);
321
322 char barstr[256];
323 sprintf(barstr, "dir_ls2%d", mypid);
324 ASSERT_EQ(ceph_statx(cmount, barstr, &stx, 0, AT_SYMLINK_NOFOLLOW), -ENOENT);
325
326 // insert files into directory and test open
327 char bazstr[256];
328 int i = 0, r = rand() % 4096;
329 if (getenv("LIBCEPHFS_RAND")) {
330 r = atoi(getenv("LIBCEPHFS_RAND"));
331 }
332 printf("rand: %d\n", r);
333 for(; i < r; ++i) {
334
335 sprintf(bazstr, "dir_ls%d/dirf%d", mypid, i);
336 int fd = ceph_open(cmount, bazstr, O_CREAT|O_RDONLY, 0666);
337 ASSERT_GT(fd, 0);
338 ASSERT_EQ(ceph_close(cmount, fd), 0);
339
340 // set file sizes for readdirplus
341 ceph_truncate(cmount, bazstr, i);
342 }
343
344 ASSERT_EQ(ceph_opendir(cmount, foostr, &ls_dir), 0);
345
346 // not guaranteed to get . and .. first, but its a safe assumption in this case
347 struct dirent *result = ceph_readdir(cmount, ls_dir);
348 ASSERT_TRUE(result != NULL);
349 ASSERT_STREQ(result->d_name, ".");
350 result = ceph_readdir(cmount, ls_dir);
351 ASSERT_TRUE(result != NULL);
352 ASSERT_STREQ(result->d_name, "..");
353
354 std::vector<std::string> entries;
355 std::map<std::string, int64_t> offset_map;
356 int64_t offset = ceph_telldir(cmount, ls_dir);
357 for(i = 0; i < r; ++i) {
358 result = ceph_readdir(cmount, ls_dir);
359 ASSERT_TRUE(result != NULL);
360 entries.push_back(result->d_name);
361 offset_map[result->d_name] = offset;
362 offset = ceph_telldir(cmount, ls_dir);
363 }
364
365 ASSERT_TRUE(ceph_readdir(cmount, ls_dir) == NULL);
366 offset = ceph_telldir(cmount, ls_dir);
367
368 ASSERT_EQ(offset_map.size(), entries.size());
369 for(i = 0; i < r; ++i) {
370 sprintf(bazstr, "dirf%d", i);
371 ASSERT_TRUE(offset_map.count(bazstr) == 1);
372 }
373
374 // test seekdir
375 ceph_seekdir(cmount, ls_dir, offset);
376 ASSERT_TRUE(ceph_readdir(cmount, ls_dir) == NULL);
377
378 for (auto p = offset_map.begin(); p != offset_map.end(); ++p) {
379 ceph_seekdir(cmount, ls_dir, p->second);
380 result = ceph_readdir(cmount, ls_dir);
381 ASSERT_TRUE(result != NULL);
382 std::string d_name(result->d_name);
383 ASSERT_EQ(p->first, d_name);
384 }
385
386 // test rewinddir
387 ceph_rewinddir(cmount, ls_dir);
388
389 result = ceph_readdir(cmount, ls_dir);
390 ASSERT_TRUE(result != NULL);
391 ASSERT_STREQ(result->d_name, ".");
392 result = ceph_readdir(cmount, ls_dir);
393 ASSERT_TRUE(result != NULL);
394 ASSERT_STREQ(result->d_name, "..");
395
396 ceph_rewinddir(cmount, ls_dir);
397
398 int t = ceph_telldir(cmount, ls_dir);
399 ASSERT_GT(t, -1);
400
401 ASSERT_TRUE(ceph_readdir(cmount, ls_dir) != NULL);
402
403 // test seekdir - move back to the beginning
404 ceph_seekdir(cmount, ls_dir, t);
405
406 // test getdents
407 struct dirent *getdents_entries;
408 size_t getdents_entries_len = (r + 2) * sizeof(*getdents_entries);
409 getdents_entries = (struct dirent *)malloc(getdents_entries_len);
410
411 int count = 0;
412 std::vector<std::string> found;
413 while (true) {
414 int len = ceph_getdents(cmount, ls_dir, (char *)getdents_entries, getdents_entries_len);
415 if (len == 0)
416 break;
417 ASSERT_GT(len, 0);
418 ASSERT_TRUE((len % sizeof(*getdents_entries)) == 0);
419 int n = len / sizeof(*getdents_entries);
420 int j;
421 if (count == 0) {
422 ASSERT_STREQ(getdents_entries[0].d_name, ".");
423 ASSERT_STREQ(getdents_entries[1].d_name, "..");
424 j = 2;
425 } else {
426 j = 0;
427 }
428 count += n;
429 for(; j < n; ++i, ++j) {
430 const char *name = getdents_entries[j].d_name;
431 found.push_back(name);
432 }
433 }
434 ASSERT_EQ(found, entries);
435 free(getdents_entries);
436
437 // test readdir_r
438 ceph_rewinddir(cmount, ls_dir);
439
440 result = ceph_readdir(cmount, ls_dir);
441 ASSERT_TRUE(result != NULL);
442 ASSERT_STREQ(result->d_name, ".");
443 result = ceph_readdir(cmount, ls_dir);
444 ASSERT_TRUE(result != NULL);
445 ASSERT_STREQ(result->d_name, "..");
446
447 found.clear();
448 while (true) {
449 struct dirent rdent;
450 int len = ceph_readdir_r(cmount, ls_dir, &rdent);
451 if (len == 0)
452 break;
453 ASSERT_EQ(len, 1);
454 found.push_back(rdent.d_name);
455 }
456 ASSERT_EQ(found, entries);
457
458 // test readdirplus
459 ceph_rewinddir(cmount, ls_dir);
460
461 result = ceph_readdir(cmount, ls_dir);
462 ASSERT_TRUE(result != NULL);
463 ASSERT_STREQ(result->d_name, ".");
464 result = ceph_readdir(cmount, ls_dir);
465 ASSERT_TRUE(result != NULL);
466 ASSERT_STREQ(result->d_name, "..");
467
468 found.clear();
469 while (true) {
470 struct dirent rdent;
471 struct ceph_statx stx;
472 int len = ceph_readdirplus_r(cmount, ls_dir, &rdent, &stx,
473 CEPH_STATX_SIZE, AT_STATX_DONT_SYNC, NULL);
474 if (len == 0)
475 break;
476 ASSERT_EQ(len, 1);
477 const char *name = rdent.d_name;
478 found.push_back(name);
479 int size;
480 sscanf(name, "dirf%d", &size);
481 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_SIZE);
482 ASSERT_EQ(stx.stx_size, (size_t)size);
483 ASSERT_EQ(stx.stx_ino, rdent.d_ino);
484 //ASSERT_EQ(st.st_mode, (mode_t)0666);
485 }
486 ASSERT_EQ(found, entries);
487
488 ASSERT_EQ(ceph_closedir(cmount, ls_dir), 0);
489
490 // cleanup
491 for(i = 0; i < r; ++i) {
492 sprintf(bazstr, "dir_ls%d/dirf%d", mypid, i);
493 ASSERT_EQ(0, ceph_unlink(cmount, bazstr));
494 }
495 ASSERT_EQ(0, ceph_rmdir(cmount, foostr));
496
497 ceph_shutdown(cmount);
498 }
499
500 TEST(LibCephFS, ManyNestedDirs) {
501 struct ceph_mount_info *cmount;
502 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
503 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
504 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
505 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
506
507 const char *many_path = "a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a";
508 ASSERT_EQ(ceph_mkdirs(cmount, many_path, 0755), 0);
509
510 int i = 0;
511
512 for(; i < 39; ++i) {
513 ASSERT_EQ(ceph_chdir(cmount, "a"), 0);
514
515 struct ceph_dir_result *dirp;
516 ASSERT_EQ(ceph_opendir(cmount, "a", &dirp), 0);
517 struct dirent *dent = ceph_readdir(cmount, dirp);
518 ASSERT_TRUE(dent != NULL);
519 ASSERT_STREQ(dent->d_name, ".");
520 dent = ceph_readdir(cmount, dirp);
521 ASSERT_TRUE(dent != NULL);
522 ASSERT_STREQ(dent->d_name, "..");
523 dent = ceph_readdir(cmount, dirp);
524 ASSERT_TRUE(dent != NULL);
525 ASSERT_STREQ(dent->d_name, "a");
526 ASSERT_EQ(ceph_closedir(cmount, dirp), 0);
527 }
528
529 ASSERT_STREQ(ceph_getcwd(cmount), "/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a");
530
531 ASSERT_EQ(ceph_chdir(cmount, "a/a/a"), 0);
532
533 for(i = 0; i < 39; ++i) {
534 ASSERT_EQ(ceph_chdir(cmount, ".."), 0);
535 ASSERT_EQ(ceph_rmdir(cmount, "a"), 0);
536 }
537
538 ASSERT_EQ(ceph_chdir(cmount, "/"), 0);
539
540 ASSERT_EQ(ceph_rmdir(cmount, "a/a/a"), 0);
541
542 ceph_shutdown(cmount);
543 }
544
545 TEST(LibCephFS, Xattrs) {
546 struct ceph_mount_info *cmount;
547 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
548 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
549 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
550 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
551
552 char test_xattr_file[256];
553 sprintf(test_xattr_file, "test_xattr_%d", getpid());
554 int fd = ceph_open(cmount, test_xattr_file, O_CREAT, 0666);
555 ASSERT_GT(fd, 0);
556
557 // test removing non-existent xattr
558 ASSERT_EQ(-ENODATA, ceph_removexattr(cmount, test_xattr_file, "user.nosuchxattr"));
559
560 char i = 'a';
561 char xattrk[128];
562 char xattrv[128];
563 for(; i < 'a'+26; ++i) {
564 sprintf(xattrk, "user.test_xattr_%c", i);
565 int len = sprintf(xattrv, "testxattr%c", i);
566 ASSERT_EQ(ceph_setxattr(cmount, test_xattr_file, xattrk, (void *) xattrv, len, XATTR_CREATE), 0);
567 }
568
569 // zero size should return required buffer length
570 int len_needed = ceph_listxattr(cmount, test_xattr_file, NULL, 0);
571 ASSERT_GT(len_needed, 0);
572
573 // buffer size smaller than needed should fail
574 char xattrlist[128*26];
575 ASSERT_GT(sizeof(xattrlist), (size_t)len_needed);
576 int len = ceph_listxattr(cmount, test_xattr_file, xattrlist, len_needed - 1);
577 ASSERT_EQ(-ERANGE, len);
578
579 len = ceph_listxattr(cmount, test_xattr_file, xattrlist, sizeof(xattrlist));
580 ASSERT_EQ(len, len_needed);
581 char *p = xattrlist;
582 char *n;
583 i = 'a';
584 while (len > 0) {
585 // ceph.* xattrs should not be listed
586 ASSERT_NE(strncmp(p, "ceph.", 5), 0);
587
588 sprintf(xattrk, "user.test_xattr_%c", i);
589 ASSERT_STREQ(p, xattrk);
590
591 char gxattrv[128];
592 std::cout << "getting attr " << p << std::endl;
593 int alen = ceph_getxattr(cmount, test_xattr_file, p, (void *) gxattrv, 128);
594 ASSERT_GT(alen, 0);
595 sprintf(xattrv, "testxattr%c", i);
596 ASSERT_TRUE(!strncmp(xattrv, gxattrv, alen));
597
598 n = index(p, '\0');
599 n++;
600 len -= (n - p);
601 p = n;
602 ++i;
603 }
604
605 i = 'a';
606 for(i = 'a'; i < 'a'+26; ++i) {
607 sprintf(xattrk, "user.test_xattr_%c", i);
608 ASSERT_EQ(ceph_removexattr(cmount, test_xattr_file, xattrk), 0);
609 }
610
611 ceph_close(cmount, fd);
612 ceph_shutdown(cmount);
613
614 }
615
616 TEST(LibCephFS, Xattrs_ll) {
617 struct ceph_mount_info *cmount;
618 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
619 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
620 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
621 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
622
623 char test_xattr_file[256];
624 sprintf(test_xattr_file, "test_xattr_%d", getpid());
625 int fd = ceph_open(cmount, test_xattr_file, O_CREAT, 0666);
626 ASSERT_GT(fd, 0);
627 ceph_close(cmount, fd);
628
629 Inode *root = NULL;
630 Inode *existent_file_handle = NULL;
631
632 int res = ceph_ll_lookup_root(cmount, &root);
633 ASSERT_EQ(res, 0);
634
635 UserPerm *perms = ceph_mount_perms(cmount);
636 struct ceph_statx stx;
637
638 res = ceph_ll_lookup(cmount, root, test_xattr_file, &existent_file_handle,
639 &stx, 0, 0, perms);
640 ASSERT_EQ(res, 0);
641
642 const char *valid_name = "user.attrname";
643 const char *value = "attrvalue";
644 char value_buf[256] = { 0 };
645
646 res = ceph_ll_setxattr(cmount, existent_file_handle, valid_name, value, strlen(value), 0, perms);
647 ASSERT_EQ(res, 0);
648
649 res = ceph_ll_getxattr(cmount, existent_file_handle, valid_name, value_buf, 256, perms);
650 ASSERT_EQ(res, (int)strlen(value));
651
652 value_buf[res] = '\0';
653 ASSERT_STREQ(value_buf, value);
654
655 ceph_shutdown(cmount);
656 }
657
658 TEST(LibCephFS, LstatSlashdot) {
659 struct ceph_mount_info *cmount;
660 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
661 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
662 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
663 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
664
665 struct ceph_statx stx;
666 ASSERT_EQ(ceph_statx(cmount, "/.", &stx, 0, AT_SYMLINK_NOFOLLOW), 0);
667 ASSERT_EQ(ceph_statx(cmount, ".", &stx, 0, AT_SYMLINK_NOFOLLOW), 0);
668
669 ceph_shutdown(cmount);
670 }
671
672 TEST(LibCephFS, StatDirNlink) {
673 struct ceph_mount_info *cmount;
674 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
675 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
676 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
677 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
678
679 char test_dir1[256];
680 sprintf(test_dir1, "dir1_symlinks_%d", getpid());
681 ASSERT_EQ(ceph_mkdir(cmount, test_dir1, 0700), 0);
682
683 int fd = ceph_open(cmount, test_dir1, O_DIRECTORY|O_RDONLY, 0);
684 ASSERT_GT(fd, 0);
685 struct ceph_statx stx;
686 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
687 ASSERT_EQ(stx.stx_nlink, 2u);
688
689 {
690 char test_dir2[296];
691 sprintf(test_dir2, "%s/.", test_dir1);
692 ASSERT_EQ(ceph_statx(cmount, test_dir2, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
693 ASSERT_EQ(stx.stx_nlink, 2u);
694 }
695
696 {
697 char test_dir2[296];
698 sprintf(test_dir2, "%s/1", test_dir1);
699 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0700), 0);
700 ASSERT_EQ(ceph_statx(cmount, test_dir2, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
701 ASSERT_EQ(stx.stx_nlink, 2u);
702 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
703 ASSERT_EQ(stx.stx_nlink, 3u);
704 sprintf(test_dir2, "%s/2", test_dir1);
705 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0700), 0);
706 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
707 ASSERT_EQ(stx.stx_nlink, 4u);
708 sprintf(test_dir2, "%s/1/1", test_dir1);
709 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0700), 0);
710 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
711 ASSERT_EQ(stx.stx_nlink, 4u);
712 ASSERT_EQ(ceph_rmdir(cmount, test_dir2), 0);
713 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
714 ASSERT_EQ(stx.stx_nlink, 4u);
715 sprintf(test_dir2, "%s/1", test_dir1);
716 ASSERT_EQ(ceph_rmdir(cmount, test_dir2), 0);
717 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
718 ASSERT_EQ(stx.stx_nlink, 3u);
719 sprintf(test_dir2, "%s/2", test_dir1);
720 ASSERT_EQ(ceph_rmdir(cmount, test_dir2), 0);
721 ASSERT_EQ(ceph_statx(cmount, test_dir1, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
722 ASSERT_EQ(stx.stx_nlink, 2u);
723 }
724
725 ASSERT_EQ(ceph_rmdir(cmount, test_dir1), 0);
726 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_NLINK, AT_SYMLINK_NOFOLLOW), 0);
727 ASSERT_EQ(stx.stx_nlink, 0u);
728
729 ceph_close(cmount, fd);
730
731 ceph_shutdown(cmount);
732 }
733
734 TEST(LibCephFS, DoubleChmod) {
735
736 struct ceph_mount_info *cmount;
737 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
738 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
739 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
740 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
741
742 char test_file[256];
743 sprintf(test_file, "test_perms_%d", getpid());
744
745 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
746 ASSERT_GT(fd, 0);
747
748 // write some stuff
749 const char *bytes = "foobarbaz";
750 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
751
752 ceph_close(cmount, fd);
753
754 // set perms to read but can't write
755 ASSERT_EQ(ceph_chmod(cmount, test_file, 0400), 0);
756
757 fd = ceph_open(cmount, test_file, O_RDWR, 0);
758 ASSERT_EQ(fd, -EACCES);
759
760 fd = ceph_open(cmount, test_file, O_RDONLY, 0);
761 ASSERT_GT(fd, -1);
762
763 char buf[100];
764 int ret = ceph_read(cmount, fd, buf, 100, 0);
765 ASSERT_EQ(ret, (int)strlen(bytes));
766 buf[ret] = '\0';
767 ASSERT_STREQ(buf, bytes);
768
769 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), -EBADF);
770
771 ceph_close(cmount, fd);
772
773 // reset back to writeable
774 ASSERT_EQ(ceph_chmod(cmount, test_file, 0600), 0);
775
776 // ensure perms are correct
777 struct ceph_statx stx;
778 ASSERT_EQ(ceph_statx(cmount, test_file, &stx, CEPH_STATX_MODE, AT_SYMLINK_NOFOLLOW), 0);
779 ASSERT_EQ(stx.stx_mode, 0100600U);
780
781 fd = ceph_open(cmount, test_file, O_RDWR, 0);
782 ASSERT_GT(fd, 0);
783
784 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
785 ceph_close(cmount, fd);
786
787 ceph_shutdown(cmount);
788 }
789
790 TEST(LibCephFS, Fchmod) {
791 struct ceph_mount_info *cmount;
792 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
793 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
794 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
795 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
796
797 char test_file[256];
798 sprintf(test_file, "test_perms_%d", getpid());
799
800 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
801 ASSERT_GT(fd, 0);
802
803 // write some stuff
804 const char *bytes = "foobarbaz";
805 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
806
807 // set perms to read but can't write
808 ASSERT_EQ(ceph_fchmod(cmount, fd, 0400), 0);
809
810 char buf[100];
811 int ret = ceph_read(cmount, fd, buf, 100, 0);
812 ASSERT_EQ(ret, (int)strlen(bytes));
813 buf[ret] = '\0';
814 ASSERT_STREQ(buf, bytes);
815
816 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
817
818 ceph_close(cmount, fd);
819
820 ASSERT_EQ(ceph_open(cmount, test_file, O_RDWR, 0), -EACCES);
821
822 // reset back to writeable
823 ASSERT_EQ(ceph_chmod(cmount, test_file, 0600), 0);
824
825 fd = ceph_open(cmount, test_file, O_RDWR, 0);
826 ASSERT_GT(fd, 0);
827
828 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
829 ceph_close(cmount, fd);
830
831 ceph_shutdown(cmount);
832 }
833
834 TEST(LibCephFS, Lchmod) {
835 struct ceph_mount_info *cmount;
836 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
837 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
838 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
839 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
840
841 char test_file[256];
842 sprintf(test_file, "test_perms_lchmod_%d", getpid());
843
844 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
845 ASSERT_GT(fd, 0);
846
847 // write some stuff
848 const char *bytes = "foobarbaz";
849 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
850 ceph_close(cmount, fd);
851
852 // Create symlink
853 char test_symlink[256];
854 sprintf(test_symlink, "test_lchmod_sym_%d", getpid());
855 ASSERT_EQ(ceph_symlink(cmount, test_file, test_symlink), 0);
856
857 // get symlink stat - lstat
858 struct ceph_statx stx_orig1;
859 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx_orig1, CEPH_STATX_ALL_STATS, AT_SYMLINK_NOFOLLOW), 0);
860
861 // Change mode on symlink file
862 ASSERT_EQ(ceph_lchmod(cmount, test_symlink, 0400), 0);
863 struct ceph_statx stx_orig2;
864 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx_orig2, CEPH_STATX_ALL_STATS, AT_SYMLINK_NOFOLLOW), 0);
865
866 // Compare modes
867 ASSERT_NE(stx_orig1.stx_mode, stx_orig2.stx_mode);
868 static const int permbits = S_IRWXU|S_IRWXG|S_IRWXO;
869 ASSERT_EQ(permbits&stx_orig1.stx_mode, 0777);
870 ASSERT_EQ(permbits&stx_orig2.stx_mode, 0400);
871
872 ceph_shutdown(cmount);
873 }
874
875 TEST(LibCephFS, Fchown) {
876 struct ceph_mount_info *cmount;
877 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
878 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
879 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
880 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
881
882 char test_file[256];
883 sprintf(test_file, "test_fchown_%d", getpid());
884
885 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
886 ASSERT_GT(fd, 0);
887
888 // set perms to readable and writeable only by owner
889 ASSERT_EQ(ceph_fchmod(cmount, fd, 0600), 0);
890
891 // change ownership to nobody -- we assume nobody exists and id is always 65534
892 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "0"), 0);
893 ASSERT_EQ(ceph_fchown(cmount, fd, 65534, 65534), 0);
894 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "1"), 0);
895
896 ceph_close(cmount, fd);
897
898 fd = ceph_open(cmount, test_file, O_RDWR, 0);
899 ASSERT_EQ(fd, -EACCES);
900
901 ceph_shutdown(cmount);
902 }
903
904 #if defined(__linux__) && defined(O_PATH)
905 TEST(LibCephFS, FlagO_PATH) {
906 struct ceph_mount_info *cmount;
907
908 ASSERT_EQ(0, ceph_create(&cmount, NULL));
909 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
910 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
911 ASSERT_EQ(0, ceph_mount(cmount, NULL));
912
913 char test_file[PATH_MAX];
914 sprintf(test_file, "test_oflag_%d", getpid());
915
916 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR|O_PATH, 0666);
917 ASSERT_EQ(-ENOENT, fd);
918
919 fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
920 ASSERT_GT(fd, 0);
921 ASSERT_EQ(0, ceph_close(cmount, fd));
922
923 // ok, the file has been created. perform real checks now
924 fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR|O_PATH, 0666);
925 ASSERT_GT(fd, 0);
926
927 char buf[128];
928 ASSERT_EQ(-EBADF, ceph_read(cmount, fd, buf, sizeof(buf), 0));
929 ASSERT_EQ(-EBADF, ceph_write(cmount, fd, buf, sizeof(buf), 0));
930
931 // set perms to readable and writeable only by owner
932 ASSERT_EQ(-EBADF, ceph_fchmod(cmount, fd, 0600));
933
934 // change ownership to nobody -- we assume nobody exists and id is always 65534
935 ASSERT_EQ(-EBADF, ceph_fchown(cmount, fd, 65534, 65534));
936
937 // try to sync
938 ASSERT_EQ(-EBADF, ceph_fsync(cmount, fd, false));
939
940 struct ceph_statx stx;
941 ASSERT_EQ(0, ceph_fstatx(cmount, fd, &stx, 0, 0));
942
943 ASSERT_EQ(0, ceph_close(cmount, fd));
944 ceph_shutdown(cmount);
945 }
946 #endif /* __linux */
947
948 TEST(LibCephFS, Symlinks) {
949 struct ceph_mount_info *cmount;
950 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
951 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
952 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
953 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
954
955 char test_file[256];
956 sprintf(test_file, "test_symlinks_%d", getpid());
957
958 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
959 ASSERT_GT(fd, 0);
960
961 ceph_close(cmount, fd);
962
963 char test_symlink[256];
964 sprintf(test_symlink, "test_symlinks_sym_%d", getpid());
965
966 ASSERT_EQ(ceph_symlink(cmount, test_file, test_symlink), 0);
967
968 // test the O_NOFOLLOW case
969 fd = ceph_open(cmount, test_symlink, O_NOFOLLOW, 0);
970 ASSERT_EQ(fd, -ELOOP);
971
972 // stat the original file
973 struct ceph_statx stx_orig;
974 ASSERT_EQ(ceph_statx(cmount, test_file, &stx_orig, CEPH_STATX_ALL_STATS, 0), 0);
975 // stat the symlink
976 struct ceph_statx stx_symlink_orig;
977 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx_symlink_orig, CEPH_STATX_ALL_STATS, 0), 0);
978 // ensure the statx bufs are equal
979 ASSERT_EQ(memcmp(&stx_orig, &stx_symlink_orig, sizeof(stx_orig)), 0);
980
981 sprintf(test_file, "/test_symlinks_abs_%d", getpid());
982
983 fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
984 ASSERT_GT(fd, 0);
985
986 ceph_close(cmount, fd);
987
988 sprintf(test_symlink, "/test_symlinks_abs_sym_%d", getpid());
989
990 ASSERT_EQ(ceph_symlink(cmount, test_file, test_symlink), 0);
991
992 // stat the original file
993 ASSERT_EQ(ceph_statx(cmount, test_file, &stx_orig, CEPH_STATX_ALL_STATS, 0), 0);
994 // stat the symlink
995 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx_symlink_orig, CEPH_STATX_ALL_STATS, 0), 0);
996 // ensure the statx bufs are equal
997 ASSERT_TRUE(!memcmp(&stx_orig, &stx_symlink_orig, sizeof(stx_orig)));
998
999 // test lstat
1000 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx_orig, CEPH_STATX_ALL_STATS, AT_SYMLINK_NOFOLLOW), 0);
1001 ASSERT_TRUE(S_ISLNK(stx_orig.stx_mode));
1002
1003 ceph_shutdown(cmount);
1004 }
1005
1006 TEST(LibCephFS, DirSyms) {
1007 struct ceph_mount_info *cmount;
1008 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1009 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1010 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1011 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1012
1013 char test_dir1[256];
1014 sprintf(test_dir1, "dir1_symlinks_%d", getpid());
1015
1016 ASSERT_EQ(ceph_mkdir(cmount, test_dir1, 0700), 0);
1017
1018 char test_symdir[256];
1019 sprintf(test_symdir, "symdir_symlinks_%d", getpid());
1020
1021 ASSERT_EQ(ceph_symlink(cmount, test_dir1, test_symdir), 0);
1022
1023 char test_file[256];
1024 sprintf(test_file, "/symdir_symlinks_%d/test_symdir_file", getpid());
1025 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0600);
1026 ASSERT_GT(fd, 0);
1027 ceph_close(cmount, fd);
1028
1029 struct ceph_statx stx;
1030 ASSERT_EQ(ceph_statx(cmount, test_file, &stx, 0, AT_SYMLINK_NOFOLLOW), 0);
1031
1032 // ensure that its a file not a directory we get back
1033 ASSERT_TRUE(S_ISREG(stx.stx_mode));
1034
1035 ceph_shutdown(cmount);
1036 }
1037
1038 TEST(LibCephFS, LoopSyms) {
1039 struct ceph_mount_info *cmount;
1040 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1041 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1042 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1043 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1044
1045 char test_dir1[256];
1046 sprintf(test_dir1, "dir1_loopsym_%d", getpid());
1047
1048 ASSERT_EQ(ceph_mkdir(cmount, test_dir1, 0700), 0);
1049
1050 char test_dir2[256];
1051 sprintf(test_dir2, "/dir1_loopsym_%d/loop_dir", getpid());
1052
1053 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0700), 0);
1054
1055 // symlink it itself: /path/to/mysym -> /path/to/mysym
1056 char test_symdir[256];
1057 sprintf(test_symdir, "/dir1_loopsym_%d/loop_dir/symdir", getpid());
1058
1059 ASSERT_EQ(ceph_symlink(cmount, test_symdir, test_symdir), 0);
1060
1061 char test_file[256];
1062 sprintf(test_file, "/dir1_loopsym_%d/loop_dir/symdir/test_loopsym_file", getpid());
1063 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0600);
1064 ASSERT_EQ(fd, -ELOOP);
1065
1066 // loop: /a -> /b, /b -> /c, /c -> /a
1067 char a[264], b[264], c[264];
1068 sprintf(a, "/%s/a", test_dir1);
1069 sprintf(b, "/%s/b", test_dir1);
1070 sprintf(c, "/%s/c", test_dir1);
1071 ASSERT_EQ(ceph_symlink(cmount, a, b), 0);
1072 ASSERT_EQ(ceph_symlink(cmount, b, c), 0);
1073 ASSERT_EQ(ceph_symlink(cmount, c, a), 0);
1074 ASSERT_EQ(ceph_open(cmount, a, O_RDWR, 0), -ELOOP);
1075
1076 ceph_shutdown(cmount);
1077 }
1078
1079 TEST(LibCephFS, HardlinkNoOriginal) {
1080
1081 int mypid = getpid();
1082
1083 struct ceph_mount_info *cmount;
1084 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1085 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1086 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1087 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1088
1089 char dir[256];
1090 sprintf(dir, "/test_rmdirfail%d", mypid);
1091 ASSERT_EQ(ceph_mkdir(cmount, dir, 0777), 0);
1092
1093 ASSERT_EQ(ceph_chdir(cmount, dir), 0);
1094
1095 int fd = ceph_open(cmount, "f1", O_CREAT, 0644);
1096 ASSERT_GT(fd, 0);
1097
1098 ceph_close(cmount, fd);
1099
1100 // create hard link
1101 ASSERT_EQ(ceph_link(cmount, "f1", "hardl1"), 0);
1102
1103 // remove file link points to
1104 ASSERT_EQ(ceph_unlink(cmount, "f1"), 0);
1105
1106 ceph_shutdown(cmount);
1107
1108 // now cleanup
1109 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1110 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1111 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1112 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1113 ASSERT_EQ(ceph_chdir(cmount, dir), 0);
1114 ASSERT_EQ(ceph_unlink(cmount, "hardl1"), 0);
1115 ASSERT_EQ(ceph_rmdir(cmount, dir), 0);
1116
1117 ceph_shutdown(cmount);
1118 }
1119
1120 TEST(LibCephFS, BadArgument) {
1121 struct ceph_mount_info *cmount;
1122 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1123 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1124 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1125 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1126
1127 int fd = ceph_open(cmount, "test_file", O_CREAT|O_RDWR, 0666);
1128 ASSERT_GT(fd, 0);
1129 char buf[100];
1130 ASSERT_EQ(ceph_write(cmount, fd, buf, sizeof(buf), 0), (int)sizeof(buf));
1131 ASSERT_EQ(ceph_read(cmount, fd, buf, 0, 5), 0);
1132 ceph_close(cmount, fd);
1133 ASSERT_EQ(ceph_unlink(cmount, "test_file"), 0);
1134
1135 ceph_shutdown(cmount);
1136 }
1137
1138 TEST(LibCephFS, BadFileDesc) {
1139 struct ceph_mount_info *cmount;
1140 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1141 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1142 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1143 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1144
1145 ASSERT_EQ(ceph_fchmod(cmount, -1, 0655), -EBADF);
1146 ASSERT_EQ(ceph_close(cmount, -1), -EBADF);
1147 ASSERT_EQ(ceph_lseek(cmount, -1, 0, SEEK_SET), -EBADF);
1148
1149 char buf[0];
1150 ASSERT_EQ(ceph_read(cmount, -1, buf, 0, 0), -EBADF);
1151 ASSERT_EQ(ceph_write(cmount, -1, buf, 0, 0), -EBADF);
1152
1153 ASSERT_EQ(ceph_ftruncate(cmount, -1, 0), -EBADF);
1154 ASSERT_EQ(ceph_fsync(cmount, -1, 0), -EBADF);
1155
1156 struct ceph_statx stx;
1157 ASSERT_EQ(ceph_fstatx(cmount, -1, &stx, 0, 0), -EBADF);
1158
1159 struct sockaddr_storage addr;
1160 ASSERT_EQ(ceph_get_file_stripe_address(cmount, -1, 0, &addr, 1), -EBADF);
1161
1162 ASSERT_EQ(ceph_get_file_stripe_unit(cmount, -1), -EBADF);
1163 ASSERT_EQ(ceph_get_file_pool(cmount, -1), -EBADF);
1164 char poolname[80];
1165 ASSERT_EQ(ceph_get_file_pool_name(cmount, -1, poolname, sizeof(poolname)), -EBADF);
1166 ASSERT_EQ(ceph_get_file_replication(cmount, -1), -EBADF);
1167 ASSERT_EQ(ceph_get_file_object_size(cmount, -1), -EBADF);
1168 int stripe_unit, stripe_count, object_size, pg_pool;
1169 ASSERT_EQ(ceph_get_file_layout(cmount, -1, &stripe_unit, &stripe_count, &object_size, &pg_pool), -EBADF);
1170 ASSERT_EQ(ceph_get_file_stripe_count(cmount, -1), -EBADF);
1171
1172 ceph_shutdown(cmount);
1173 }
1174
1175 TEST(LibCephFS, ReadEmptyFile) {
1176 struct ceph_mount_info *cmount;
1177 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1178 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1179 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1180 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1181
1182 // test the read_sync path in the client for zero files
1183 ASSERT_EQ(ceph_conf_set(cmount, "client_debug_force_sync_read", "true"), 0);
1184
1185 int mypid = getpid();
1186 char testf[256];
1187
1188 sprintf(testf, "test_reademptyfile%d", mypid);
1189 int fd = ceph_open(cmount, testf, O_CREAT|O_TRUNC|O_WRONLY, 0644);
1190 ASSERT_GT(fd, 0);
1191
1192 ceph_close(cmount, fd);
1193
1194 fd = ceph_open(cmount, testf, O_RDONLY, 0);
1195 ASSERT_GT(fd, 0);
1196
1197 char buf[4096];
1198 ASSERT_EQ(ceph_read(cmount, fd, buf, 4096, 0), 0);
1199
1200 ceph_close(cmount, fd);
1201 ceph_shutdown(cmount);
1202 }
1203
1204 TEST(LibCephFS, PreadvPwritev) {
1205 struct ceph_mount_info *cmount;
1206 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1207 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1208 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1209 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1210
1211 int mypid = getpid();
1212 char testf[256];
1213
1214 sprintf(testf, "test_preadvpwritevfile%d", mypid);
1215 int fd = ceph_open(cmount, testf, O_CREAT|O_RDWR, 0666);
1216 ASSERT_GT(fd, 0);
1217
1218 char out0[] = "hello ";
1219 char out1[] = "world\n";
1220 struct iovec iov_out[2] = {
1221 {out0, sizeof(out0)},
1222 {out1, sizeof(out1)},
1223 };
1224 char in0[sizeof(out0)];
1225 char in1[sizeof(out1)];
1226 struct iovec iov_in[2] = {
1227 {in0, sizeof(in0)},
1228 {in1, sizeof(in1)},
1229 };
1230 ssize_t nwritten = iov_out[0].iov_len + iov_out[1].iov_len;
1231 ssize_t nread = iov_in[0].iov_len + iov_in[1].iov_len;
1232
1233 ASSERT_EQ(ceph_pwritev(cmount, fd, iov_out, 2, 0), nwritten);
1234 ASSERT_EQ(ceph_preadv(cmount, fd, iov_in, 2, 0), nread);
1235 ASSERT_EQ(0, strncmp((const char*)iov_in[0].iov_base, (const char*)iov_out[0].iov_base, iov_out[0].iov_len));
1236 ASSERT_EQ(0, strncmp((const char*)iov_in[1].iov_base, (const char*)iov_out[1].iov_base, iov_out[1].iov_len));
1237
1238 ceph_close(cmount, fd);
1239 ceph_shutdown(cmount);
1240 }
1241
1242 TEST(LibCephFS, LlreadvLlwritev) {
1243 struct ceph_mount_info *cmount;
1244 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1245 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1246 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1247 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1248
1249 int mypid = getpid();
1250 char filename[256];
1251
1252 sprintf(filename, "test_llreadvllwritevfile%u", mypid);
1253
1254 Inode *root, *file;
1255 ASSERT_EQ(ceph_ll_lookup_root(cmount, &root), 0);
1256
1257 Fh *fh;
1258 struct ceph_statx stx;
1259 UserPerm *perms = ceph_mount_perms(cmount);
1260
1261 ASSERT_EQ(ceph_ll_create(cmount, root, filename, 0666,
1262 O_RDWR|O_CREAT|O_TRUNC, &file, &fh, &stx, 0, 0, perms), 0);
1263
1264 /* Reopen read-only */
1265 char out0[] = "hello ";
1266 char out1[] = "world\n";
1267 struct iovec iov_out[2] = {
1268 {out0, sizeof(out0)},
1269 {out1, sizeof(out1)},
1270 };
1271 char in0[sizeof(out0)];
1272 char in1[sizeof(out1)];
1273 struct iovec iov_in[2] = {
1274 {in0, sizeof(in0)},
1275 {in1, sizeof(in1)},
1276 };
1277 ssize_t nwritten = iov_out[0].iov_len + iov_out[1].iov_len;
1278 ssize_t nread = iov_in[0].iov_len + iov_in[1].iov_len;
1279
1280 ASSERT_EQ(ceph_ll_writev(cmount, fh, iov_out, 2, 0), nwritten);
1281 ASSERT_EQ(ceph_ll_readv(cmount, fh, iov_in, 2, 0), nread);
1282 ASSERT_EQ(0, strncmp((const char*)iov_in[0].iov_base, (const char*)iov_out[0].iov_base, iov_out[0].iov_len));
1283 ASSERT_EQ(0, strncmp((const char*)iov_in[1].iov_base, (const char*)iov_out[1].iov_base, iov_out[1].iov_len));
1284
1285 ceph_ll_close(cmount, fh);
1286 ceph_shutdown(cmount);
1287 }
1288
1289 TEST(LibCephFS, StripeUnitGran) {
1290 struct ceph_mount_info *cmount;
1291 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1292 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1293 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1294 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1295 ASSERT_GT(ceph_get_stripe_unit_granularity(cmount), 0);
1296 ceph_shutdown(cmount);
1297 }
1298
1299 TEST(LibCephFS, Rename) {
1300 struct ceph_mount_info *cmount;
1301 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1302 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1303 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1304 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1305
1306 int mypid = getpid();
1307 char path_src[256];
1308 char path_dst[256];
1309
1310 /* make a source file */
1311 sprintf(path_src, "test_rename_src%d", mypid);
1312 int fd = ceph_open(cmount, path_src, O_CREAT|O_TRUNC|O_WRONLY, 0777);
1313 ASSERT_GT(fd, 0);
1314 ASSERT_EQ(0, ceph_close(cmount, fd));
1315
1316 /* rename to a new dest path */
1317 sprintf(path_dst, "test_rename_dst%d", mypid);
1318 ASSERT_EQ(0, ceph_rename(cmount, path_src, path_dst));
1319
1320 /* test that dest path exists */
1321 struct ceph_statx stx;
1322 ASSERT_EQ(0, ceph_statx(cmount, path_dst, &stx, 0, 0));
1323
1324 /* test that src path doesn't exist */
1325 ASSERT_EQ(-ENOENT, ceph_statx(cmount, path_src, &stx, 0, AT_SYMLINK_NOFOLLOW));
1326
1327 /* rename with non-existent source path */
1328 ASSERT_EQ(-ENOENT, ceph_rename(cmount, path_src, path_dst));
1329
1330 ASSERT_EQ(0, ceph_unlink(cmount, path_dst));
1331 ceph_shutdown(cmount);
1332 }
1333
1334 TEST(LibCephFS, UseUnmounted) {
1335 struct ceph_mount_info *cmount;
1336 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1337 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1338 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1339
1340 struct statvfs stvfs;
1341 EXPECT_EQ(-ENOTCONN, ceph_statfs(cmount, "/", &stvfs));
1342 EXPECT_EQ(-ENOTCONN, ceph_get_local_osd(cmount));
1343 EXPECT_EQ(-ENOTCONN, ceph_chdir(cmount, "/"));
1344
1345 struct ceph_dir_result *dirp;
1346 EXPECT_EQ(-ENOTCONN, ceph_opendir(cmount, "/", &dirp));
1347 EXPECT_EQ(-ENOTCONN, ceph_closedir(cmount, dirp));
1348
1349 ceph_readdir(cmount, dirp);
1350 EXPECT_EQ(ENOTCONN, errno);
1351
1352 struct dirent rdent;
1353 EXPECT_EQ(-ENOTCONN, ceph_readdir_r(cmount, dirp, &rdent));
1354
1355 struct ceph_statx stx;
1356 EXPECT_EQ(-ENOTCONN, ceph_readdirplus_r(cmount, dirp, &rdent, &stx, 0, 0, NULL));
1357 EXPECT_EQ(-ENOTCONN, ceph_getdents(cmount, dirp, NULL, 0));
1358 EXPECT_EQ(-ENOTCONN, ceph_getdnames(cmount, dirp, NULL, 0));
1359 EXPECT_EQ(-ENOTCONN, ceph_telldir(cmount, dirp));
1360 EXPECT_EQ(-ENOTCONN, ceph_link(cmount, "/", "/link"));
1361 EXPECT_EQ(-ENOTCONN, ceph_unlink(cmount, "/path"));
1362 EXPECT_EQ(-ENOTCONN, ceph_rename(cmount, "/path", "/path"));
1363 EXPECT_EQ(-ENOTCONN, ceph_mkdir(cmount, "/", 0655));
1364 EXPECT_EQ(-ENOTCONN, ceph_mkdirs(cmount, "/", 0655));
1365 EXPECT_EQ(-ENOTCONN, ceph_rmdir(cmount, "/path"));
1366 EXPECT_EQ(-ENOTCONN, ceph_readlink(cmount, "/path", NULL, 0));
1367 EXPECT_EQ(-ENOTCONN, ceph_symlink(cmount, "/path", "/path"));
1368 EXPECT_EQ(-ENOTCONN, ceph_statx(cmount, "/path", &stx, 0, 0));
1369 EXPECT_EQ(-ENOTCONN, ceph_setattrx(cmount, "/path", &stx, 0, 0));
1370 EXPECT_EQ(-ENOTCONN, ceph_getxattr(cmount, "/path", "name", NULL, 0));
1371 EXPECT_EQ(-ENOTCONN, ceph_lgetxattr(cmount, "/path", "name", NULL, 0));
1372 EXPECT_EQ(-ENOTCONN, ceph_listxattr(cmount, "/path", NULL, 0));
1373 EXPECT_EQ(-ENOTCONN, ceph_llistxattr(cmount, "/path", NULL, 0));
1374 EXPECT_EQ(-ENOTCONN, ceph_removexattr(cmount, "/path", "name"));
1375 EXPECT_EQ(-ENOTCONN, ceph_lremovexattr(cmount, "/path", "name"));
1376 EXPECT_EQ(-ENOTCONN, ceph_setxattr(cmount, "/path", "name", NULL, 0, 0));
1377 EXPECT_EQ(-ENOTCONN, ceph_lsetxattr(cmount, "/path", "name", NULL, 0, 0));
1378 EXPECT_EQ(-ENOTCONN, ceph_fsetattrx(cmount, 0, &stx, 0));
1379 EXPECT_EQ(-ENOTCONN, ceph_chmod(cmount, "/path", 0));
1380 EXPECT_EQ(-ENOTCONN, ceph_fchmod(cmount, 0, 0));
1381 EXPECT_EQ(-ENOTCONN, ceph_chown(cmount, "/path", 0, 0));
1382 EXPECT_EQ(-ENOTCONN, ceph_lchown(cmount, "/path", 0, 0));
1383 EXPECT_EQ(-ENOTCONN, ceph_fchown(cmount, 0, 0, 0));
1384
1385 struct utimbuf utb;
1386 EXPECT_EQ(-ENOTCONN, ceph_utime(cmount, "/path", &utb));
1387 EXPECT_EQ(-ENOTCONN, ceph_truncate(cmount, "/path", 0));
1388 EXPECT_EQ(-ENOTCONN, ceph_mknod(cmount, "/path", 0, 0));
1389 EXPECT_EQ(-ENOTCONN, ceph_open(cmount, "/path", 0, 0));
1390 EXPECT_EQ(-ENOTCONN, ceph_open_layout(cmount, "/path", 0, 0, 0, 0, 0, "pool"));
1391 EXPECT_EQ(-ENOTCONN, ceph_close(cmount, 0));
1392 EXPECT_EQ(-ENOTCONN, ceph_lseek(cmount, 0, 0, SEEK_SET));
1393 EXPECT_EQ(-ENOTCONN, ceph_read(cmount, 0, NULL, 0, 0));
1394 EXPECT_EQ(-ENOTCONN, ceph_write(cmount, 0, NULL, 0, 0));
1395 EXPECT_EQ(-ENOTCONN, ceph_ftruncate(cmount, 0, 0));
1396 EXPECT_EQ(-ENOTCONN, ceph_fsync(cmount, 0, 0));
1397 EXPECT_EQ(-ENOTCONN, ceph_fstatx(cmount, 0, &stx, 0, 0));
1398 EXPECT_EQ(-ENOTCONN, ceph_sync_fs(cmount));
1399 EXPECT_EQ(-ENOTCONN, ceph_get_file_stripe_unit(cmount, 0));
1400 EXPECT_EQ(-ENOTCONN, ceph_get_file_stripe_count(cmount, 0));
1401 EXPECT_EQ(-ENOTCONN, ceph_get_file_layout(cmount, 0, NULL, NULL ,NULL ,NULL));
1402 EXPECT_EQ(-ENOTCONN, ceph_get_file_object_size(cmount, 0));
1403 EXPECT_EQ(-ENOTCONN, ceph_get_file_pool(cmount, 0));
1404 EXPECT_EQ(-ENOTCONN, ceph_get_file_pool_name(cmount, 0, NULL, 0));
1405 EXPECT_EQ(-ENOTCONN, ceph_get_file_replication(cmount, 0));
1406 EXPECT_EQ(-ENOTCONN, ceph_get_path_replication(cmount, "/path"));
1407 EXPECT_EQ(-ENOTCONN, ceph_get_path_layout(cmount, "/path", NULL, NULL, NULL, NULL));
1408 EXPECT_EQ(-ENOTCONN, ceph_get_path_object_size(cmount, "/path"));
1409 EXPECT_EQ(-ENOTCONN, ceph_get_path_stripe_count(cmount, "/path"));
1410 EXPECT_EQ(-ENOTCONN, ceph_get_path_stripe_unit(cmount, "/path"));
1411 EXPECT_EQ(-ENOTCONN, ceph_get_path_pool(cmount, "/path"));
1412 EXPECT_EQ(-ENOTCONN, ceph_get_path_pool_name(cmount, "/path", NULL, 0));
1413 EXPECT_EQ(-ENOTCONN, ceph_get_pool_name(cmount, 0, NULL, 0));
1414 EXPECT_EQ(-ENOTCONN, ceph_get_file_stripe_address(cmount, 0, 0, NULL, 0));
1415 EXPECT_EQ(-ENOTCONN, ceph_localize_reads(cmount, 0));
1416 EXPECT_EQ(-ENOTCONN, ceph_debug_get_fd_caps(cmount, 0));
1417 EXPECT_EQ(-ENOTCONN, ceph_debug_get_file_caps(cmount, "/path"));
1418 EXPECT_EQ(-ENOTCONN, ceph_get_stripe_unit_granularity(cmount));
1419 EXPECT_EQ(-ENOTCONN, ceph_get_pool_id(cmount, "data"));
1420 EXPECT_EQ(-ENOTCONN, ceph_get_pool_replication(cmount, 1));
1421
1422 ceph_release(cmount);
1423 }
1424
1425 TEST(LibCephFS, GetPoolId) {
1426 struct ceph_mount_info *cmount;
1427 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1428 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1429 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1430 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1431
1432 char name[80];
1433 memset(name, 0, sizeof(name));
1434 ASSERT_LE(0, ceph_get_path_pool_name(cmount, "/", name, sizeof(name)));
1435 ASSERT_GE(ceph_get_pool_id(cmount, name), 0);
1436 ASSERT_EQ(ceph_get_pool_id(cmount, "weflkjwelfjwlkejf"), -ENOENT);
1437
1438 ceph_shutdown(cmount);
1439 }
1440
1441 TEST(LibCephFS, GetPoolReplication) {
1442 struct ceph_mount_info *cmount;
1443 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1444 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1445 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1446 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1447
1448 /* negative pools */
1449 ASSERT_EQ(ceph_get_pool_replication(cmount, -10), -ENOENT);
1450
1451 /* valid pool */
1452 int pool_id;
1453 int stripe_unit, stripe_count, object_size;
1454 ASSERT_EQ(0, ceph_get_path_layout(cmount, "/", &stripe_unit, &stripe_count,
1455 &object_size, &pool_id));
1456 ASSERT_GE(pool_id, 0);
1457 ASSERT_GT(ceph_get_pool_replication(cmount, pool_id), 0);
1458
1459 ceph_shutdown(cmount);
1460 }
1461
1462 TEST(LibCephFS, GetExtentOsds) {
1463 struct ceph_mount_info *cmount;
1464 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1465
1466 EXPECT_EQ(-ENOTCONN, ceph_get_file_extent_osds(cmount, 0, 0, NULL, NULL, 0));
1467
1468 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1469 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1470 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1471
1472 int stripe_unit = (1<<18);
1473
1474 /* make a file! */
1475 char test_file[256];
1476 sprintf(test_file, "test_extent_osds_%d", getpid());
1477 int fd = ceph_open_layout(cmount, test_file, O_CREAT|O_RDWR, 0666,
1478 stripe_unit, 2, stripe_unit*2, NULL);
1479 ASSERT_GT(fd, 0);
1480
1481 /* get back how many osds > 0 */
1482 int ret = ceph_get_file_extent_osds(cmount, fd, 0, NULL, NULL, 0);
1483 EXPECT_GT(ret, 0);
1484
1485 int64_t len;
1486 int osds[ret];
1487
1488 /* full stripe extent */
1489 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 0, &len, osds, ret));
1490 EXPECT_EQ(len, (int64_t)stripe_unit);
1491
1492 /* half stripe extent */
1493 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, stripe_unit/2, &len, osds, ret));
1494 EXPECT_EQ(len, (int64_t)stripe_unit/2);
1495
1496 /* 1.5 stripe unit offset -1 byte */
1497 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 3*stripe_unit/2-1, &len, osds, ret));
1498 EXPECT_EQ(len, (int64_t)stripe_unit/2+1);
1499
1500 /* 1.5 stripe unit offset +1 byte */
1501 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 3*stripe_unit/2+1, &len, osds, ret));
1502 EXPECT_EQ(len, (int64_t)stripe_unit/2-1);
1503
1504 /* only when more than 1 osd */
1505 if (ret > 1) {
1506 EXPECT_EQ(-ERANGE, ceph_get_file_extent_osds(cmount, fd, 0, NULL, osds, 1));
1507 }
1508
1509 ceph_close(cmount, fd);
1510
1511 ceph_shutdown(cmount);
1512 }
1513
1514 TEST(LibCephFS, GetOsdCrushLocation) {
1515 struct ceph_mount_info *cmount;
1516 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1517
1518 EXPECT_EQ(-ENOTCONN, ceph_get_osd_crush_location(cmount, 0, NULL, 0));
1519
1520 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1521 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1522 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1523
1524 ASSERT_EQ(ceph_get_osd_crush_location(cmount, 0, NULL, 1), -EINVAL);
1525
1526 char path[256];
1527 ASSERT_EQ(ceph_get_osd_crush_location(cmount, 9999999, path, 0), -ENOENT);
1528 ASSERT_EQ(ceph_get_osd_crush_location(cmount, -1, path, 0), -EINVAL);
1529
1530 char test_file[256];
1531 sprintf(test_file, "test_osds_loc_%d", getpid());
1532 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
1533 ASSERT_GT(fd, 0);
1534
1535 /* get back how many osds > 0 */
1536 int ret = ceph_get_file_extent_osds(cmount, fd, 0, NULL, NULL, 0);
1537 EXPECT_GT(ret, 0);
1538
1539 /* full stripe extent */
1540 int osds[ret];
1541 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 0, NULL, osds, ret));
1542
1543 ASSERT_GT(ceph_get_osd_crush_location(cmount, 0, path, 0), 0);
1544 ASSERT_EQ(ceph_get_osd_crush_location(cmount, 0, path, 1), -ERANGE);
1545
1546 for (int i = 0; i < ret; i++) {
1547 int len = ceph_get_osd_crush_location(cmount, osds[i], path, sizeof(path));
1548 ASSERT_GT(len, 0);
1549 int pos = 0;
1550 while (pos < len) {
1551 std::string type(path + pos);
1552 ASSERT_GT((int)type.size(), 0);
1553 pos += type.size() + 1;
1554
1555 std::string name(path + pos);
1556 ASSERT_GT((int)name.size(), 0);
1557 pos += name.size() + 1;
1558 }
1559 }
1560
1561 ceph_close(cmount, fd);
1562 ceph_shutdown(cmount);
1563 }
1564
1565 TEST(LibCephFS, GetOsdAddr) {
1566 struct ceph_mount_info *cmount;
1567 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1568
1569 EXPECT_EQ(-ENOTCONN, ceph_get_osd_addr(cmount, 0, NULL));
1570
1571 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1572 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1573 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1574
1575 ASSERT_EQ(-EINVAL, ceph_get_osd_addr(cmount, 0, NULL));
1576
1577 struct sockaddr_storage addr;
1578 ASSERT_EQ(-ENOENT, ceph_get_osd_addr(cmount, -1, &addr));
1579 ASSERT_EQ(-ENOENT, ceph_get_osd_addr(cmount, 9999999, &addr));
1580
1581 ASSERT_EQ(0, ceph_get_osd_addr(cmount, 0, &addr));
1582
1583 ceph_shutdown(cmount);
1584 }
1585
1586 TEST(LibCephFS, OpenNoClose) {
1587 struct ceph_mount_info *cmount;
1588 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1589 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1590 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1591 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1592
1593 pid_t mypid = getpid();
1594 char str_buf[256];
1595 sprintf(str_buf, "open_no_close_dir%d", mypid);
1596 ASSERT_EQ(0, ceph_mkdirs(cmount, str_buf, 0777));
1597
1598 struct ceph_dir_result *ls_dir = NULL;
1599 ASSERT_EQ(ceph_opendir(cmount, str_buf, &ls_dir), 0);
1600
1601 sprintf(str_buf, "open_no_close_file%d", mypid);
1602 int fd = ceph_open(cmount, str_buf, O_RDONLY|O_CREAT, 0666);
1603 ASSERT_LT(0, fd);
1604
1605 // shutdown should force close opened file/dir
1606 ceph_shutdown(cmount);
1607 }
1608
1609 TEST(LibCephFS, Nlink) {
1610 struct ceph_mount_info *cmount;
1611 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1612 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1613 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1614 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1615
1616 Inode *root, *dir, *file;
1617
1618 ASSERT_EQ(ceph_ll_lookup_root(cmount, &root), 0);
1619
1620 char dirname[32], filename[32], linkname[32];
1621 sprintf(dirname, "nlinkdir%x", getpid());
1622 sprintf(filename, "nlinkorig%x", getpid());
1623 sprintf(linkname, "nlinklink%x", getpid());
1624
1625 struct ceph_statx stx;
1626 Fh *fh;
1627 UserPerm *perms = ceph_mount_perms(cmount);
1628
1629 ASSERT_EQ(ceph_ll_mkdir(cmount, root, dirname, 0755, &dir, &stx, 0, 0, perms), 0);
1630 ASSERT_EQ(ceph_ll_create(cmount, dir, filename, 0666, O_RDWR|O_CREAT|O_EXCL,
1631 &file, &fh, &stx, CEPH_STATX_NLINK, 0, perms), 0);
1632 ASSERT_EQ(ceph_ll_close(cmount, fh), 0);
1633 ASSERT_EQ(stx.stx_nlink, (nlink_t)1);
1634
1635 ASSERT_EQ(ceph_ll_link(cmount, file, dir, linkname, perms), 0);
1636 ASSERT_EQ(ceph_ll_getattr(cmount, file, &stx, CEPH_STATX_NLINK, 0, perms), 0);
1637 ASSERT_EQ(stx.stx_nlink, (nlink_t)2);
1638
1639 ASSERT_EQ(ceph_ll_unlink(cmount, dir, linkname, perms), 0);
1640 ASSERT_EQ(ceph_ll_lookup(cmount, dir, filename, &file, &stx,
1641 CEPH_STATX_NLINK, 0, perms), 0);
1642 ASSERT_EQ(stx.stx_nlink, (nlink_t)1);
1643
1644 ceph_shutdown(cmount);
1645 }
1646
1647 TEST(LibCephFS, SlashDotDot) {
1648 struct ceph_mount_info *cmount;
1649 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1650 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1651 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1652 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1653
1654 struct ceph_statx stx;
1655 ASSERT_EQ(ceph_statx(cmount, "/.", &stx, CEPH_STATX_INO, 0), 0);
1656
1657 ino_t ino = stx.stx_ino;
1658 ASSERT_EQ(ceph_statx(cmount, "/..", &stx, CEPH_STATX_INO, 0), 0);
1659
1660 /* At root, "." and ".." should be the same inode */
1661 ASSERT_EQ(ino, stx.stx_ino);
1662
1663 /* Test accessing the parent of an unlinked directory */
1664 char dir1[32], dir2[56];
1665 sprintf(dir1, "/sldotdot%x", getpid());
1666 sprintf(dir2, "%s/sub%x", dir1, getpid());
1667
1668 ASSERT_EQ(ceph_mkdir(cmount, dir1, 0755), 0);
1669 ASSERT_EQ(ceph_mkdir(cmount, dir2, 0755), 0);
1670
1671 ASSERT_EQ(ceph_chdir(cmount, dir2), 0);
1672
1673 /* Test behavior when unlinking cwd */
1674 struct ceph_dir_result *rdir;
1675 ASSERT_EQ(ceph_opendir(cmount, ".", &rdir), 0);
1676 ASSERT_EQ(ceph_rmdir(cmount, dir2), 0);
1677
1678 /* get "." entry */
1679 struct dirent *result = ceph_readdir(cmount, rdir);
1680 ino = result->d_ino;
1681
1682 /* get ".." entry */
1683 result = ceph_readdir(cmount, rdir);
1684 ASSERT_EQ(ino, result->d_ino);
1685 ceph_closedir(cmount, rdir);
1686
1687 /* Make sure it works same way when mounting subtree */
1688 ASSERT_EQ(ceph_unmount(cmount), 0);
1689 ASSERT_EQ(ceph_mount(cmount, dir1), 0);
1690 ASSERT_EQ(ceph_statx(cmount, "/..", &stx, CEPH_STATX_INO, 0), 0);
1691
1692 /* Test readdir behavior */
1693 ASSERT_EQ(ceph_opendir(cmount, "/", &rdir), 0);
1694 result = ceph_readdir(cmount, rdir);
1695 ASSERT_TRUE(result != NULL);
1696 ASSERT_STREQ(result->d_name, ".");
1697 ino = result->d_ino;
1698 result = ceph_readdir(cmount, rdir);
1699 ASSERT_TRUE(result != NULL);
1700 ASSERT_STREQ(result->d_name, "..");
1701 ASSERT_EQ(ino, result->d_ino);
1702
1703 ceph_shutdown(cmount);
1704 }
1705
1706 static inline bool
1707 timespec_eq(timespec const& lhs, timespec const& rhs)
1708 {
1709 return lhs.tv_sec == rhs.tv_sec && lhs.tv_nsec == rhs.tv_nsec;
1710 }
1711
1712 TEST(LibCephFS, Btime) {
1713 struct ceph_mount_info *cmount;
1714 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1715 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1716 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1717 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1718
1719 char filename[32];
1720 sprintf(filename, "/getattrx%x", getpid());
1721
1722 ceph_unlink(cmount, filename);
1723 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1724 ASSERT_LT(0, fd);
1725
1726 /* make sure fstatx works */
1727 struct ceph_statx stx;
1728
1729 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_CTIME|CEPH_STATX_BTIME, 0), 0);
1730 ASSERT_TRUE(stx.stx_mask & (CEPH_STATX_CTIME|CEPH_STATX_BTIME));
1731 ASSERT_TRUE(timespec_eq(stx.stx_ctime, stx.stx_btime));
1732 ceph_close(cmount, fd);
1733
1734 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_CTIME|CEPH_STATX_BTIME, 0), 0);
1735 ASSERT_TRUE(timespec_eq(stx.stx_ctime, stx.stx_btime));
1736 ASSERT_TRUE(stx.stx_mask & (CEPH_STATX_CTIME|CEPH_STATX_BTIME));
1737
1738 struct timespec old_btime = stx.stx_btime;
1739
1740 /* Now sleep, do a chmod and verify that the ctime changed, but btime didn't */
1741 sleep(1);
1742 ASSERT_EQ(ceph_chmod(cmount, filename, 0644), 0);
1743 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_CTIME|CEPH_STATX_BTIME, 0), 0);
1744 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_BTIME);
1745 ASSERT_TRUE(timespec_eq(stx.stx_btime, old_btime));
1746 ASSERT_FALSE(timespec_eq(stx.stx_ctime, stx.stx_btime));
1747
1748 ceph_shutdown(cmount);
1749 }
1750
1751 TEST(LibCephFS, SetBtime) {
1752 struct ceph_mount_info *cmount;
1753 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1754 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1755 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1756 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1757
1758 char filename[32];
1759 sprintf(filename, "/setbtime%x", getpid());
1760
1761 ceph_unlink(cmount, filename);
1762 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1763 ASSERT_LT(0, fd);
1764 ceph_close(cmount, fd);
1765
1766 struct ceph_statx stx;
1767 struct timespec old_btime = { 1, 2 };
1768
1769 stx.stx_btime = old_btime;
1770
1771 ASSERT_EQ(ceph_setattrx(cmount, filename, &stx, CEPH_SETATTR_BTIME, 0), 0);
1772
1773 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_BTIME, 0), 0);
1774 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_BTIME);
1775 ASSERT_TRUE(timespec_eq(stx.stx_btime, old_btime));
1776
1777 ceph_shutdown(cmount);
1778 }
1779
1780 TEST(LibCephFS, LazyStatx) {
1781 struct ceph_mount_info *cmount1, *cmount2;
1782 ASSERT_EQ(ceph_create(&cmount1, NULL), 0);
1783 ASSERT_EQ(ceph_create(&cmount2, NULL), 0);
1784 ASSERT_EQ(ceph_conf_read_file(cmount1, NULL), 0);
1785 ASSERT_EQ(ceph_conf_read_file(cmount2, NULL), 0);
1786 ASSERT_EQ(0, ceph_conf_parse_env(cmount1, NULL));
1787 ASSERT_EQ(0, ceph_conf_parse_env(cmount2, NULL));
1788 ASSERT_EQ(ceph_mount(cmount1, "/"), 0);
1789 ASSERT_EQ(ceph_mount(cmount2, "/"), 0);
1790
1791 char filename[32];
1792 sprintf(filename, "lazystatx%x", getpid());
1793
1794 Inode *root1, *file1, *root2, *file2;
1795 struct ceph_statx stx;
1796 Fh *fh;
1797 UserPerm *perms1 = ceph_mount_perms(cmount1);
1798 UserPerm *perms2 = ceph_mount_perms(cmount2);
1799
1800 ASSERT_EQ(ceph_ll_lookup_root(cmount1, &root1), 0);
1801 ceph_ll_unlink(cmount1, root1, filename, perms1);
1802 ASSERT_EQ(ceph_ll_create(cmount1, root1, filename, 0666, O_RDWR|O_CREAT|O_EXCL,
1803 &file1, &fh, &stx, 0, 0, perms1), 0);
1804 ASSERT_EQ(ceph_ll_close(cmount1, fh), 0);
1805
1806 ASSERT_EQ(ceph_ll_lookup_root(cmount2, &root2), 0);
1807
1808 ASSERT_EQ(ceph_ll_lookup(cmount2, root2, filename, &file2, &stx, CEPH_STATX_CTIME, 0, perms2), 0);
1809
1810 struct timespec old_ctime = stx.stx_ctime;
1811
1812 /*
1813 * Now sleep, do a chmod on the first client and the see whether we get a
1814 * different ctime with a statx that uses AT_STATX_DONT_SYNC
1815 */
1816 sleep(1);
1817 stx.stx_mode = 0644;
1818 ASSERT_EQ(ceph_ll_setattr(cmount1, file1, &stx, CEPH_SETATTR_MODE, perms1), 0);
1819
1820 ASSERT_EQ(ceph_ll_getattr(cmount2, file2, &stx, CEPH_STATX_CTIME, AT_STATX_DONT_SYNC, perms2), 0);
1821 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_CTIME);
1822 ASSERT_TRUE(stx.stx_ctime.tv_sec == old_ctime.tv_sec &&
1823 stx.stx_ctime.tv_nsec == old_ctime.tv_nsec);
1824
1825 ceph_shutdown(cmount1);
1826 ceph_shutdown(cmount2);
1827 }
1828
1829 TEST(LibCephFS, ChangeAttr) {
1830 struct ceph_mount_info *cmount;
1831 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1832 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1833 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1834 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1835
1836 char filename[32];
1837 sprintf(filename, "/changeattr%x", getpid());
1838
1839 ceph_unlink(cmount, filename);
1840 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1841 ASSERT_LT(0, fd);
1842
1843 struct ceph_statx stx;
1844 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1845 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1846
1847 uint64_t old_change_attr = stx.stx_version;
1848
1849 /* do chmod, and check whether change_attr changed */
1850 ASSERT_EQ(ceph_chmod(cmount, filename, 0644), 0);
1851 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1852 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1853 ASSERT_NE(stx.stx_version, old_change_attr);
1854 old_change_attr = stx.stx_version;
1855
1856 /* now do a write and see if it changed again */
1857 ASSERT_EQ(3, ceph_write(cmount, fd, "foo", 3, 0));
1858 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1859 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1860 ASSERT_NE(stx.stx_version, old_change_attr);
1861 old_change_attr = stx.stx_version;
1862
1863 /* Now truncate and check again */
1864 ASSERT_EQ(0, ceph_ftruncate(cmount, fd, 0));
1865 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1866 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1867 ASSERT_NE(stx.stx_version, old_change_attr);
1868
1869 ceph_close(cmount, fd);
1870 ceph_shutdown(cmount);
1871 }
1872
1873 TEST(LibCephFS, DirChangeAttr) {
1874 struct ceph_mount_info *cmount;
1875 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1876 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1877 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1878 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1879
1880 char dirname[32], filename[56];
1881 sprintf(dirname, "/dirchange%x", getpid());
1882 sprintf(filename, "%s/foo", dirname);
1883
1884 ASSERT_EQ(ceph_mkdir(cmount, dirname, 0755), 0);
1885
1886 struct ceph_statx stx;
1887 ASSERT_EQ(ceph_statx(cmount, dirname, &stx, CEPH_STATX_VERSION, 0), 0);
1888 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1889
1890 uint64_t old_change_attr = stx.stx_version;
1891
1892 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1893 ASSERT_LT(0, fd);
1894 ceph_close(cmount, fd);
1895
1896 ASSERT_EQ(ceph_statx(cmount, dirname, &stx, CEPH_STATX_VERSION, 0), 0);
1897 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1898 ASSERT_NE(stx.stx_version, old_change_attr);
1899
1900 old_change_attr = stx.stx_version;
1901
1902 ASSERT_EQ(ceph_unlink(cmount, filename), 0);
1903 ASSERT_EQ(ceph_statx(cmount, dirname, &stx, CEPH_STATX_VERSION, 0), 0);
1904 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1905 ASSERT_NE(stx.stx_version, old_change_attr);
1906
1907 ceph_shutdown(cmount);
1908 }
1909
1910 TEST(LibCephFS, SetSize) {
1911 struct ceph_mount_info *cmount;
1912 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1913 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1914 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1915 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1916
1917 char filename[32];
1918 sprintf(filename, "/setsize%x", getpid());
1919
1920 ceph_unlink(cmount, filename);
1921 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1922 ASSERT_LT(0, fd);
1923
1924 struct ceph_statx stx;
1925 uint64_t size = 8388608;
1926 stx.stx_size = size;
1927 ASSERT_EQ(ceph_fsetattrx(cmount, fd, &stx, CEPH_SETATTR_SIZE), 0);
1928 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_SIZE, 0), 0);
1929 ASSERT_EQ(stx.stx_size, size);
1930
1931 ceph_close(cmount, fd);
1932 ceph_shutdown(cmount);
1933 }
1934
1935 TEST(LibCephFS, ClearSetuid) {
1936 struct ceph_mount_info *cmount;
1937 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1938 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1939 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1940 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1941
1942 Inode *root;
1943 ASSERT_EQ(ceph_ll_lookup_root(cmount, &root), 0);
1944
1945 char filename[32];
1946 sprintf(filename, "clearsetuid%x", getpid());
1947
1948 Fh *fh;
1949 Inode *in;
1950 struct ceph_statx stx;
1951 const mode_t after_mode = S_IRWXU;
1952 const mode_t before_mode = S_IRWXU | S_ISUID | S_ISGID;
1953 const unsigned want = CEPH_STATX_UID|CEPH_STATX_GID|CEPH_STATX_MODE;
1954 UserPerm *usercred = ceph_mount_perms(cmount);
1955
1956 ceph_ll_unlink(cmount, root, filename, usercred);
1957 ASSERT_EQ(ceph_ll_create(cmount, root, filename, before_mode,
1958 O_RDWR|O_CREAT|O_EXCL, &in, &fh, &stx, want, 0,
1959 usercred), 0);
1960
1961 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, before_mode);
1962
1963 // write
1964 ASSERT_EQ(ceph_ll_write(cmount, fh, 0, 3, "foo"), 3);
1965 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1966 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1967 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, after_mode);
1968
1969 // reset mode
1970 stx.stx_mode = before_mode;
1971 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE, usercred), 0);
1972 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1973 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1974 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, before_mode);
1975
1976 // truncate
1977 stx.stx_size = 1;
1978 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_SIZE, usercred), 0);
1979 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1980 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1981 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, after_mode);
1982
1983 // reset mode
1984 stx.stx_mode = before_mode;
1985 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE, usercred), 0);
1986 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1987 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1988 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, before_mode);
1989
1990 // chown -- for this we need to be "root"
1991 UserPerm *rootcred = ceph_userperm_new(0, 0, 0, NULL);
1992 ASSERT_TRUE(rootcred);
1993 stx.stx_uid++;
1994 stx.stx_gid++;
1995 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_UID|CEPH_SETATTR_GID, rootcred), 0);
1996 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1997 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1998 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, after_mode);
1999
2000 /* test chown with supplementary groups, and chown with/without exe bit */
2001 uid_t u = 65534;
2002 gid_t g = 65534;
2003 gid_t gids[] = {65533,65532};
2004 UserPerm *altcred = ceph_userperm_new(u, g, sizeof gids / sizeof gids[0], gids);
2005 stx.stx_uid = u;
2006 stx.stx_gid = g;
2007 mode_t m = S_ISGID|S_ISUID|S_IRUSR|S_IWUSR;
2008 stx.stx_mode = m;
2009 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE|CEPH_SETATTR_UID|CEPH_SETATTR_GID, rootcred), 0);
2010 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
2011 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m);
2012 /* not dropped without exe bit */
2013 stx.stx_gid = gids[0];
2014 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_GID, altcred), 0);
2015 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
2016 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m);
2017 /* now check dropped with exe bit */
2018 m = S_ISGID|S_ISUID|S_IRWXU;
2019 stx.stx_mode = m;
2020 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE, altcred), 0);
2021 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
2022 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m);
2023 stx.stx_gid = gids[1];
2024 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_GID, altcred), 0);
2025 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
2026 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m&(S_IRWXU|S_IRWXG|S_IRWXO));
2027 ceph_userperm_destroy(altcred);
2028
2029 ASSERT_EQ(ceph_ll_close(cmount, fh), 0);
2030 ceph_shutdown(cmount);
2031 }
2032
2033 TEST(LibCephFS, OperationsOnRoot)
2034 {
2035 struct ceph_mount_info *cmount;
2036 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2037 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2038 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2039 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
2040
2041 char dirname[32];
2042 sprintf(dirname, "/somedir%x", getpid());
2043
2044 ASSERT_EQ(ceph_mkdir(cmount, dirname, 0755), 0);
2045
2046 ASSERT_EQ(ceph_rmdir(cmount, "/"), -EBUSY);
2047
2048 ASSERT_EQ(ceph_link(cmount, "/", "/"), -EEXIST);
2049 ASSERT_EQ(ceph_link(cmount, dirname, "/"), -EEXIST);
2050 ASSERT_EQ(ceph_link(cmount, "nonExisitingDir", "/"), -ENOENT);
2051
2052 ASSERT_EQ(ceph_unlink(cmount, "/"), -EISDIR);
2053
2054 ASSERT_EQ(ceph_rename(cmount, "/", "/"), -EBUSY);
2055 ASSERT_EQ(ceph_rename(cmount, dirname, "/"), -EBUSY);
2056 ASSERT_EQ(ceph_rename(cmount, "nonExistingDir", "/"), -EBUSY);
2057 ASSERT_EQ(ceph_rename(cmount, "/", dirname), -EBUSY);
2058 ASSERT_EQ(ceph_rename(cmount, "/", "nonExistingDir"), -EBUSY);
2059
2060 ASSERT_EQ(ceph_mkdir(cmount, "/", 0777), -EEXIST);
2061
2062 ASSERT_EQ(ceph_mknod(cmount, "/", 0, 0), -EEXIST);
2063
2064 ASSERT_EQ(ceph_symlink(cmount, "/", "/"), -EEXIST);
2065 ASSERT_EQ(ceph_symlink(cmount, dirname, "/"), -EEXIST);
2066 ASSERT_EQ(ceph_symlink(cmount, "nonExistingDir", "/"), -EEXIST);
2067
2068 ceph_shutdown(cmount);
2069 }
2070
2071 static void shutdown_racer_func()
2072 {
2073 const int niter = 32;
2074 struct ceph_mount_info *cmount;
2075 int i;
2076
2077 for (i = 0; i < niter; ++i) {
2078 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2079 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2080 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2081 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
2082 ceph_shutdown(cmount);
2083 }
2084 }
2085
2086 // See tracker #20988
2087 TEST(LibCephFS, ShutdownRace)
2088 {
2089 const int nthreads = 32;
2090 std::thread threads[nthreads];
2091
2092 // Need a bunch of fd's for this test
2093 struct rlimit rold, rnew;
2094 ASSERT_EQ(getrlimit(RLIMIT_NOFILE, &rold), 0);
2095 rnew = rold;
2096 rnew.rlim_cur = rnew.rlim_max;
2097
2098 cout << "Setting RLIMIT_NOFILE from " << rold.rlim_cur <<
2099 " to " << rnew.rlim_cur << std::endl;
2100
2101 ASSERT_EQ(setrlimit(RLIMIT_NOFILE, &rnew), 0);
2102
2103 for (int i = 0; i < nthreads; ++i)
2104 threads[i] = std::thread(shutdown_racer_func);
2105
2106 for (int i = 0; i < nthreads; ++i)
2107 threads[i].join();
2108 /*
2109 * Let's just ignore restoring the open files limit,
2110 * the kernel will defer releasing the file descriptors
2111 * and then the process will be possibly reachthe open
2112 * files limit. More detail, please see tracer#43039
2113 */
2114 // ASSERT_EQ(setrlimit(RLIMIT_NOFILE, &rold), 0);
2115 }
2116
2117 static void get_current_time_utimbuf(struct utimbuf *utb)
2118 {
2119 utime_t t = ceph_clock_now();
2120 utb->actime = t.sec();
2121 utb->modtime = t.sec();
2122 }
2123
2124 static void get_current_time_timeval(struct timeval tv[2])
2125 {
2126 utime_t t = ceph_clock_now();
2127 t.copy_to_timeval(&tv[0]);
2128 t.copy_to_timeval(&tv[1]);
2129 }
2130
2131 static void get_current_time_timespec(struct timespec ts[2])
2132 {
2133 utime_t t = ceph_clock_now();
2134 t.to_timespec(&ts[0]);
2135 t.to_timespec(&ts[1]);
2136 }
2137
2138 TEST(LibCephFS, TestUtime) {
2139 struct ceph_mount_info *cmount;
2140 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2141 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2142 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2143 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2144
2145 char test_file[256];
2146 sprintf(test_file, "test_utime_file_%d", getpid());
2147 int fd = ceph_open(cmount, test_file, O_CREAT, 0666);
2148 ASSERT_GT(fd, 0);
2149
2150 struct utimbuf utb;
2151 struct ceph_statx stx;
2152
2153 get_current_time_utimbuf(&utb);
2154
2155 // ceph_utime()
2156 EXPECT_EQ(0, ceph_utime(cmount, test_file, &utb));
2157 ASSERT_EQ(ceph_statx(cmount, test_file, &stx,
2158 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
2159 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(utb.actime, 0));
2160 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(utb.modtime, 0));
2161
2162 get_current_time_utimbuf(&utb);
2163
2164 // ceph_futime()
2165 EXPECT_EQ(0, ceph_futime(cmount, fd, &utb));
2166 ASSERT_EQ(ceph_statx(cmount, test_file, &stx,
2167 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
2168 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(utb.actime, 0));
2169 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(utb.modtime, 0));
2170
2171 ceph_close(cmount, fd);
2172 ceph_shutdown(cmount);
2173 }
2174
2175 TEST(LibCephFS, TestUtimes) {
2176 struct ceph_mount_info *cmount;
2177 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2178 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2179 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2180 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2181
2182 char test_file[256];
2183 char test_symlink[256];
2184
2185 sprintf(test_file, "test_utimes_file_%d", getpid());
2186 sprintf(test_symlink, "test_utimes_symlink_%d", getpid());
2187 int fd = ceph_open(cmount, test_file, O_CREAT, 0666);
2188 ASSERT_GT(fd, 0);
2189
2190 ASSERT_EQ(ceph_symlink(cmount, test_file, test_symlink), 0);
2191
2192 struct timeval times[2];
2193 struct ceph_statx stx;
2194
2195 get_current_time_timeval(times);
2196
2197 // ceph_utimes() on symlink, validate target file time
2198 EXPECT_EQ(0, ceph_utimes(cmount, test_symlink, times));
2199 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx,
2200 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
2201 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(times[0]));
2202 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(times[1]));
2203
2204 get_current_time_timeval(times);
2205
2206 // ceph_lutimes() on symlink, validate symlink time
2207 EXPECT_EQ(0, ceph_lutimes(cmount, test_symlink, times));
2208 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx,
2209 CEPH_STATX_MTIME|CEPH_STATX_ATIME, AT_SYMLINK_NOFOLLOW), 0);
2210 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(times[0]));
2211 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(times[1]));
2212
2213 get_current_time_timeval(times);
2214
2215 // ceph_futimes()
2216 EXPECT_EQ(0, ceph_futimes(cmount, fd, times));
2217 ASSERT_EQ(ceph_statx(cmount, test_file, &stx,
2218 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
2219 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(times[0]));
2220 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(times[1]));
2221
2222 ceph_close(cmount, fd);
2223 ceph_shutdown(cmount);
2224 }
2225
2226 TEST(LibCephFS, TestFutimens) {
2227 struct ceph_mount_info *cmount;
2228 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2229 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2230 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2231 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2232
2233 char test_file[256];
2234
2235 sprintf(test_file, "test_futimens_file_%d", getpid());
2236 int fd = ceph_open(cmount, test_file, O_CREAT, 0666);
2237 ASSERT_GT(fd, 0);
2238
2239 struct timespec times[2];
2240 struct ceph_statx stx;
2241
2242 get_current_time_timespec(times);
2243
2244 // ceph_futimens()
2245 EXPECT_EQ(0, ceph_futimens(cmount, fd, times));
2246 ASSERT_EQ(ceph_statx(cmount, test_file, &stx,
2247 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
2248 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(times[0]));
2249 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(times[1]));
2250
2251 ceph_close(cmount, fd);
2252 ceph_shutdown(cmount);
2253 }
2254
2255 TEST(LibCephFS, OperationsOnDotDot) {
2256 struct ceph_mount_info *cmount;
2257 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2258 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2259 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2260 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2261
2262 char c_dir[512], c_dir_dot[1024], c_dir_dotdot[1024];
2263 char c_non_existent_dir[1024], c_non_existent_dirs[1024];
2264 char c_temp[1024];
2265
2266 pid_t mypid = getpid();
2267 sprintf(c_dir, "/oodd_dir_%d", mypid);
2268 sprintf(c_dir_dot, "/%s/.", c_dir);
2269 sprintf(c_dir_dotdot, "/%s/..", c_dir);
2270 sprintf(c_non_existent_dir, "/%s/../oodd_nonexistent/..", c_dir);
2271 sprintf(c_non_existent_dirs,
2272 "/%s/../ood_nonexistent1_%d/oodd_nonexistent2_%d", c_dir, mypid, mypid);
2273 sprintf(c_temp, "/oodd_temp_%d", mypid);
2274
2275 ASSERT_EQ(0, ceph_mkdir(cmount, c_dir, 0777));
2276 ASSERT_EQ(-EEXIST, ceph_mkdir(cmount, c_dir_dot, 0777));
2277 ASSERT_EQ(-EEXIST, ceph_mkdir(cmount, c_dir_dotdot, 0777));
2278 ASSERT_EQ(0, ceph_mkdirs(cmount, c_non_existent_dirs, 0777));
2279
2280 ASSERT_EQ(-ENOTEMPTY, ceph_rmdir(cmount, c_dir_dot));
2281 ASSERT_EQ(-ENOTEMPTY, ceph_rmdir(cmount, c_dir_dotdot));
2282 // non existent directory should return -ENOENT
2283 ASSERT_EQ(-ENOENT, ceph_rmdir(cmount, c_non_existent_dir));
2284
2285 ASSERT_EQ(-EBUSY, ceph_rename(cmount, c_dir_dot, c_temp));
2286 ASSERT_EQ(0, ceph_chdir(cmount, c_dir));
2287 ASSERT_EQ(0, ceph_mkdir(cmount, c_temp, 0777));
2288 ASSERT_EQ(-EBUSY, ceph_rename(cmount, c_temp, ".."));
2289
2290 ceph_shutdown(cmount);
2291 }
2292
2293 TEST(LibCephFS, Caps_vxattr) {
2294 struct ceph_mount_info *cmount;
2295 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2296 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2297 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2298 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2299
2300 char test_caps_vxattr_file[256];
2301 char gxattrv[128];
2302 int xbuflen = sizeof(gxattrv);
2303 pid_t mypid = getpid();
2304
2305 sprintf(test_caps_vxattr_file, "test_caps_vxattr_%d", mypid);
2306 int fd = ceph_open(cmount, test_caps_vxattr_file, O_CREAT, 0666);
2307 ASSERT_GT(fd, 0);
2308 ceph_close(cmount, fd);
2309
2310 int alen = ceph_getxattr(cmount, test_caps_vxattr_file, "ceph.caps", (void *)gxattrv, xbuflen);
2311 ASSERT_GT(alen, 0);
2312 gxattrv[alen] = '\0';
2313
2314 char caps_regex[] = "pA[sx]*L[sx]*X[sx]*F[sxcrwbal]*/0x[0-9a-fA-f]+";
2315 ASSERT_TRUE(regex_match(gxattrv, regex(caps_regex)) == 1);
2316 ceph_shutdown(cmount);
2317 }
2318
2319 TEST(LibCephFS, SnapXattrs) {
2320 struct ceph_mount_info *cmount;
2321 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2322 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2323 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2324 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2325
2326 char test_snap_xattr_file[256];
2327 char c_temp[PATH_MAX];
2328 char gxattrv[128];
2329 char gxattrv2[128];
2330 int xbuflen = sizeof(gxattrv);
2331 pid_t mypid = getpid();
2332
2333 sprintf(test_snap_xattr_file, "test_snap_xattr_%d", mypid);
2334 int fd = ceph_open(cmount, test_snap_xattr_file, O_CREAT, 0666);
2335 ASSERT_GT(fd, 0);
2336 ceph_close(cmount, fd);
2337
2338 sprintf(c_temp, "/.snap/test_snap_xattr_snap_%d", mypid);
2339 ASSERT_EQ(0, ceph_mkdir(cmount, c_temp, 0777));
2340
2341 int alen = ceph_getxattr(cmount, c_temp, "ceph.snap.btime", (void *)gxattrv, xbuflen);
2342 // xattr value is secs.nsecs (don't assume zero-term)
2343 ASSERT_LT(0, alen);
2344 ASSERT_LT(alen, xbuflen);
2345 gxattrv[alen] = '\0';
2346 char *s = strchrnul(gxattrv, '.');
2347 ASSERT_LT(s, gxattrv + alen);
2348 ASSERT_EQ('.', *s);
2349 *s = '\0';
2350 utime_t btime = utime_t(strtoull(gxattrv, NULL, 10), strtoull(s + 1, NULL, 10));
2351 *s = '.'; // restore for later strcmp
2352
2353 // file within the snapshot should carry the same btime
2354 sprintf(c_temp, "/.snap/test_snap_xattr_snap_%d/%s", mypid, test_snap_xattr_file);
2355
2356 int alen2 = ceph_getxattr(cmount, c_temp, "ceph.snap.btime", (void *)gxattrv2, xbuflen);
2357 ASSERT_EQ(alen, alen2);
2358 ASSERT_EQ(0, strncmp(gxattrv, gxattrv2, alen));
2359
2360 // non-snap file shouldn't carry the xattr
2361 alen = ceph_getxattr(cmount, test_snap_xattr_file, "ceph.snap.btime", (void *)gxattrv2, xbuflen);
2362 ASSERT_EQ(-ENODATA, alen);
2363
2364 // create a second snapshot
2365 sprintf(c_temp, "/.snap/test_snap_xattr_snap2_%d", mypid);
2366 ASSERT_EQ(0, ceph_mkdir(cmount, c_temp, 0777));
2367
2368 // check that the btime for the newer snapshot is > older
2369 alen = ceph_getxattr(cmount, c_temp, "ceph.snap.btime", (void *)gxattrv2, xbuflen);
2370 ASSERT_LT(0, alen);
2371 ASSERT_LT(alen, xbuflen);
2372 gxattrv2[alen] = '\0';
2373 s = strchrnul(gxattrv2, '.');
2374 ASSERT_LT(s, gxattrv2 + alen);
2375 ASSERT_EQ('.', *s);
2376 *s = '\0';
2377 utime_t new_btime = utime_t(strtoull(gxattrv2, NULL, 10), strtoull(s + 1, NULL, 10));
2378 ASSERT_LT(btime, new_btime);
2379
2380 // listxattr() shouldn't return snap.btime vxattr
2381 char xattrlist[512];
2382 int len = ceph_listxattr(cmount, test_snap_xattr_file, xattrlist, sizeof(xattrlist));
2383 ASSERT_GE(sizeof(xattrlist), (size_t)len);
2384 char *p = xattrlist;
2385 int found = 0;
2386 while (len > 0) {
2387 if (strcmp(p, "ceph.snap.btime") == 0)
2388 found++;
2389 len -= strlen(p) + 1;
2390 p += strlen(p) + 1;
2391 }
2392 ASSERT_EQ(found, 0);
2393
2394 ceph_shutdown(cmount);
2395 }
2396
2397 TEST(LibCephFS, SnapQuota) {
2398 struct ceph_mount_info *cmount;
2399 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2400 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2401 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2402 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2403
2404 char test_snap_dir_quota_xattr[256];
2405 char test_snap_subdir_quota_xattr[256];
2406 char test_snap_subdir_noquota_xattr[256];
2407 char xattrk[128];
2408 char xattrv[128];
2409 char c_temp[PATH_MAX];
2410 char gxattrv[128];
2411 int xbuflen = sizeof(gxattrv);
2412 pid_t mypid = getpid();
2413
2414 // create dir and set quota
2415 sprintf(test_snap_dir_quota_xattr, "test_snap_dir_quota_xattr_%d", mypid);
2416 ASSERT_EQ(0, ceph_mkdir(cmount, test_snap_dir_quota_xattr, 0777));
2417
2418 sprintf(xattrk, "ceph.quota.max_bytes");
2419 sprintf(xattrv, "65536");
2420 ASSERT_EQ(0, ceph_setxattr(cmount, test_snap_dir_quota_xattr, xattrk, (void *)xattrv, 5, XATTR_CREATE));
2421
2422 // create subdir and set quota
2423 sprintf(test_snap_subdir_quota_xattr, "test_snap_dir_quota_xattr_%d/subdir_quota", mypid);
2424 ASSERT_EQ(0, ceph_mkdirs(cmount, test_snap_subdir_quota_xattr, 0777));
2425
2426 sprintf(xattrk, "ceph.quota.max_bytes");
2427 sprintf(xattrv, "32768");
2428 ASSERT_EQ(0, ceph_setxattr(cmount, test_snap_subdir_quota_xattr, xattrk, (void *)xattrv, 5, XATTR_CREATE));
2429
2430 // create subdir with no quota
2431 sprintf(test_snap_subdir_noquota_xattr, "test_snap_dir_quota_xattr_%d/subdir_noquota", mypid);
2432 ASSERT_EQ(0, ceph_mkdirs(cmount, test_snap_subdir_noquota_xattr, 0777));
2433
2434 // snapshot dir
2435 sprintf(c_temp, "/.snap/test_snap_dir_quota_xattr_snap_%d", mypid);
2436 ASSERT_EQ(0, ceph_mkdirs(cmount, c_temp, 0777));
2437
2438 // check dir quota under snap
2439 sprintf(c_temp, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d", mypid, mypid);
2440 int alen = ceph_getxattr(cmount, c_temp, "ceph.quota.max_bytes", (void *)gxattrv, xbuflen);
2441 ASSERT_LT(0, alen);
2442 ASSERT_LT(alen, xbuflen);
2443 gxattrv[alen] = '\0';
2444 ASSERT_STREQ(gxattrv, "65536");
2445
2446 // check subdir quota under snap
2447 sprintf(c_temp, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d/subdir_quota", mypid, mypid);
2448 alen = ceph_getxattr(cmount, c_temp, "ceph.quota.max_bytes", (void *)gxattrv, xbuflen);
2449 ASSERT_LT(0, alen);
2450 ASSERT_LT(alen, xbuflen);
2451 gxattrv[alen] = '\0';
2452 ASSERT_STREQ(gxattrv, "32768");
2453
2454 // ensure subdir noquota xattr under snap
2455 sprintf(c_temp, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d/subdir_noquota", mypid, mypid);
2456 EXPECT_EQ(-ENODATA, ceph_getxattr(cmount, c_temp, "ceph.quota.max_bytes", (void *)gxattrv, xbuflen));
2457
2458 // listxattr() shouldn't return ceph.quota.max_bytes vxattr
2459 sprintf(c_temp, "/.snap/test_snap_dir_quota_xattr_snap_%d/test_snap_dir_quota_xattr_%d", mypid, mypid);
2460 char xattrlist[512];
2461 int len = ceph_listxattr(cmount, c_temp, xattrlist, sizeof(xattrlist));
2462 ASSERT_GE(sizeof(xattrlist), (size_t)len);
2463 char *p = xattrlist;
2464 int found = 0;
2465 while (len > 0) {
2466 if (strcmp(p, "ceph.quota.max_bytes") == 0)
2467 found++;
2468 len -= strlen(p) + 1;
2469 p += strlen(p) + 1;
2470 }
2471 ASSERT_EQ(found, 0);
2472
2473 ceph_shutdown(cmount);
2474 }
2475
2476 TEST(LibCephFS, Lseek) {
2477 struct ceph_mount_info *cmount;
2478 ASSERT_EQ(0, ceph_create(&cmount, NULL));
2479 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
2480 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2481 ASSERT_EQ(0, ceph_mount(cmount, "/"));
2482
2483 char c_path[1024];
2484 sprintf(c_path, "test_lseek_%d", getpid());
2485 int fd = ceph_open(cmount, c_path, O_RDWR|O_CREAT|O_TRUNC, 0666);
2486 ASSERT_LT(0, fd);
2487
2488 const char *out_buf = "hello world";
2489 size_t size = strlen(out_buf);
2490 ASSERT_EQ(ceph_write(cmount, fd, out_buf, size, 0), (int)size);
2491
2492 /* basic SEEK_SET/END/CUR tests */
2493 ASSERT_EQ(0, ceph_lseek(cmount, fd, 0, SEEK_SET));
2494 ASSERT_EQ(size, ceph_lseek(cmount, fd, 0, SEEK_END));
2495 ASSERT_EQ(0, ceph_lseek(cmount, fd, -size, SEEK_CUR));
2496
2497 /* Test basic functionality and out of bounds conditions for SEEK_HOLE/DATA */
2498 #ifdef SEEK_HOLE
2499 ASSERT_EQ(size, ceph_lseek(cmount, fd, 0, SEEK_HOLE));
2500 ASSERT_EQ(-ENXIO, ceph_lseek(cmount, fd, -1, SEEK_HOLE));
2501 ASSERT_EQ(-ENXIO, ceph_lseek(cmount, fd, size + 1, SEEK_HOLE));
2502 #endif
2503 #ifdef SEEK_DATA
2504 ASSERT_EQ(0, ceph_lseek(cmount, fd, 0, SEEK_DATA));
2505 ASSERT_EQ(-ENXIO, ceph_lseek(cmount, fd, -1, SEEK_DATA));
2506 ASSERT_EQ(-ENXIO, ceph_lseek(cmount, fd, size + 1, SEEK_DATA));
2507 #endif
2508
2509 ASSERT_EQ(0, ceph_close(cmount, fd));
2510 ceph_shutdown(cmount);
2511 }
2512
2513 TEST(LibCephFS, SnapInfoOnNonSnapshot) {
2514 struct ceph_mount_info *cmount;
2515 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2516 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2517 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2518 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2519
2520 struct snap_info info;
2521 ASSERT_EQ(-EINVAL, ceph_get_snap_info(cmount, "/", &info));
2522
2523 ceph_shutdown(cmount);
2524 }
2525
2526 TEST(LibCephFS, EmptySnapInfo) {
2527 struct ceph_mount_info *cmount;
2528 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2529 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2530 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2531 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2532
2533 char dir_path[64];
2534 char snap_path[PATH_MAX];
2535 sprintf(dir_path, "/dir0_%d", getpid());
2536 sprintf(snap_path, "%s/.snap/snap0_%d", dir_path, getpid());
2537
2538 ASSERT_EQ(0, ceph_mkdir(cmount, dir_path, 0755));
2539 // snapshot without custom metadata
2540 ASSERT_EQ(0, ceph_mkdir(cmount, snap_path, 0755));
2541
2542 struct snap_info info;
2543 ASSERT_EQ(0, ceph_get_snap_info(cmount, snap_path, &info));
2544 ASSERT_GT(info.id, 0);
2545 ASSERT_EQ(info.nr_snap_metadata, 0);
2546
2547 ASSERT_EQ(0, ceph_rmdir(cmount, snap_path));
2548 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
2549 ceph_shutdown(cmount);
2550 }
2551
2552 TEST(LibCephFS, SnapInfo) {
2553 struct ceph_mount_info *cmount;
2554 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2555 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2556 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2557 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2558
2559 char dir_path[64];
2560 char snap_name[64];
2561 char snap_path[PATH_MAX];
2562 sprintf(dir_path, "/dir0_%d", getpid());
2563 sprintf(snap_name, "snap0_%d", getpid());
2564 sprintf(snap_path, "%s/.snap/%s", dir_path, snap_name);
2565
2566 ASSERT_EQ(0, ceph_mkdir(cmount, dir_path, 0755));
2567 // snapshot with custom metadata
2568 struct snap_metadata snap_meta[] = {{"foo", "bar"},{"this", "that"},{"abcdefg", "12345"}};
2569 ASSERT_EQ(0, ceph_mksnap(cmount, dir_path, snap_name, 0755, snap_meta, std::size(snap_meta)));
2570
2571 struct snap_info info;
2572 ASSERT_EQ(0, ceph_get_snap_info(cmount, snap_path, &info));
2573 ASSERT_GT(info.id, 0);
2574 ASSERT_EQ(info.nr_snap_metadata, std::size(snap_meta));
2575 for (size_t i = 0; i < info.nr_snap_metadata; ++i) {
2576 auto &k1 = info.snap_metadata[i].key;
2577 auto &v1 = info.snap_metadata[i].value;
2578 bool found = false;
2579 for (size_t j = 0; j < info.nr_snap_metadata; ++j) {
2580 auto &k2 = snap_meta[j].key;
2581 auto &v2 = snap_meta[j].value;
2582 if (strncmp(k1, k2, strlen(k1)) == 0 && strncmp(v1, v2, strlen(v1)) == 0) {
2583 found = true;
2584 break;
2585 }
2586 }
2587 ASSERT_TRUE(found);
2588 }
2589 ceph_free_snap_info_buffer(&info);
2590
2591 ASSERT_EQ(0, ceph_rmsnap(cmount, dir_path, snap_name));
2592 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
2593
2594 ceph_shutdown(cmount);
2595 }
2596
2597 TEST(LibCephFS, LookupInoMDSDir) {
2598 struct ceph_mount_info *cmount;
2599 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2600 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2601 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2602 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2603
2604 Inode *inode;
2605 auto ino = inodeno_t(0x100); /* rank 0 ~mdsdir */
2606 ASSERT_EQ(-ESTALE, ceph_ll_lookup_inode(cmount, ino, &inode));
2607 ino = inodeno_t(0x600); /* rank 0 first stray dir */
2608 ASSERT_EQ(-ESTALE, ceph_ll_lookup_inode(cmount, ino, &inode));
2609
2610 ceph_shutdown(cmount);
2611 }
2612
2613 TEST(LibCephFS, LookupVino) {
2614 struct ceph_mount_info *cmount;
2615 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2616 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2617 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2618 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2619
2620 char dir_path[64];
2621 char snap_name[64];
2622 char snapdir_path[128];
2623 char snap_path[256];
2624 char file_path[PATH_MAX];
2625 char snap_file[PATH_MAX];
2626 sprintf(dir_path, "/dir0_%d", getpid());
2627 sprintf(snap_name, "snap0_%d", getpid());
2628 sprintf(file_path, "%s/file_%d", dir_path, getpid());
2629 sprintf(snapdir_path, "%s/.snap", dir_path);
2630 sprintf(snap_path, "%s/%s", snapdir_path, snap_name);
2631 sprintf(snap_file, "%s/file_%d", snap_path, getpid());
2632
2633 ASSERT_EQ(0, ceph_mkdir(cmount, dir_path, 0755));
2634 int fd = ceph_open(cmount, file_path, O_WRONLY|O_CREAT, 0666);
2635 ASSERT_LE(0, fd);
2636 ASSERT_EQ(0, ceph_close(cmount, fd));
2637 ASSERT_EQ(0, ceph_mksnap(cmount, dir_path, snap_name, 0755, nullptr, 0));
2638
2639 // record vinos for all of them
2640 struct ceph_statx stx;
2641 ASSERT_EQ(0, ceph_statx(cmount, dir_path, &stx, CEPH_STATX_INO, 0));
2642 vinodeno_t dir_vino(stx.stx_ino, stx.stx_dev);
2643
2644 ASSERT_EQ(0, ceph_statx(cmount, file_path, &stx, CEPH_STATX_INO, 0));
2645 vinodeno_t file_vino(stx.stx_ino, stx.stx_dev);
2646
2647 ASSERT_EQ(0, ceph_statx(cmount, snapdir_path, &stx, CEPH_STATX_INO, 0));
2648 vinodeno_t snapdir_vino(stx.stx_ino, stx.stx_dev);
2649
2650 ASSERT_EQ(0, ceph_statx(cmount, snap_path, &stx, CEPH_STATX_INO, 0));
2651 vinodeno_t snap_vino(stx.stx_ino, stx.stx_dev);
2652
2653 ASSERT_EQ(0, ceph_statx(cmount, snap_file, &stx, CEPH_STATX_INO, 0));
2654 vinodeno_t snap_file_vino(stx.stx_ino, stx.stx_dev);
2655
2656 // Remount
2657 ASSERT_EQ(0, ceph_unmount(cmount));
2658 ASSERT_EQ(0, ceph_create(&cmount, NULL));
2659 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
2660 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2661 ASSERT_EQ(0, ceph_mount(cmount, NULL));
2662
2663 // Find them all
2664 Inode *inode;
2665 ASSERT_EQ(0, ceph_ll_lookup_vino(cmount, dir_vino, &inode));
2666 ceph_ll_put(cmount, inode);
2667 ASSERT_EQ(0, ceph_ll_lookup_vino(cmount, file_vino, &inode));
2668 ceph_ll_put(cmount, inode);
2669 ASSERT_EQ(0, ceph_ll_lookup_vino(cmount, snapdir_vino, &inode));
2670 ceph_ll_put(cmount, inode);
2671 ASSERT_EQ(0, ceph_ll_lookup_vino(cmount, snap_vino, &inode));
2672 ceph_ll_put(cmount, inode);
2673 ASSERT_EQ(0, ceph_ll_lookup_vino(cmount, snap_file_vino, &inode));
2674 ceph_ll_put(cmount, inode);
2675
2676 // cleanup
2677 ASSERT_EQ(0, ceph_rmsnap(cmount, dir_path, snap_name));
2678 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
2679 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
2680
2681 ceph_shutdown(cmount);
2682 }
2683
2684 TEST(LibCephFS, Openat) {
2685 pid_t mypid = getpid();
2686 struct ceph_mount_info *cmount;
2687 ASSERT_EQ(0, ceph_create(&cmount, NULL));
2688 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
2689 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2690 ASSERT_EQ(0, ceph_mount(cmount, "/"));
2691
2692 char c_rel_dir[64];
2693 char c_dir[128];
2694 sprintf(c_rel_dir, "open_test_%d", mypid);
2695 sprintf(c_dir, "/%s", c_rel_dir);
2696 ASSERT_EQ(0, ceph_mkdir(cmount, c_dir, 0777));
2697
2698 int root_fd = ceph_open(cmount, "/", O_DIRECTORY | O_RDONLY, 0);
2699 ASSERT_LE(0, root_fd);
2700
2701 int dir_fd = ceph_openat(cmount, root_fd, c_rel_dir, O_DIRECTORY | O_RDONLY, 0);
2702 ASSERT_LE(0, dir_fd);
2703
2704 struct ceph_statx stx;
2705 ASSERT_EQ(ceph_statxat(cmount, root_fd, c_rel_dir, &stx, 0, 0), 0);
2706 ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFDIR);
2707
2708 char c_rel_path[64];
2709 char c_path[256];
2710 sprintf(c_rel_path, "created_file_%d", mypid);
2711 sprintf(c_path, "%s/created_file_%d", c_dir, mypid);
2712 int file_fd = ceph_openat(cmount, dir_fd, c_rel_path, O_RDONLY | O_CREAT, 0666);
2713 ASSERT_LE(0, file_fd);
2714
2715 ASSERT_EQ(ceph_statxat(cmount, dir_fd, c_rel_path, &stx, 0, 0), 0);
2716 ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
2717
2718 ASSERT_EQ(0, ceph_close(cmount, file_fd));
2719 ASSERT_EQ(0, ceph_close(cmount, dir_fd));
2720 ASSERT_EQ(0, ceph_close(cmount, root_fd));
2721
2722 ASSERT_EQ(0, ceph_unlink(cmount, c_path));
2723 ASSERT_EQ(0, ceph_rmdir(cmount, c_dir));
2724
2725 ceph_shutdown(cmount);
2726 }
2727
2728 TEST(LibCephFS, Statxat) {
2729 struct ceph_mount_info *cmount;
2730 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2731 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2732 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2733 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2734
2735 char dir_name[64];
2736 char rel_file_name_1[128];
2737 char rel_file_name_2[256];
2738
2739 char dir_path[512];
2740 char file_path[1024];
2741
2742 // relative paths for *at() calls
2743 sprintf(dir_name, "dir0_%d", getpid());
2744 sprintf(rel_file_name_1, "file_%d", getpid());
2745 sprintf(rel_file_name_2, "%s/%s", dir_name, rel_file_name_1);
2746
2747 sprintf(dir_path, "/%s", dir_name);
2748 sprintf(file_path, "%s/%s", dir_path, rel_file_name_1);
2749
2750 ASSERT_EQ(0, ceph_mkdir(cmount, dir_path, 0755));
2751 int fd = ceph_open(cmount, file_path, O_WRONLY|O_CREAT, 0666);
2752 ASSERT_LE(0, fd);
2753 ASSERT_EQ(0, ceph_close(cmount, fd));
2754
2755 struct ceph_statx stx;
2756
2757 // test relative to root
2758 fd = ceph_open(cmount, "/", O_DIRECTORY | O_RDONLY, 0);
2759 ASSERT_LE(0, fd);
2760 ASSERT_EQ(ceph_statxat(cmount, fd, dir_name, &stx, 0, 0), 0);
2761 ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFDIR);
2762 ASSERT_EQ(ceph_statxat(cmount, fd, rel_file_name_2, &stx, 0, 0), 0);
2763 ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
2764 ASSERT_EQ(0, ceph_close(cmount, fd));
2765
2766 // test relative to dir
2767 fd = ceph_open(cmount, dir_path, O_DIRECTORY | O_RDONLY, 0);
2768 ASSERT_LE(0, fd);
2769 ASSERT_EQ(ceph_statxat(cmount, fd, rel_file_name_1, &stx, 0, 0), 0);
2770 ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
2771
2772 // delete the dirtree, recreate and verify
2773 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
2774 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
2775 ASSERT_EQ(0, ceph_mkdir(cmount, dir_path, 0755));
2776 int fd1 = ceph_open(cmount, file_path, O_WRONLY|O_CREAT, 0666);
2777 ASSERT_LE(0, fd1);
2778 ASSERT_EQ(0, ceph_close(cmount, fd1));
2779 ASSERT_EQ(ceph_statxat(cmount, fd, rel_file_name_1, &stx, 0, 0), -ENOENT);
2780 ASSERT_EQ(0, ceph_close(cmount, fd));
2781
2782 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
2783 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
2784
2785 ceph_shutdown(cmount);
2786 }
2787
2788 TEST(LibCephFS, StatxatATFDCWD) {
2789 struct ceph_mount_info *cmount;
2790 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2791 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2792 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2793 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
2794
2795 char dir_name[64];
2796 char rel_file_name_1[128];
2797
2798 char dir_path[512];
2799 char file_path[1024];
2800
2801 // relative paths for *at() calls
2802 sprintf(dir_name, "dir0_%d", getpid());
2803 sprintf(rel_file_name_1, "file_%d", getpid());
2804
2805 sprintf(dir_path, "/%s", dir_name);
2806 sprintf(file_path, "%s/%s", dir_path, rel_file_name_1);
2807
2808 ASSERT_EQ(0, ceph_mkdir(cmount, dir_path, 0755));
2809 int fd = ceph_open(cmount, file_path, O_WRONLY|O_CREAT, 0666);
2810 ASSERT_LE(0, fd);
2811 ASSERT_EQ(0, ceph_close(cmount, fd));
2812
2813 struct ceph_statx stx;
2814 // chdir and test with CEPHFS_AT_FDCWD
2815 ASSERT_EQ(0, ceph_chdir(cmount, dir_path));
2816 ASSERT_EQ(ceph_statxat(cmount, CEPHFS_AT_FDCWD, rel_file_name_1, &stx, 0, 0), 0);
2817 ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
2818
2819 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
2820 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
2821
2822 ceph_shutdown(cmount);
2823 }
2824
2825 TEST(LibCephFS, Fdopendir) {
2826 pid_t mypid = getpid();
2827
2828 struct ceph_mount_info *cmount;
2829 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2830 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2831 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2832 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
2833
2834 char foostr[256];
2835 sprintf(foostr, "/dir_ls%d", mypid);
2836 ASSERT_EQ(ceph_mkdir(cmount, foostr, 0777), 0);
2837
2838 char bazstr[512];
2839 sprintf(bazstr, "%s/elif", foostr);
2840 int fd = ceph_open(cmount, bazstr, O_CREAT|O_RDONLY, 0666);
2841 ASSERT_LE(0, fd);
2842 ASSERT_EQ(0, ceph_close(cmount, fd));
2843
2844 fd = ceph_open(cmount, foostr, O_DIRECTORY | O_RDONLY, 0);
2845 ASSERT_LE(0, fd);
2846 struct ceph_dir_result *ls_dir = NULL;
2847 ASSERT_EQ(ceph_fdopendir(cmount, fd, &ls_dir), 0);
2848
2849 // not guaranteed to get . and .. first, but its a safe assumption in this case
2850 struct dirent *result = ceph_readdir(cmount, ls_dir);
2851 ASSERT_TRUE(result != NULL);
2852 ASSERT_STREQ(result->d_name, ".");
2853 result = ceph_readdir(cmount, ls_dir);
2854 ASSERT_TRUE(result != NULL);
2855 ASSERT_STREQ(result->d_name, "..");
2856 result = ceph_readdir(cmount, ls_dir);
2857 ASSERT_TRUE(result != NULL);
2858 ASSERT_STREQ(result->d_name, "elif");
2859
2860 ASSERT_TRUE(ceph_readdir(cmount, ls_dir) == NULL);
2861
2862 ASSERT_EQ(0, ceph_close(cmount, fd));
2863 ASSERT_EQ(0, ceph_closedir(cmount, ls_dir));
2864 ASSERT_EQ(0, ceph_unlink(cmount, bazstr));
2865 ASSERT_EQ(0, ceph_rmdir(cmount, foostr));
2866 ceph_shutdown(cmount);
2867 }
2868
2869 TEST(LibCephFS, FdopendirATFDCWD) {
2870 pid_t mypid = getpid();
2871
2872 struct ceph_mount_info *cmount;
2873 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2874 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2875 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2876 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
2877
2878 char foostr[256];
2879 sprintf(foostr, "/dir_ls%d", mypid);
2880 ASSERT_EQ(ceph_mkdir(cmount, foostr, 0777), 0);
2881
2882 char bazstr[512];
2883 sprintf(bazstr, "%s/elif", foostr);
2884 int fd = ceph_open(cmount, bazstr, O_CREAT|O_RDONLY, 0666);
2885 ASSERT_LE(0, fd);
2886 ASSERT_EQ(0, ceph_close(cmount, fd));
2887
2888 ASSERT_EQ(0, ceph_chdir(cmount, foostr));
2889 struct ceph_dir_result *ls_dir = NULL;
2890 ASSERT_EQ(ceph_fdopendir(cmount, CEPHFS_AT_FDCWD, &ls_dir), 0);
2891
2892 // not guaranteed to get . and .. first, but its a safe assumption in this case
2893 struct dirent *result = ceph_readdir(cmount, ls_dir);
2894 ASSERT_TRUE(result != NULL);
2895 ASSERT_STREQ(result->d_name, ".");
2896 result = ceph_readdir(cmount, ls_dir);
2897 ASSERT_TRUE(result != NULL);
2898 ASSERT_STREQ(result->d_name, "..");
2899 result = ceph_readdir(cmount, ls_dir);
2900 ASSERT_TRUE(result != NULL);
2901 ASSERT_STREQ(result->d_name, "elif");
2902
2903 ASSERT_TRUE(ceph_readdir(cmount, ls_dir) == NULL);
2904
2905 ASSERT_EQ(0, ceph_closedir(cmount, ls_dir));
2906 ASSERT_EQ(0, ceph_unlink(cmount, bazstr));
2907 ASSERT_EQ(0, ceph_rmdir(cmount, foostr));
2908 ceph_shutdown(cmount);
2909 }
2910
2911 TEST(LibCephFS, FdopendirReaddirTestWithDelete) {
2912 pid_t mypid = getpid();
2913
2914 struct ceph_mount_info *cmount;
2915 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2916 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2917 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2918 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
2919
2920 char foostr[256];
2921 sprintf(foostr, "/dir_ls%d", mypid);
2922 ASSERT_EQ(ceph_mkdir(cmount, foostr, 0777), 0);
2923
2924 char bazstr[512];
2925 sprintf(bazstr, "%s/elif", foostr);
2926 int fd = ceph_open(cmount, bazstr, O_CREAT|O_RDONLY, 0666);
2927 ASSERT_LE(0, fd);
2928 ASSERT_EQ(0, ceph_close(cmount, fd));
2929
2930 fd = ceph_open(cmount, foostr, O_DIRECTORY | O_RDONLY, 0);
2931 ASSERT_LE(0, fd);
2932 struct ceph_dir_result *ls_dir = NULL;
2933 ASSERT_EQ(ceph_fdopendir(cmount, fd, &ls_dir), 0);
2934
2935 ASSERT_EQ(0, ceph_unlink(cmount, bazstr));
2936 ASSERT_EQ(0, ceph_rmdir(cmount, foostr));
2937
2938 // not guaranteed to get . and .. first, but its a safe assumption
2939 // in this case. also, note that we may or may not get other
2940 // entries.
2941 struct dirent *result = ceph_readdir(cmount, ls_dir);
2942 ASSERT_TRUE(result != NULL);
2943 ASSERT_STREQ(result->d_name, ".");
2944 result = ceph_readdir(cmount, ls_dir);
2945 ASSERT_TRUE(result != NULL);
2946 ASSERT_STREQ(result->d_name, "..");
2947
2948 ASSERT_EQ(0, ceph_close(cmount, fd));
2949 ASSERT_EQ(0, ceph_closedir(cmount, ls_dir));
2950 ceph_shutdown(cmount);
2951 }
2952
2953 TEST(LibCephFS, FdopendirOnNonDir) {
2954 pid_t mypid = getpid();
2955
2956 struct ceph_mount_info *cmount;
2957 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2958 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2959 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2960 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
2961
2962 char foostr[256];
2963 sprintf(foostr, "/dir_ls%d", mypid);
2964 ASSERT_EQ(ceph_mkdir(cmount, foostr, 0777), 0);
2965
2966 char bazstr[512];
2967 sprintf(bazstr, "%s/file", foostr);
2968 int fd = ceph_open(cmount, bazstr, O_CREAT|O_RDONLY, 0666);
2969 ASSERT_LE(0, fd);
2970
2971 struct ceph_dir_result *ls_dir = NULL;
2972 ASSERT_EQ(ceph_fdopendir(cmount, fd, &ls_dir), -ENOTDIR);
2973 ASSERT_EQ(0, ceph_close(cmount, fd));
2974
2975 ASSERT_EQ(0, ceph_unlink(cmount, bazstr));
2976 ASSERT_EQ(0, ceph_rmdir(cmount, foostr));
2977
2978 ceph_shutdown(cmount);
2979 }
2980
2981 TEST(LibCephFS, Mkdirat) {
2982 pid_t mypid = getpid();
2983
2984 struct ceph_mount_info *cmount;
2985 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
2986 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
2987 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
2988 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
2989
2990 char dir_name[128];
2991 char dir_path1[256];
2992 sprintf(dir_name, "dir_%d", mypid);
2993 sprintf(dir_path1, "/%s", dir_name);
2994
2995 char dir_path2[512];
2996 char rel_dir_path2[512];
2997 sprintf(dir_path2, "%s/dir_%d", dir_path1, mypid);
2998 sprintf(rel_dir_path2, "%s/dir_%d", dir_name, mypid);
2999
3000 int fd = ceph_open(cmount, "/", O_DIRECTORY | O_RDONLY, 0);
3001 ASSERT_LE(0, fd);
3002
3003 ASSERT_EQ(0, ceph_mkdirat(cmount, fd, dir_name, 0777));
3004 ASSERT_EQ(0, ceph_mkdirat(cmount, fd, rel_dir_path2, 0666));
3005
3006 ASSERT_EQ(0, ceph_close(cmount, fd));
3007 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path2));
3008 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path1));
3009 ceph_shutdown(cmount);
3010 }
3011
3012 TEST(LibCephFS, MkdiratATFDCWD) {
3013 pid_t mypid = getpid();
3014
3015 struct ceph_mount_info *cmount;
3016 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3017 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3018 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3019 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
3020
3021 char dir_name[128];
3022 char dir_path1[256];
3023 sprintf(dir_name, "dir_%d", mypid);
3024 sprintf(dir_path1, "/%s", dir_name);
3025
3026 char dir_path2[512];
3027 sprintf(dir_path2, "%s/dir_%d", dir_path1, mypid);
3028
3029 ASSERT_EQ(0, ceph_mkdirat(cmount, CEPHFS_AT_FDCWD, dir_name, 0777));
3030
3031 ASSERT_EQ(0, ceph_chdir(cmount, dir_path1));
3032 ASSERT_EQ(0, ceph_mkdirat(cmount, CEPHFS_AT_FDCWD, dir_name, 0666));
3033
3034 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path2));
3035 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path1));
3036 ceph_shutdown(cmount);
3037 }
3038
3039 TEST(LibCephFS, Readlinkat) {
3040 pid_t mypid = getpid();
3041
3042 struct ceph_mount_info *cmount;
3043 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3044 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3045 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3046 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
3047
3048 char dir_name[128];
3049 char dir_path[256];
3050 sprintf(dir_name, "dir_%d", mypid);
3051 sprintf(dir_path, "/%s", dir_name);
3052 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3053
3054 char file_path[512];
3055 char rel_file_path[512];
3056 sprintf(rel_file_path, "%s/elif", dir_name);
3057 sprintf(file_path, "%s/elif", dir_path);
3058 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDONLY, 0666);
3059 ASSERT_LE(0, fd);
3060 ASSERT_EQ(0, ceph_close(cmount, fd));
3061
3062 char link_path[128];
3063 char rel_link_path[64];
3064 sprintf(rel_link_path, "linkfile_%d", mypid);
3065 sprintf(link_path, "/%s", rel_link_path);
3066 ASSERT_EQ(0, ceph_symlink(cmount, rel_file_path, link_path));
3067
3068 fd = ceph_open(cmount, "/", O_DIRECTORY | O_RDONLY, 0);
3069 ASSERT_LE(0, fd);
3070 size_t target_len = strlen(rel_file_path);
3071 char target[target_len+1];
3072 ASSERT_EQ(target_len, ceph_readlinkat(cmount, fd, rel_link_path, target, target_len));
3073 target[target_len] = '\0';
3074 ASSERT_EQ(0, memcmp(target, rel_file_path, target_len));
3075
3076 ASSERT_EQ(0, ceph_close(cmount, fd));
3077 ASSERT_EQ(0, ceph_unlink(cmount, link_path));
3078 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
3079 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
3080 ceph_shutdown(cmount);
3081 }
3082
3083 TEST(LibCephFS, ReadlinkatATFDCWD) {
3084 pid_t mypid = getpid();
3085
3086 struct ceph_mount_info *cmount;
3087 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3088 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3089 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3090 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
3091
3092 char dir_name[128];
3093 char dir_path[256];
3094 sprintf(dir_name, "dir_%d", mypid);
3095 sprintf(dir_path, "/%s", dir_name);
3096 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3097
3098 char file_path[512];
3099 char rel_file_path[512] = "./elif";
3100 sprintf(file_path, "%s/elif", dir_path);
3101 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDONLY, 0666);
3102 ASSERT_LE(0, fd);
3103 ASSERT_EQ(0, ceph_close(cmount, fd));
3104
3105 char link_path[PATH_MAX];
3106 char rel_link_path[1024];
3107 sprintf(rel_link_path, "./linkfile_%d", mypid);
3108 sprintf(link_path, "%s/%s", dir_path, rel_link_path);
3109 ASSERT_EQ(0, ceph_symlink(cmount, rel_file_path, link_path));
3110
3111 ASSERT_EQ(0, ceph_chdir(cmount, dir_path));
3112 size_t target_len = strlen(rel_file_path);
3113 char target[target_len+1];
3114 ASSERT_EQ(target_len, ceph_readlinkat(cmount, CEPHFS_AT_FDCWD, rel_link_path, target, target_len));
3115 target[target_len] = '\0';
3116 ASSERT_EQ(0, memcmp(target, rel_file_path, target_len));
3117
3118 ASSERT_EQ(0, ceph_unlink(cmount, link_path));
3119 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
3120 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
3121 ceph_shutdown(cmount);
3122 }
3123
3124 TEST(LibCephFS, Symlinkat) {
3125 pid_t mypid = getpid();
3126
3127 struct ceph_mount_info *cmount;
3128 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3129 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3130 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3131 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
3132
3133 char dir_name[128];
3134 char dir_path[256];
3135 sprintf(dir_name, "dir_%d", mypid);
3136 sprintf(dir_path, "/%s", dir_name);
3137 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3138
3139 char file_path[512];
3140 char rel_file_path[512];
3141 sprintf(rel_file_path, "%s/elif", dir_name);
3142 sprintf(file_path, "%s/elif", dir_path);
3143
3144 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDONLY, 0666);
3145 ASSERT_LE(0, fd);
3146 ASSERT_EQ(0, ceph_close(cmount, fd));
3147
3148 char link_path[128];
3149 char rel_link_path[64];
3150 sprintf(rel_link_path, "linkfile_%d", mypid);
3151 sprintf(link_path, "/%s", rel_link_path);
3152
3153 fd = ceph_open(cmount, "/", O_DIRECTORY | O_RDONLY, 0);
3154 ASSERT_LE(0, fd);
3155 ASSERT_EQ(0, ceph_symlinkat(cmount, rel_file_path, fd, rel_link_path));
3156
3157 size_t target_len = strlen(rel_file_path);
3158 char target[target_len+1];
3159 ASSERT_EQ(target_len, ceph_readlinkat(cmount, fd, rel_link_path, target, target_len));
3160 target[target_len] = '\0';
3161 ASSERT_EQ(0, memcmp(target, rel_file_path, target_len));
3162
3163 ASSERT_EQ(0, ceph_close(cmount, fd));
3164 ASSERT_EQ(0, ceph_unlink(cmount, link_path));
3165 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
3166 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
3167 ceph_shutdown(cmount);
3168 }
3169
3170 TEST(LibCephFS, SymlinkatATFDCWD) {
3171 pid_t mypid = getpid();
3172
3173 struct ceph_mount_info *cmount;
3174 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3175 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3176 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3177 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
3178
3179 char dir_name[128];
3180 char dir_path[256];
3181 sprintf(dir_name, "dir_%d", mypid);
3182 sprintf(dir_path, "/%s", dir_name);
3183 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3184
3185 char file_path[512];
3186 char rel_file_path[512] = "./elif";
3187 sprintf(file_path, "%s/elif", dir_path);
3188 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDONLY, 0666);
3189 ASSERT_LE(0, fd);
3190 ASSERT_EQ(0, ceph_close(cmount, fd));
3191
3192 char link_path[PATH_MAX];
3193 char rel_link_path[1024];
3194 sprintf(rel_link_path, "./linkfile_%d", mypid);
3195 sprintf(link_path, "%s/%s", dir_path, rel_link_path);
3196 ASSERT_EQ(0, ceph_chdir(cmount, dir_path));
3197 ASSERT_EQ(0, ceph_symlinkat(cmount, rel_file_path, CEPHFS_AT_FDCWD, rel_link_path));
3198
3199 size_t target_len = strlen(rel_file_path);
3200 char target[target_len+1];
3201 ASSERT_EQ(target_len, ceph_readlinkat(cmount, CEPHFS_AT_FDCWD, rel_link_path, target, target_len));
3202 target[target_len] = '\0';
3203 ASSERT_EQ(0, memcmp(target, rel_file_path, target_len));
3204
3205 ASSERT_EQ(0, ceph_unlink(cmount, link_path));
3206 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
3207 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
3208 ceph_shutdown(cmount);
3209 }
3210
3211 TEST(LibCephFS, Unlinkat) {
3212 pid_t mypid = getpid();
3213
3214 struct ceph_mount_info *cmount;
3215 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3216 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3217 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3218 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
3219
3220 char dir_name[128];
3221 char dir_path[256];
3222 sprintf(dir_name, "dir_%d", mypid);
3223 sprintf(dir_path, "/%s", dir_name);
3224 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3225
3226 char file_path[512];
3227 char rel_file_path[512] = "elif";
3228 sprintf(file_path, "%s/elif", dir_path);
3229
3230 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDONLY, 0666);
3231 ASSERT_LE(0, fd);
3232 ASSERT_EQ(0, ceph_close(cmount, fd));
3233
3234 fd = ceph_open(cmount, dir_path, O_DIRECTORY | O_RDONLY, 0);
3235 ASSERT_LE(0, fd);
3236 ASSERT_EQ(-ENOTDIR, ceph_unlinkat(cmount, fd, rel_file_path, AT_REMOVEDIR));
3237 ASSERT_EQ(0, ceph_unlinkat(cmount, fd, rel_file_path, 0));
3238 ASSERT_EQ(0, ceph_close(cmount, fd));
3239
3240 fd = ceph_open(cmount, "/", O_DIRECTORY | O_RDONLY, 0);
3241 ASSERT_EQ(-EISDIR, ceph_unlinkat(cmount, fd, dir_name, 0));
3242 ASSERT_EQ(0, ceph_unlinkat(cmount, fd, dir_name, AT_REMOVEDIR));
3243 ASSERT_LE(0, fd);
3244
3245 ceph_shutdown(cmount);
3246 }
3247
3248 TEST(LibCephFS, UnlinkatATFDCWD) {
3249 pid_t mypid = getpid();
3250
3251 struct ceph_mount_info *cmount;
3252 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3253 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3254 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3255 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
3256
3257 char dir_name[128];
3258 char dir_path[256];
3259 sprintf(dir_name, "dir_%d", mypid);
3260 sprintf(dir_path, "/%s", dir_name);
3261 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3262
3263 char file_path[512];
3264 char rel_file_path[512] = "elif";
3265 sprintf(file_path, "%s/elif", dir_path);
3266
3267 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDONLY, 0666);
3268 ASSERT_LE(0, fd);
3269 ASSERT_EQ(0, ceph_close(cmount, fd));
3270
3271 ASSERT_EQ(0, ceph_chdir(cmount, dir_path));
3272 ASSERT_EQ(-ENOTDIR, ceph_unlinkat(cmount, CEPHFS_AT_FDCWD, rel_file_path, AT_REMOVEDIR));
3273 ASSERT_EQ(0, ceph_unlinkat(cmount, CEPHFS_AT_FDCWD, rel_file_path, 0));
3274
3275 ASSERT_EQ(0, ceph_chdir(cmount, "/"));
3276 ASSERT_EQ(-EISDIR, ceph_unlinkat(cmount, CEPHFS_AT_FDCWD, dir_name, 0));
3277 ASSERT_EQ(0, ceph_unlinkat(cmount, CEPHFS_AT_FDCWD, dir_name, AT_REMOVEDIR));
3278
3279 ceph_shutdown(cmount);
3280 }
3281
3282 TEST(LibCephFS, Chownat) {
3283 pid_t mypid = getpid();
3284
3285 struct ceph_mount_info *cmount;
3286 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3287 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3288 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3289 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
3290
3291 char dir_name[128];
3292 char dir_path[256];
3293 sprintf(dir_name, "dir_%d", mypid);
3294 sprintf(dir_path, "/%s", dir_name);
3295 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3296
3297 char file_path[512];
3298 char rel_file_path[512] = "elif";
3299 sprintf(file_path, "%s/elif", dir_path);
3300 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDWR, 0666);
3301 ASSERT_LE(0, fd);
3302
3303 // set perms to readable and writeable only by owner
3304 ASSERT_EQ(ceph_fchmod(cmount, fd, 0600), 0);
3305 ceph_close(cmount, fd);
3306
3307 fd = ceph_open(cmount, dir_path, O_DIRECTORY | O_RDONLY, 0);
3308 // change ownership to nobody -- we assume nobody exists and id is always 65534
3309 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "0"), 0);
3310 ASSERT_EQ(ceph_chownat(cmount, fd, rel_file_path, 65534, 65534, 0), 0);
3311 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "1"), 0);
3312 ceph_close(cmount, fd);
3313
3314 fd = ceph_open(cmount, file_path, O_RDWR, 0);
3315 ASSERT_EQ(fd, -EACCES);
3316
3317 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "0"), 0);
3318 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
3319 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "1"), 0);
3320 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
3321 ceph_shutdown(cmount);
3322 }
3323
3324 TEST(LibCephFS, ChownatATFDCWD) {
3325 pid_t mypid = getpid();
3326
3327 struct ceph_mount_info *cmount;
3328 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3329 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3330 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3331 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
3332
3333 char dir_name[128];
3334 char dir_path[256];
3335 sprintf(dir_name, "dir_%d", mypid);
3336 sprintf(dir_path, "/%s", dir_name);
3337 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3338
3339 char file_path[512];
3340 char rel_file_path[512] = "elif";
3341 sprintf(file_path, "%s/elif", dir_path);
3342 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDWR, 0666);
3343 ASSERT_LE(0, fd);
3344
3345 // set perms to readable and writeable only by owner
3346 ASSERT_EQ(ceph_fchmod(cmount, fd, 0600), 0);
3347 ceph_close(cmount, fd);
3348
3349 ASSERT_EQ(0, ceph_chdir(cmount, dir_path));
3350 // change ownership to nobody -- we assume nobody exists and id is always 65534
3351 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "0"), 0);
3352 ASSERT_EQ(ceph_chownat(cmount, CEPHFS_AT_FDCWD, rel_file_path, 65534, 65534, 0), 0);
3353 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "1"), 0);
3354
3355 fd = ceph_open(cmount, file_path, O_RDWR, 0);
3356 ASSERT_EQ(fd, -EACCES);
3357
3358 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "0"), 0);
3359 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
3360 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "1"), 0);
3361 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
3362 ceph_shutdown(cmount);
3363 }
3364
3365 TEST(LibCephFS, Chmodat) {
3366 pid_t mypid = getpid();
3367
3368 struct ceph_mount_info *cmount;
3369 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3370 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3371 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3372 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
3373
3374 char dir_name[128];
3375 char dir_path[256];
3376 sprintf(dir_name, "dir_%d", mypid);
3377 sprintf(dir_path, "/%s", dir_name);
3378 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3379
3380 char file_path[512];
3381 char rel_file_path[512] = "elif";
3382 sprintf(file_path, "%s/elif", dir_path);
3383 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDWR, 0666);
3384 ASSERT_LE(0, fd);
3385 const char *bytes = "foobarbaz";
3386 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
3387 ASSERT_EQ(0, ceph_close(cmount, fd));
3388
3389 fd = ceph_open(cmount, dir_path, O_DIRECTORY | O_RDONLY, 0);
3390
3391 // set perms to read but can't write
3392 ASSERT_EQ(ceph_chmodat(cmount, fd, rel_file_path, 0400, 0), 0);
3393 ASSERT_EQ(ceph_open(cmount, file_path, O_RDWR, 0), -EACCES);
3394
3395 // reset back to writeable
3396 ASSERT_EQ(ceph_chmodat(cmount, fd, rel_file_path, 0600, 0), 0);
3397 int fd2 = ceph_open(cmount, file_path, O_RDWR, 0);
3398 ASSERT_LE(0, fd2);
3399
3400 ASSERT_EQ(0, ceph_close(cmount, fd2));
3401 ASSERT_EQ(0, ceph_close(cmount, fd));
3402
3403 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
3404 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
3405 ceph_shutdown(cmount);
3406 }
3407
3408 TEST(LibCephFS, ChmodatATFDCWD) {
3409 pid_t mypid = getpid();
3410
3411 struct ceph_mount_info *cmount;
3412 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3413 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3414 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3415 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
3416
3417 char dir_name[128];
3418 char dir_path[256];
3419 sprintf(dir_name, "dir_%d", mypid);
3420 sprintf(dir_path, "/%s", dir_name);
3421 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3422
3423 char file_path[512];
3424 char rel_file_path[512] = "elif";
3425 sprintf(file_path, "%s/elif", dir_path);
3426 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDWR, 0666);
3427 ASSERT_LE(0, fd);
3428 const char *bytes = "foobarbaz";
3429 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
3430 ASSERT_EQ(0, ceph_close(cmount, fd));
3431
3432 // set perms to read but can't write
3433 ASSERT_EQ(0, ceph_chdir(cmount, dir_path));
3434 ASSERT_EQ(ceph_chmodat(cmount, CEPHFS_AT_FDCWD, rel_file_path, 0400, 0), 0);
3435 ASSERT_EQ(ceph_open(cmount, file_path, O_RDWR, 0), -EACCES);
3436
3437 // reset back to writeable
3438 ASSERT_EQ(ceph_chmodat(cmount, CEPHFS_AT_FDCWD, rel_file_path, 0600, 0), 0);
3439 int fd2 = ceph_open(cmount, file_path, O_RDWR, 0);
3440 ASSERT_LE(0, fd2);
3441 ASSERT_EQ(0, ceph_close(cmount, fd2));
3442
3443 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
3444 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
3445 ceph_shutdown(cmount);
3446 }
3447
3448 TEST(LibCephFS, Utimensat) {
3449 pid_t mypid = getpid();
3450
3451 struct ceph_mount_info *cmount;
3452 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3453 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3454 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3455 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
3456
3457 char dir_name[128];
3458 char dir_path[256];
3459 sprintf(dir_name, "dir_%d", mypid);
3460 sprintf(dir_path, "/%s", dir_name);
3461 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3462
3463 char file_path[512];
3464 char rel_file_path[512] = "elif";
3465 sprintf(file_path, "%s/elif", dir_path);
3466 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDWR, 0666);
3467 ASSERT_LE(0, fd);
3468
3469 struct timespec times[2];
3470 get_current_time_timespec(times);
3471
3472 fd = ceph_open(cmount, dir_path, O_DIRECTORY | O_RDONLY, 0);
3473 ASSERT_LE(0, fd);
3474 EXPECT_EQ(0, ceph_utimensat(cmount, fd, rel_file_path, times, 0));
3475 ceph_close(cmount, fd);
3476
3477 struct ceph_statx stx;
3478 ASSERT_EQ(ceph_statx(cmount, file_path, &stx,
3479 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
3480 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(times[0]));
3481 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(times[1]));
3482
3483 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
3484 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
3485 ceph_shutdown(cmount);
3486 }
3487
3488 TEST(LibCephFS, UtimensatATFDCWD) {
3489 pid_t mypid = getpid();
3490
3491 struct ceph_mount_info *cmount;
3492 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3493 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3494 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3495 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
3496
3497 char dir_name[128];
3498 char dir_path[256];
3499 sprintf(dir_name, "dir_%d", mypid);
3500 sprintf(dir_path, "/%s", dir_name);
3501 ASSERT_EQ(ceph_mkdir(cmount, dir_path, 0777), 0);
3502
3503 char file_path[512];
3504 char rel_file_path[512] = "elif";
3505 sprintf(file_path, "%s/elif", dir_path);
3506 int fd = ceph_open(cmount, file_path, O_CREAT|O_RDWR, 0666);
3507 ASSERT_LE(0, fd);
3508
3509 struct timespec times[2];
3510 get_current_time_timespec(times);
3511
3512 ASSERT_EQ(0, ceph_chdir(cmount, dir_path));
3513 EXPECT_EQ(0, ceph_utimensat(cmount, CEPHFS_AT_FDCWD, rel_file_path, times, 0));
3514
3515 struct ceph_statx stx;
3516 ASSERT_EQ(ceph_statx(cmount, file_path, &stx,
3517 CEPH_STATX_MTIME|CEPH_STATX_ATIME, 0), 0);
3518 ASSERT_EQ(utime_t(stx.stx_atime), utime_t(times[0]));
3519 ASSERT_EQ(utime_t(stx.stx_mtime), utime_t(times[1]));
3520
3521 ASSERT_EQ(0, ceph_unlink(cmount, file_path));
3522 ASSERT_EQ(0, ceph_rmdir(cmount, dir_path));
3523 ceph_shutdown(cmount);
3524 }
3525
3526 TEST(LibCephFS, LookupMdsPrivateInos) {
3527 struct ceph_mount_info *cmount;
3528 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3529 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3530 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3531 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
3532
3533 Inode *inode;
3534 for (int ino = 0; ino < MDS_INO_SYSTEM_BASE; ino++) {
3535 if (MDS_IS_PRIVATE_INO(ino)) {
3536 ASSERT_EQ(-ESTALE, ceph_ll_lookup_inode(cmount, ino, &inode));
3537 } else if (ino == CEPH_INO_ROOT || ino == CEPH_INO_GLOBAL_SNAPREALM) {
3538 ASSERT_EQ(0, ceph_ll_lookup_inode(cmount, ino, &inode));
3539 ceph_ll_put(cmount, inode);
3540 } else if (ino == CEPH_INO_LOST_AND_FOUND) {
3541 // the ino 3 will only exists after the recovery tool ran, so
3542 // it may return -ESTALE with a fresh fs cluster
3543 int r = ceph_ll_lookup_inode(cmount, ino, &inode);
3544 if (r == 0) {
3545 ceph_ll_put(cmount, inode);
3546 } else {
3547 ASSERT_TRUE(r == -ESTALE);
3548 }
3549 } else {
3550 // currently the ino 0 and 4~99 is not useded yet.
3551 ASSERT_EQ(-ESTALE, ceph_ll_lookup_inode(cmount, ino, &inode));
3552 }
3553 }
3554
3555 ceph_shutdown(cmount);
3556 }
3557
3558 TEST(LibCephFS, SetMountTimeoutPostMount) {
3559 struct ceph_mount_info *cmount;
3560 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3561 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3562 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3563 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
3564
3565 ASSERT_EQ(-EINVAL, ceph_set_mount_timeout(cmount, 5));
3566 ceph_shutdown(cmount);
3567 }
3568
3569 TEST(LibCephFS, SetMountTimeout) {
3570 struct ceph_mount_info *cmount;
3571 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
3572 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
3573 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
3574 ASSERT_EQ(0, ceph_set_mount_timeout(cmount, 5));
3575 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
3576
3577 ceph_shutdown(cmount);
3578 }