プロが教えるわが家の防犯対策術!

タイトルに問題と書きましたが、課題や何かじゃないので咎めないでください。

FAT12でフォーマットしたFDにファイルを直接ディスクに書き込もうと思っています。
しかし、FAT16と違ってFATにクラスタ番号を書き込むのが難しいわけです。
環境はC言語で、アルゴリズムだけなので必要は無いかと思いますが、
Win32APIを使用できる環境です。

1.クラスタ番号は12bit長で
0x003 0x004 0x005 0x006 0xFFFをFATに書き込むと
03 40 00 05 60 00 FF 0F と記録されます。

2.ディスクへの書き込みは実装してあるためバッファへの書き込みが出来ればよい。

3.ディスクは初期化された状態で、0番と1番のテーブルは予約済み。2番からクラスタ番号を書き込むこととする。

4.一つのファイルを整列された状態で書き込むこと。初期化されているため、2番から後のテーブルは全て未使用。

5.クラスタサイズは1セクタ(512バイト)である。

6.書き込まれるファイルサイズは規定していないため、ループによる処理が望ましい。

7.ファイルサイズより必要なクラスタ数は求めてある。

typedef unsigned char byte;
typedef unsigned short word, *pword;
typedef unsigned long dword;
byte fat[512];//FATへの書き込みバッファ 0クリアされている。
dword clust;//必要なクラスタ数 既に求めてある。
dword i;//インクリメント

自分で書いたFAT16用のFAT書き込みコード
((pword)fat)[0] = 0xFFF8;//0番目のクラスタ(予約)
((pword)fat)[1] = 0xFFFF;//1番目のクラスタ(予約)
if (clust == 1) {//クラスタサイズが1なら
    ((pword)fat)[2] = 0xFFFF;//最終クラスタを示す値を書き込む
} else {//複数のクラスタに分割されるなら
    for (i=0; i<clust-1; i++) {//クラスタサイズの-1個分までインクリメント
        ((pword)fat)[i+2] = (word)i+3;//n番(2番から始まる)のクラスタにn+1のクラスタ番号を書き込んでいく
    }
    ((pword)fat)[i+2] = 0xFFFF;//最終クラスタを示す値を書き込む
}

書きかけのFAT12
((pword)fat)[0] |= 0x0FF0;
*((pword)&fat[1]) |= 0xFFF0;
if (clust == 1) {
    *((pword)&fat[3]) = 0x0FFF;
} else {
    /*ここに1クラスタを超えたファイルのクラスタ番号をFATに書き込む処理*/
}

どなたか、ヒントや情報をいただけると幸いです。
コードは書き直してもいいですし、変数も適当に名前付けて構いません。
他に必要な変数などがあれば追加してください。

また、補足要求があれば何なりとお書きください。
よろしくお願いいたします。

A 回答 (3件)

おっと。

シフトすんの忘れてる。


>// *p = (*p & 0x0f) | (WData & 0xf0); //1バイト目
>  *p |= WData & 0xf0; //1バイト目


<// *p = (*p & 0x0f) | ((WData << 4) & 0xf0); //1バイト目
<  *p |= (WData << 4) & 0xf0; //1バイト目
    • good
    • 0

まず第一の問題は「FATへのクラスタ番号の書き込みを関数にしてない」のが問題。



第二の問題は「何故第2FATを書かないのか」と言う事。

第三の問題は「ルートディレクトリは書かないのか?」と言う事。

とりあえず「第一の問題」だけ回答。

//先頭から順番に書き込まず、ランダムに書く場合は、コメントした行を使う
void WriteFAT12(byte *fat,int CNo,int WData)
{
 byte *p = &fat[CNo * 3 / 2]; //書き込み位置を求める
 if (CNo & 1) { //クラスタ番号が奇数か偶数か
// *p = (*p & 0x0f) | (WData & 0xf0); //1バイト目
  *p |= WData & 0xf0; //1バイト目
  *++p = (WData >> 4); //2バイト目
 } else {
  *p++ = WData & 0xff; //1バイト目
// *p = (*p & 0xf0) | ((WData >> 8) & 0x0f); //2バイト目
  *p = (WData >> 8) & 0x0f; //2バイト目
 }
}

int i;
WriteFAT12(fat, 0, 0xFF8);//0番目のクラスタ(予約)
WriteFAT12(fat, 1, 0xFFF);//1番目のクラスタ(予約)
for (i = 1; i < clust; i++) {//クラスタサイズの-1分までインクリメント
    WriteFAT12(fat, i + 1, i + 2);//n番(2番から始まる)のクラスタにn+1のクラスタ番号を書き込んでいく
}
WriteFAT12(fat, clust + 1, 0xFFF);//最後のクラスタに終了マークを書き込む

いちいちclustが1か1以外か場合分けする必要はない。「clustが1ならループを回らないforループ」と「clustが1だろうが何だろうが、最後のクラスタにFFFを書き込む」と書けば済む。

この回答への補足

>「FATへのクラスタ番号の書き込みを関数にしてない」
これは、限られた条件の(初期化された状態で2番のクラスタから順番にかきこむ)ため
関数化の必要を感じていなかった訳です。

>「何故第2FATを書かないのか」
バッファを1stFATへ書き込んだ後に2ndFATに書き込むつもりでした。

>「ルートディレクトリは書かないのか?」
初期化された状態で書き込むので、ルートディレクトリエントリの最初に構造体を書き込もうと思っています。
何も書き込まれていないのが条件なので、特に問題は無いと思ってます。

>いちいちclustが1か1以外か場合分けする必要はない。
言われてから気づきました。
そうですよね、よく考えたらわざわざ処理分けする必要なんてありませんでした。

ご指摘ありがとう御座います。

補足日時:2009/01/23 00:49
    • good
    • 0
この回答へのお礼

お手本を示していただいたコードを元に
自分なりに書き直してみた結果です。
((pword)fat)[0] |= 0x0FF0;
*((pword)&fat[1]) |= 0xFFF0;
for (i=1; i<clust; i++) {
    clustNo = ((i+1)*3)>>1;
    if (i & 0x01) {
        *((pword)&fat[clustNo]) |= (i+2);
    } else {
        *((pword)&fat[clustNo]) |= (i+2) << 4;
    }
}
clustNo = ((i+1)*3)>>1;
if (i & 0x01) *((pword)&fat[clustNo]) = 0x0FFF;
else *((pword)&fat[clustNo]) = 0xFFF0;

>>start..
A Drive was Opened.
Boot sector was Read.
System file was Read.
Size of system file. [3168]
Size put together on sector boundary. [3584]
Necessary number of clusters. [7]
つたない英語はお許しください。
F0 FF FF 03 40 00 05 60
00 07 80 00 FF 0F 00 00
一応、期待通りに動いたみたいです。

大変参考になるコードを示していただき感謝いたします。
ありがとうございました。

お礼日時:2009/01/23 01:43

クラスタ番号を書き込むときに, 次に書き込むべき位置が「バイト境界にそろっているかどうか」を判断するフラグが 1個必要ではないでしょうか. そして,


バイト境界に揃っているのであれば
fat[i++] = cluster & 0xff;
fat[i] = cluster >> 8;
揃っていなければ
fat[i++] |= (cluster & 0x0f) << 4;
fat[i++] = cluster >> 4;
という処理になるかと. もちろん, 処理するごとにフラグを反転させる必要があります. また, 512バイトを超えちゃったときの処理も別途必要かもしれません.
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!