|
|
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: // ファイルがなければ作成する。これは SRAM とか用。
49: // 成功すれば mmap した領域のポインタを返す。
50: // 失敗すればエラーメッセージを表示して NULL を返す。
51: uint8 *
52: MappedFile::OpenCreate(off_t memlen_)
53: {
54: memlen = memlen_;
55:
56: fd = open(filename.c_str(), O_RDWR);
57: if (fd < 0) {
58: if (errno != ENOENT) {
59: warn("%s open failed", dispname.c_str());
60: return NULL;
61: } else {
62: // オープンできない理由が ENOENT ならファイルを作ってみる
63: fd = open(filename.c_str(), O_RDWR | O_CREAT, 0644);
64: if (fd < 0) {
65: warn("%s create failed", dispname.c_str());
66: return NULL;
67: }
68:
69: // ゼロで埋める
70: std::vector<char> zerobuf(memlen);
71: if (write(fd, &zerobuf[0], zerobuf.size()) < 0) {
72: warn("%s write failed", dispname.c_str());
73: Close();
74: return NULL;
75: }
76:
77: warnx("%s created", dispname.c_str());
78: // FALLTHROUGH
79: }
80: }
81:
82: if (CheckFilesize() == false) {
83: Close();
84: return NULL;
85: }
86:
87: // mmap する。
88: void *m = mmap(NULL, memlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
89: if (m == MAP_FAILED) {
90: warn("%s mmap failed", dispname.c_str());
91: Close();
92: return NULL;
93: }
94: mem = (uint8 *)m;
95:
96: return mem;
97: }
98:
99: // ファイルサイズが memlen と同じかどうか調べる。
100: // ファイルサイズが memlen より短ければエラーメッセージを表示し false を返す。
101: // ファイルサイズが memlen より長ければワーニングを表示し true を返す。
102: // ファイルサイズが memlen と同じなら true を返す。
103: bool
104: MappedFile::CheckFilesize() const
105: {
106: struct stat st;
107:
108: // ファイルサイズをチェック。
109: // ファイルが短くても mmap は黙って成功してしまうようなので。
110: if (fstat(fd, &st) < 0) {
111: warn("%s fstat failed", dispname.c_str());
112: return false;
113: }
114:
115: if (st.st_size < memlen) {
116: warnx("%s is too short (filesize is expected %jd but %jd)",
117: dispname.c_str(), (intmax_t)memlen, (intmax_t)st.st_size);
118: return false;
119: }
120: if (st.st_size > memlen) {
121: // 大きすぎるほうはワーニングだけでいいか
122: warnx("%s is too large (ignore %jd bytes)",
123: dispname.c_str(), (intmax_t)(st.st_size - memlen));
124: }
125: return true;
126: }
127:
128: // ファイルをクローズする。
129: // 呼び出しに副作用はない。
130: void
131: MappedFile::Close()
132: {
133: if (mem != NULL) {
134: munmap(mem, memlen);
135: mem = NULL;
136: memlen = 0;
137: }
1.1.1.2 root 138: fd.Close();
1.1 root 139:
140: filename.clear();
141: dispname.clear();
142: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.