Annotation of nono/vm/ufs.cpp, revision 1.1.1.4

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

unix.superglobalmegacorp.com

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