|
|
|
@@ -47,37 +47,32 @@ void get_times_ns(const std::string &path, long long &at_ns, long long &mt_ns) {
|
|
|
|
|
#endif // defined(__APPLE__)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto ts_make(time_t sec, long nsec) -> struct timespec {
|
|
|
|
|
struct timespec spec{};
|
|
|
|
|
spec.tv_sec = sec;
|
|
|
|
|
spec.tv_nsec = nsec;
|
|
|
|
|
return spec;
|
|
|
|
|
[[nodiscard]] auto ts_make(time_t sec, long nsec) -> timespec {
|
|
|
|
|
return timespec{
|
|
|
|
|
.tv_sec = sec,
|
|
|
|
|
.tv_nsec = nsec,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] auto
|
|
|
|
|
to_ns(const struct timespec &spec) -> long long {
|
|
|
|
|
[[nodiscard]] auto to_ns(const timespec &spec) -> long long {
|
|
|
|
|
return static_cast<long long>(spec.tv_sec) *
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND) +
|
|
|
|
|
static_cast<long long>(spec.tv_nsec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] auto now_ns() -> long long {
|
|
|
|
|
struct timespec spec{};
|
|
|
|
|
timespec spec{};
|
|
|
|
|
#if defined(CLOCK_REALTIME)
|
|
|
|
|
clock_gettime(CLOCK_REALTIME, &spec);
|
|
|
|
|
#else
|
|
|
|
|
struct timeval val{};
|
|
|
|
|
#else // defined(CLOCK_REALTIME)
|
|
|
|
|
timeval val{};
|
|
|
|
|
gettimeofday(&val, nullptr);
|
|
|
|
|
spec.tv_sec = val.tv_sec;
|
|
|
|
|
spec.tv_nsec = val.tv_usec * 1000;
|
|
|
|
|
#endif
|
|
|
|
|
#endif // !defined(CLOCK_REALTIME)
|
|
|
|
|
return to_ns(spec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] auto llabsll(long long value) -> long long {
|
|
|
|
|
return (value < 0) ? -value : value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr long long GRANULAR_TOL_NS =
|
|
|
|
|
1LL * static_cast<long long>(NANOS_PER_SECOND);
|
|
|
|
|
constexpr long long NOW_TOL_NS = 5LL * static_cast<long long>(NANOS_PER_SECOND);
|
|
|
|
@@ -102,7 +97,7 @@ TYPED_TEST(fuse_test, utimens_set_both_times_specific_values) {
|
|
|
|
|
auto target_mt =
|
|
|
|
|
now - 1800LL * static_cast<long long>(NANOS_PER_SECOND) + 222222222LL;
|
|
|
|
|
|
|
|
|
|
struct timespec spec[2]{
|
|
|
|
|
auto spec = std::array<timespec, 2U>{
|
|
|
|
|
ts_make(static_cast<time_t>(target_at /
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND)),
|
|
|
|
|
static_cast<long>(target_at %
|
|
|
|
@@ -110,17 +105,18 @@ TYPED_TEST(fuse_test, utimens_set_both_times_specific_values) {
|
|
|
|
|
ts_make(static_cast<time_t>(target_mt /
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND)),
|
|
|
|
|
static_cast<long>(target_mt %
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND)))};
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND))),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
ASSERT_EQ(0, ::utimensat(AT_FDCWD, src.c_str(), spec, 0));
|
|
|
|
|
ASSERT_EQ(0, ::utimensat(AT_FDCWD, src.c_str(), spec.data(), 0));
|
|
|
|
|
|
|
|
|
|
long long at1{};
|
|
|
|
|
long long mt1{};
|
|
|
|
|
get_times_ns(src, at1, mt1);
|
|
|
|
|
|
|
|
|
|
EXPECT_LE(llabsll(at1 - target_at), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(llabsll(mt1 - target_mt), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(at1 - target_at), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(mt1 - target_mt), GRANULAR_TOL_NS);
|
|
|
|
|
|
|
|
|
|
this->unlink_file_and_test(src);
|
|
|
|
|
}
|
|
|
|
@@ -136,22 +132,23 @@ TYPED_TEST(fuse_test, utimens_set_atime_only_omit_mtime) {
|
|
|
|
|
long long target_at =
|
|
|
|
|
now_ns() - 10LL * static_cast<long long>(NANOS_PER_SECOND);
|
|
|
|
|
|
|
|
|
|
struct timespec spec[2]{
|
|
|
|
|
auto spec = std::array<timespec, 2U>{
|
|
|
|
|
ts_make(static_cast<time_t>(target_at /
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND)),
|
|
|
|
|
static_cast<long>(target_at %
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND))),
|
|
|
|
|
ts_make(0, UTIME_OMIT)};
|
|
|
|
|
ts_make(0, UTIME_OMIT),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
ASSERT_EQ(0, ::utimensat(AT_FDCWD, src.c_str(), spec, 0));
|
|
|
|
|
ASSERT_EQ(0, ::utimensat(AT_FDCWD, src.c_str(), spec.data(), 0));
|
|
|
|
|
|
|
|
|
|
long long at_after{};
|
|
|
|
|
long long mt_after{};
|
|
|
|
|
get_times_ns(src, at_after, mt_after);
|
|
|
|
|
|
|
|
|
|
EXPECT_LE(llabsll(at_after - target_at), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(llabsll(mt_after - mt_before), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(at_after - target_at), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(mt_after - mt_before), GRANULAR_TOL_NS);
|
|
|
|
|
|
|
|
|
|
this->unlink_file_and_test(src);
|
|
|
|
|
}
|
|
|
|
@@ -166,22 +163,23 @@ TYPED_TEST(fuse_test, utimens_set_mtime_only_omit_atime) {
|
|
|
|
|
|
|
|
|
|
auto target_mt = now_ns() - 30LL * static_cast<long long>(NANOS_PER_SECOND);
|
|
|
|
|
|
|
|
|
|
struct timespec spec[2]{
|
|
|
|
|
auto spec = std::array<timespec, 2U>{
|
|
|
|
|
ts_make(0, UTIME_OMIT),
|
|
|
|
|
ts_make(static_cast<time_t>(target_mt /
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND)),
|
|
|
|
|
static_cast<long>(target_mt %
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND)))};
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND))),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
ASSERT_EQ(0, ::utimensat(AT_FDCWD, src.c_str(), spec, 0));
|
|
|
|
|
ASSERT_EQ(0, ::utimensat(AT_FDCWD, src.c_str(), spec.data(), 0));
|
|
|
|
|
|
|
|
|
|
long long at_after{};
|
|
|
|
|
long long mt_after{};
|
|
|
|
|
get_times_ns(src, at_after, mt_after);
|
|
|
|
|
|
|
|
|
|
EXPECT_LE(llabsll(mt_after - target_mt), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(llabsll(at_after - at_before), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(mt_after - target_mt), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(at_after - at_before), GRANULAR_TOL_NS);
|
|
|
|
|
|
|
|
|
|
this->unlink_file_and_test(src);
|
|
|
|
|
}
|
|
|
|
@@ -190,29 +188,36 @@ TYPED_TEST(fuse_test, utimens_set_now_for_both) {
|
|
|
|
|
std::string name{"utimens"};
|
|
|
|
|
auto src = this->create_file_and_test(name);
|
|
|
|
|
|
|
|
|
|
struct timespec spec[2]{ts_make(0, UTIME_NOW), ts_make(0, UTIME_NOW)};
|
|
|
|
|
auto spec = std::array<timespec, 2U>{
|
|
|
|
|
ts_make(0, UTIME_NOW),
|
|
|
|
|
ts_make(0, UTIME_NOW),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
ASSERT_EQ(0, ::utimensat(AT_FDCWD, src.c_str(), spec, 0));
|
|
|
|
|
ASSERT_EQ(0, ::utimensat(AT_FDCWD, src.c_str(), spec.data(), 0));
|
|
|
|
|
|
|
|
|
|
auto now_after = now_ns();
|
|
|
|
|
long long access_time{};
|
|
|
|
|
long long modified_time{};
|
|
|
|
|
get_times_ns(src, access_time, modified_time);
|
|
|
|
|
|
|
|
|
|
EXPECT_LE(llabsll(access_time - now_after), NOW_TOL_NS);
|
|
|
|
|
EXPECT_LE(llabsll(modified_time - now_after), NOW_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(access_time - now_after), NOW_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(modified_time - now_after), NOW_TOL_NS);
|
|
|
|
|
|
|
|
|
|
this->unlink_file_and_test(src);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TYPED_TEST(fuse_test, utimens_nonexistent_path_returns_enoent) {
|
|
|
|
|
std::string missing =
|
|
|
|
|
this->mount_location + "/utimens_missing_" + std::to_string(::getpid());
|
|
|
|
|
std::string file_name{"utimens"};
|
|
|
|
|
auto missing = this->create_file_path(file_name);
|
|
|
|
|
|
|
|
|
|
auto spec = std::array<timespec, 2U>{
|
|
|
|
|
ts_make(123, 0),
|
|
|
|
|
ts_make(456, 0),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct timespec spec[2]{ts_make(123, 0), ts_make(456, 0)};
|
|
|
|
|
errno = 0;
|
|
|
|
|
EXPECT_EQ(-1, ::utimensat(AT_FDCWD, missing.c_str(), spec, 0));
|
|
|
|
|
EXPECT_EQ(-1, ::utimensat(AT_FDCWD, missing.c_str(), spec.data(), 0));
|
|
|
|
|
EXPECT_EQ(ENOENT, errno);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -220,10 +225,13 @@ TYPED_TEST(fuse_test, utimens_invalid_nsec_returns_einval) {
|
|
|
|
|
std::string name{"utimens"};
|
|
|
|
|
auto src = this->create_file_and_test(name);
|
|
|
|
|
|
|
|
|
|
struct timespec spec[2]{ts_make(0, 1000000000L), ts_make(0, 0)};
|
|
|
|
|
auto spec = std::array<timespec, 2U>{
|
|
|
|
|
ts_make(0, 1000000000L),
|
|
|
|
|
ts_make(0, 0),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
EXPECT_EQ(-1, ::utimensat(AT_FDCWD, src.c_str(), spec, 0));
|
|
|
|
|
EXPECT_EQ(-1, ::utimensat(AT_FDCWD, src.c_str(), spec.data(), 0));
|
|
|
|
|
EXPECT_EQ(EINVAL, errno);
|
|
|
|
|
|
|
|
|
|
this->unlink_file_and_test(src);
|
|
|
|
@@ -242,7 +250,7 @@ TYPED_TEST(fuse_test, futimens_set_both_times_specific_values) {
|
|
|
|
|
auto target_mt =
|
|
|
|
|
now - 600LL * static_cast<long long>(NANOS_PER_SECOND) + 444444444LL;
|
|
|
|
|
|
|
|
|
|
struct timespec spec[2]{
|
|
|
|
|
auto spec = std::array<timespec, 2U>{
|
|
|
|
|
ts_make(static_cast<time_t>(target_at /
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND)),
|
|
|
|
|
static_cast<long>(target_at %
|
|
|
|
@@ -250,17 +258,18 @@ TYPED_TEST(fuse_test, futimens_set_both_times_specific_values) {
|
|
|
|
|
ts_make(static_cast<time_t>(target_mt /
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND)),
|
|
|
|
|
static_cast<long>(target_mt %
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND)))};
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND))),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
ASSERT_EQ(0, ::futimens(desc, spec));
|
|
|
|
|
ASSERT_EQ(0, ::futimens(desc, spec.data()));
|
|
|
|
|
::close(desc);
|
|
|
|
|
|
|
|
|
|
long long access_time{};
|
|
|
|
|
long long modified_time{};
|
|
|
|
|
get_times_ns(src, access_time, modified_time);
|
|
|
|
|
EXPECT_LE(llabsll(access_time - target_at), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(llabsll(modified_time - target_mt), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(access_time - target_at), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(modified_time - target_mt), GRANULAR_TOL_NS);
|
|
|
|
|
|
|
|
|
|
this->unlink_file_and_test(src);
|
|
|
|
|
}
|
|
|
|
@@ -278,23 +287,24 @@ TYPED_TEST(fuse_test, futimens_set_mtime_only_omit_atime) {
|
|
|
|
|
|
|
|
|
|
auto target_mt = now_ns() - 20LL * static_cast<long long>(NANOS_PER_SECOND);
|
|
|
|
|
|
|
|
|
|
struct timespec spec[2]{
|
|
|
|
|
auto spec = std::array<timespec, 2U>{
|
|
|
|
|
ts_make(0, UTIME_OMIT),
|
|
|
|
|
ts_make(static_cast<time_t>(target_mt /
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND)),
|
|
|
|
|
static_cast<long>(target_mt %
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND)))};
|
|
|
|
|
static_cast<long long>(NANOS_PER_SECOND))),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
ASSERT_EQ(0, ::futimens(desc, spec));
|
|
|
|
|
ASSERT_EQ(0, ::futimens(desc, spec.data()));
|
|
|
|
|
::close(desc);
|
|
|
|
|
|
|
|
|
|
long long at_after{};
|
|
|
|
|
long long mt_after{};
|
|
|
|
|
get_times_ns(src, at_after, mt_after);
|
|
|
|
|
|
|
|
|
|
EXPECT_LE(llabsll(mt_after - target_mt), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(llabsll(at_after - at_before), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(mt_after - target_mt), GRANULAR_TOL_NS);
|
|
|
|
|
EXPECT_LE(std::abs(at_after - at_before), GRANULAR_TOL_NS);
|
|
|
|
|
|
|
|
|
|
this->unlink_file_and_test(src);
|
|
|
|
|
}
|
|
|
|
@@ -306,10 +316,13 @@ TYPED_TEST(fuse_test, futimens_invalid_nsec_returns_einval) {
|
|
|
|
|
auto desc = ::open(src.c_str(), O_RDWR);
|
|
|
|
|
ASSERT_NE(desc, -1);
|
|
|
|
|
|
|
|
|
|
struct timespec spec[2]{ts_make(0, 0), ts_make(0, 1000000000L)};
|
|
|
|
|
auto spec = std::array<timespec, 2U>{
|
|
|
|
|
ts_make(0, 0),
|
|
|
|
|
ts_make(0, 1000000000L),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
EXPECT_EQ(-1, ::futimens(desc, spec));
|
|
|
|
|
EXPECT_EQ(-1, ::futimens(desc, spec.data()));
|
|
|
|
|
EXPECT_EQ(EINVAL, errno);
|
|
|
|
|
|
|
|
|
|
::close(desc);
|
|
|
|
|