Compartir a través de


Cambio de nombre y procesamiento de vínculos físicos

Un área de especial preocupación para los sistemas de archivos es el control adecuado de las operaciones de cambio de nombre. Un área similar de preocupación es la creación de vínculos físicos para sistemas de archivos que admiten vínculos físicos. Para las operaciones de cambio de nombre, es posible que un sistema de archivos elimine un archivo (el destino de la operación de cambio de nombre), que requiere comprobaciones de seguridad adicionales por parte del sistema de archivos.

Al examinar la estructura de control para una operación de cambio de nombre, uno de los campos de estructura es la opción ReplaceIfExists :

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

Del mismo modo, en la estructura de control de la operación de vínculo físico, uno de los campos de estructura es la opción ReplaceIfExists :

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

En ambos casos, la opción es reemplazar el destino de la operación, si existe. Aunque el sistema de archivos FASTFAT no admite vínculos duros, admite operaciones de cambio de nombre. Estas semánticas y comportamientos se pueden ver en el código fuente del sistema de archivos FASTFAT en la función FatSetRenameInfo (vea el archivo de origen Fileinfo.c de los ejemplos fastfat que contiene el WDK).

En el ejemplo de código siguiente para controlar una operación de cambio de nombre se imitan las comprobaciones del sistema de archivos para eliminar el archivo. En el caso de un sistema de archivos con un modelo de seguridad más sólido (NTFS, por ejemplo), esta comprobación también requeriría la comprobación de seguridad para asegurarse de que el autor de la llamada podía eliminar el archivo determinado (el autor de la llamada tenía los permisos adecuados necesarios para su eliminación).

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