MS−DOS上でプログラミングをする場合には, MS−DOSの持つシステムコールの理解は必須となります. Cでプログラミングする場合には, コンパイラが提供する標準ライブラリにDOSのシステムコールが簡単に使える専用関数が備わっていますので処理は簡単です. ただこれらの関数が呼び出すファイル処理関連のシステムコールをよく調べてみますとほとんどが新しい形のものです. CP/Mから受け継いだFCBによるファイル処理というものはないようです. DOSのマニュアル上でもファイルハンドルを用いたプログラミングを推奨していますので当たり前といえば当たり前です.
こんな中でよく使うものに find_first, find_next があります.これらは目的のファイルをディスク上から見つけてくれるものですが, 定められた引数構造体の中にファイル名だけでなく, ファイル更新時刻, ファイルサイズ, 属性などの有用な情報を返してくれます. 雑誌上のプログラミング例にもこれらの応用がたくさん紹介されている事は周知のことと思います. find_first, find_next の機能はFCBを用いたシステムコールも存在しますが, 旧形式であることや機能に若干の制限もあることから利用されないのがほとんどです.
さて, 本題です. プログラムのコピープロテクトですが, ゲームなどのようにフロッピーディスクでのみ利用するプログラムではFDCを高度に制御したDISKCOPYのプロテクト手法が開発されており, 今更私がとやかく書くようなこともありません. ところがビジネス用のアプリケーションともなるとハードディスクへのインストールが前提となります. このような場合には, ハードディスク上にインストールされたプログラムのコピープロテクトが問題となります. ハードディスクはユーザーによってその構成や種類が特定できません. FDC制御などのハードウェア制御を用いた手法は期待できません. なんとかソフトウェアだけで, インストールされたプログラムを, 例えばフロッピーディスクにコピーしたものや同じハードディスク上で別のディレクトリにコピーしたものは動作しないようにできないものでしょうか? DOSの COPY コマンドやその他ユーティリティによりコピーされたプログラムの動作を禁止する方法はあるのでしょうか? 一つの解決策に同一ディレクトリにヒドゥン属性のついた特定のファイルを設けておいてそのファイルの存在の有無(find_first などで見つけられます)により動作を制御する方法があります. ところがこの方法は2,3年前ならば結構通用した方法ですが, 冒頭でも書きましたように find_first などのシステムコールを用いた最近のユーティリティではいとも簡単にヒドゥン属性のついたファイルを見つけてしまいます.
何かうまい方法はないものかと次のような手法について色々検討してみました. ここからの記述にはひょっとして思い違いや誤りがあるかも知れないことをお断りしておきます. 気付いた方はレスして頂けるとありがたいだす.
- ファイルのアーカイブ属性を検査する
ファイル属性にはアーカイブ属性ビットが存在します. ファイルに変更があるとこのビットがオンとなります. これを利用する方法です. インストールした時点ではこのビットをクリアしておきます. COPY コマンドではコピーされた方のファイルにはこのビットが必ずオンとなります. これによってインストールされたものかそうでないものか見分けることができます. find_first などのシステムコールで簡単に検査できます. ところがです, 市販の最近のユーティリティのコピー処理ではこのビットをわざわざクリアするものがあります. この方法のみでは完全ではないようです.
- 更新時刻, サイズの変更を検査する
COPY コマンドなどは更新時刻やファイルサイズを変更しませんのでこの方法はダメですが, 仮にデバッガやエディタ(バイナリエディットできるもの)などで編集後に書き戻されたものに対しては有効かも知れません.
- ボリュームラベルを検査する
インストールされた時のディスクのボリュームラベルを記憶しておいて, プログラム起動時のディスクのそれと照合するというものです. これもボリュームラベルがつけられてない場合や, ディスク毎にユニークであることが保証されていないことから不完全です. また利用者がボリュームラベルを付け変えたとたんにプログラムが動作しなくなるというのも困りものです.
- ディスク上のファイルが格納された最後のクラスタを検査する
ディスク上にファイルが格納される時にはクラスタ単位に領域を確保しますのでファイルサイズによっては最後のクラスタには使用されない部分が生じます.この使用されない領域に検査用の識別コードを埋めておいてそれの有無を検査するというものです. この方法はなかなかうまい方法のように思うのですが, 実現するのは簡単ではなさそうです. インストール時点やプログラム起動時に最後のクラスタをどのようにして見つけるか? クラスタサイズはディスク容量によって違いますし, ディスクアクセスを直接行う必要がありそうでへたをするとハードディスクを壊してしまいそうです. ちょっと不安材料が多そうです. システムコールの中にも最終クラスタ位置を返してくれるようなものはありません(と思います).
- ディスク上のファイル格納位置を検査する
インストール時点でのファイルが格納された物理的な位置を記憶しておいて照合する方法です. COPY されたファイルは元のファイルと同じ位置に格納されることは絶対にありません. よしんばフロッピーディスクや別ドライブのハードディスクに COPY されたとしても元のディスクと状態が全く同じであるということはほぼないでしょう. この方法もうまい方法に思えます. ではファイルの格納位置は何で知ればよいのでしょうか? ディレクトリエントリにはファイルが格納されたディスク上の最初のクラスタ位置が書かれています. これを読みとる事ができればいいわけです. ではディレクトリエントリは簡単に読み取ることができるの でしょうか? (4) で検討したようにディスクを直接アクセスするのでは困ります. 仮に直接アクセスするとしてもルートディレクトリならディスクの固定位置に存在しますの簡単に読めそうですが, サブディレクトリともなると目的のディレクトリエントリの位置を見つけるのが大変そうです. クラスタサイズやシリンダ当たりのセクタ数なども考慮するとなれば不安です. find_first などのシステムコールではファイルの先頭クラスタ位置までは返してくれません. ところがFCBを用いた古いシステムコールの中に目的のディレクトリエントリの32バイトをそのまま返してくれるものがあります. これを使えばディスクの形式等一切考慮せず簡単にできそうです.
ながなが書きましたがCP/M時代の影を引きづったFCBによるシステムコールにもまだまだ役にたつものがあるということです. 暇をみてはDOSのマニュアルをよく読んでみると新たな発見がまだまだあるかもしれません.
(PS)ここに書きましたプロテクト方法ですがこれらは初歩の部類に入るものだと思います. すでにその手の書籍などで書かれているのではないか思います. 実用的ではありませんがこんな事をあれこれ考えてみるのも何かの勉強になるのではと 参考に書いてみた次第です.