예제 #1
0
NTSTATUS
FatSetFsLabelInfo (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb,
    IN PFILE_FS_LABEL_INFORMATION Buffer
    )

/*++

Routine Description:

    This routine implements the set volume label call

Arguments:

    Vcb - Supplies the Vcb being queried

    Buffer - Supplies the input where the information is stored.

Return Value:

    NTSTATUS - Returns the status for the operation

--*/

{
    NTSTATUS Status;

    PDIRENT Dirent;
    PBCB DirentBcb = NULL;
    ULONG ByteOffset;

    WCHAR TmpBuffer[11];
    UCHAR OemBuffer[11];
    OEM_STRING OemLabel;
    UNICODE_STRING UnicodeString;
    UNICODE_STRING UpcasedLabel;

    DebugTrace(+1, Dbg, "FatSetFsLabelInfo...\n", 0);

    //
    //  Setup our local variable
    //

    UnicodeString.Length = (USHORT)Buffer->VolumeLabelLength;
    UnicodeString.MaximumLength = UnicodeString.Length;
    UnicodeString.Buffer = (PWSTR) &Buffer->VolumeLabel[0];

    //
    //  Make sure the name can fit into the stack buffer
    //

    if ( UnicodeString.Length > 11*sizeof(WCHAR) ) {

        return STATUS_INVALID_VOLUME_LABEL;
    }

    //
    //  Upcase the name and convert it to the Oem code page.
    //

    OemLabel.Buffer = &OemBuffer[0];
    OemLabel.Length = 0;
    OemLabel.MaximumLength = 11;

    Status = RtlUpcaseUnicodeStringToCountedOemString( &OemLabel,
                                                       &UnicodeString,
                                                       FALSE );

    //
    //  Volume label that fits in 11 unicode character length limit
    //  is not necessary within 11 characters in OEM character set.
    //

    if (!NT_SUCCESS( Status )) {

        DebugTrace(-1, Dbg, "FatSetFsLabelInfo:  Label must be too long. %08lx\n", Status );

        return STATUS_INVALID_VOLUME_LABEL;
    }

    //
    //  Strip spaces off of the label.
    //

    if (OemLabel.Length > 0) {

        USHORT i;
        USHORT LastSpaceIndex = MAXUSHORT;

        //
        //  Check the label for illegal characters
        //

        for ( i = 0; i < (ULONG)OemLabel.Length; i += 1 ) {

            if ( FsRtlIsLeadDbcsCharacter( OemLabel.Buffer[i] ) ) {

                LastSpaceIndex = MAXUSHORT;
                i += 1;
                continue;
            }

            if (!FsRtlIsAnsiCharacterLegalFat(OemLabel.Buffer[i], FALSE) ||
                (OemLabel.Buffer[i] == '.')) {

                return STATUS_INVALID_VOLUME_LABEL;
            }

            //
            //  Watch for the last run of spaces, so we can strip them.
            //

            if (OemLabel.Buffer[i] == ' ' &&
                LastSpaceIndex == MAXUSHORT) {
                LastSpaceIndex = i;
            } else {
                LastSpaceIndex = MAXUSHORT;
            }
        }

        if (LastSpaceIndex != MAXUSHORT) {
            OemLabel.Length = LastSpaceIndex;
        }
    }

    //
    //  Get the Unicode upcased string to store in the VPB.
    //

    UpcasedLabel.Length = UnicodeString.Length;
    UpcasedLabel.MaximumLength = 11*sizeof(WCHAR);
    UpcasedLabel.Buffer = &TmpBuffer[0];

    Status = RtlOemStringToCountedUnicodeString( &UpcasedLabel,
                                                 &OemLabel,
                                                 FALSE );

    if (!NT_SUCCESS( Status )) {

        DebugTrace(-1, Dbg, "FatSetFsLabelInfo:  Label must be too long. %08lx\n", Status );

        return STATUS_INVALID_VOLUME_LABEL;
    }

    DirentBcb = NULL;

    //
    //  Make this look like a write through to disk.  This is important to
    //  avoid a unpleasant window where it looks like we have the wrong volume.
    //

    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH );

    try {

        //
        //  Are we setting or removing the label?  Note that shaving spaces could
        //  make this different than wondering if the input buffer is non-zero length.
        //
        
        if (OemLabel.Length > 0) {

            //
            //  Locate the volume label if there already is one
            //

            FatLocateVolumeLabel( IrpContext,
                                  Vcb,
                                  &Dirent,
                                  &DirentBcb,
                                  &ByteOffset );

            //
            //  Check that we really got one, if not then we need to create
            //  a new one.  The procedure we call will raise an appropriate
            //  status if we are not able to allocate a new dirent
            //

            if (Dirent == NULL) {

                ByteOffset = FatCreateNewDirent( IrpContext,
                                                 Vcb->RootDcb,
                                                 1 );

                FatPrepareWriteDirectoryFile( IrpContext,
                                              Vcb->RootDcb,
                                              ByteOffset,
                                              sizeof(DIRENT),
                                              &DirentBcb,
                                              &Dirent,
                                              FALSE,
                                              TRUE,
                                              &Status );

                ASSERT( NT_SUCCESS( Status ));
            
            } else {

                //
                //  Just mark this guy dirty now.
                //
            
                FatSetDirtyBcb( IrpContext, DirentBcb, Vcb, TRUE );
            }

            //
            //  Now reconstruct the volume label dirent.
            //

            FatConstructLabelDirent( IrpContext,
                                     Dirent,
                                     &OemLabel );

            //
            //  Unpin the Bcb here so that we will get any IO errors
            //  here before changing the VPB label.
            //

            FatUnpinBcb( IrpContext, DirentBcb );
            FatUnpinRepinnedBcbs( IrpContext );

            //
            //  Now set the upcased label in the VPB
            //

            RtlCopyMemory( &Vcb->Vpb->VolumeLabel[0],
                           &UpcasedLabel.Buffer[0],
                           UpcasedLabel.Length );

            Vcb->Vpb->VolumeLabelLength = UpcasedLabel.Length;

        } else {

            //
            //  Otherwise we're trying to delete the label
            //  Locate the current volume label if there already is one
            //

            FatLocateVolumeLabel( IrpContext,
                                  Vcb,
                                  &Dirent,
                                  &DirentBcb,
                                  &ByteOffset );

            //
            //  Check that we really got one
            //

            if (Dirent == NULL) {

                try_return( Status = STATUS_SUCCESS );
            }

            //
            //  Now delete the current label.
            //

            Dirent->FileName[0] = FAT_DIRENT_DELETED;

            ASSERT( (Vcb->RootDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) ||
                    RtlAreBitsSet( &Vcb->RootDcb->Specific.Dcb.FreeDirentBitmap,
                                   ByteOffset / sizeof(DIRENT),
                                   1 ) );

            RtlClearBits( &Vcb->RootDcb->Specific.Dcb.FreeDirentBitmap,
                          ByteOffset / sizeof(DIRENT),
                          1 );

            FatSetDirtyBcb( IrpContext, DirentBcb, Vcb, TRUE );

            //
            //  Unpin the Bcb here so that we will get any IO errors
            //  here before changing the VPB label.
            //

            FatUnpinBcb( IrpContext, DirentBcb );
            FatUnpinRepinnedBcbs( IrpContext );

            //
            //  Now set the label in the VPB
            //

            Vcb->Vpb->VolumeLabelLength = 0;
        }

        Status = STATUS_SUCCESS;
        
        FatSortDirectory(IrpContext, Vcb->RootDcb);
    try_exit: NOTHING;
    } finally {

        DebugUnwind( FatSetFsALabelInfo );

        FatUnpinBcb( IrpContext, DirentBcb );

        DebugTrace(-1, Dbg, "FatSetFsALabelInfo -> STATUS_SUCCESS\n", 0);
    }

    return Status;
}
예제 #2
0
VOID
FatGetUnicodeNameFromFcb (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN OUT PUNICODE_STRING Lfn
    )

