Annotation of nono/lib/mappedfile.cpp, revision 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.