From 69f30a350575b4aa0267f3f8f222e3dcc63c698e Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jan 2020 01:01:39 +0300 Subject: [PATCH] Add real_size to Stat. GitOrigin-RevId: 3b8b4c24504ed1fa7eed1885abd3a3e9014eb2c4 --- tdutils/td/utils/port/FileFd.cpp | 10 ++++++++++ tdutils/td/utils/port/FileFd.h | 4 ++++ tdutils/td/utils/port/Stat.cpp | 1 + tdutils/td/utils/port/Stat.h | 1 + tdutils/test/port.cpp | 16 ++++++++++++++++ 5 files changed, 32 insertions(+) diff --git a/tdutils/td/utils/port/FileFd.cpp b/tdutils/td/utils/port/FileFd.cpp index fc4096af..2f65df61 100644 --- a/tdutils/td/utils/port/FileFd.cpp +++ b/tdutils/td/utils/port/FileFd.cpp @@ -480,6 +480,11 @@ Result FileFd::get_size() const { return s.size_; } +Result FileFd::get_real_size() const { + TRY_RESULT(s, stat()); + return s.real_size_; +} + #if TD_PORT_WINDOWS static uint64 filetime_to_unix_time_nsec(LONGLONG filetime) { const auto FILETIME_UNIX_TIME_DIFF = 116444736000000000ll; @@ -510,6 +515,11 @@ Result FileFd::stat() const { return OS_ERROR("Get FileStandardInfo failed"); } res.size_ = standard_info.EndOfFile.QuadPart; + res.real_size_ = standard_info.AllocationSize.QuadPart; + + if (res.size_ != 0 && res.real_size_ <= 0 ) { + res.real_size_ = res.size_; // just in case + } return res; #endif diff --git a/tdutils/td/utils/port/FileFd.h b/tdutils/td/utils/port/FileFd.h index f70a6dfe..2751af84 100644 --- a/tdutils/td/utils/port/FileFd.h +++ b/tdutils/td/utils/port/FileFd.h @@ -50,11 +50,15 @@ class FileFd { PollableFdInfo &get_poll_info(); const PollableFdInfo &get_poll_info() const; + void close(); + bool empty() const; Result get_size() const; + Result get_real_size() const; + Result stat() const; Status sync() TD_WARN_UNUSED_RESULT; diff --git a/tdutils/td/utils/port/Stat.cpp b/tdutils/td/utils/port/Stat.cpp index baccc9e5..ff1e20d9 100644 --- a/tdutils/td/utils/port/Stat.cpp +++ b/tdutils/td/utils/port/Stat.cpp @@ -106,6 +106,7 @@ Stat from_native_stat(const struct ::stat &buf) { res.atime_nsec_ = static_cast(buf.st_atime) * 1000000000 + time_nsec.first; res.mtime_nsec_ = static_cast(buf.st_mtime) * 1000000000 + time_nsec.second / 1000 * 1000; res.size_ = buf.st_size; + res.real_size_ = buf.st_blocks * 512; res.is_dir_ = (buf.st_mode & S_IFMT) == S_IFDIR; res.is_reg_ = (buf.st_mode & S_IFMT) == S_IFREG; return res; diff --git a/tdutils/td/utils/port/Stat.h b/tdutils/td/utils/port/Stat.h index 48463b30..1e0fc297 100644 --- a/tdutils/td/utils/port/Stat.h +++ b/tdutils/td/utils/port/Stat.h @@ -18,6 +18,7 @@ struct Stat { bool is_dir_; bool is_reg_; int64 size_; + int64 real_size_; uint64 atime_nsec_; uint64 mtime_nsec_; }; diff --git a/tdutils/test/port.cpp b/tdutils/test/port.cpp index 3dba488e..5a16dc3d 100644 --- a/tdutils/test/port.cpp +++ b/tdutils/test/port.cpp @@ -95,6 +95,22 @@ TEST(Port, files) { ASSERT_STREQ("Habcd world?!", buf_slice.substr(0, 13)); } +TEST(Port, SparseFiles) { + CSlice path = "sparse.txt"; + unlink(path).ignore(); + auto fd = FileFd::open(path, FileFd::Write | FileFd::CreateNew).move_as_ok(); + ASSERT_EQ(0, fd.get_size().move_as_ok()); + ASSERT_EQ(0, fd.get_real_size().move_as_ok()); + int64 offset = 100000000; + fd.pwrite("a", offset); + ASSERT_EQ(offset + 1, fd.get_size().move_as_ok()); + auto real_size = fd.get_real_size().move_as_ok(); + if (real_size == offset + 1) { + LOG(ERROR) << "File system doesn't support sparse files, rewind during streaming can be slow"; + } + unlink(path).ensure(); +} + TEST(Port, Writev) { std::vector vec; CSlice test_file_path = "test.txt";