--- nono/host/diskimage.cpp 2026/04/29 17:04:57 1.1.1.1 +++ nono/host/diskimage.cpp 2026/04/29 17:05:11 1.1.1.3 @@ -5,26 +5,245 @@ // // -// ディスクイメージの基本クラス +// ディスクイメージ // #include "diskimage.h" #include "diskimage_raw.h" +#include "mainapp.h" +#include + +// +// ディスクイメージクラス (外部向け) +// // コンストラクタ -DiskImage::DiskImage(DiskImage::Type type_) +DiskImage::DiskImage() { - type = type_; } // デストラクタ DiskImage::~DiskImage() { + Close(); } -/*static*/ DiskImage * -DiskImage::Create(const std::string& pathname_) +// パス名を指定して、下位ドライバをオープン +bool +DiskImage::CreateHandler(const std::string& pathname_) { + pathname = pathname_; + cow_enable = false; + // 今の所 Raw しかない - return new DiskImageRaw(pathname_); + try { + driver.reset(new DiskImageRaw(pathname)); + return true; + } catch (...) { + } + + return false; +} + + +// このディスクイメージのサイズと書き込み可能かどうかを返す。 +// Open() 前でも動作する。 +bool +DiskImage::GetInfo(off_t *sizep, bool *w_ok) +{ + assert((bool)driver); + return driver->GetInfo(sizep, w_ok); +} + +// オープン +// +// ro cow +// false false : RW オープン、書き込み可 +// true false : RO オープン、読み込み専用 +// * true : RO オープン、CoW +bool +DiskImage::Open(bool read_only, bool cow_enable_) +{ + assert((bool)driver); + cow_enable = cow_enable_; + + // ベースファイルをオープン + if (cow_enable) { + read_only = true; + } + if (driver->Open(read_only) == false) { + return false; + } + + if (cow_enable) { + // CoW なら一時ファイルもオープン + + // VM ディレクトリに適当な名前の隠しファイルで作成 + auto pos = pathname.rfind('/'); + if (pos != std::string::npos) { + // パス区切りがあればファイル名部分 + cowname = pathname.substr(pos + 1); + } else { + // なければ全部 + cowname = pathname; + } + // 空になることはないはず + assert(cowname.empty() == false); + + cowname = gMainApp.GetVMDir() + "/." + cowname + ".cow"; + cowfd = open(cowname.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644); + if (cowfd < 0) { + return false; + } + } + + return true; +} + +// クローズ +void +DiskImage::Close() +{ + if (cow_enable) { + if (cowfd.Valid()) { + cowfd.Close(); + unlink(cowname.c_str()); + } + cow_enable = false; + } + + if ((bool)driver) { + driver.reset(); + } +} + +// このディスクイメージのサイズ(バイト数)を返す。 +// オープン後のみ使用可能。 +off_t +DiskImage::GetSize() const +{ + assert((bool)driver); + return driver->GetSize(); +} + +// 読み出し +bool +DiskImage::Read(void *buf, off_t offset, size_t size) const +{ + assert((bool)driver); + + if (__predict_false(offset + size > GetSize())) { + return false; + } + + if (__predict_true(cow_enable == false)) { + // 通常モード + return driver->Read(buf, offset, size); + + } else { + // Copy-on-Write モード + while (size > 0) { + off_t blk_addr = offset / BLKSIZE; + size_t blk_off = offset % BLKSIZE; + size_t blk_size = std::min(size, BLKSIZE - blk_off); + + if (map_contains(blk_addr)) { + // キャッシュにあればそこから読み出す。 + auto cow_offset = map.at(blk_addr); + if (lseek(cowfd, cow_offset + blk_off, SEEK_SET) < 0) { + return false; + } + if (read(cowfd, buf, blk_size) < 0) { + return false; + } + } else { + // キャッシュになければファイルから直接読む + if (driver->Read(buf, offset, blk_size) == false) { + return false; + } + } + + buf = (uint8 *)buf + blk_size; + offset += blk_size; + size -= blk_size; + } + } + + return true; +} + +// 書き込み +bool +DiskImage::Write(const void *buf, off_t offset, size_t size) +{ + assert((bool)driver); + + if (__predict_false(offset + size > GetSize())) { + return false; + } + + if (__predict_true(cow_enable == false)) { + // 通常モード + return driver->Write(buf, offset, size); + + } else { + // Copy-on-Write モード + + off_t cow_offset; + while (size > 0) { + off_t blk_addr = offset / BLKSIZE; + size_t blk_off = offset % BLKSIZE; + size_t blk_size = std::min(size, BLKSIZE - blk_off); + + if (map_contains(blk_addr) == false) { + // キャッシュになければファイルから読んで.. + SectBuf newbuf; + off_t read_off = blk_addr * BLKSIZE; + if (driver->Read(&newbuf[0], read_off, BLKSIZE) == false) { + return false; + } + + // それをキャッシュの末尾に追加 + cow_offset = lseek(cowfd, 0, SEEK_END); + if (cow_offset == (off_t)-1) { + return false; + } + if (write(cowfd, &newbuf[0], BLKSIZE) < BLKSIZE) { + return false; + } + map.emplace(blk_addr, cow_offset); + } + + // キャッシュに書き込む + cow_offset = map.at(blk_addr); + if (lseek(cowfd, cow_offset + blk_off, SEEK_SET) < 0) { + return false; + } + if (write(cowfd, buf, blk_size) < 0) { + return false; + } + + buf = (const uint8 *)buf + blk_size; + offset += blk_size; + size -= blk_size; + } + } + + return true; +} + + +// +// ディスクイメージドライバの基本クラス +// + +// コンストラクタ +DiskImageDriver::DiskImageDriver(const std::string& pathname_) + : pathname(pathname_) +{ +} + +// デストラクタ +DiskImageDriver::~DiskImageDriver() +{ }