|
|
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:
1.1.1.3 ! root 135: if (__predict_false(offset + size > GetSize())) {
1.1.1.2 root 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:
1.1.1.3 ! root 181: if (__predict_false(offset + size > GetSize())) {
1.1.1.2 root 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.