Annotation of nono/vm/ufs.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: // 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.