Share via


Umbenennen und Hartlinkverarbeitung

Ein bereich von besonderem Interesse für Dateisysteme ist die ordnungsgemäße Handhabung von Umbenennungsvorgängen. Ein ähnliches Problem besteht in der Erstellung harter Verknüpfungen für Dateisysteme, die feste Links unterstützen. Bei Umbenennungsvorgängen ist es möglich, dass ein Dateisystem eine Datei (das Ziel des Umbenennungsvorgangs) löscht, was zusätzliche Sicherheitsüberprüfungen durch das Dateisystem erfordert.

Wenn Sie die Steuerelementstruktur für einen Umbenennungsvorgang betrachten, ist eines der Strukturfelder die Option ReplaceIfExists :

typedef struct _FILE_RENAME_INFORMATION {
    BOOLEAN ReplaceIfExists;
    HANDLE RootDirectory;
    ULONG FileNameLength;
    WCHAR FileName[1];
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;

Ebenso ist in der Steuerungsstruktur des Vorgangs für feste Verknüpfung eines der Strukturfelder die Option ReplaceIfExists :

typedef struct _FILE_LINK_INFORMATION {
    BOOLEAN ReplaceIfExists;
    HANDLE RootDirectory;
    ULONG FileNameLength;
    WCHAR FileName[1];
} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;

In beiden Fällen besteht die Option darin, das Ziel des Vorgangs zu ersetzen, sofern vorhanden. Das FASTFAT-Dateisystem unterstützt zwar keine harten Links, unterstützt jedoch Umbenennungsvorgänge. Diese Semantik und das Verhalten können im Quellcode des FASTFAT-Dateisystems in der FatSetRenameInfo-Funktion angezeigt werden (siehe die Fileinfo.c-Quelldatei aus den fastfat-Beispielen, die das WDK enthält).

Das folgende Codebeispiel zum Behandeln eines Umbenennungsvorgangs imitiert die Dateisystemüberprüfungen auf das Löschen der Datei. Für ein Dateisystem mit einem robusteren Sicherheitsmodell (z. B. NTFS) würde diese Überprüfung auch eine Sicherheitsüberprüfung erfordern, um sicherzustellen, dass der Aufrufer die angegebene Datei löschen darf (der Aufrufer verfügte über die entsprechenden Berechtigungen zum Löschen).

    //
    //  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;
}