HPFS 2.05 の読み書き
1998-2001, Mikulas Patocka

email: mikulas@artax.karlin.mff.cuni.cz
homepage: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi

CREDITS:
Chris Smith, 1993, 元々の読み出し専用の HPFS, コードおよび HPFS 構造体
        ファイルを彼のものから流用しました。
Jacques Gelinas, MSDos mmap, fs/nfs/mmap.c (Jon Tombs 15 Aug 1993) か
        らの着想
Werner Almesberger, 1992, 1993, MSDos オプションの parser および CR/LF
        変換

日本語訳：野本浩一 <hng@ps.ksky.ne.jp>
    校正：武井伸光さん <takei@webmasters.gr.jp>


マウントオプション

uid=xxx,gid=xxx,umask=xxx (既定値、uid, gid は共に 0、umask はシステム
                          のデフォルトの umask です)
        拡張属性で指定される owner/group/mode を持っていないファイルに
        それらを設定します。mode は umask のビット否定です - 例えば、
        umask が 027 なら、owner はすべて許可、group は読み出しのみ、
        other はアクセスできないパーミッションになります。ファイルの
        mode は 0666 とのビット積になることに注意してください。ファイ
        ルに 'x' 権を持たせたい場合、拡張属性を使用しなければなりませ
        ん。
case=lower,asis (既定値は asis)
        readdir で返るファイル名は小文字になります。
conv=binary,text,auto (既定値は binary)
        auto の場合、CR/LF を LF に変換するかどうかは拡張子によります
        - テキストの拡張子のリストがあります (私は、バイナリファイルを
        破損するよりテキストファイルを変換しないほうがよいと思います)。
        そのリストを変更したければ、ソースの中のリストを変更してくださ
        い。元々の読み出し専用の HPFS は、私が削除した奇妙なヒューリス
        ティックアルゴリズムを含んでいました。私はファイルがテキストか
        バイナリかコンピュータに決定させるのは危険だと考えました。例え
        ば DJGPP バイナリは最初に小さなテキストメッセージを含んでいて、
        ある環境下ではそれらを誤認し、破損するかもしれません。
check=none,normal,strict (既定値は normal)
        Check のレベルです。none を選択すると、ちょっと速くなるのと引
        き換えに、大きな危険をもたらします。私は、不整合のあるファイル
        システム上で check=normal でも、クラッシュしないように書きまし
        た。check=strict は多くの過剰なチェックを行います - デバッグに
        使われます (例えば、ファイルにアクセスする時、ファイルがビット
        マップ中で割り当てられているかチェックします)。
errors=continue,remount-ro,panic (既定値は remount-ro)
        ファイルシステムのエラーが見つかった時の振る舞いです。
chkdsk=no,errors,always (既定値は errors)
        OS/2 がチェックするように、ファイルシステムを dirty とマークす
        べき時。
eas=no,ro,rw (既定値は rw)
        拡張属性をどのように扱うか。'no' - それらを無視し、常に
        uid/gid/mode オプションで指定された値を用います。'ro' - 拡張属
        性を読みますが、作成はしません。'rw' - ファイルシステム上で
        chmod/chown/chgrp/mknod/ln -s を使うときに、拡張属性を作成しま
        す。
timeshift=(-)nnn (既定値は 0)
        nnn 秒ぶん時間をずらします。例えば、OS/2 でのタイムスタンプと
        比べて、Linux だと 1 時間進んで表示される場合、timeshift=-3600
        とします。


ファイル名

OS/2 でのように、ファイル名は大文字小文字を区別しません。しかし、シェ
ルは、名前には大文字小文字の区別があると考えますので、例えば、ファイル
FOO を作成した場合、'cat FOO', 'cat Foo', 'cat foo', 'cat F*' を使えま
すが、'cat f*' は使えません。さらに、カーネルは bootsect.S や
bootsect.s のような名前を持ったファイルを作成するので、HPFS の上で
Linux カーネル (やたぶん他のもの) のコンパイルができないということに注
意してください。128 文字以上の名前を持ったファイルの検索には、コードペー
ジが使用されます - 以下を参照してください。
OS/2 は、ファイル名の最後のドットおよびスペースを無視しますので、この
ドライバも同様にしています。'a. ...' を作成する場合、ファイル 'a' が作
成されますが、今までどおり 'a.', 'a..', 'a .  . . ' などの名前でもアク
セスできます。


拡張属性

