|
|
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:
346: __unreachable();
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.