다음을 통해 공유


이름 바꾸기 및 하드 링크 처리

파일 시스템에 특히 중요한 영역은 이름 바꾸기 작업의 적절한 처리입니다. 비슷한 문제가 있는 영역은 하드 링크를 지원하는 파일 시스템에 대한 하드 링크 만들기입니다. 이름 바꾸기 작업의 경우 파일 시스템에서 파일(이름 바꾸기 작업의 대상)을 삭제할 수 있으며, 파일 시스템에서 추가 보안 검사가 필요합니다.

이름 바꾸기 작업에 대한 컨트롤 구조를 확인할 때 구조 필드 중 하나는 ReplaceIfExists 옵션입니다.

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

마찬가지로 하드 링크 작업의 제어 구조에서 구조 필드 중 하나는 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;
}