mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Allow set and get last modified times on files.
PiperOrigin-RevId: 791407269
This commit is contained in:
committed by
Copybara-Service
parent
09e11ee122
commit
38827f2b4b
@@ -352,6 +352,7 @@ cc_library(
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_absl//absl/types:optional",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "internal/platform/file.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace nearby {
|
||||
|
||||
@@ -37,6 +41,10 @@ std::string InputFile::GetFilePath() const { return impl_->GetFilePath(); }
|
||||
// Returns total size of this file in bytes.
|
||||
std::int64_t InputFile::GetTotalSize() const { return impl_->GetTotalSize(); }
|
||||
|
||||
absl::Time InputFile::GetLastModifiedTime() const {
|
||||
return impl_->GetLastModifiedTime();
|
||||
}
|
||||
|
||||
ExceptionOr<size_t> InputFile::Skip(size_t offset) {
|
||||
return impl_->Skip(offset);
|
||||
}
|
||||
@@ -81,4 +89,8 @@ Exception OutputFile::Close() { return impl_->Close(); }
|
||||
// versa.
|
||||
OutputStream& OutputFile::GetOutputStream() { return *impl_; }
|
||||
|
||||
void OutputFile::SetLastModifiedTime(absl::Time last_modified_time) {
|
||||
impl_->SetLastModifiedTime(last_modified_time);
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/implementation/input_file.h"
|
||||
@@ -66,6 +67,8 @@ class InputFile final {
|
||||
// versa.
|
||||
InputStream& GetInputStream();
|
||||
|
||||
absl::Time GetLastModifiedTime() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::InputFile> impl_;
|
||||
};
|
||||
@@ -98,6 +101,8 @@ class OutputFile final {
|
||||
// versa.
|
||||
OutputStream& GetOutputStream();
|
||||
|
||||
void SetLastModifiedTime(absl::Time last_modified_time);
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::OutputFile> impl_;
|
||||
};
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
#define PLATFORM_API_INPUT_FILE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/input_stream.h"
|
||||
|
||||
namespace nearby {
|
||||
@@ -30,6 +30,7 @@ class InputFile : public InputStream {
|
||||
~InputFile() override = default;
|
||||
virtual std::string GetFilePath() const = 0;
|
||||
virtual std::int64_t GetTotalSize() const = 0;
|
||||
virtual absl::Time GetLastModifiedTime() const = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef PLATFORM_API_OUTPUT_FILE_H_
|
||||
#define PLATFORM_API_OUTPUT_FILE_H_
|
||||
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/output_stream.h"
|
||||
|
||||
@@ -25,6 +26,7 @@ namespace api {
|
||||
class OutputFile : public OutputStream {
|
||||
public:
|
||||
~OutputFile() override = default;
|
||||
virtual void SetLastModifiedTime(absl::Time last_modified_time) = 0;
|
||||
// File flush is a no-op.
|
||||
Exception Flush() override { return {Exception::kSuccess}; }
|
||||
};
|
||||
|
||||
@@ -66,6 +66,7 @@ cc_library(
|
||||
"//internal/platform/implementation:types",
|
||||
"@com_google_absl//absl/memory",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/time",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/exception.h"
|
||||
|
||||
namespace nearby {
|
||||
@@ -94,9 +96,13 @@ Exception IOFile::Write(const ByteArray& data) {
|
||||
return {file_.good() ? Exception::kSuccess : Exception::kIo};
|
||||
}
|
||||
|
||||
Exception IOFile::Flush() {
|
||||
file_.flush();
|
||||
return {file_.good() ? Exception::kSuccess : Exception::kIo};
|
||||
absl::Time IOFile::GetLastModifiedTime() const {
|
||||
// TODO(ftsui): Implement this method.
|
||||
return absl::Now();
|
||||
}
|
||||
|
||||
void IOFile::SetLastModifiedTime(absl::Time last_modified_time) {
|
||||
// TODO(ftsui): Implement this method.
|
||||
}
|
||||
|
||||
} // namespace shared
|
||||
|
||||
@@ -15,11 +15,14 @@
|
||||
#ifndef PLATFORM_IMPL_SHARED_FILE_H_
|
||||
#define PLATFORM_IMPL_SHARED_FILE_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/implementation/input_file.h"
|
||||
#include "internal/platform/implementation/output_file.h"
|
||||
@@ -42,7 +45,9 @@ class IOFile final : public api::InputFile, public api::OutputFile {
|
||||
Exception Close() override;
|
||||
|
||||
Exception Write(const ByteArray& data) override;
|
||||
Exception Flush() override;
|
||||
|
||||
absl::Time GetLastModifiedTime() const override;
|
||||
void SetLastModifiedTime(absl::Time last_modified_time) override;
|
||||
|
||||
private:
|
||||
explicit IOFile(const absl::string_view file_path, size_t size);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <fileapi.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
@@ -24,6 +25,9 @@
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/civil_time.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/implementation/windows/string_utils.h"
|
||||
@@ -31,6 +35,57 @@
|
||||
|
||||
namespace nearby::windows {
|
||||
|
||||
namespace {
|
||||
static const absl::Time kFiletimeEpoch =
|
||||
absl::FromCivil(absl::CivilYear(1601), absl::UTCTimeZone());
|
||||
|
||||
constexpr absl::Duration kFiletimeUnit = absl::Nanoseconds(100);
|
||||
const int64_t kFiletimeUnitsPerSecond = absl::Seconds(1) / kFiletimeUnit;
|
||||
|
||||
static const absl::Time kMinDosFileTime =
|
||||
absl::FromCivil(absl::CivilYear(1980), absl::UTCTimeZone());
|
||||
static const absl::Time kMaxDosFileTime =
|
||||
absl::FromCivil(absl::CivilYear(2108), absl::UTCTimeZone()) - kFiletimeUnit;
|
||||
|
||||
absl::Duration DurationFromFiletime(const FILETIME& file_time) {
|
||||
LONGLONG quadDateTime =
|
||||
(static_cast<LONGLONG>(file_time.dwHighDateTime) << 32) |
|
||||
static_cast<LONGLONG>(file_time.dwLowDateTime);
|
||||
|
||||
const absl::Duration subsecond =
|
||||
kFiletimeUnit * (quadDateTime % kFiletimeUnitsPerSecond);
|
||||
const absl::Duration seconds =
|
||||
absl::Seconds(quadDateTime / kFiletimeUnitsPerSecond);
|
||||
return seconds + subsecond;
|
||||
}
|
||||
|
||||
absl::Time TimeFromFiletime(const FILETIME& file_time) {
|
||||
return kFiletimeEpoch + DurationFromFiletime(file_time);
|
||||
}
|
||||
|
||||
bool DurationToFiletime(const absl::Duration duration, FILETIME* file_time) {
|
||||
absl::Duration remainder;
|
||||
const int64_t filetime_value =
|
||||
absl::IDivDuration(duration, kFiletimeUnit, &remainder);
|
||||
if (remainder <= -kFiletimeUnit || remainder >= kFiletimeUnit) {
|
||||
return false;
|
||||
}
|
||||
file_time->dwLowDateTime = static_cast<DWORD>(filetime_value);
|
||||
file_time->dwHighDateTime = static_cast<DWORD>(filetime_value >> 32);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TimeToFiletime(absl::Time time, FILETIME* file_time) {
|
||||
// Clamp to the range that FileTimeToDosDateTime supports. Explorer's date
|
||||
// display and built-in zip feature can only handle this range.
|
||||
time = std::clamp(time, kMinDosFileTime, kMaxDosFileTime);
|
||||
|
||||
if (!DurationToFiletime(time - kFiletimeEpoch, file_time)) {
|
||||
DurationToFiletime(kMaxDosFileTime - kFiletimeEpoch, file_time);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// InputFile
|
||||
std::unique_ptr<IOFile> IOFile::CreateInputFile(absl::string_view file_path,
|
||||
size_t size) {
|
||||
@@ -128,4 +183,34 @@ Exception IOFile::Write(const ByteArray& data) {
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
absl::Time IOFile::GetLastModifiedTime() const {
|
||||
if (file_ == INVALID_HANDLE_VALUE) {
|
||||
LOG(ERROR) << "Failed to get file modified time for: " << path_;
|
||||
return absl::Now();
|
||||
}
|
||||
FILETIME last_write_time;
|
||||
if (::GetFileTime(file_, /*lpCreationTime=*/nullptr,
|
||||
/*lpLastAccessTime=*/nullptr, &last_write_time) == 0) {
|
||||
LOG(ERROR) << "Failed to get file last write time: " << path_
|
||||
<< " with error: " << ::GetLastError();
|
||||
return absl::Now();
|
||||
}
|
||||
return TimeFromFiletime(last_write_time);
|
||||
}
|
||||
|
||||
void IOFile::SetLastModifiedTime(absl::Time last_modified_time) {
|
||||
if (file_ == INVALID_HANDLE_VALUE) {
|
||||
LOG(ERROR) << "Failed to set file modified time for: " << path_;
|
||||
return;
|
||||
}
|
||||
FILETIME last_write_time;
|
||||
TimeToFiletime(last_modified_time, &last_write_time);
|
||||
// Set both creation time and last write time.
|
||||
if (::SetFileTime(file_, /*lpCreationTime=*/&last_write_time,
|
||||
/*lpLastAccessTime=*/nullptr, &last_write_time) == 0) {
|
||||
LOG(ERROR) << "Failed to set file last write time: " << path_
|
||||
<< " with error: " << ::GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nearby::windows
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/implementation/input_file.h"
|
||||
@@ -49,6 +50,8 @@ class IOFile final : public api::InputFile, public api::OutputFile {
|
||||
Exception Close() override;
|
||||
|
||||
Exception Write(const ByteArray& data) override;
|
||||
absl::Time GetLastModifiedTime() const override;
|
||||
void SetLastModifiedTime(absl::Time last_modified_time) override;
|
||||
|
||||
private:
|
||||
explicit IOFile(absl::string_view file_path, size_t size);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/logging.h"
|
||||
@@ -187,5 +188,21 @@ TEST(IOFileTest, OutputFileWrite) {
|
||||
::DeleteFileA(temp_file.data());
|
||||
}
|
||||
|
||||
TEST(IOFileTest, GetSetModifiedTime) {
|
||||
std::string temp_file = GetTempFileName("GetSetModifiedTime");
|
||||
std::unique_ptr<IOFile> output_file = IOFile::CreateOutputFile(temp_file);
|
||||
ASSERT_NE(output_file, nullptr);
|
||||
|
||||
output_file->SetLastModifiedTime(absl::FromUnixSeconds(1234567890));
|
||||
output_file->Close();
|
||||
|
||||
std::unique_ptr<IOFile> input_file =
|
||||
IOFile::CreateInputFile(temp_file, /*size=*/0);
|
||||
EXPECT_EQ(input_file->GetLastModifiedTime(),
|
||||
absl::FromUnixSeconds(1234567890));
|
||||
|
||||
::DeleteFileA(temp_file.data());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby::windows
|
||||
|
||||
Reference in New Issue
Block a user