|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: // ファイルを mmap して提供するクラス
8:
9: #include "mappedfile.h"
10: #include "mystring.h"
11: #include <vector>
12: #include <fcntl.h>
13: #include <sys/stat.h>
14: #include <sys/mman.h>
15:
16: // コンストラクタ
17: MappedFile::MappedFile()
18: {
19: }
20:
21: // デストラクタ
22: MappedFile::~MappedFile()
23: {
24: Close();
25: }
26:
27: // ファイル名を指定する。
28: // filename_ が空でないことは呼び出し側で保証すること。
29: void
30: MappedFile::SetFilename(const std::string& filename_)
31: {
32: filename = filename_;
33: assert(!filename.empty());
34:
35: // 表示名を更新
36: SetDispname(string_format("\"%s\"", filename.c_str()));
37: }
38:
39: // 表示名を設定する。
40: // デフォルトのから変えたい時にどうぞ。
41: void
42: MappedFile::SetDispname(const std::string& name)
43: {
44: dispname = name;
45: }
46:
47: // サイズが len で確定しているファイルを読み込み専用でオープンして mmap する。
48: // ファイルがなければエラー。これは ROM とか用。
49: // 成功すれば mmap した領域のポインタを返す。
50: // 失敗すればエラーメッセージを表示して NULL を返す。
51: uint8 *
52: MappedFile::OpenRdOnly(off_t len)
53: {
54: memlen = len;
55:
56: fd = open(filename.c_str(), O_RDONLY);
57: if (fd < 0) {
58: warn("%s open failed", dispname.c_str());
59: return NULL;
60: }
61:
62: if (CheckFilesize() == false) {
63: Close();
64: return NULL;
65: }
66:
67: // mmap する。
68: // RDONLY なのでファイルには書き戻さないけど、
69: // オンメモリでハックを入れたりできるよう MAP_PRIVATE を指定する。
70: void *m = mmap(NULL, memlen, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
71: if (m == MAP_FAILED) {
72: warn("%s mmap failed", dispname.c_str());
73: Close();
74: return NULL;
75: }
76: mem = (uint8 *)m;
77:
78: return mem;
79: }
80:
81: // サイズが len で確定しているファイルを読み書き両用でオープンして mmap する。
82: // ファイルがなければ作成する。これは SRAM とか用。
83: // 成功すれば mmap した領域のポインタを返す。
84: // 失敗すればエラーメッセージを表示して NULL を返す。
85: uint8 *
86: MappedFile::OpenCreate(off_t memlen_)
87: {
88: memlen = memlen_;
89:
90: fd = open(filename.c_str(), O_RDWR);
91: if (fd < 0) {
92: if (errno != ENOENT) {
93: warn("%s open failed", dispname.c_str());
94: return NULL;
95: } else {
96: // オープンできない理由が ENOENT ならファイルを作ってみる
97: fd = open(filename.c_str(), O_RDWR | O_CREAT, 0644);
98: if (fd < 0) {
99: warn("%s create failed", dispname.c_str());
100: return NULL;
101: }
102:
103: // ゼロで埋める
104: std::vector<char> zerobuf(memlen);
105: if (write(fd, &zerobuf[0], zerobuf.size()) < 0) {
106: warn("%s write failed", dispname.c_str());
107: Close();
108: return NULL;
109: }
110:
111: warnx("%s created", dispname.c_str());
112: // FALLTHROUGH
113: }
114: }
115:
116: if (CheckFilesize() == false) {
117: Close();
118: return NULL;
119: }
120:
121: // mmap する。
122: void *m = mmap(NULL, memlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
123: if (m == MAP_FAILED) {
124: warn("%s mmap failed", dispname.c_str());
125: Close();
126: return NULL;
127: }
128: mem = (uint8 *)m;
129:
130: return mem;
131: }
132:
133: // サイズの確定していないファイルを読み書き両用でオープンして mmap する。
134: // ファイルがなければエラー。これはディスクイメージ用。
135: // 成功すれば mmap した領域のポインタを返す。
136: // 失敗すればエラーメッセージを表示して NULL を返す。
137: uint8 *
138: MappedFile::OpenFile()
139: {
140: struct stat st;
141:
142: fd = open(filename.c_str(), O_RDWR);
143: if (fd < 0) {
144: warn("%s open failed", dispname.c_str());
145: return NULL;
146: }
147:
148: // ファイルサイズを取得
149: if (fstat(fd, &st) < 0) {
150: warn("%s stat failed", dispname.c_str());
151: Close();
152: return NULL;
153: }
154: memlen = st.st_size;
155:
156: // mmap する。
157: void *m = mmap(NULL, memlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
158: if (mem == MAP_FAILED) {
159: warn("%s mmap failed", dispname.c_str());
160: Close();
161: return NULL;
162: }
163: mem = (uint8 *)m;
164:
165: return mem;
166: }
167:
168: // ファイルサイズが memlen と同じかどうか調べる。
169: // ファイルサイズが memlen より短ければエラーメッセージを表示し false を返す。
170: // ファイルサイズが memlen より長ければワーニングを表示し true を返す。
171: // ファイルサイズが memlen と同じなら true を返す。
172: bool
173: MappedFile::CheckFilesize() const
174: {
175: struct stat st;
176:
177: // ファイルサイズをチェック。
178: // ファイルが短くても mmap は黙って成功してしまうようなので。
179: if (fstat(fd, &st) < 0) {
180: warn("%s fstat failed", dispname.c_str());
181: return false;
182: }
183:
184: if (st.st_size < memlen) {
185: warnx("%s is too short (filesize is expected %jd but %jd)",
186: dispname.c_str(), (intmax_t)memlen, (intmax_t)st.st_size);
187: return false;
188: }
189: if (st.st_size > memlen) {
190: // 大きすぎるほうはワーニングだけでいいか
191: warnx("%s is too large (ignore %jd bytes)",
192: dispname.c_str(), (intmax_t)(st.st_size - memlen));
193: }
194: return true;
195: }
196:
197: // ファイルをクローズする。
198: // 呼び出しに副作用はない。
199: void
200: MappedFile::Close()
201: {
202: if (mem != NULL) {
203: munmap(mem, memlen);
204: mem = NULL;
205: memlen = 0;
206: }
1.1.1.2 ! root 207: fd.Close();
1.1 root 208:
209: filename.clear();
210: dispname.clear();
211: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.