HPFS パーティションで、OS/2 は拡張属性と呼ばれる特別な情報を各ファイル
に関連付けることができます。拡張属性はキーと値のペアで、属性を識別する
アスキー文字列で、可変バイト長の任意の文字列です。OS/2 はウィンドウお
よびアイコンの位置、ファイルタイプをそこに格納します。そこにファイルの
所有者やアクセス権のような unix 固有の情報も格納してしまったらどうでしょ
うか？このドライバはそれを行っています。HPFS パーティション上で
chown/chgrp/chmod を実行すると、キー "UID"/"GID"/"MODE" および 2 バイ
トの値が作成されます。拡張属性のそれらの値は、マウントオプションで指定
された既定値と異なるものが、作成されるだけです。作成されると、拡張属性
は削除されず、変更されるだけです。これは、既定値 uid=0 で、'chown
luser file; chown root file' のような入力をした時、ファイルが拡張属性
UID=0 になることを意味します。そして、ファイルシステムを umount して、
uid="ローカルユーザの uid" を伴って再度 mount した時、ファイルのユーザ
は今までどおり root に所有されます！ファイルを 444 に chmod するなら、
拡張属性 "MODE" は設定されず、この特別な場合は 読み出し専用フラグが設
定されます。ブロックもしくはキャラクタデバイスを mknod する時、"MODE"
に加えて、特別な 4 バイトの拡張属性 "DEV" がデバイス番号を含んで作成さ
れます。現在、このドライバは拡張属性のサイズを変更できません - これは、
誰か (誰かは知りません) が異なるサイズで "UID", "GID", "MODE", "DEV"
属性を設定した場合、それらが書き直されず、これらの値の変更が効かないと
いうことを意味します。


シンボリックリンク

HPFS パーティション上でシンボリックリンクを作れます。シンボリックリン
クは symlink の値を伴う "SYMLINK" という名前の拡張属性を設定することに
より、実現されています。ext2 と同様に、シンボリックリンクを chown およ
び chgrp できますが、私は何に役立つのか知りません。シンボリックリンク
を chmod することは、シンボリックリンクが指すファイルを chmod すること
になります。これらのシンボリックリンクは Linux 用途向きですが、OS/2 と
は互換性がありません。OS/2 PmShell のシンボリックリンクは、とてもむちゃ
な方法で格納されるので、サポートされません。ファイルが移動された時リン
クを変更するようにしようとしました・・・時々動作します。しかし、リンク
は部分的にディレクトリの拡張属性および部分的に OS2SYS.INI に格納されま
す。OS2SYS.INI を解析し変更することを私はしたくありません (どうやるか
知らないし)。


コードページ

HPFS は、いくつかのコードページ用のいくつかの大文字化のためのテーブル
を含むことができ、各ファイルは名前の中にあるコードページへのポインタを
持っています。しかしながら、OS/2 はコードページにあまり気遣わない人た
ちのアメリカで作成されましたので、複数のコードページのサポートはとても
多くのバグがあります。私は、ディスク上にコードページ 852 で動くチェコ
版の OS/2 を持っています。以前、私は cp 850 で動く英語版の OS/2 を起動
し、852 のパーティション上にファイルを作成しました。それは 850 として
ファイル名のコードページをマークしました - いいぞ。しかし、再びチェコ
版の OS/2 を起動したところ、ファイルはいかなる名前でも全くアクセスでき
なくなりました。OS/2 はシステムのコードページ (852) を検索パターンの大
文字とし、ファイルのコードページ (850) の名前と比較しているようです。
これらは一致することはありません。これは実際に IBM の開発者が望んだも
のでしょうか？しかし、不具合は続きました。私がチェコ版の OS/2 でそのディ
レクトリに別のファイルを作成した時、そのファイルはまたアクセスできませ
んでした。たぶん、OS/2 はファイル (HPFS ディレクトリ内のファイルはソー
トされていることに注意してください) が置かれた場所を検索する時およびファ
イルを検索する時、異なる大文字化の方法を使います。最終的に PmShell で
このディレクトリをオープンした時、PmShell はクラッシュしました (奇妙な
ことに、再起動した時、PmShell はこのディレクトリを再度オープンしようと
しました :-)。幸いなことに、chkdsk はこれらのエラーを無視して、
low-level ディスク修復だけが私を救ってくれました。HPFS は一つのシステ
ム上に OS/2 の異なる言語バージョンをミックスできるよう設計されましたが、
決してこれは行わないでください。
さて、私は複雑なコードページのサポートをこのドライバに実装できましたが、
私は利益になるより OS/2 のバグのある実装のような多くの不具合の原因にな
ると考えます。なので、ファイルのコードページインデックスが何であろうと、
大文字化および小文字化してファイルを探すために、このドライバは単純に
ファーストコードページを使います。通常、すべてのファイル名はこのコード
ページの中にあります - あなたが上記で述べたことをしていなければ :-)


既知のバグ

