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