| 500 | } |
| 501 | |
| 502 | void lv2_file::save(utils::serial &ar) { |
| 503 | USING_SERIALIZATION_VERSION(lv2_fs); |
| 504 | ar(name, mode, flags, type, lock, |
| 505 | ensure(vfs::retrieve(real_path), FN(!x.empty()))); |
| 506 | |
| 507 | if (type == lv2_file_type::edata) { |
| 508 | auto file_ptr = file.release(); |
| 509 | ar(static_cast<EDATADecrypter *>(file_ptr.get())->get_key()); |
| 510 | file.reset(std::move(file_ptr)); |
| 511 | } |
| 512 | |
| 513 | if (!mp.read_only && flags & CELL_FS_O_ACCMODE) { |
| 514 | // Ensure accurate timestamps and content on disk |
| 515 | file.sync(); |
| 516 | } |
| 517 | |
| 518 | // UNIX allows deletion of files while descriptors are still opened |
| 519 | // descriptors shall keep the data in memory in this case |
| 520 | const bool in_mem = [&]() { |
| 521 | if (mp.read_only) { |
| 522 | return false; |
| 523 | } |
| 524 | |
| 525 | fs::file test{real_path}; |
| 526 | |
| 527 | if (!test) { |
| 528 | if (fs::is_file(real_path + ".66600")) { |
| 529 | // May be a split-files descriptor, don't even bother |
| 530 | return false; |
| 531 | } |
| 532 | |
| 533 | return true; |
| 534 | } |
| 535 | |
| 536 | fs::file_id test_s = test.get_id(); |
| 537 | fs::file_id file_s = file.get_id(); |
| 538 | |
| 539 | return !test_s.is_coherent_with(file_s); |
| 540 | }(); |
| 541 | |
| 542 | ar(in_mem); |
| 543 | |
| 544 | if (in_mem) { |
| 545 | fs::stat_t stats = file.get_stat(); |
| 546 | |
| 547 | sys_fs.error("Saving \'%s\' LV2 file descriptor in memory! (exists=%s, " |
| 548 | "type=%s, flags=0x%x, size=0x%x)", |
| 549 | name.data(), fs::is_file(real_path), type, flags, stats.size); |
| 550 | |
| 551 | const usz patch_stats_pos = ar.seek_end(); |
| 552 | |
| 553 | ar(stats); |
| 554 | |
| 555 | const usz old_end = ar.pad_from_end(stats.size); |
| 556 | |
| 557 | if (usz read_size = file.read_at(0, &ar.data[old_end], stats.size); |
| 558 | read_size != stats.size) { |
| 559 | ensure(read_size < stats.size); |
nothing calls this directly
no test coverage detected