ceph_shutdown(cmount);
}
+
+TEST(LibCephFS, SnapXattrs) {
+ struct ceph_mount_info *cmount;
+ ASSERT_EQ(ceph_create(&cmount, NULL), 0);
+ ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
+ ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
+ ASSERT_EQ(ceph_mount(cmount, NULL), 0);
+
+ char test_snap_xattr_file[256];
+ char c_temp[PATH_MAX];
+ char gxattrv[128];
+ char gxattrv2[128];
+ int xbuflen = sizeof(gxattrv);
+ pid_t mypid = getpid();
+
+ sprintf(test_snap_xattr_file, "test_snap_xattr_%d", mypid);
+ int fd = ceph_open(cmount, test_snap_xattr_file, O_CREAT, 0666);
+ ASSERT_GT(fd, 0);
+ ceph_close(cmount, fd);
+
+ sprintf(c_temp, "/.snap/test_snap_xattr_snap_%d", mypid);
+ ASSERT_EQ(0, ceph_mkdir(cmount, c_temp, 0777));
+
+ int alen = ceph_getxattr(cmount, c_temp, "ceph.snap.btime", (void *)gxattrv, xbuflen);
+ // xattr value is secs.nsecs (don't assume zero-term)
+ ASSERT_LT(0, alen);
+ ASSERT_LT(alen, xbuflen);
+ gxattrv[alen] = '\0';
+ char *s = strchrnul(gxattrv, '.');
+ ASSERT_LT(s, gxattrv + alen);
+ ASSERT_EQ('.', *s);
+ *s = '\0';
+ utime_t btime = utime_t(strtoull(gxattrv, NULL, 10), strtoull(s + 1, NULL, 10));
+ *s = '.'; // restore for later strcmp
+
+ // file within the snapshot should carry the same btime
+ sprintf(c_temp, "/.snap/test_snap_xattr_snap_%d/%s", mypid, test_snap_xattr_file);
+
+ int alen2 = ceph_getxattr(cmount, c_temp, "ceph.snap.btime", (void *)gxattrv2, xbuflen);
+ ASSERT_EQ(alen, alen2);
+ ASSERT_EQ(0, strncmp(gxattrv, gxattrv2, alen));
+
+ // non-snap file shouldn't carry the xattr
+ alen = ceph_getxattr(cmount, test_snap_xattr_file, "ceph.snap.btime", (void *)gxattrv2, xbuflen);
+ ASSERT_EQ(-ENODATA, alen);
+
+ // create a second snapshot
+ sprintf(c_temp, "/.snap/test_snap_xattr_snap2_%d", mypid);
+ ASSERT_EQ(0, ceph_mkdir(cmount, c_temp, 0777));
+
+ // check that the btime for the newer snapshot is > older
+ alen = ceph_getxattr(cmount, c_temp, "ceph.snap.btime", (void *)gxattrv2, xbuflen);
+ ASSERT_LT(0, alen);
+ ASSERT_LT(alen, xbuflen);
+ gxattrv2[alen] = '\0';
+ s = strchrnul(gxattrv2, '.');
+ ASSERT_LT(s, gxattrv2 + alen);
+ ASSERT_EQ('.', *s);
+ *s = '\0';
+ utime_t new_btime = utime_t(strtoull(gxattrv2, NULL, 10), strtoull(s + 1, NULL, 10));
+ ASSERT_LT(btime, new_btime);
+
+ ceph_shutdown(cmount);
+}