Annotation of nono/vm/ufs.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: // UFS
        !             8: 
        !             9: #include "ufs.h"
        !            10: #include "ffs_dir.h"
        !            11: #include "scsidev.h"
        !            12: 
        !            13: //
        !            14: // ファイルシステムハンドルっぽいもの
        !            15: //
        !            16: 
        !            17: // コンストラクタ
        !            18: Filesys::Filesys(Device *parent_)
        !            19: {
        !            20:        parent = parent_;
        !            21:        fs = &fs0;
        !            22: }
        !            23: 
        !            24: // デストラクタ
        !            25: Filesys::~Filesys()
        !            26: {
        !            27: }
        !            28: 
        !            29: // パーティションを FFS としてオープンする(マウントのようなイメージ)。
        !            30: // start, size はこのパーティションの開始セクタとセクタ数。
        !            31: // 成功すれば true を返す。
        !            32: // 失敗すれば errstr にエラーメッセージをセットして false を返す。
        !            33: bool
        !            34: Filesys::Mount(SCSIHD *hd_, uint32 start, uint32 size)
        !            35: {
        !            36:        hd = hd_;
        !            37:        part_start = start;
        !            38:        part_size  = size;
        !            39: 
        !            40:        // FFS の先頭にはブートブロックがあり、続けてスーパーブロックがある。
        !            41:        // ブートブロックはブートローダのための領域で、ここもファイルシステムの
        !            42:        // 内側という認識のようだ。
        !            43:        //
        !            44:        // ブートブロックの大きさはおそらくファイルシステムごとに固定で、
        !            45:        // FFSv1(?) なら 8KB のようだ。ここは LUNA-I の ROM が解釈できるのと
        !            46:        // 同じファイルシステムだけ扱えればよいので、8KB 固定とする。
        !            47:        // 続いてスーパーブロックがある。ここにこのファイルシステムのパラメータ
        !            48:        // が書いてある。
        !            49:        //
        !            50:        // +-------------+ 0   <- part_start (パーティション先頭)
        !            51:        // | BootBlock   |
        !            52:        // +-------------+ 8KB
        !            53:        // | SuperBlock  |
        !            54:        // |    fs_iblkno ---+
        !            55:        // +-------------+   |
        !            56:        // :             :   |
        !            57:        //                   |
        !            58:        // :             :   |
        !            59:        // +-------------+ <-+
        !            60:        // | InodeBlock? |
        !            61:        //
        !            62:        // スーパーブロックの構造は <ufs/ffs/fs.h> の struct fs 参照。
        !            63: 
        !            64:        // スーパーブロックを読む (ここはまだ PeekBlock() は使えない)
        !            65:        hd->PeekImage(&fs0, part_start * 512 + 8192, sizeof(fs0));
        !            66:        // 読み込んだスーパーブロックはゲストエンディアン(BE) なので
        !            67:        // 使う前に (もう面倒なのでほぼ全部) ホストエンディアンにしておく。
        !            68:        // ヘッダに定義してあるマクロをそのまま使いたいからだけど、正気かなこれ。
        !            69:        fs->fs_firstfield               = be32toh(fs->fs_firstfield);
        !            70:        fs->fs_sblkno                   = be32toh(fs->fs_sblkno);
        !            71:        fs->fs_cblkno                   = be32toh(fs->fs_cblkno);
        !            72:        fs->fs_iblkno                   = be32toh(fs->fs_iblkno);
        !            73:        fs->fs_dblkno                   = be32toh(fs->fs_dblkno);
        !            74:        fs->fs_old_cgoffset             = be32toh(fs->fs_old_cgoffset);
        !            75:        fs->fs_old_cgmask               = be32toh(fs->fs_old_cgmask);
        !            76:        fs->fs_old_time                 = be32toh(fs->fs_old_time);
        !            77:        fs->fs_old_size                 = be32toh(fs->fs_old_size);
        !            78:        fs->fs_old_dsize                = be32toh(fs->fs_old_dsize);
        !            79:        fs->fs_ncg                              = be32toh(fs->fs_ncg);
        !            80:        fs->fs_bsize                    = be32toh(fs->fs_bsize);
        !            81:        fs->fs_fsize                    = be32toh(fs->fs_fsize);
        !            82:        fs->fs_frag                             = be32toh(fs->fs_frag);
        !            83:        fs->fs_minfree                  = be32toh(fs->fs_minfree);
        !            84:        fs->fs_old_rotdelay             = be32toh(fs->fs_old_rotdelay);
        !            85:        fs->fs_old_rps                  = be32toh(fs->fs_old_rps);
        !            86:        fs->fs_bmask                    = be32toh(fs->fs_bmask);
        !            87:        fs->fs_fmask                    = be32toh(fs->fs_fmask);
        !            88:        fs->fs_bshift                   = be32toh(fs->fs_bshift);
        !            89:        fs->fs_fshift                   = be32toh(fs->fs_fshift);
        !            90:        fs->fs_maxcontig                = be32toh(fs->fs_maxcontig);
        !            91:        fs->fs_maxbpg                   = be32toh(fs->fs_maxbpg);
        !            92:        fs->fs_fragshift                = be32toh(fs->fs_fragshift);
        !            93:        fs->fs_fsbtodb                  = be32toh(fs->fs_fsbtodb);
        !            94:        fs->fs_sbsize                   = be32toh(fs->fs_sbsize);
        !            95:        //fs->fs_spare1[2]
        !            96:        fs->fs_nindir                   = be32toh(fs->fs_nindir);
        !            97:        fs->fs_inopb                    = be32toh(fs->fs_inopb);
        !            98:        fs->fs_old_nspf                 = be32toh(fs->fs_old_nspf);
        !            99:        fs->fs_optim                    = be32toh(fs->fs_optim);
        !           100:        fs->fs_old_npsect               = be32toh(fs->fs_old_npsect);
        !           101:        fs->fs_old_interleave   = be32toh(fs->fs_old_interleave);
        !           102:        fs->fs_old_trackskew    = be32toh(fs->fs_old_trackskew);
        !           103:        fs->fs_id[0]                    = be32toh(fs->fs_id[0]);
        !           104:        fs->fs_id[1]                    = be32toh(fs->fs_id[1]);
        !           105:        fs->fs_old_csaddr               = be32toh(fs->fs_old_csaddr);
        !           106:        fs->fs_cssize                   = be32toh(fs->fs_cssize);
        !           107:        fs->fs_cgsize                   = be32toh(fs->fs_cgsize);
        !           108:        fs->fs_spare2                   = be32toh(fs->fs_spare2);
        !           109:        fs->fs_old_nsect                = be32toh(fs->fs_old_nsect);
        !           110:        fs->fs_old_spc                  = be32toh(fs->fs_old_spc);
        !           111:        fs->fs_old_ncyl                 = be32toh(fs->fs_old_ncyl);
        !           112:        fs->fs_old_cpg                  = be32toh(fs->fs_old_cpg);
        !           113:        fs->fs_ipg                              = be32toh(fs->fs_ipg);
        !           114:        fs->fs_fpg                              = be32toh(fs->fs_fpg);
        !           115:        //struct csum fs_old_cstotal
        !           116:        //u_char fs_fsmnt[MAXMNTLEN]
        !           117:        //u_char fs_volname[MAXVOLLEN]
        !           118:        fs->fs_swuid                    = be64toh(fs->fs_swuid);
        !           119:        fs->fs_pad                              = be32toh(fs->fs_pad);
        !           120:        fs->fs_cgrotor                  = be32toh(fs->fs_cgrotor);
        !           121:        //void *fs_ocsp[NOCSPTRS]
        !           122:        //struct csum *fs_csp
        !           123:        //uint32_t *fs_maxcluster
        !           124:        //u_char *fs_active
        !           125:        fs->fs_old_cpc                  = be32toh(fs->fs_old_cpc);
        !           126:        fs->fs_maxbsize                 = be32toh(fs->fs_maxbsize);
        !           127:        fs->fs_journal_flags    = be32toh(fs->fs_journal_flags);
        !           128:        //uint64_t fs->fs_journallocs[4]
        !           129:        fs->fs_quota_magic              = be32toh(fs->fs_quota_magic);
        !           130:        //uint64_t fs->fs_quotafile[2]
        !           131:        //uint64_t fs->fs_sparecon64[9]
        !           132:        fs->fs_sblockloc                = be64toh(fs->fs_sblockloc);
        !           133:        //struct csum_total fs_cstotal
        !           134:        fs->fs_time                             = be64toh(fs->fs_time);
        !           135:        fs->fs_size                             = be64toh(fs->fs_size);
        !           136:        fs->fs_dsize                    = be64toh(fs->fs_dsize);
        !           137:        fs->fs_csaddr                   = be64toh(fs->fs_csaddr);
        !           138:        fs->fs_pendingblocks    = be64toh(fs->fs_pendingblocks);
        !           139:        fs->fs_pendinginodes    = be32toh(fs->fs_pendinginodes);
        !           140:        // uint32_t fs->fs_snapinum[FSMAXSNAP]
        !           141:        fs->fs_avgfilesize              = be32toh(fs->fs_avgfilesize);
        !           142:        fs->fs_avgfpdir                 = be32toh(fs->fs_avgfpdir);
        !           143:        fs->fs_save_cgsize              = be32toh(fs->fs_save_cgsize);
        !           144:        // uint32_t fs->fs_sparecon32[26]
        !           145:        fs->fs_flags                    = be32toh(fs->fs_flags);
        !           146:        fs->fs_contigsumsize    = be32toh(fs->fs_contigsumsize);
        !           147:        fs->fs_maxsymlinklen    = be32toh(fs->fs_maxsymlinklen);
        !           148:        fs->fs_old_inodefmt             = be32toh(fs->fs_old_inodefmt);
        !           149:        fs->fs_maxfilesize              = be64toh(fs->fs_maxfilesize);
        !           150:        fs->fs_qbmask                   = be64toh(fs->fs_qbmask);
        !           151:        fs->fs_qfmask                   = be64toh(fs->fs_qfmask);
        !           152:        fs->fs_state                    = be32toh(fs->fs_state);
        !           153:        fs->fs_old_postblformat = be32toh(fs->fs_old_postblformat);
        !           154:        fs->fs_old_nrpos                = be32toh(fs->fs_old_nrpos);
        !           155:        // uint32_t fs->fs_spare5[2]
        !           156:        fs->fs_magic                    = be32toh(fs->fs_magic);
        !           157: 
        !           158:        // マジック
        !           159:        if (fs->fs_magic != FS_UFS1_MAGIC) {
        !           160:                errstr = string_format("Bad superblock magic 0x%08x (!= 0x%08x)",
        !           161:                        fs->fs_magic, FS_UFS1_MAGIC);
        !           162:                return false;
        !           163:        }
        !           164: 
        !           165:        // なんとなく主要なパラメータを表示してみるか
        !           166:        if (parent->loglevel >= 2) {
        !           167:                uint32 sblkno = fs->fs_sblkno;          // super block in filesys
        !           168:                uint32 cblkno = fs->fs_cblkno;          // cylinder group block in filesys
        !           169:                uint32 iblkno = fs->fs_iblkno;          // inode block in filesys
        !           170:                uint32 dblkno = fs->fs_dblkno;          // data block in filesys
        !           171:                uint32 bsize  = fs->fs_bsize;           // size of basic blocks
        !           172:                uint32 ipg    = fs->fs_ipg;                     // inodes per group
        !           173:                uint32 fpg    = fs->fs_fpg;                     // blocks per group x fs_frag
        !           174:                uint32 old_cgoffset = fs->fs_old_cgoffset;      // cg. offset in cyl.
        !           175:                uint32 fsbtodb= fs->fs_fsbtodb;         // shift constant
        !           176: 
        !           177:                parent->putmsgn("%s fs.fs_sblkno=0x%x (0x%x)",
        !           178:                        __func__, sblkno, sblkno * 512);
        !           179:                parent->putmsgn("%s fs.fs_cblkno=0x%x (0x%x)",
        !           180:                        __func__, cblkno, cblkno * 512);
        !           181:                parent->putmsgn("%s fs.fs_dblkno=0x%x (0x%x)",
        !           182:                        __func__, dblkno, dblkno * 512);
        !           183:                parent->putmsgn("%s fs.fs_iblkno=0x%x (0x%x)",
        !           184:                        __func__, iblkno, iblkno * 512);
        !           185:                parent->putmsgn("%s fs.fs_bsize=0x%x", __func__, bsize);
        !           186:                parent->putmsgn("%s fs.fs_ipg=0x%x", __func__, ipg);
        !           187:                parent->putmsgn("%s fs.fs_fpg=0x%x", __func__, fpg);
        !           188:                parent->putmsgn("%s fs.fs_old_cgoffset=0x%x", __func__, old_cgoffset);
        !           189:                parent->putmsgn("%s fs.fs_fsbtodb=%d", __func__, fsbtodb);
        !           190:        }
        !           191: 
        !           192:        return true;
        !           193: }
        !           194: 
        !           195: // ファイル名からファイルをオープンする。
        !           196: // オープンできれば file を埋めて true を返す。
        !           197: // オープンできなければ errstr にエラーメッセージをセットして false を返す。
        !           198: bool
        !           199: Filesys::OpenFile(inodefile& file, const std::string& filename_)
        !           200: {
        !           201:        std::string filename(filename_);
        !           202:        std::vector<std::string> path;
        !           203:        int idx = 0;
        !           204:        inodefile dir(parent);
        !           205: 
        !           206:        enum {
        !           207:                STATE_REG,      // 通常ファイル (終了条件)
        !           208:                STATE_PATH,     // パス解析
        !           209:                STATE_DIR,      // ディレクトリ読み込み
        !           210:                STATE_FIND,     // ディレクトリからファイルを検索
        !           211:                STATE_LINK,     // シンボリックリンク
        !           212:        } state;
        !           213: 
        !           214:        // DKFILE の先頭に '/' がなければここで足しておく。
        !           215:        // ファイル名を分解する際にルートディレクトリマークが必要なので。
        !           216:        if (filename[0] != '/') {
        !           217:                filename.insert(0, 1, '/');
        !           218:        }
        !           219:        state = STATE_PATH;
        !           220: 
        !           221:        while (state != STATE_REG) {
        !           222:                switch (state) {
        !           223:                 case STATE_PATH:
        !           224:                        // ファイル名をパスに分解
        !           225:                        // filename にパス名をセットしてからここに来ること。
        !           226:                        parent->putmsgf(1, lstr("%s Path filename=|%s|",
        !           227:                                lam_func, filename.c_str()));
        !           228:                        if (filename.empty()) {
        !           229:                                errstr = "Filename empty?";
        !           230:                                return false;
        !           231:                        }
        !           232:                        path.clear();
        !           233:                        for (int s = 0; s < filename.size(); ) {
        !           234:                                int p = filename.find('/', s);
        !           235:                                if (p == std::string::npos) {
        !           236:                                        p = filename.size();
        !           237:                                }
        !           238:                                // '/' が連続していなければパスコンポーネント
        !           239:                                if (p != s) {
        !           240:                                        path.push_back(filename.substr(s, p - s));
        !           241:                                }
        !           242:                                s = p + 1;
        !           243:                        }
        !           244:                        idx = 0;
        !           245:                        if (parent->loglevel >= 1) {
        !           246:                                for (int i = 0; i < path.size(); i++) {
        !           247:                                        parent->putmsgn("%s path[%d]=|%s|",
        !           248:                                                __func__, i, path[i].c_str());
        !           249:                                }
        !           250:                        }
        !           251:                        // パスが '/' から始まっていればルートディレクトリの読み込みから。
        !           252:                        // そうでなければ現在のディレクトリでファイルの検索から。
        !           253:                        if (filename[0] == '/') {
        !           254:                                // ルートディレクトリの inode 番号は伝統的に #2 と
        !           255:                                // いうことになっている。
        !           256:                                dir.ino = 2;
        !           257:                                state = STATE_DIR;
        !           258:                        } else {
        !           259:                                state = STATE_FIND;
        !           260:                        }
        !           261:                        break;
        !           262: 
        !           263:                 case STATE_DIR:
        !           264:                        // inode 番号からディレクトリエントリを取得。
        !           265:                        // dir.ino をセットしてからここに来ること。
        !           266:                        parent->putmsgf(1, lstr("%s Readdir ino=%d", lam_func, dir.ino));
        !           267:                        Readi(dir);
        !           268:                        // 中身(ディレクトリエントリ) を取得
        !           269:                        ReadData(dir);
        !           270:                        state = STATE_FIND;
        !           271:                        break;
        !           272: 
        !           273:                 case STATE_FIND:
        !           274:                        // ディレクトリエントリ dir.data から
        !           275:                        // ファイル名 path[idx] を探す。
        !           276:                        parent->putmsgf(1, lstr("%s FindFile %s",
        !           277:                                lam_func, path[idx].c_str()));
        !           278:                        file.ino = dir.FindFile(path[idx]);
        !           279:                        if (file.ino == 0) {
        !           280:                                errstr = string_format("file not found");
        !           281:                                return false;
        !           282:                        }
        !           283:                        // ファイルの inode 情報を取得。
        !           284:                        Readi(file);
        !           285:                        switch (be16toh(file.di.di_mode) & IFMT) {
        !           286:                         case IFREG:    // 通常ファイル
        !           287:                                state = STATE_REG;
        !           288:                                break;
        !           289: 
        !           290:                         case IFLNK:    // シンボリックリンク
        !           291:                                state = STATE_LINK;
        !           292:                                break;
        !           293: 
        !           294:                         case IFDIR:    // ディレクトリ
        !           295:                                dir.ino = file.ino;
        !           296:                                idx++;
        !           297:                                // パスの最後のコンポーネントがまだディレクトリならエラー
        !           298:                                if (idx >= path.size()) {
        !           299:                                        errstr = "is a directory";
        !           300:                                        return false;
        !           301:                                }
        !           302:                                state = STATE_DIR;
        !           303:                                break;
        !           304: 
        !           305:                         default:               // それ以外は対応してないし来ないはず
        !           306:                                errstr = string_format("invalid filemode %06o",
        !           307:                                        be16toh(file.di.di_mode));
        !           308:                                return false;
        !           309:                        }
        !           310:                        break;
        !           311: 
        !           312:                 case STATE_LINK:
        !           313:                        // リンク先ファイル名を取り出す
        !           314:                        parent->putmsgf(1, lstr("%s Readlink", lam_func));
        !           315:                        ReadData(file);
        !           316:                        filename = std::string((const char *)file.data.data(),
        !           317:                                file.data.size());
        !           318:                        // パス解析へ
        !           319:                        state = STATE_PATH;
        !           320:                        break;
        !           321: 
        !           322:                 default:
        !           323:                        __unreachable();
        !           324:                }
        !           325:        }
        !           326:        // 通常ファイルに到達
        !           327: 
        !           328:        if (idx != path.size() - 1) {
        !           329:                // パスの最後のコンポーネントじゃなければエラー
        !           330:                errstr = "path not found";
        !           331:                return false;
        !           332:        }
        !           333: 
        !           334:        return true;
        !           335: }
        !           336: 
        !           337: // inode(.di) で指定されたファイル(またはディレクトリ)の本文を
        !           338: // inode.data に返す。
        !           339: // 今の所エラーは起きない。
        !           340: void
        !           341: Filesys::ReadData(inodefile& inode)
        !           342: {
        !           343:        // di (ufs1_dinode) にはこの inode (ファイルまたはディレクトリ)の
        !           344:        // データの格納ブロックが記録されている。ディレクトリとは中身が
        !           345:        // ディレクトリエントリであるファイルと同じ構造のもの。
        !           346:        //  di_db[] (直接ブロック)
        !           347:        //  di_ib[] (間接ブロック)
        !           348:        //  di_blocks (実際に使用しているブロック数)
        !           349:        //
        !           350:        // 直接ブロック di_db[] は12要素の配列で、データブロックの位置が
        !           351:        // 記録されている (未使用なら 0 のようだ)。
        !           352:        // データブロックは fs->fs_bsize でたぶん基本 4KB のやつ。
        !           353:        // これもパーティション先頭からのセクタ番号で表記される。なので
        !           354:        // ディスク上で連続しているファイルなら di_db[N] と di_db[N + 1] は
        !           355:        // 8 ずつ増えてるのが見えるはず。
        !           356:        // 例えば以下のサンプル断片は、直接ブロック2つでセクタ 100 から
        !           357:        // セクタ 115 までの連続する 16KB を所有している様子を示している。
        !           358:        //
        !           359:        //                        #100   #101   #102          #107
        !           360:        //                      +------+------+------+- .. -+------+
        !           361:        // di_db[0] = 100  ---> | Data | Data | Data |      | Data |
        !           362:        //                      +------+------+------+- .. -+------+
        !           363:        //
        !           364:        //                        #108                        #115
        !           365:        //                      +------+------+------+- .. -+------+
        !           366:        // di_db[1] = 108  ---> | Data | Data | Data |      | Data |
        !           367:        //                      +------+------+------+- .. -+------+
        !           368:        //
        !           369:        // 間接ブロック di_ib[0], [1], [2] はそれぞれ一次、二次、三次の
        !           370:        // 間接記録になっている。一次間接だとこういう感じ。
        !           371:        //
        !           372:        //                        #120
        !           373:        //                      +--------+           +------+- ..
        !           374:        // di_ib[0] = 120  ---> | #200  ------> #200 | Data |
        !           375:        //                      |        |           +------+- ..
        !           376:        //                      | #208  ------> #208 | Data |
        !           377:        //                      +--------+           +------+- ..
        !           378:        //
        !           379: 
        !           380:        uint32 ino = inode.ino;
        !           381:        struct ufs1_dinode *di = &inode.di;
        !           382:        std::vector<uint8>& data = inode.data;
        !           383:        uint64 bsize64 = (uint64)fs->fs_bsize;
        !           384: 
        !           385:        uint64 di_size   = be64toh(di->di_size);
        !           386:        uint32 di_blocks = be32toh(di->di_blocks);
        !           387:        // di->di_db[] にファイル(またはディレクトリ)の内容の位置が並んでいる
        !           388:        if (parent->loglevel >= 2) {
        !           389:                parent->putmsgn("%s di[%d].di_blocks=%u", __func__, ino, di_blocks);
        !           390: 
        !           391:                std::string dbstr;
        !           392:                for (int i = 0; i < UFS_NDADDR; i++) {
        !           393:                        dbstr += string_format(" %u", be32toh(di->di_db[i]));
        !           394:                }
        !           395:                parent->putmsgn("%s di[%d].di_db[]=%s, di_ib[]=%u %u %u",
        !           396:                        __func__, ino, dbstr.c_str() + 1,
        !           397:                        be32toh(di->di_ib[0]),
        !           398:                        be32toh(di->di_ib[1]),
        !           399:                        be32toh(di->di_ib[2]));
        !           400:        }
        !           401: 
        !           402:        uint64 offset = 0;      // 次に読み込む位置 (ここまでに読み込んだバイト数)
        !           403: 
        !           404:        // サイズが分かっているのであらかじめ確保しておく
        !           405:        data.resize(di_size);
        !           406: 
        !           407:        // 直接ブロック
        !           408:        for (int i = 0; i < countof(di->di_db); i++) {
        !           409:                uint64 remain = di_size - offset;       // 残りバイト数
        !           410:                uint32 nbytes = std::min(remain, bsize64);      // 今回読み込み分
        !           411:                PeekBlock(&data[offset], be32toh(di->di_db[i]), nbytes);
        !           412:                offset += nbytes;
        !           413:                if (offset >= di_size) {
        !           414:                        return;
        !           415:                }
        !           416:        }
        !           417:        // 一次間接ブロック
        !           418:        std::vector<uint32> ib0buf(fs->fs_bsize / sizeof(uint32));
        !           419:        PeekBlock(&ib0buf[0], be32toh(di->di_ib[0]), fs->fs_bsize);
        !           420:        if (parent->loglevel >= 2) {
        !           421:                std::string distr;
        !           422:                for (const auto& x : ib0buf) {
        !           423:                        if (x == 0)
        !           424:                                break;
        !           425:                        distr += string_format(" %u", be32toh(x));
        !           426:                }
        !           427:                parent->putmsgn("%s di[%d].di_ib[0]=%s",
        !           428:                        __func__, ino, distr.c_str() + 1);
        !           429:        }
        !           430:        for (const auto& x : ib0buf) {
        !           431:                uint64 remain = di_size - offset;       // 残りバイト数
        !           432:                uint32 nbytes = std::min(remain, bsize64);      // 今回読み込み分
        !           433:                PeekBlock(&data[offset], be32toh(x), nbytes);
        !           434:                offset += nbytes;
        !           435:                if (offset >= di_size) {
        !           436:                        return;
        !           437:                }
        !           438:        }
        !           439: 
        !           440:        // 二次、三次ブロックは未対応
        !           441:        if (offset < di_size) {
        !           442:                PANIC("di_ib[1] not supported");
        !           443:        }
        !           444: }
        !           445: 
        !           446: // inode.ino で指定された disk inode 情報を inode.di に返す。
        !           447: // 今の所エラーは起きない。
        !           448: void
        !           449: Filesys::Readi(inodefile& inode)
        !           450: {
        !           451:        // di は inode のディスク上の記録構造で 128 バイト長。
        !           452:        // 詳細は <ufs/ufs/dinode.h> の ufs1_dinode 参照。
        !           453:        // 基本的には inode ブロックにこの dinode が配列のように並んでいるが
        !           454:        // シリンダグループを越えるためには謎のマクロを使う。
        !           455:        // sys/lib/libsa/ufs.c 参照。
        !           456:        //
        !           457:        // dinode のうち、ここで関係するかも知れないのは
        !           458:        //  di_mode (のうちファイルモード)
        !           459:        //  di_size (ファイルサイズ)
        !           460:        //  di_db[] (直接ブロック)
        !           461:        //  di_ib[] (間接ブロック)
        !           462:        //  di_blocks (ブロック数)
        !           463:        // くらいか。
        !           464: 
        !           465:        uint32 ino = inode.ino;
        !           466: 
        !           467:        // ino が含まれるブロックを読み込む。
        !           468:        // ino_to_fsba(fs, ino) が指定の ino が含まれるブロックを返す。
        !           469:        // ino_to_fsbo(fs, ino) はそのブロック内での ino のオフセットを返す。
        !           470:        // 例えば inode=2 の fsba が 0x18、fsbo が 2 なら、0x18ブロック目の
        !           471:        // [2] からつまり256バイト目からとなる。
        !           472:        std::vector<char> buf(fs->fs_bsize);
        !           473:        uint64 fsba = ino_to_fsba(fs, ino);
        !           474:        uint32 fsbo = ino_to_fsbo(fs, ino);
        !           475:        PeekBlock(&buf[0], fsba, buf.size());
        !           476: 
        !           477:        // ino で示される inode のディスク上構造を
        !           478:        // (ゲストエンディアンのまま) di にコピーして持っておく。
        !           479:        struct ufs1_dinode *di = &inode.di;
        !           480:        memcpy(di, &((ufs1_dinode *)(&buf[0]))[fsbo], sizeof(*di));
        !           481:        uint16 di_mode   = be16toh(di->di_mode);
        !           482:        uint16 di_nlink  = be16toh(di->di_nlink);
        !           483:        uint64 di_size   = be64toh(di->di_size);
        !           484:        parent->putmsgf(2,
        !           485:                lstr("%s di[%d].di_mode=%05o di_nlink=%d di_size=%" PRIu64,
        !           486:                lam_func, ino, di_mode, di_nlink, di_size));
        !           487: }
        !           488: 
        !           489: // ディスクの指定ブロック b の先頭から len バイト読み出して buf に返す。
        !           490: // buf は少なくとも len バイト確保してあること。
        !           491: void
        !           492: Filesys::PeekBlock(void *buf, uint32 b, uint32 len) const
        !           493: {
        !           494:        // FFS_FSBTODB(fs, b) がブロック番号 b をセクタ番号に変換する。
        !           495:        uint32 sector = part_start + FFS_FSBTODB(fs, b);
        !           496:        hd->PeekImage(buf, sector * 512, len);
        !           497: }
        !           498: 
        !           499: 
        !           500: //
        !           501: // inode 情報クラス
        !           502: //
        !           503: 
        !           504: // コンストラクタ
        !           505: inodefile::inodefile(Device *parent_)
        !           506: {
        !           507:        parent = parent_;
        !           508: }
        !           509: 
        !           510: // デストラクタ
        !           511: inodefile::~inodefile()
        !           512: {
        !           513: }
        !           514: 
        !           515: // ディレクトリエントリ dirbuf から name で指定されるファイル名に対応する
        !           516: // inode 番号を返す。見付からなければ 0 を返す。
        !           517: uint32
        !           518: inodefile::FindFile(const std::string& name)
        !           519: {
        !           520:        // ディレクトリエントリは struct direct が可変長で並んでいる。
        !           521:        // ../host/ffs_dir.h (元は NetBSD の <ufs/ufs/dir.h>) 参照。
        !           522:        // d->d_reclen がこの1つ分のエントリの長さなので、次のエントリ位置は
        !           523:        // このエントリの頭から d->d_reclen を足したところになる。
        !           524:        // 最終エントリの d_reclen を足すとバッファ末尾になるようになっている
        !           525:        // ようだ。
        !           526:        const char *dp = (const char *)(data.data());
        !           527:        const char *dend = dp + data.size();
        !           528:        uint32 file_ino;
        !           529:        uint16 reclen;
        !           530: 
        !           531:        for (; dp < dend; dp += reclen) {
        !           532:                const struct direct *d = (const struct direct *)dp;
        !           533:                file_ino = be32toh(d->d_fileno);
        !           534:                reclen = be16toh(d->d_reclen);
        !           535: 
        !           536:                std::string str = string_format("ino=%u reclen=%u name=|%s|",
        !           537:                        file_ino, reclen, d->d_name);
        !           538:                if (d->d_reclen == 0) {
        !           539:                        parent->putmsgf(1, lstr("%s reclen=0 !", lam_func));
        !           540:                        break;
        !           541:                }
        !           542: 
        !           543:                if (strcmp(name.c_str(), d->d_name) == 0) {
        !           544:                        parent->putmsgf(2, lstr("%s %s found", lam_func, str.c_str()));
        !           545:                        return file_ino;
        !           546:                } else {
        !           547:                        parent->putmsgf(2, lstr("%s %s skip", lam_func, str.c_str()));
        !           548:                }
        !           549:        }
        !           550:        parent->putmsgf(2, lstr("%s %s not found", lam_func, name.c_str()));
        !           551:        return 0;
        !           552: }

unix.superglobalmegacorp.com

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