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