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