OS/2 サーバ上の HPFS386 はサポートされません。正常な OS/2 クライアント
上にインストールされた HPFS386 は動くはずです。OS/2 サーバを持っている
場合、単に読み出し専用モードで使用してください。私は、アクセスコントロー
ルリストもしくは拡張パーミッションリストのようないくつかの HPFS386 構
造を扱う方法を知らず、ファイルが削除される場合それらを削除する方法およ
び拡張属性を上書きしない方法も知りません。私にこれらの構造の情報を送っ
てくれれば、それを作るでしょう。しかしながら、このドライバは、HPFS386
構造の存在を検知し、それらを破壊しないために読み出し専用で再マウントす
べきです (私の希望)。

拡張属性のための十分な領域がない場合、それらは切り捨てられ、エラーは返
りません。

パスが約 256 文字より長い場合、OS/2 はファイルにアクセスできませんが、
このドライバではできます。chkdsk はこのようなエラーを無視します。

時々、非常に満杯のファイルシステム上のファイルを削除できなくことがあり
ます (エラー ENOSPC が返ります)。ディレクトリツリー (一つのディレクト
リが大きければ、HPFS 上のツリーの中に dirent が複数あります) の
non-leaf ノード中のファイルは、削除される時に、別のノードに再配置され
ます。そして、その新しいファイルは古いものより大きな name を持つかもし
れないので、新しい name はディレクトリノード (dnode) に収まらなくなり
ます。その結果、ディレクトリツリーは分割され、ディスク領域を食うことに
なります。対処方法は、leaf (たぶん non-leaf なファイルは約 1/50 です)
な他のファイルを削除するか、領域を作るために最初にファイルを切り詰めま
す。この問題が起きるのは、ディレクトリがたくさんある時だけなので、ディ
レクトリ用の領域を十分に確保しておきます。すなわち、
	ディレクトリ数 / ファイルシステムのサイズ(MB) > 4

オープンしているディレクトリを削除できません。

ディレクトリを超えた rename はできません (何に役立つの？)。

大文字小文字だけを変更するファイル名の rename は動作しません。このドラ
イバはそれをサポートしますが、vfs はしていません。'mv file FILE' のよ
うなものは動作しません。

すべての atime および ディレクトリの mtime は更新されません。パフォー
マンスの問題があるからです。それらを更新する要望が大きければ、私に知ら
せてくれれば、書きましょう (しかし、進捗は遅いでしょう)。

システムのメモリおよびスワップが枯渇した場合、ファイルシステムを少し壊
すかもしれません (ファイルの消失、unbalanced directory)。(私はファイル
システムがそうなってしまうと思います)。

コンパイル時に、"function declaration isn't a prototype" という
warning があります。何を意味するのか誰か知ってますか？

"unbalanced tree" のメッセージは何を意味しますか？

このドライバの古いバージョンは、時々 unbalanced dnode tree を作成しま
した。OS/2 の chkdsk は、tree が unbalance でも処理します (また時々
unbalanced tree を作成してしまいます :-) が、HPFS と HPFS386 の両方は
稀に tree が balance していない時にクラッシュするバグがあります。この
ドライバは unbalanced tree を見つけると、それらを正常に扱い、warning
を書きます。このメッセージが出るのは、たぶん、ディレクトリがこのドライ
バの古いバージョンで作成されているからです。対処は、すべてのファイルを
そのディレクトリから別のディレクトリに移動させ、次に、元のディレクトリ
に戻します。OS/2 ではなく、Linux で行います！このドライバで全体が作成
されたディレクトリでこのメッセージが出るなら、それはバグです - それを
私に連絡してください。


OS/2 におけるバグ

各々のディレクトリを指す二つ (以上) のディレクトリをロスとした場合、
chkdsk がファイルシステムを修復する時にロックします。

OS/2 下で 1 文字の名前のファイルを作成した時に、時々 (私はランダムだと
思います)、OS/2 はそれを「長い名前」とマークします。chkdsk はこのフラ
グを削除する時に "Minor fs error corrected" と伝えます。

"a .b" のようなファイル名は OS/2 によって「長い名前」としてマークされ
ますが、chkdsk はそれを "訂正" し、「短い名前」とマークします (そして、
"minor fs error corrected" を書きます)。このバグは HPFS386 では、あり
ません。

コードページのバグは上記で述べました。

fixpacks をインストールしなければ、さらに、さらに多く・・・あります。


履歴

0.90 最初の公開リリース
0.91 オープンしている inode に対し write_inode をコールするとメモリ
     shoot を起こす (滅多に起きません) バグを修正しました。
0.92 ディレクトリの inode の解放でのちょっとしたメモリリークを修正しま
     した。
0.93 最初の15 文字が同じファイル名がたくさんある時、マシンがロックする
     バグを修正しました。
     ファイルサイズがゼロのファイルの終端への write_file を修正しまし
     た。
0.94 使用中のファイルもしくはディレクトリを削除しようとした時のちょっ
     としたメモリリークを修正しました。
