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