Annotation of nono/lib/mappedfile.cpp, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.