/*++

Routine Description:

    This routine will return the unicode name for a given Fcb.  If the
    file has an LFN, it will return this.  Otherwise it will return
    the UNICODE conversion of the Oem name, properly cased.

Arguments:

    Fcb - Supplies the Fcb to query.

    Lfn - Supplies a string that already has enough storage for the
        full unicode name.

Return Value:

    None

--*/

{
    PDIRENT Dirent;
    PBCB DirentBcb = NULL;
    ULONG DirentByteOffset;

    CCB LocalCcb;

    ASSERT((MAX_LFN_CHARACTERS * sizeof( WCHAR)) == Lfn->MaximumLength);
    
    //
    //  We'll start by locating the dirent for the name.
    //

    FatStringTo8dot3( IrpContext,
                      Fcb->ShortName.Name.Oem,
                      &LocalCcb.OemQueryTemplate.Constant );

    LocalCcb.Flags = 0;
    LocalCcb.UnicodeQueryTemplate.Length = 0;
    LocalCcb.ContainsWildCards = FALSE;

    FatLocateDirent( IrpContext,
                     Fcb->ParentDcb,
                     &LocalCcb,
                     Fcb->LfnOffsetWithinDirectory,
                     &Dirent,
                     &DirentBcb,
                     &DirentByteOffset,
                     NULL,
                     Lfn);
    try {

        //
        //  If we didn't find the Dirent, something is terribly wrong.
        //

        if ((DirentBcb == NULL) ||
            (DirentByteOffset != Fcb->DirentOffsetWithinDirectory)) {

            FatRaiseStatus( IrpContext, STATUS_FILE_INVALID );
        }

        //
        //  Check for the easy case.
        //

        if (Lfn->Length == 0) {

            NTSTATUS Status;
            OEM_STRING ShortName;
            UCHAR ShortNameBuffer[12];

            //
            //  If we thought that there was an LFN here and didn't find one,
            //  we're as dead.  This shouldn't happen in normal operation, but
            //  if someone scrambles a directory by hand ...
            //
            
            ASSERT( Fcb->LfnOffsetWithinDirectory == Fcb->DirentOffsetWithinDirectory );

            if (Fcb->LfnOffsetWithinDirectory != Fcb->DirentOffsetWithinDirectory) {

                FatRaiseStatus( IrpContext, STATUS_FILE_INVALID );
            }

            //
            //  There is no LFN, so manufacture a UNICODE name.
            //

            ShortName.Length = 0;
            ShortName.MaximumLength = 12;
            ShortName.Buffer = ShortNameBuffer;

            Fat8dot3ToString( IrpContext, Dirent, TRUE, &ShortName );

            //
            //  OK, now convert this string to UNICODE
            //

            Status = RtlOemStringToCountedUnicodeString( Lfn,
                                                         &ShortName,
                                                         FALSE );

            ASSERT( Status == STATUS_SUCCESS );
        }

    } finally {

        FatUnpinBcb( IrpContext, DirentBcb );
    }
}
예제 #3
0
파일: fcb.c 프로젝트: hoangduit/reactos
VOID
NTAPI
FatGetFcbUnicodeName(IN PFAT_IRP_CONTEXT IrpContext,
                     IN PFCB Fcb,
                     OUT PUNICODE_STRING LongName)
{
    FF_DIRENT DirEnt;
    FF_ERROR Err;
    OEM_STRING ShortName;
    CHAR ShortNameBuf[13];
    UCHAR EntryBuffer[32];
    UCHAR NumLFNs;
    OEM_STRING LongNameOem;
    NTSTATUS Status;

    /* Make sure this FCB has a FullFAT handle associated with it */
    if (Fcb->FatHandle == NULL &&
        FatNodeType(Fcb) == FAT_NTC_DCB)
    {
        /* Open the dir with FullFAT */
        Fcb->FatHandle = FF_OpenW(Fcb->Vcb->Ioman, &Fcb->FullFileName, FF_MODE_DIR, NULL);
        if (!Fcb->FatHandle)
        {
            ASSERT(FALSE);
        }
    }

    /* Get the dir entry */
    Err = FF_GetEntry(Fcb->Vcb->Ioman,
                      Fcb->FatHandle->DirEntry,
                      Fcb->FatHandle->DirCluster,
                      &DirEnt);

    if (Err != FF_ERR_NONE)
    {
        DPRINT1("Error %d getting dirent of a file\n", Err);
        return;
    }

    /* Read the dirent to fetch the raw short name */
    FF_FetchEntry(Fcb->Vcb->Ioman,
                  Fcb->FatHandle->DirCluster,
                  Fcb->FatHandle->DirEntry,
                  EntryBuffer);
    NumLFNs = (UCHAR)(EntryBuffer[0] & ~0x40);

    /* Check if we only have a short name.
       Convert it to unicode and return if that's the case */
    if (NumLFNs == 0)
    {
        /* Initialize short name string */
        ShortName.Buffer = ShortNameBuf;
        ShortName.Length = 0;
        ShortName.MaximumLength = 12;

        /* Convert raw short name to a proper string */
        Fati8dot3ToString((PCHAR)EntryBuffer, FALSE, &ShortName);

        /* Convert it to unicode */
        Status = RtlOemStringToCountedUnicodeString(LongName,
                                                    &ShortName,
                                                    FALSE);

        /* Ensure conversion was successful */
        ASSERT(Status == STATUS_SUCCESS);

        /* Exit */
        return;
    }

    /* Convert LFN from OEM to unicode and return */
    LongNameOem.Buffer = DirEnt.FileName;
    LongNameOem.MaximumLength = FF_MAX_FILENAME;
    LongNameOem.Length = strlen(DirEnt.FileName);

    /* Convert it to unicode */
    Status = RtlOemStringToUnicodeString(LongName, &LongNameOem, FALSE);

    /* Ensure conversion was successful */
    ASSERT(Status == STATUS_SUCCESS);
}