Rinomina e elaborazione collegamento rigido
Un'area di particolare preoccupazione per i file system è la corretta gestione delle operazioni di ridenominazione. Un'area simile di preoccupazione è la creazione di collegamenti rigidi per i file system che supportano i collegamenti rigidi. Per le operazioni di ridenominazione, è possibile che un file system elimini un file (destinazione dell'operazione di ridenominazione), che richiede controlli di sicurezza aggiuntivi dal file system.
Quando si esamina la struttura di controllo per un'operazione di ridenominazione, uno dei campi della struttura è l'opzione ReplaceIfExists :
typedef struct _FILE_RENAME_INFORMATION {
BOOLEAN ReplaceIfExists;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
Analogamente, nella struttura di controllo dell'operazione di collegamento rigido, uno dei campi della struttura è l'opzione ReplaceIfExists :
typedef struct _FILE_LINK_INFORMATION {
BOOLEAN ReplaceIfExists;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;
In entrambi i casi, l'opzione consiste nel sostituire la destinazione dell'operazione, se presente. Anche se il file system FASTFAT non supporta collegamenti rigidi, supporta le operazioni di ridenominazione. Queste semantiche e il comportamento possono essere visualizzate all'interno del codice sorgente del file system FASTFAT nella funzione FatSetRenameInfo (vedere il file di origine Fileinfo.c dagli esempi fastfat che il WDK contiene).
L'esempio di codice seguente per gestire un'operazione di ridenominazione simula i controlli del file system per l'eliminazione del file. Per un file system con un modello di sicurezza più affidabile (NTFS, ad esempio), questo controllo richiederebbe anche il controllo della sicurezza per assicurarsi che il chiamante sia stato autorizzato a eliminare il file specificato (il chiamante aveva le autorizzazioni appropriate necessarie per l'eliminazione).
//
// 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;
}