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