📄 dirsup.c
字号:
// Save a pointer to the time stamps.
//
Dirent->CdTime = RawDirent->RecordTime;
//
// Copy the dirent flags.
//
Dirent->DirentFlags = CdRawDirentFlags( IrpContext, RawDirent );
//
// For both the file unit and interleave skip we want to take the
// logical block count.
//
Dirent->FileUnitSize =
Dirent->InterleaveGapSize = 0;
if (RawDirent->IntLeaveSize != 0) {
Dirent->FileUnitSize = RawDirent->IntLeaveSize;
Dirent->InterleaveGapSize = RawDirent->IntLeaveSkip;
}
//
// Get the name length and remember a pointer to the start of the
// name string. We don't do any processing on the name at this
// point.
//
// Check that the name length is non-zero.
//
if (RawDirent->FileIdLen == 0) {
CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
}
Dirent->FileNameLen = RawDirent->FileIdLen;
Dirent->FileName = RawDirent->FileId;
//
// If there are any remaining bytes at the end of the dirent then
// there may be a system use area. We protect ourselves from
// disks which don't pad the dirent entries correctly by using
// a fudge factor of one. All system use areas must have a length
// greater than one. Don't bother with the system use area
// if this is a directory.
//
Dirent->XAAttributes = 0;
Dirent->XAFileNumber = 0;
Dirent->ExtentType = Form1Data;
Dirent->SystemUseOffset = 0;
if (!FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY ) &&
(Dirent->DirentLength > ((FIELD_OFFSET( RAW_DIRENT, FileId ) + Dirent->FileNameLen) + 1))) {
Dirent->SystemUseOffset = WordAlign( FIELD_OFFSET( RAW_DIRENT, FileId ) + Dirent->FileNameLen );
}
return;
}
VOID
CdUpdateDirentName (
IN PIRP_CONTEXT IrpContext,
IN OUT PDIRENT Dirent,
IN ULONG IgnoreCase
)
/*++
Routine Description:
This routine is called to update the name in the dirent with the name
from the disk. We will look for the special case of the self and
parent entries and also construct the Unicode name for the Joliet disk
in order to work around the BigEndian on-disk structure.
Arguments:
Dirent - Pointer to the in-memory dirent structure.
IgnoreCase - TRUE if we should build the upcased version. Otherwise we
use the exact case name.
Return Value:
None.
--*/
{
UCHAR DirectoryValue;
ULONG Length;
NTSTATUS Status;
PAGED_CODE();
//
// Check if this is a self or parent entry. There is no version number
// in these cases. We use a fixed string for these.
//
// Self-Entry - Length is 1, value is 0.
// Parent-Entry - Length is 1, value is 1.
//
if ((Dirent->FileNameLen == 1) &&
FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) {
DirectoryValue = *((PCHAR) Dirent->FileName);
if ((DirectoryValue == 0) || (DirectoryValue == 1)) {
//
// We should not have allocated a name by the time we see these cases.
// If we have, this means that the image is in violation of ISO 9660 7.6.2,
// which states that the ./.. entries must be the first two in the directory.
//
if (FlagOn( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER )) {
CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
}
//
// Now use one of the hard coded directory names.
//
Dirent->CdFileName.FileName = CdUnicodeDirectoryNames[DirectoryValue];
//
// Show that there is no version number.
//
Dirent->CdFileName.VersionString.Length = 0;
//
// The case name is the same as the exact name.
//
Dirent->CdCaseFileName = Dirent->CdFileName;
//
// Mark this as a constant value entry.
//
SetFlag( Dirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY );
//
// Return now.
//
return;
}
}
//
// Mark this as a non-constant value entry.
//
ClearFlag( Dirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY );
//
// Compute how large a buffer we will need. If this is an ignore
// case operation then we will want a double size buffer. If the disk is not
// a Joliet disk then we might need two bytes for each byte in the name.
//
Length = Dirent->FileNameLen;
if (IgnoreCase) {
Length *= 2;
}
if (!FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_JOLIET )) {
Length *= sizeof( WCHAR );
}
//
// Now decide if we need to allocate a new buffer. We will if
// this name won't fit in the embedded name buffer and it is
// larger than the current allocated buffer. We always use the
// allocated buffer if present.
//
// If we haven't allocated a buffer then use the embedded buffer if the data
// will fit. This is the typical case.
//
if (!FlagOn( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER ) &&
(Length <= sizeof( Dirent->NameBuffer ))) {
Dirent->CdFileName.FileName.MaximumLength = sizeof( Dirent->NameBuffer );
Dirent->CdFileName.FileName.Buffer = Dirent->NameBuffer;
} else {
//
// We need to use an allocated buffer. Check if the current buffer
// is large enough.
//
if (Length > Dirent->CdFileName.FileName.MaximumLength) {
//
// Free any allocated buffer.
//
if (FlagOn( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER )) {
CdFreePool( &Dirent->CdFileName.FileName.Buffer );
ClearFlag( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER );
}
Dirent->CdFileName.FileName.Buffer = FsRtlAllocatePoolWithTag( CdPagedPool,
Length,
TAG_DIRENT_NAME );
SetFlag( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER );
Dirent->CdFileName.FileName.MaximumLength = (USHORT) Length;
}
}
//
// We now have a buffer for the name. We need to either convert the on-disk bigendian
// to little endian or covert the name to Unicode.
//
if (!FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_JOLIET )) {
Status = RtlOemToUnicodeN( Dirent->CdFileName.FileName.Buffer,
Dirent->CdFileName.FileName.MaximumLength,
&Length,
Dirent->FileName,
Dirent->FileNameLen );
ASSERT( Status == STATUS_SUCCESS );
Dirent->CdFileName.FileName.Length = (USHORT) Length;
} else {
//
// Convert this string to little endian.
//
CdConvertBigToLittleEndian( IrpContext,
Dirent->FileName,
Dirent->FileNameLen,
(PCHAR) Dirent->CdFileName.FileName.Buffer );
Dirent->CdFileName.FileName.Length = (USHORT) Dirent->FileNameLen;
}
//
// Split the name into name and version strings.
//
CdConvertNameToCdName( IrpContext,
&Dirent->CdFileName );
//
// The name length better be non-zero.
//
if (Dirent->CdFileName.FileName.Length == 0) {
CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
}
//
// If the filename ends with a period then back up one character.
//
if (Dirent->CdFileName.FileName.Buffer[(Dirent->CdFileName.FileName.Length - sizeof( WCHAR )) / 2] == L'.') {
//
// Slide the version string down.
//
if (Dirent->CdFileName.VersionString.Length != 0) {
PWCHAR NewVersion;
//
// Start from the position currently containing the separator.
//
NewVersion = Add2Ptr( Dirent->CdFileName.FileName.Buffer,
Dirent->CdFileName.FileName.Length,
PWCHAR );
//
// Now overwrite the period.
//
RtlMoveMemory( NewVersion - 1,
NewVersion,
Dirent->CdFileName.VersionString.Length + sizeof( WCHAR ));
//
// Now point to the new version string.
//
Dirent->CdFileName.VersionString.Buffer = NewVersion;
}
//
// Shrink the filename length.
//
Dirent->CdFileName.FileName.Length -= sizeof( WCHAR );
}
//
// If this an exact case operation then use the filename exactly.
//
if (!IgnoreCase) {
Dirent->CdCaseFileName = Dirent->CdFileName;
//
// Otherwise perform our upcase operation. We already have guaranteed the buffers are
// there.
//
} else {
Dirent->CdCaseFileName.FileName.Buffer = Add2Ptr( Dirent->CdFileName.FileName.Buffer,
Dirent->CdFileName.FileName.MaximumLength / 2,
PWCHAR);
Dirent->CdCaseFileName.FileName.MaximumLength = Dirent->CdFileName.FileName.MaximumLength / 2;
CdUpcaseName( IrpContext,
&Dirent->CdFileName,
&Dirent->CdCaseFileName );
}
return;
}
BOOLEAN
CdFindFile (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb,
IN PCD_NAME Name,
IN BOOLEAN IgnoreCase,
IN OUT PFILE_ENUM_CONTEXT FileContext,
OUT PCD_NAME *MatchingName
)
/*++
Routine Description:
This routine is called to search a dirctory for a file matching the input
name. This name has been upcased at this point if this a case-insensitive
search. The name has been separated into separate name and version strings.
We look for an exact match in the name and only consider the version if
there is a version specified in the search name.
Arguments:
Fcb - Fcb for the directory being scanned.
Name - Name to search for.
IgnoreCase - Indicates the case of the search.
FileContext - File context to use for the search. This has already been
initialized.
MatchingName - Pointer to buffer containing matching name. We need this
in case we don't match the name in the directory but match the
short name instead.
Return Value:
BOOLEAN - TRUE if matching entry is found, FALSE otherwise.
--*/
{
PDIRENT Dirent;
ULONG ShortNameDirentOffset;
BOOLEAN Found = FALSE;
PAGED_CODE();
//
// Make sure there is a stream file for this Fcb.
//
CdVerifyOrCreateDirStreamFile( IrpContext, Fcb);
//
// Check to see whether we need to check for a possible short name.
//
ShortNameDirentOffset = CdShortNameDirentOffset( IrpContext, &Name->FileName );
//
// Position ourselves at the first entry.
//
CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, Fcb->StreamOffset );
//
// Loop while there are more entries in this directory.
//
do {
Dirent = &FileContext->InitialDirent->Dirent;
//
// We only consider files which don't have the associated bit set.
// We also only look for files. All directories would already
// have been found.
//
if (!FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_ASSOC | CD_ATTRIBUTE_DIRECTORY )) {
//
// Update the name in the current dirent.
//
CdUpdateDirentName( IrpContext, Dirent, IgnoreCase );
//
// Don't bother with constant entries.
//
if (FlagOn( Dirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY )) {
continue;
}
//
// Now check whether we have a name match.
// We exit the loop if we have a match.
//
if (CdIsNameInExpression( IrpContext,
&Dirent->CdCaseFileName,
Name,
0,
TRUE )) {
*MatchingName = &Dirent->CdCaseFileName;
Found = TRUE;
break;
}
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -