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