名前変更とハード リンク処理
ファイル システムにとって特に重要な領域は、名前の変更操作の適切な処理です。 同様の懸念事項は、ハード リンクをサポートするファイル システムのハード リンクの作成です。 名前の変更操作では、ファイル システムがファイル (名前の変更操作のターゲット) を削除できます。これには、ファイル システムによる追加のセキュリティチェックが必要です。
名前の変更操作のコントロール構造を見ると、構造フィールドの 1 つが ReplaceIfExists オプションです。
typedef struct _FILE_RENAME_INFORMATION {
BOOLEAN ReplaceIfExists;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
同様に、ハード リンク操作の制御構造では、構造体フィールドの 1 つが ReplaceIfExists オプションです。
typedef struct _FILE_LINK_INFORMATION {
BOOLEAN ReplaceIfExists;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;
どちらの場合も、操作のターゲット (存在する場合) を置き換えることができます。 FASTFAT ファイル システムはハード リンクをサポートしていませんが、名前の変更操作をサポートします。 これらのセマンティクスと動作は、FatSetRenameInfo 関数の FASTFAT ファイル システム ソース コード内で確認できます (WDK に含まれている fastfat サンプルの Fileinfo.c ソース ファイルを参照してください)。
名前の変更操作を処理する次のコード例は、ファイルを削除するためのファイル システムのチェックを模倣しています。 より堅牢なセキュリティ モデル (NTFS など) を持つファイル システムの場合、このチェックでは、呼び出し元が特定のファイルを削除できるようにセキュリティチェックも必要になります (呼び出し元には削除に必要な適切なアクセス許可がありました)。
//
// The name already exists. Check if the user wants
// to overwrite the name and has access to do the overwrite.
// We cannot overwrite a directory.
//
if ((!ReplaceIfExists) ||
(FlagOn(TargetDirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY)) ||
(FlagOn(TargetDirent->Attributes, FAT_DIRENT_ATTR_READ_ONLY))) {
try_return( Status = STATUS_OBJECT_NAME_COLLISION );
}
//
// Check that the file has no open user handles; otherwise,
// access will be denied. To do the check, search
// the list of FCBs opened under the parent Dcb, and make
// sure that none of the matching FCBs have a nonzero unclean count or
// outstanding image sections.
//
for (Links = TargetDcb->Specific.Dcb.ParentDcbQueue.Flink;
Links != &TargetDcb->Specific.Dcb.ParentDcbQueue; ) {
TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
//
// Advance now. The image section flush may cause the final
// close, which will recursively happen underneath of us here.
// It would be unfortunate if we looked through free memory.
//
Links = Links->Flink;
if ((TempFcb->DirentOffsetWithinDirectory == TargetDirentOffset) &&
((TempFcb->UncleanCount != 0) ||
!MmFlushImageSection( &TempFcb->NonPaged->SectionObjectPointers,
MmFlushForDelete))) {
//
// If there are batch oplocks on this file, then break the
// oplocks before failing the rename.
//
Status = STATUS_ACCESS_DENIED;
if ((NodeType(TempFcb) == FAT_NTC_FCB) &&
FsRtlCurrentBatchOplock( &TempFcb->Specific.Fcb.Oplock )) {
//
// Do all of the cleanup now since the IrpContext
// could go away when this request is posted.
//
FatUnpinBcb( IrpContext, TargetDirentBcb );
Status = FsRtlCheckOplock( &TempFcb->Specific.Fcb.Oplock,
Irp,
IrpContext,
FatOplockComplete,
NULL );
if (Status != STATUS_PENDING) {
Status = STATUS_ACCESS_DENIED;
}
}
try_return( NOTHING );
}
}
//
// OK, this target is finished. Remember the Lfn offset.
//
TargetLfnOffset = TargetDirentOffset -
FAT_LFN_DIRENTS_NEEDED(&TargetLfn) * sizeof(DIRENT);
DeleteTarget = TRUE;
}