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