@@ -44,7 +44,12 @@ Record read(const fs::path& path, std::string_view tag) {
4444 if (!input) {
4545 std::error_code ec;
4646 if (!fs::exists (path,ec) && !ec) return std::optional<Fields>{};
47- return std::unexpected (" cannot read compiler transaction record" );
47+ if (ec)return std::unexpected (" cannot read compiler transaction record" );
48+ // An atomic publisher may install the record between the failed open
49+ // and the existence probe. Retry once; a persistent refusal still
50+ // fails rather than being mistaken for an absent record.
51+ input.open (path,std::ios::binary);
52+ if (!input)return std::unexpected (" cannot read compiler transaction record" );
4853 }
4954 std::string bytes (65537 ,' \0 ' );
5055 input.read (bytes.data (),bytes.size ());bytes.resize (static_cast <std::size_t >(input.gcount ()));
@@ -99,7 +104,10 @@ std::optional<long long> journal_time(fs::file_time_type time) {
99104}
100105std::optional<Fields> identity (const fs::path& path) {
101106 if (path.empty ())return Fields{" " , " " };
102- std::error_code ec;const auto size=fs::file_size (path,ec);if (ec)return {};
107+ std::error_code ec;
108+ const auto status=fs::symlink_status (path,ec);
109+ if (ec||status.type ()!=fs::file_type::regular)return {};
110+ const auto size=fs::file_size (path,ec);if (ec)return {};
103111 const auto time=fs::last_write_time (path,ec);if (ec)return {};
104112 const auto ticks=journal_time (time);if (!ticks)return {};
105113 return Fields{std::to_string (size),std::to_string (*ticks)};
@@ -377,21 +385,27 @@ private:
377385 std::atomic<bool > stopping_{false },failed_{false };
378386 std::mutex admission_;
379387 ObserverMap held_;
388+ void fail (std::string_view reason) {
389+ if (!failed_.exchange (true ))
390+ std::println (std::cerr," mcpp: compiler witness: {}" ,reason);
391+ }
380392 void audit () {
381393 for (auto it=held_.begin ();it!=held_.end ();) {
382394 const auto directory=named (it->first );
383395 auto retired=read (directory/" retired" ," mcpp-retired-v1" );
384- if (!retired||(*retired&&(**retired).size ()!=3 )) {failed_.store (true );++it;continue ;}
396+ if (!retired) {fail (retired.error ());++it;continue ;}
397+ if (*retired&&(**retired).size ()!=3 ) {fail (" invalid retirement certificate" );++it;continue ;}
385398 if (*retired) {it=held_.erase (it);continue ;}
386399 auto attempt=Attempt::load (directory);
387- if (!attempt) {failed_. store ( true );++it;continue ;}
400+ if (!attempt) {fail (attempt. error () );++it;continue ;}
388401 if (!controller_alive (*attempt)) {
389402 // Retirement can be published between the first read and the
390403 // controller's exit. Observe it again before reporting loss.
391404 retired=read (directory/" retired" ," mcpp-retired-v1" );
392- if (!retired||(*retired&&(**retired).size ()!=3 ))failed_.store (true );
405+ if (!retired)fail (retired.error ());
406+ else if (*retired&&(**retired).size ()!=3 )fail (" invalid retirement certificate" );
393407 else if (*retired) {it=held_.erase (it);continue ;}
394- else failed_. store ( true );
408+ else fail ( " controller ended without retirement certificate " );
395409 }
396410 ++it;
397411 }
0 commit comments