Renommer et traiter les liens durs
Un domaine particulièrement préoccupant pour les systèmes de fichiers est la gestion appropriée des opérations de renommage. La création de liens physiques pour les systèmes de fichiers qui prennent en charge les liens physiques est un sujet de préoccupation similaire. Pour les opérations de renommage, il est possible pour un système de fichiers de supprimer un fichier (la cible de l’opération de renommage), ce qui nécessite des vérifications de sécurité supplémentaires par le système de fichiers.
Lorsque vous examinez la structure de contrôle pour une opération de renommage, l’un des champs de structure est l’option ReplaceIfExists :
typedef struct _FILE_RENAME_INFORMATION {
BOOLEAN ReplaceIfExists;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
De même, dans la structure de contrôle de l’opération de liaison matérielle, l’un des champs de structure est l’option ReplaceIfExists :
typedef struct _FILE_LINK_INFORMATION {
BOOLEAN ReplaceIfExists;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;
Dans les deux cas, l’option consiste à remplacer la cible de l’opération, si elle existe. Bien que le système de fichiers FASTFAT ne prend pas en charge les liens physiques, il prend en charge les opérations de renommage. Ces sémantiques et ce comportement sont visibles dans le code source du système de fichiers FASTFAT dans la fonction FatSetRenameInfo (consultez le fichier source Fileinfo.c à partir des exemples fastfat que contient le WDK).
L’exemple de code suivant pour gérer une opération de renommage imite la suppression du fichier par le système de fichiers. Pour un système de fichiers avec un modèle de sécurité plus robuste (NTFS, par exemple), cette case activée nécessiterait également une vérification de sécurité pour s’assurer que l’appelant était autorisé à supprimer le fichier donné (l’appelant disposait des autorisations appropriées requises pour la suppression).
//
// 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;
}