30 std::function<
void(std::string_view,
float)> reportProgress_)
31 : fileCache(
std::move(fileCache_))
32 , getDirectories(
std::move(getDirectories_))
33 , reportProgress(
std::move(reportProgress_))
49void FilePoolCore::insert(
const Sha1Sum&
sum, time_t time,
const std::string& filename)
51 stringBuffer.push_back(filename);
52 auto idx = pool.
emplace(
sum, time, stringBuffer.back()).idx;
53 auto it = std::ranges::upper_bound(sha1Index,
sum, {},
GetSha1{pool});
54 sha1Index.insert(it, idx);
59FilePoolCore::Sha1Index::iterator FilePoolCore::getSha1Iterator(Index idx,
const Entry& entry)
62 for (
auto [b, e] = std::ranges::equal_range(sha1Index, entry.sum, {},
GetSha1{pool}); b !=
e; ++b) {
67 assert(
false);
return sha1Index.end();
70void FilePoolCore::remove(Sha1Index::iterator it)
73 filenameIndex.
erase(idx);
79void FilePoolCore::remove(Index idx,
const Entry& entry)
81 remove(getSha1Iterator(idx, entry));
84void FilePoolCore::remove(Index idx)
86 remove(idx, pool[idx]);
95bool FilePoolCore::adjustSha1(Sha1Index::iterator it, Entry& entry,
const Sha1Sum& newSum)
98 auto newIt = std::ranges::upper_bound(sha1Index, newSum, {},
GetSha1{pool});
102 rotate(it, it + 1, newIt);
107 rotate(newIt, it, it + 1);
117bool FilePoolCore::adjustSha1(Index idx, Entry& entry,
const Sha1Sum& newSum)
119 return adjustSha1(getSha1Iterator(idx, entry), entry, newSum);
122time_t FilePoolCore::Entry::getTime()
130void FilePoolCore::Entry::setTime(time_t
t)
137static std::optional<std::tuple<Sha1Sum, const char*, std::string_view>> parse(
138 std::span<char> line)
140 if (line.size() <= 68)
return {};
143 if (line[40] !=
' ')
return {};
144 if (line[41] !=
' ')
return {};
145 if (line[45] !=
' ')
return {};
146 if (line[49] !=
' ')
return {};
147 if (line[52] !=
' ')
return {};
148 if (line[55] !=
':')
return {};
149 if (line[58] !=
':')
return {};
150 if (line[61] !=
' ')
return {};
151 if (line[66] !=
' ')
return {};
152 if (line[67] !=
' ')
return {};
154 Sha1Sum sha1(Sha1Sum::UninitializedTag{});
156 sha1.parse40(subspan<40>(line));
157 }
catch (MSXException&) {
161 const char* timeStr = &line[42];
164 std::string_view filename(&line[68], line.size() - 68);
166 return std::tuple{sha1, timeStr, filename};
169void FilePoolCore::readSha1sums()
171 assert(sha1Index.empty());
172 assert(fileMem.
empty());
174 File file(fileCache);
175 auto size = file.getSize();
177 file.read(fileMem.
first(size));
178 fileMem[
size] =
'\n';
182 char* data = fileMem.
begin();
183 char* data_end = fileMem.
end();
184 while (data != data_end) {
186 auto* it =
static_cast<char*
>(memchr(data,
'\n', data_end - data));
187 if (it ==
nullptr) it = data_end;
188 if ((it != data) && (it[-1] ==
'\r')) --it;
190 if (
auto r = parse({data, it})) {
191 auto [
sum, timeStr, filename] = *r;
192 sha1Index.push_back(pool.
emplace(
sum, timeStr, filename).idx);
196 data = std::find_if(it + 1, data_end, [](
char c) {
197 return c !=
one_of(
'\n',
'\r');
210 auto n = sha1Index.size();
214 Index idx = sha1Index[n];
215 bool inserted = filenameIndex.
insert(idx);
224void FilePoolCore::writeSha1sums()
228 if (!file.is_open()) {
231 for (
auto idx : sha1Index) {
232 const auto& entry = pool[idx];
233 file << entry.sum.toString() <<
" ";
235 file << entry.timeStr;
240 file <<
" " << entry.filename <<
'\n';
246 File result = getFromPool(sha1sum);
247 if (result.
is_open())
return result;
251 ScanProgress progress {
255 for (
const auto& [path, types] : getDirectories()) {
259 if (progress.printed) {
267 if (progress.printed) {
268 reportProgress(
tmpStrCat(
"Did not find file with sha1sum ", sha1sum.
toString()), 1.0f);
277 constexpr size_t STEP_SIZE = 1024 * 1024;
279 auto data = file.
mmap();
282 size_t size = data.size();
284 size_t remaining = size;
286 bool everShowedProgress =
false;
288 auto report = [&](
float fraction) {
293 while (remaining > STEP_SIZE) {
294 sha1.
update({&data[done], STEP_SIZE});
296 remaining -= STEP_SIZE;
299 if ((now - lastShowedProgress) > 250'000) {
300 report(
float(done) /
float(size));
301 lastShowedProgress = now;
302 everShowedProgress =
true;
307 sha1.
update({&data[done], remaining});
309 if (everShowedProgress) {
315File FilePoolCore::getFromPool(
const Sha1Sum& sha1sum)
317 auto [b,
e] = std::ranges::equal_range(sha1Index, sha1sum, {},
GetSha1{pool});
322 auto it =
begin(sha1Index) + i;
323 auto& entry = pool[*it];
332 File file(std::string(entry.filename));
334 if (entry.getTime() == newTime) {
340 entry.setTime(newTime);
342 auto newSum = calcSha1sum(file);
343 if (newSum == sha1sum) {
350 if (adjustSha1(it, entry, newSum)) {
357 }
catch (FileException&) {
367File FilePoolCore::scanDirectory(
368 const Sha1Sum& sha1sum,
const std::string& directory, std::string_view poolPath,
369 ScanProgress& progress)
377 assert(!result.is_open());
380 result = scanFile(sha1sum, path, st, poolPath, progress);
381 return !result.is_open();
387File FilePoolCore::scanFile(
const Sha1Sum& sha1sum,
const std::string& filename,
389 ScanProgress& progress)
391 ++progress.amountScanned;
394 now > (progress.lastTime + 250'000)) {
395 progress.lastTime = now;
396 progress.printed =
true;
398 "Searching for file with sha1sum ", sha1sum.toString(),
399 "...\nIndexing filepool ", poolPath,
": [",
400 progress.amountScanned,
"]: ",
401 std::string_view(filename).substr(poolPath.size())),
406 if (
auto [idx, entry] = findInDatabase(filename); idx == Index(-1)) {
410 auto sum = calcSha1sum(file);
411 insert(
sum, time, filename);
412 if (
sum == sha1sum) {
415 }
catch (FileException&) {
420 assert(filename == entry->filename);
422 if (entry->getTime() == time) {
424 if (entry->sum == sha1sum) {
425 return File(filename);
430 auto sum = calcSha1sum(file);
431 entry->setTime(time);
432 adjustSha1(idx, *entry,
sum);
433 if (
sum == sha1sum) {
437 }
catch (FileException&) {
445std::pair<FilePoolCore::Index, FilePoolCore::Entry*> FilePoolCore::findInDatabase(std::string_view filename)
447 auto it = filenameIndex.
find(filename);
448 if (!it)
return {Index(-1),
nullptr};
451 auto& entry = pool[idx];
452 assert(entry.filename == filename);
456 return {Index(-1),
nullptr};
458 return {idx, &entry};
464 const std::string& filename = file.
getURL();
466 auto [idx, entry] = findInDatabase(filename);
467 if ((idx != Index(-1)) && (entry->getTime() == time)) {
474 auto sum = calcSha1sum(file);
475 if (idx == Index(-1)) {
477 insert(
sum, time, filename);
480 entry->setTime(time);
481 adjustSha1(idx, *entry,
sum);
EmplaceResult emplace(Args &&...args)
Value * find(const Value2 &val) const
bool insert(Value2 &&val)
bool erase(const Value2 &val)
Sha1Sum getSha1Sum(File &file)
Calculate sha1sum for the given File object.
File getFile(FileType fileType, const Sha1Sum &sha1sum)
Search file with the given sha1sum.
std::vector< Dir > Directories
FilePoolCore(std::string fileCache, std::function< Directories()> getDirectories, std::function< void(std::string_view, float)> reportProgress)
std::span< const uint8_t > mmap()
Map file in memory.
std::string_view getOriginalName()
Get Original filename for this object.
time_t getModificationDate()
Get the date/time of last modification.
bool is_open() const
Return true iff this file handle refers to an open file.
const std::string & getURL() const
Returns the URL of this file object.
std::span< const T > first(size_t n) const
void resize(size_t size)
Grow or shrink the memory block.
Helper class to perform a sha1 calculation.
Sha1Sum digest()
Get the final hash.
void update(std::span< const uint8_t > data)
Incrementally calculate the hash value.
This class represents the result of a sha1 calculation (a 160-bit value).
std::string toString() const
mat4 rotate(float angle, const vec3 &axis)
std::string toString(time_t time)
time_t fromString(std::span< const char, 24 > s)
constexpr time_t INVALID_TIME_T
string expandTilde(string path)
Expand the '~' character to the users home directory.
void openOfStream(std::ofstream &stream, zstring_view filename)
Open an ofstream in a platform-independent manner.
time_t getModificationDate(const Stat &st)
Get the date/time of last modification.
uint64_t getTime()
Get current (real) time in us.
This file implemented 3 utility functions:
bool foreach_file_recursive(std::string path, FileAction fileAction)
bool is_sorted(ForwardRange &&range, Compare comp={}, Proj proj={})
constexpr void sort(RandomAccessRange &&range)
size_t size(std::string_view utf8)
auto distance(octet_iterator first, octet_iterator last)
constexpr auto sum(InputRange &&range, Proj proj={})
TemporaryString tmpStrCat(Ts &&... ts)
const Sha1Sum & operator()(FilePoolCore::Index idx) const
const FilePoolCore::Pool & pool
constexpr auto begin(const zstring_view &x)