cramfs を読む
cramfs は読み取り専用のファイルシステムで、linux 界によって創造された。
小規模なファイルを扱うことに特化しており、さらにデータは圧縮される。ブータブル CD や組み込み機器向けによく利用されているようだ。
一般的なファイルシステムの持つ機能をばっさり省き、最低限の機能しかもっていないが、目的に一致するならばとても有用な選択となる。
cramfs の特徴
- ボリュームは最大 256 MiB + α。
- 1ファイルあたり最大 16 MiB 未満。
-
GID が0 から 255 まで。
通常 GID は16ビットなので、上位8ビットが欠落する。このことはセキュリティリスクとなるとの注意書きかある。 - ファイル名は最大 252 文字。
- シンボリックリンクはサポートされるが、ハードリンクはサポートされない。
でぃれくとりえんとりちゅうに inode がかくのうされるため。
ただし、実データが同じものは同じ場所を指すことが出来る。 - inode は作成日時や更新日時を持たない。
- ファイルデータは『ページ』に分割して格納される。ページサイズは 4096 バイトで固定?
cramfs のバイトオーダー
cramfs の バイトオーダーは定義されていない (!)。「作成と利用は同じアーキテクチャでやってね!」的な発想のようだ。
もっともスーパーブロックのマジックナンバーで判断可能である。
内部構造
+========================================+
| スーパーブロック |
+========================================+
| ファイルデータやディレクトリエントリ |
| ファイルデータやディレクトリエントリ |
| ファイルデータやディレクトリエントリ |
| ファイルデータやディレクトリエントリ |
| ファイルデータやディレクトリエントリ |
| ファイルデータやディレクトリエントリ |
| ファイルデータやディレクトリエントリ |
| ファイルデータやディレクトリエントリ |
+========================================+
データはブロック単位で扱われるものと思いきや、バイト単位であった。
ひとつのディレクトリエントリやファイルデータは必ず連続したものであり、断片化は発生のしようがない。
スーパーブロック
スーパーブロックは多くのファイルシステムと同じく、ファイルシステムの識別情報がまとめてある部分である。
(cramfs-1.1/linux/cramfs_fs.h から引用)
cramfs-1.1/linux/cramfs_fs.h
struct cramfs_super {
u32 magic; /* 0x28cd3d45 - random number /
u32 size; / length in bytes /
u32 flags; / feature flags /
u32 future; / reserved for future use /
u8 signature[16]; / "Compressed ROMFS" /
struct cramfs_info fsid; / unique filesystem info /
u8 name[16]; / user-defined name /
struct cramfs_inode root; / root inode data */
};
先に述べたように、バイトオーダーの判断を magic
で確認するべきである。
inode
(cramfs-1.1/linux/cramfs_fs.h より引用)
cramfs-1.1/linux/cramfs_fs.h
struct cramfs_inode {
u32 mode:CRAMFS_MODE_WIDTH, uid:CRAMFS_UID_WIDTH;
/* SIZE for device files is i_rdev /
u32 size:CRAMFS_SIZE_WIDTH, gid:CRAMFS_GID_WIDTH;
/ NAMELEN is the length of the file name, divided by 4 and
rounded up. (cramfs doesn't support hard links.) /
/ OFFSET: For symlinks and non-empty regular files, this
contains the offset (divided by 4) of the file data in
compressed form (starting with an array of block pointers;
see README). For non-empty directories it is the offset
(divided by 4) of the inode of the first file in that
directory. For anything else, offset is zero. */
u32 namelen:CRAMFS_NAMELEN_WIDTH, offset:CRAMFS_OFFSET_WIDTH;
};
見てわかるように 12 バイトしか使わない。
ビット割り当てがどうなっているのかを見るために、定数を見てみる。
(cramfs-1.1/linux/cramfs_fs.h より引用)
cramfs-1.1/linux/cramfs_fs.h
#define CRAMFS_MODE_WIDTH 16
#define CRAMFS_UID_WIDTH 16
#define CRAMFS_SIZE_WIDTH 24
#define CRAMFS_GID_WIDTH 8
#define CRAMFS_NAMELEN_WIDTH 6
#define CRAMFS_OFFSET_WIDTH 26
構造体の気をつけたいところはビットフィールドを用いていることと、namelen
と offset
が 4 で割られ端数は切り上げられている点だ。
ディレクトリエントリ
ディレクトリエントリには inode と名前が格納される。このディレクトリエントリは 圧縮されない。
名前は inode の直後に4バイト単位に NUL 拡張されて格納される。
ただし、自身と親ディレクトリエントリを示す『.』『..』は格納されない。
+============================
| ディレクトリエントリ
|
| +=======+======+
| | inode | 名前 |
| +=======+======+
| | inode | 名前 |
| +=======+======+
| / ............ /
| +=======+======+
|
+============================
ファイルデータ
ファイルデータは『ページ』という単位にして連続して格納される。このページのデータは zlib ヘッダ付きで deflate によって つねに 圧縮されている。
各ページの開始位置はひとまとめにされて第1ページの前、つまりはファイルデータブロックの最初に配置される。このページ位置は32ビット整数値で、そのインデックスに対するページはどこまで読めばよいのかを示している。
ページデータの各終端位置はひとつうしろのページ位置に等しい。第1ページの開始位置はページインデックスの直後となるので、すでにわかっている。
これでページデータを読むのに必要な情報がそろったので、ファイルデータを読むことができる。
ファイルデータ配置
+=======================+ ページインデックスの開始位置 = ファイルデータの開始位置
| ページインデックス | <-- 4バイト×ページ数
+=======================+ ページ[0]の開始位置 = ページインデックスの終端位置
| ページデータ (任意長) |
+=======================+ ページ[1]の開始位置 = ページ[0]の終端位置
| ページデータ (任意長) |
+=======================+ ページ[2]の開始位置 = ページ[1]の終端位置
| ページデータ (任意長) |
+=======================+ ページ[3]の開始位置 = ページ[2]の終端位置 ≦ (ファイルデータ開始位置 + ファイルデータサイズ)
参考文献
- cramfs tools (公式プロジェクト):
<http://sourceforge.net/projects/cramfs/\>
<http://sourceforge.net/projects/cramfs/files/cramfs/1.1/cramfs-1.1.tar.gz\> - CRAMFS ファイルシステム解説
<http://archive.linux.or.jp/JF/JFdocs/kernel-docs-2.6/filesystems/cramfs.txt.html\> - Cramfs
<http://ja.wikipedia.org/wiki/Cramfs\>
To the extent possible under law,
dearblue
has waived all copyright and related or neighboring rights to
this work.