28 using std::unique_ptr;
34 static string initialFilePoolSettingValue()
58 controller,
"__filepool",
59 "This is an internal setting. Don't change this directly, "
60 "instead use the 'filepool' command.",
61 initialFilePoolSettingValue()))
62 , distributor(distributor_)
63 , cliComm(controller.getCliComm())
66 filePoolSetting->attach(*
this);
78 filePoolSetting->detach(*
this);
81 void FilePool::insert(
const Sha1Sum& sum, time_t time,
const string& filename)
83 auto it = pool.insert(make_pair(sum, make_pair(time, filename)));
84 reversePool.insert(make_pair(it->second.second, it));
88 void FilePool::remove(Pool::iterator it)
90 reversePool.erase(it->second.second);
95 static bool parse(
const string& line, Sha1Sum& sha1, time_t& time,
string& filename)
97 if (line.size() <= 68)
return false;
100 sha1.parse40(line.data());
101 }
catch (MSXException& ) {
106 if (time == time_t(-1))
return false;
108 filename.assign(line, 68, line.size());
112 void FilePool::readSha1sums()
115 ifstream file(cacheFile.c_str());
120 while (file.good()) {
122 if (parse(line, sum, time, filename)) {
123 insert(sum, time, filename);
128 void FilePool::writeSha1sums()
133 if (!file.is_open()) {
136 for (
auto& p : pool) {
137 file << p.first.toString() <<
" "
144 static int parseTypes(
const TclObject& list)
147 unsigned num = list.getListLength();
148 for (
unsigned i = 0; i < num; ++i) {
149 string_ref elem = list.getListIndex(i).getString();
150 if (elem ==
"system_rom") {
152 }
else if (elem ==
"rom") {
154 }
else if (elem ==
"disk") {
156 }
else if (elem ==
"tape") {
159 throw CommandException(
"Unknown type: " + elem);
165 void FilePool::update(
const Setting& setting)
167 assert(&setting == filePoolSetting.get()); (void)setting;
171 FilePool::Directories FilePool::getDirectories()
const
174 TclObject all(filePoolSetting->getValue());
175 unsigned numLines = all.getListLength();
176 for (
unsigned i = 0; i < numLines; ++i) {
178 bool hasPath =
false;
180 TclObject line = all.getListIndex(i);
181 unsigned numItems = line.getListLength();
183 throw CommandException(
184 "Expected a list with an even number "
185 "of elements, but got " + line.getString());
187 for (
unsigned j = 0; j < numItems; j += 2) {
188 string_ref name = line.getListIndex(j + 0).getString();
189 TclObject value = line.getListIndex(j + 1);
190 if (name ==
"-path") {
191 entry.path = value.getString().
str();
193 }
else if (name ==
"-types") {
194 entry.types = parseTypes(value);
196 throw CommandException(
197 "Unknown item: " + name);
201 throw CommandException(
202 "Missing -path item: " + line.getString());
204 if (entry.types == 0) {
205 throw CommandException(
206 "Missing -types item: " + line.getString());
208 result.push_back(entry);
215 unique_ptr<File> result;
216 result = getFromPool(sha1sum);
224 Directories directories;
226 directories = getDirectories();
228 cliComm.
printWarning(
"Error while parsing '__filepool' setting" +
231 for (
auto& d : directories) {
232 if (d.types & fileType) {
234 result = scanDirectory(sha1sum, path, d.path);
251 unique_ptr<File> FilePool::getFromPool(
const Sha1Sum& sha1sum)
253 auto bound = pool.equal_range(sha1sum);
254 auto it = bound.first;
255 while (it != bound.second) {
256 auto& time = it->second.first;
257 const auto& filename = it->second.second;
259 auto file = make_unique<File>(filename);
261 if (time == newTime) {
267 auto newSum = calcSha1sum(*file, cliComm, distributor);
268 if (newSum == sha1sum) {
278 insert(newSum, newTime, filename);
279 }
catch (FileException&) {
288 unique_ptr<File> FilePool::scanDirectory(
const Sha1Sum& sha1sum,
const string& directory,
const string& poolPath)
290 ReadDir dir(directory);
291 while (dirent* d = dir.getEntry()) {
298 string file = d->d_name;
299 string path = directory +
'/' + file;
302 unique_ptr<File> result;
304 result = scanFile(sha1sum, path, st, poolPath);
306 if ((file !=
".") && (file !=
"..")) {
307 result = scanDirectory(sha1sum, path, poolPath);
318 unique_ptr<File> FilePool::scanFile(
const Sha1Sum& sha1sum,
const string& filename,
324 if (now > (lastTime + 250000)) {
327 sha1sum.toString() +
"...\nIndexing filepool " + poolPath +
329 filename.substr(poolPath.size()));
336 auto it = findInDatabase(filename);
337 if (it == pool.end()) {
340 auto file = make_unique<File>(filename);
341 auto sum = calcSha1sum(*file, cliComm, distributor);
343 insert(sum, time, filename);
344 if (sum == sha1sum) {
347 }
catch (FileException&) {
352 assert(filename == it->second.second);
355 if (time == it->second.first) {
357 if (it->first == sha1sum) {
358 return make_unique<File>(filename);
362 auto file = make_unique<File>(filename);
363 auto sum = calcSha1sum(*file, cliComm, distributor);
365 insert(sum, time, filename);
366 if (sum == sha1sum) {
370 }
catch (FileException&) {
378 FilePool::Pool::iterator FilePool::findInDatabase(
const string& filename)
380 auto it = reversePool.find(filename);
381 if (it != reversePool.end()) {
391 const auto& filename = file.
getURL();
393 auto it = findInDatabase(filename);
394 if (it != pool.end()) {
396 if (time == it->second.first) {
405 auto sum = calcSha1sum(file, cliComm, distributor);
406 insert(sum, time, filename);
412 auto it = findInDatabase(file.
getURL());
413 if (it != pool.end()) {
418 int FilePool::signalEvent(
const std::shared_ptr<const Event>& event)