CCF
Loading...
Searching...
No Matches
filenames.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5#include <filesystem>
6#include <optional>
7#include <string>
8
9namespace snapshots
10{
11 namespace fs = std::filesystem;
12
13 static constexpr auto snapshot_file_prefix = "snapshot";
14 static constexpr auto snapshot_idx_delimiter = "_";
15 static constexpr auto snapshot_committed_suffix = ".committed";
16
17 static bool is_snapshot_file(const std::string& file_name)
18 {
19 return file_name.starts_with(snapshot_file_prefix);
20 }
21
22 static bool is_snapshot_file_committed(const std::string& file_name)
23 {
24 return file_name.find(snapshot_committed_suffix) != std::string::npos;
25 }
26
27 static size_t read_idx(const std::string& str)
28 {
29 size_t idx = 0;
30 auto end_ptr = str.data() + str.size();
31
32 auto res = std::from_chars(str.data(), end_ptr, idx);
33 if (res.ec != std::errc())
34 {
35 throw std::logic_error(
36 fmt::format("Could not read idx from string \"{}\": {}", str, res.ec));
37 }
38 else if (res.ptr != end_ptr)
39 {
40 throw std::logic_error(fmt::format(
41 "Trailing characters in \"{}\" cannot be converted to idx: \"{}\"",
42 str,
43 std::string(res.ptr, end_ptr)));
44 }
45 return idx;
46 }
47
48 static std::optional<size_t> get_evidence_commit_idx_from_file_name(
49 const std::string& file_name)
50 {
51 // Only returns an evidence commit index for 1.x committed snapshots.
52 // 1.x committed snapshots file names are of the form:
53 // "snapshot_X_Y.committed_Z" while 2.x+ ones are of the form:
54 // "snapshot_X_Y.committed"
55 auto pos = file_name.find(snapshot_committed_suffix);
56 if (pos == std::string::npos)
57 {
58 throw std::logic_error(
59 fmt::format("Snapshot file \"{}\" is not committed", file_name));
60 }
61
62 pos = file_name.find(snapshot_idx_delimiter, pos);
63 if (pos == std::string::npos)
64 {
65 // 2.x+ snapshot
66 return std::nullopt;
67 }
68
69 return read_idx(file_name.substr(pos + 1));
70 }
71
72 static size_t get_snapshot_idx_from_file_name(const std::string& file_name)
73 {
74 if (!is_snapshot_file(file_name))
75 {
76 throw std::logic_error(
77 fmt::format("File \"{}\" is not a valid snapshot file", file_name));
78 }
79
80 auto idx_pos = file_name.find_first_of(snapshot_idx_delimiter);
81 if (idx_pos == std::string::npos)
82 {
83 throw std::logic_error(fmt::format(
84 "Snapshot file name {} does not contain snapshot seqno", file_name));
85 }
86
87 auto evidence_idx_pos =
88 file_name.find_first_of(snapshot_idx_delimiter, idx_pos + 1);
89 if (evidence_idx_pos == std::string::npos)
90 {
91 throw std::logic_error(fmt::format(
92 "Snapshot file \"{}\" does not contain evidence index", file_name));
93 }
94
95 return read_idx(
96 file_name.substr(idx_pos + 1, evidence_idx_pos - idx_pos - 1));
97 }
98
99 static size_t get_snapshot_evidence_idx_from_file_name(
100 const std::string& file_name)
101 {
102 if (!is_snapshot_file(file_name))
103 {
104 throw std::logic_error(
105 fmt::format("File \"{}\" is not a valid snapshot file", file_name));
106 }
107
108 auto idx_pos = file_name.find_first_of(snapshot_idx_delimiter);
109 if (idx_pos == std::string::npos)
110 {
111 throw std::logic_error(
112 fmt::format("Snapshot file \"{}\" does not contain index", file_name));
113 }
114
115 auto evidence_idx_pos =
116 file_name.find_first_of(snapshot_idx_delimiter, idx_pos + 1);
117 if (evidence_idx_pos == std::string::npos)
118 {
119 throw std::logic_error(fmt::format(
120 "Snapshot file \"{}\" does not contain evidence index", file_name));
121 }
122
123 // Note: Snapshot file may not be committed
124 size_t end_str = std::string::npos;
125 auto commit_suffix_pos =
126 file_name.find_first_of(snapshot_committed_suffix, evidence_idx_pos + 1);
127 if (commit_suffix_pos != std::string::npos)
128 {
129 end_str = commit_suffix_pos - evidence_idx_pos - 1;
130 }
131
132 return read_idx(file_name.substr(evidence_idx_pos + 1, end_str));
133 }
134
135 inline std::optional<fs::path> find_latest_committed_snapshot_in_directory(
136 const fs::path& directory, size_t& latest_committed_snapshot_idx)
137 {
138 std::optional<fs::path> latest_committed_snapshot_file_name = std::nullopt;
139
140 for (auto& f : fs::directory_iterator(directory))
141 {
142 auto file_name = f.path().filename();
143 if (!is_snapshot_file(file_name))
144 {
145 LOG_INFO_FMT("Ignoring non-snapshot file {}", file_name);
146 continue;
147 }
148
149 if (!is_snapshot_file_committed(file_name))
150 {
151 LOG_INFO_FMT("Ignoring non-committed snapshot file {}", file_name);
152 continue;
153 }
154
155 if (fs::exists(f.path()) && fs::is_empty(f.path()))
156 {
157 LOG_INFO_FMT("Ignoring empty snapshot file {}", file_name);
158 continue;
159 }
160
161 auto snapshot_idx = get_snapshot_idx_from_file_name(file_name);
162 if (snapshot_idx > latest_committed_snapshot_idx)
163 {
164 latest_committed_snapshot_file_name = file_name;
165 latest_committed_snapshot_idx = snapshot_idx;
166 }
167 }
168
169 return latest_committed_snapshot_file_name;
170 }
171}
#define LOG_INFO_FMT
Definition logger.h:362
Definition fetch.h:35
std::optional< fs::path > find_latest_committed_snapshot_in_directory(const fs::path &directory, size_t &latest_committed_snapshot_idx)
Definition filenames.h:135