0.95 ファイルを移動する時に i_hpfs_parent_dir が更新されないバグを修正
     しました。
1.90 2.1.1xx カーネル向けの最初のバージョン
1.91 ディスクの最後のセクタで chk_sectors が失敗するバグを修正しました。
     ファイルの削除で呼ばれる write_inode の race-condition を修正しま
     した。
     ファイル名に 0xff を使用する場合、(非常に低い確率で) 起きるかもし
     れないバグを修正しました。
     race-condition を回避するためにロッキングを書き直しました。
     マウントオプション 'eas' を機能するようにしました。
     Fsync がエラーを返さなくしました。
     '.' で始まるファイルは hidden (隠しファイル) とマークされます。
     remount のサポートを追加しました。
     ファイルシステムが満杯になった時、alloc が遅くならないようにしま
     した。
     atime の更新は動作を遅くするので、行わないことにしました。
     コードの整理 (すべてのコメントになっていたデバッグプリントを削除)
     をしました。
1.92 ファイルの close 前に sync が呼ばれた時のバグを訂正しました。
1.93 カーネル 2.1.131 以上で動作するように変更しました。前のバージョン
     で動作するかどうかわかりません。
     64G を超えるディスクで考えうる不具合を修正しました (しかし、そん
     なディスクを持っていないので検証できません)。
     ファイルが 2G でオーバフローするのを修正しました。
     新しいオプション 'timeshift' を追加しました。
     HPFS386 上の振る舞いを変更しました - これにより HPFS386 を読み出
     し専用モードで操作できます。
     領域の 100% が割当てられた時に alloc が遅くなるバグを修正しました。
1.94 Linux でのあるバグについての対処を追加しました。
     あるバッファリークを修正しました。
     大きな拡張属性 (large extended attributes) に互換性がなかったもの
     を修正しました (しかし、まだ、100% ok ではなく、私はその情報を持っ
     ていないし、OS/2 も資料を出してくれません)。
     割当ての書き直し
     i_blocks に関するバグを修正しました (du は時々正常な値を表示しま
     せんでした)。
     ディレクトリは属性セットの履歴を保持しなくしました (これを好まな
     いプログラムがあります)。
     大きな anode ツリーで誤ったフラグを設定するバグを修正しました (壊
     すほどのものではありませんでした)。
1.95 壊れかけたファイルシステムで起こることのあるバッファリークを修正
     しました。
     1.94 での割当てのバグを修正しました。
1.96 OS/2 でのあるバグについての対処を追加しました (PMSHELL でディレク
     トリを open する場合、時々、HPFS はロックし、HPFS386 はエラーを報
     告しました)。
     考えうる bitmap race を修正しました。
     考えうる大きなディスクの不具合を修正しました。
     open しているファイルを削除できるようにしました。
     rename での非破壊型 race を修正しました。
1.97 (大きなパーティション上の) HPFS v3 をサポートしました。
     128M 以上のファイルを作成できなかったバグを修正しました (2G まで
     できるはずです)。
1.97.1 グローバルシンボルの名前を変更しました。
       ルートディレクトリを chmode もしくは chown する時のバグを修正し
       ました。
1.98 old_readdir を使った時のデッドロックを修正しました。
     ディレクトリの扱いを改善しました - OS/2 の "unbalanced tree" のバ
     グの対処。
1.99 ファイルを削除する時に十分な領域がなくなった場合の考えうる不具合
     を訂正しました。
     削除時、十分な領域がなくなった場合、ファイルを切り詰めるようにし
     ました。
     冗長なコードをたくさん削除しました。
2.00 rename におけるバグ (1.96 からありました) を修正しました。
     フラグメンテーションを起こさない手法を改善しました。
2.01 NFS 上のディレクトリ一覧をする時のバグを修正しました。
     ディレクトリの lseek で適切な引き数のチェックを行うようにしました。
     バッファのコードにおける race-condition を修正しました - この問題
     は Linux のすべてのファイルシステムにあります。ファイルの作成中に
     デバイスを読む (cat /dev/hda 等) 場合、ファイルが損傷を与えるかも
     しれませんでした。
2.02 Linux の breada におけるバグの対処をしました。breada はパーティショ
     ンの最後を超えてアクセスしてしまうかもしれませんでした。
2.03 キャラクタ／ブロックデバイスおよびパイプは正しく作成されます。
     unlink の非破壊型 race を修正しました (Alexander Viro)。
     OS/2 の日本語バージョンで動作するようにしました。
2.04 ftruncate を拡張ファイルに使った時のエラーを修正しました。
2.05 マウントで引き数に = がない場合、クラッシュしたのを修正しました。
     anode の割当てがディスクが満杯で失敗した場合、クラッシュしたのを
     修正しました。
     ブロック IO もしくは inode 割当てで失敗した場合、クラッシュしたの
     を修正しました。
