|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2021 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
1.1.1.2 ! root 8: // ディスクイメージ
1.1 root 9: //
10:
11: #include "diskimage.h"
12: #include "diskimage_raw.h"
1.1.1.2 ! root 13: #include "mainapp.h"
! 14: #include <fcntl.h>
! 15:
! 16: //
! 17: // ディスクイメージクラス (外部向け)
! 18: //
1.1 root 19:
20: // コンストラクタ
1.1.1.2 ! root 21: DiskImage::DiskImage()
1.1 root 22: {
23: }
24:
25: // デストラクタ
26: DiskImage::~DiskImage()
27: {
1.1.1.2 ! root 28: Close();
1.1 root 29: }
30:
1.1.1.2 ! root 31: // パス名を指定して、下位ドライバをオープン
! 32: bool
! 33: DiskImage::CreateHandler(const std::string& pathname_)
1.1 root 34: {
1.1.1.2 ! root 35: pathname = pathname_;
! 36: cow_enable = false;
! 37:
1.1 root 38: // 今の所 Raw しかない
1.1.1.2 ! root 39: try {
! 40: driver.reset(new DiskImageRaw(pathname));
! 41: return true;
! 42: } catch (...) {
! 43: }
! 44:
! 45: return false;
! 46: }
! 47:
! 48:
! 49: // このディスクイメージのサイズと書き込み可能かどうかを返す。
! 50: // Open() 前でも動作する。
! 51: bool
! 52: DiskImage::GetInfo(off_t *sizep, bool *w_ok)
! 53: {
! 54: assert((bool)driver);
! 55: return driver->GetInfo(sizep, w_ok);
! 56: }
! 57:
! 58: // オープン
! 59: //
! 60: // ro cow
! 61: // false false : RW オープン、書き込み可
! 62: // true false : RO オープン、読み込み専用
! 63: // * true : RO オープン、CoW
! 64: bool
! 65: DiskImage::Open(bool read_only, bool cow_enable_)
! 66: {
! 67: assert((bool)driver);
! 68: cow_enable = cow_enable_;
! 69:
! 70: // ベースファイルをオープン
! 71: if (cow_enable) {
! 72: read_only = true;
! 73: }
! 74: if (driver->Open(read_only) == false) {
! 75: return false;
! 76: }
! 77:
! 78: if (cow_enable) {
! 79: // CoW なら一時ファイルもオープン
! 80:
! 81: // VM ディレクトリに適当な名前の隠しファイルで作成
! 82: auto pos = pathname.rfind('/');
! 83: if (pos != std::string::npos) {
! 84: // パス区切りがあればファイル名部分
! 85: cowname = pathname.substr(pos + 1);
! 86: } else {
! 87: // なければ全部
! 88: cowname = pathname;
! 89: }
! 90: // 空になることはないはず
! 91: assert(cowname.empty() == false);
! 92:
! 93: cowname = gMainApp.GetVMDir() + "/." + cowname + ".cow";
! 94: cowfd = open(cowname.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
! 95: if (cowfd < 0) {
! 96: return false;
! 97: }
! 98: }
! 99:
! 100: return true;
! 101: }
! 102:
! 103: // クローズ
! 104: void
! 105: DiskImage::Close()
! 106: {
! 107: if (cow_enable) {
! 108: if (cowfd.Valid()) {
! 109: cowfd.Close();
! 110: unlink(cowname.c_str());
! 111: }
! 112: cow_enable = false;
! 113: }
! 114:
! 115: if ((bool)driver) {
! 116: driver.reset();
! 117: }
! 118: }
! 119:
! 120: // このディスクイメージのサイズ(バイト数)を返す。
! 121: // オープン後のみ使用可能。
! 122: off_t
! 123: DiskImage::GetSize() const
! 124: {
! 125: assert((bool)driver);
! 126: return driver->GetSize();
! 127: }
! 128:
! 129: // 読み出し
! 130: bool
! 131: DiskImage::Read(void *buf, off_t offset, size_t size) const
! 132: {
! 133: assert((bool)driver);
! 134:
! 135: if (__predict_false(offset + size >= GetSize())) {
! 136: return false;
! 137: }
! 138:
! 139: if (__predict_true(cow_enable == false)) {
! 140: // 通常モード
! 141: return driver->Read(buf, offset, size);
! 142:
! 143: } else {
! 144: // Copy-on-Write モード
! 145: while (size > 0) {
! 146: off_t blk_addr = offset / BLKSIZE;
! 147: size_t blk_off = offset % BLKSIZE;
! 148: size_t blk_size = std::min(size, BLKSIZE - blk_off);
! 149:
! 150: if (map_contains(blk_addr)) {
! 151: // キャッシュにあればそこから読み出す。
! 152: auto cow_offset = map.at(blk_addr);
! 153: if (lseek(cowfd, cow_offset + blk_off, SEEK_SET) < 0) {
! 154: return false;
! 155: }
! 156: if (read(cowfd, buf, blk_size) < 0) {
! 157: return false;
! 158: }
! 159: } else {
! 160: // キャッシュになければファイルから直接読む
! 161: if (driver->Read(buf, offset, blk_size) == false) {
! 162: return false;
! 163: }
! 164: }
! 165:
! 166: buf = (uint8 *)buf + blk_size;
! 167: offset += blk_size;
! 168: size -= blk_size;
! 169: }
! 170: }
! 171:
! 172: return true;
! 173: }
! 174:
! 175: // 書き込み
! 176: bool
! 177: DiskImage::Write(const void *buf, off_t offset, size_t size)
! 178: {
! 179: assert((bool)driver);
! 180:
! 181: if (__predict_false(offset + size >= GetSize())) {
! 182: return false;
! 183: }
! 184:
! 185: if (__predict_true(cow_enable == false)) {
! 186: // 通常モード
! 187: return driver->Write(buf, offset, size);
! 188:
! 189: } else {
! 190: // Copy-on-Write モード
! 191:
! 192: off_t cow_offset;
! 193: while (size > 0) {
! 194: off_t blk_addr = offset / BLKSIZE;
! 195: size_t blk_off = offset % BLKSIZE;
! 196: size_t blk_size = std::min(size, BLKSIZE - blk_off);
! 197:
! 198: if (map_contains(blk_addr) == false) {
! 199: // キャッシュになければファイルから読んで..
! 200: SectBuf newbuf;
! 201: off_t read_off = blk_addr * BLKSIZE;
! 202: if (driver->Read(&newbuf[0], read_off, BLKSIZE) == false) {
! 203: return false;
! 204: }
! 205:
! 206: // それをキャッシュの末尾に追加
! 207: cow_offset = lseek(cowfd, 0, SEEK_END);
! 208: if (cow_offset == (off_t)-1) {
! 209: return false;
! 210: }
! 211: if (write(cowfd, &newbuf[0], BLKSIZE) < BLKSIZE) {
! 212: return false;
! 213: }
! 214: map.emplace(blk_addr, cow_offset);
! 215: }
! 216:
! 217: // キャッシュに書き込む
! 218: cow_offset = map.at(blk_addr);
! 219: if (lseek(cowfd, cow_offset + blk_off, SEEK_SET) < 0) {
! 220: return false;
! 221: }
! 222: if (write(cowfd, buf, blk_size) < 0) {
! 223: return false;
! 224: }
! 225:
! 226: buf = (const uint8 *)buf + blk_size;
! 227: offset += blk_size;
! 228: size -= blk_size;
! 229: }
! 230: }
! 231:
! 232: return true;
! 233: }
! 234:
! 235:
! 236: //
! 237: // ディスクイメージドライバの基本クラス
! 238: //
! 239:
! 240: // コンストラクタ
! 241: DiskImageDriver::DiskImageDriver(const std::string& pathname_)
! 242: : pathname(pathname_)
! 243: {
! 244: }
! 245:
! 246: // デストラクタ
! 247: DiskImageDriver::~DiskImageDriver()
! 248: {
1.1 root 249: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.