|
|
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.