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

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: // ファイルがなければエラー。これは ROM とか用。
                     49: // 成功すれば mmap した領域のポインタを返す。
                     50: // 失敗すればエラーメッセージを表示して NULL を返す。
                     51: uint8 *
                     52: MappedFile::OpenRdOnly(off_t len)
                     53: {
                     54:        memlen = len;
                     55: 
                     56:        fd = open(filename.c_str(), O_RDONLY);
                     57:        if (fd < 0) {
                     58:                warn("%s open failed", dispname.c_str());
                     59:                return NULL;
                     60:        }
                     61: 
                     62:        if (CheckFilesize() == false) {
                     63:                Close();
                     64:                return NULL;
                     65:        }
                     66: 
                     67:        // mmap する。
                     68:        // RDONLY なのでファイルには書き戻さないけど、
                     69:        // オンメモリでハックを入れたりできるよう MAP_PRIVATE を指定する。
                     70:        void *m = mmap(NULL, memlen, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
                     71:        if (m == MAP_FAILED) {
                     72:                warn("%s mmap failed", dispname.c_str());
                     73:                Close();
                     74:                return NULL;
                     75:        }
                     76:        mem = (uint8 *)m;
                     77: 
                     78:        return mem;
                     79: }
                     80: 
                     81: // サイズが len で確定しているファイルを読み書き両用でオープンして mmap する。
                     82: // ファイルがなければ作成する。これは SRAM とか用。
                     83: // 成功すれば mmap した領域のポインタを返す。
                     84: // 失敗すればエラーメッセージを表示して NULL を返す。
                     85: uint8 *
                     86: MappedFile::OpenCreate(off_t memlen_)
                     87: {
                     88:        memlen = memlen_;
                     89: 
                     90:        fd = open(filename.c_str(), O_RDWR);
                     91:        if (fd < 0) {
                     92:                if (errno != ENOENT) {
                     93:                        warn("%s open failed", dispname.c_str());
                     94:                        return NULL;
                     95:                } else {
                     96:                        // オープンできない理由が ENOENT ならファイルを作ってみる
                     97:                        fd = open(filename.c_str(), O_RDWR | O_CREAT, 0644);
                     98:                        if (fd < 0) {
                     99:                                warn("%s create failed", dispname.c_str());
                    100:                                return NULL;
                    101:                        }
                    102: 
                    103:                        // ゼロで埋める
                    104:                        std::vector<char> zerobuf(memlen);
                    105:                        if (write(fd, &zerobuf[0], zerobuf.size()) < 0) {
                    106:                                warn("%s write failed", dispname.c_str());
                    107:                                Close();
                    108:                                return NULL;
                    109:                        }
                    110: 
                    111:                        warnx("%s created", dispname.c_str());
                    112:                        // FALLTHROUGH
                    113:                }
                    114:        }
                    115: 
                    116:        if (CheckFilesize() == false) {
                    117:                Close();
                    118:                return NULL;
                    119:        }
                    120: 
                    121:        // mmap する。
                    122:        void *m = mmap(NULL, memlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
                    123:        if (m == MAP_FAILED) {
                    124:                warn("%s mmap failed", dispname.c_str());
                    125:                Close();
                    126:                return NULL;
                    127:        }
                    128:        mem = (uint8 *)m;
                    129: 
                    130:        return mem;
                    131: }
                    132: 
                    133: // サイズの確定していないファイルを読み書き両用でオープンして mmap する。
                    134: // ファイルがなければエラー。これはディスクイメージ用。
                    135: // 成功すれば mmap した領域のポインタを返す。
                    136: // 失敗すればエラーメッセージを表示して NULL を返す。
                    137: uint8 *
                    138: MappedFile::OpenFile()
                    139: {
                    140:        struct stat st;
                    141: 
                    142:        fd = open(filename.c_str(), O_RDWR);
                    143:        if (fd < 0) {
                    144:                warn("%s open failed", dispname.c_str());
                    145:                return NULL;
                    146:        }
                    147: 
                    148:        // ファイルサイズを取得
                    149:        if (fstat(fd, &st) < 0) {
                    150:                warn("%s stat failed", dispname.c_str());
                    151:                Close();
                    152:                return NULL;
                    153:        }
                    154:        memlen = st.st_size;
                    155: 
                    156:        // mmap する。
                    157:        void *m = mmap(NULL, memlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
                    158:        if (mem == MAP_FAILED) {
                    159:                warn("%s mmap failed", dispname.c_str());
                    160:                Close();
                    161:                return NULL;
                    162:        }
                    163:        mem = (uint8 *)m;
                    164: 
                    165:        return mem;
                    166: }
                    167: 
                    168: // ファイルサイズが memlen と同じかどうか調べる。
                    169: // ファイルサイズが memlen より短ければエラーメッセージを表示し false を返す。
                    170: // ファイルサイズが memlen より長ければワーニングを表示し true を返す。
                    171: // ファイルサイズが memlen と同じなら true を返す。
                    172: bool
                    173: MappedFile::CheckFilesize() const
                    174: {
                    175:        struct stat st;
                    176: 
                    177:        // ファイルサイズをチェック。
                    178:        // ファイルが短くても mmap は黙って成功してしまうようなので。
                    179:        if (fstat(fd, &st) < 0) {
                    180:                warn("%s fstat failed", dispname.c_str());
                    181:                return false;
                    182:        }
                    183: 
                    184:        if (st.st_size < memlen) {
                    185:                warnx("%s is too short (filesize is expected %jd but %jd)",
                    186:                        dispname.c_str(), (intmax_t)memlen, (intmax_t)st.st_size);
                    187:                return false;
                    188:        }
                    189:        if (st.st_size > memlen) {
                    190:                // 大きすぎるほうはワーニングだけでいいか
                    191:                warnx("%s is too large (ignore %jd bytes)",
                    192:                        dispname.c_str(), (intmax_t)(st.st_size - memlen));
                    193:        }
                    194:        return true;
                    195: }
                    196: 
                    197: // ファイルをクローズする。
                    198: // 呼び出しに副作用はない。
                    199: void
                    200: MappedFile::Close()
                    201: {
                    202:        if (mem != NULL) {
                    203:                munmap(mem, memlen);
                    204:                mem = NULL;
                    205:                memlen = 0;
                    206:        }
1.1.1.2 ! root      207:        fd.Close();
1.1       root      208: 
                    209:        filename.clear();
                    210:        dispname.clear();
                    211: }

unix.superglobalmegacorp.com

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