📄 dirsup.c
字号:
/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
DirSup.c
Abstract:
This module implements the dirent support routines for Cdfs.
Directories on a CD consist of a number of contiguous sectors on
the disk. File descriptors consist of one or more directory entries
(dirents) within a directory. Files may contain version numbers. If
present all like-named files will be ordered contiguously in the
directory by decreasing version numbers. We will only return the
first of these on a directory query unless the user explicitly
asks for version numbers. Finally dirents will not span sector
boundaries. Unused bytes at the end of a sector will be zero
filled.
Directory sector: Offset
2048
+---------------------------------------------------------------+
| | | | | | |
| foo;4 | foo;4 | foo;3 | hat | zebra | Zero|
| | | | | | Fill|
| | final | single | | | |
| | extent | extent | | | |
+---------------------------------------------------------------+
Dirent operations:
- Position scan at known offset in directory. Dirent at this
offset must exist and is valid. Used when scanning a directory
from the beginning when the self entry is known to be valid.
Used when positioning at the first dirent for an open
file to scan the allocation information. Used when resuming
a directory enumeration from a valid directory entry.
- Position scan at known offset in directory. Dirent is known to
start at this position but must be checked for validity.
Used to read the self-directory entry.
- Move to the next dirent within a directory.
- Given a known starting dirent, collect all the dirents for
that file. Scan will finish positioned at the last dirent
for the file. We will accumulate the extent lengths to
find the size of the file.
- Given a known starting dirent, position the scan for the first
dirent of the following file. Used when not interested in
all of the details for the current file and are looking for
the next file.
- Update a common dirent structure with the details of the on-disk
structure. This is used to smooth out the differences
- Build the filename (name and version strings) out of the stream
of bytes in the file name on disk. For Joliet disks we will have
to convert to little endian.
--*/
#include "CdProcs.h"
//
// The Bug check file id for this module
//
#define BugCheckFileId (CDFS_BUG_CHECK_DIRSUP)
//
// Local macros
//
//
// PRAW_DIRENT
// CdRawDirent (
// IN PIRP_CONTEXT IrpContext,
// IN PDIR_ENUM_CONTEXT DirContext
// );
//
#define CdRawDirent(IC,DC) \
Add2Ptr( (DC)->Sector, (DC)->SectorOffset, PRAW_DIRENT )
//
// Local support routines
//
ULONG
CdCheckRawDirentBounds (
IN PIRP_CONTEXT IrpContext,
IN PDIRENT_ENUM_CONTEXT DirContext
);
XA_EXTENT_TYPE
CdCheckForXAExtent (
IN PIRP_CONTEXT IrpContext,
IN PRAW_DIRENT RawDirent,
IN OUT PDIRENT Dirent
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, CdCheckForXAExtent)
#pragma alloc_text(PAGE, CdCheckRawDirentBounds)
#pragma alloc_text(PAGE, CdCleanupFileContext)
#pragma alloc_text(PAGE, CdFindFile)
#pragma alloc_text(PAGE, CdFindDirectory)
#pragma alloc_text(PAGE, CdFindFileByShortName)
#pragma alloc_text(PAGE, CdLookupDirent)
#pragma alloc_text(PAGE, CdLookupLastFileDirent)
#pragma alloc_text(PAGE, CdLookupNextDirent)
#pragma alloc_text(PAGE, CdLookupNextInitialFileDirent)
#pragma alloc_text(PAGE, CdUpdateDirentFromRawDirent)
#pragma alloc_text(PAGE, CdUpdateDirentName)
#endif
VOID
CdLookupDirent (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb,
IN ULONG DirentOffset,
OUT PDIRENT_ENUM_CONTEXT DirContext
)
/*++
Routine Description:
This routine is called to initiate a walk through a directory. We will
position ourselves in the directory at offset DirentOffset. We know that
a dirent begins at this boundary but may have to verify the dirent bounds.
We will call this routine when looking up the first entry of a known
file or verifying the self entry of a directory.
Arguments:
Fcb - Fcb for the directory being traversed.
DirentOffset - This is our target point in the directory. We will map the
page containing this entry and possibly verify the dirent bounds at
this location.
DirContext - This is the dirent context for this scan. We update it with
the location of the dirent we found. This structure has been initialized
outside of this call.
Return Value:
None.
--*/
{
LONGLONG BaseOffset;
PAGED_CODE();
//
// Initialize the offset of the first dirent we want to map.
//
DirContext->BaseOffset = SectorTruncate( DirentOffset );
BaseOffset = DirContext->BaseOffset;
DirContext->DataLength = SECTOR_SIZE;
DirContext->SectorOffset = SectorOffset( DirentOffset );
//
// Truncate the data length if we are at the end of the file.
//
if (DirContext->DataLength > (Fcb->FileSize.QuadPart - BaseOffset)) {
DirContext->DataLength = (ULONG) (Fcb->FileSize.QuadPart - BaseOffset);
}
//
// Now map the data at this offset.
//
CcMapData( Fcb->FileObject,
(PLARGE_INTEGER) &BaseOffset,
DirContext->DataLength,
TRUE,
&DirContext->Bcb,
&DirContext->Sector );
//
// Verify the dirent bounds.
//
DirContext->NextDirentOffset = CdCheckRawDirentBounds( IrpContext,
DirContext );
return;
}
BOOLEAN
CdLookupNextDirent (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb,
IN PDIRENT_ENUM_CONTEXT CurrentDirContext,
OUT PDIRENT_ENUM_CONTEXT NextDirContext
)
/*++
Routine Description:
This routine is called to find the next dirent in the directory. The
current position is given and we look for the next. We leave the context
for the starting position untouched and update the context for the
dirent we found. The target context may already be initialized so we
may already have the sector in memory.
This routine will position the enumeration context for the next dirent and
verify the dirent bounds.
NOTE - This routine can be called with CurrentDirContext and NextDirContext
pointing to the same enumeration context.
Arguments:
Fcb - Fcb for the directory being traversed.
CurrentDirContext - This is the dirent context for this scan. We update
it with the location of the dirent we found. This is currently
pointing to a dirent location. The dirent bounds at this location
have already been verified.
NextDirContext - This is the dirent context to update with the dirent we
find. This may already point to a dirent so we need to check if
we are in the same sector and unmap any buffer as necessary.
This dirent is left in an indeterminant state if we don't find a dirent.
Return Value:
BOOLEAN - TRUE if we find a location for the next dirent, FALSE otherwise.
This routine can cause a raise if the directory is corrupt.
--*/
{
LONGLONG CurrentBaseOffset = CurrentDirContext->BaseOffset;
ULONG TempUlong;
BOOLEAN FoundDirent = FALSE;
PAGED_CODE();
//
// Check if a different sector is mapped. If so then move our target
// enumeration context to the same sector.
//
if ((CurrentDirContext->BaseOffset != NextDirContext->BaseOffset) ||
(NextDirContext->Bcb == NULL)) {
//
// Unpin the current target Bcb and map the next sector.
//
CdUnpinData( IrpContext, &NextDirContext->Bcb );
CcMapData( Fcb->FileObject,
(PLARGE_INTEGER) &CurrentBaseOffset,
CurrentDirContext->DataLength,
TRUE,
&NextDirContext->Bcb,
&NextDirContext->Sector );
//
// Copy the data length and sector offset.
//
NextDirContext->DataLength = CurrentDirContext->DataLength;
NextDirContext->BaseOffset = CurrentDirContext->BaseOffset;
}
//
// Now move to the same offset in the sector.
//
NextDirContext->SectorOffset = CurrentDirContext->SectorOffset;
//
// If the value is zero then unmap the current sector and set up
// the base offset to the beginning of the next sector.
//
if (CurrentDirContext->NextDirentOffset == 0) {
CurrentBaseOffset = NextDirContext->BaseOffset + NextDirContext->DataLength;
//
// Unmap the current sector. We test the value of the Bcb in the
// loop below to see if we need to read in another sector.
//
CdUnpinData( IrpContext, &NextDirContext->Bcb );
//
// There is another possible dirent in the current sector. Update the
// enumeration context to reflect this.
//
} else {
NextDirContext->SectorOffset += CurrentDirContext->NextDirentOffset;
}
//
// Now loop until we find the next possible dirent or walk off the directory.
//
while (TRUE) {
//
// If we don't currently have a sector mapped then map the
// directory at the current offset.
//
if (NextDirContext->Bcb == NULL) {
TempUlong = SECTOR_SIZE;
if (TempUlong > (ULONG) (Fcb->FileSize.QuadPart - CurrentBaseOffset)) {
TempUlong = (ULONG) (Fcb->FileSize.QuadPart - CurrentBaseOffset);
//
// If the length is zero then there is no dirent.
//
if (TempUlong == 0) {
break;
}
}
CcMapData( Fcb->FileObject,
(PLARGE_INTEGER) &CurrentBaseOffset,
TempUlong,
TRUE,
&NextDirContext->Bcb,
&NextDirContext->Sector );
NextDirContext->BaseOffset = (ULONG) CurrentBaseOffset;
NextDirContext->SectorOffset = 0;
NextDirContext->DataLength = TempUlong;
}
//
// The CDFS spec allows for sectors in a directory to contain all zeroes.
// In this case we need to move to the next sector. So look at the
// current potential dirent for a zero length. Move to the next
// dirent if length is zero.
//
if (*((PCHAR) CdRawDirent( IrpContext, NextDirContext )) != 0) {
FoundDirent = TRUE;
break;
}
CurrentBaseOffset = NextDirContext->BaseOffset + NextDirContext->DataLength;
CdUnpinData( IrpContext, &NextDirContext->Bcb );
}
//
// Check the dirent bounds if we found a dirent.
//
if (FoundDirent) {
NextDirContext->NextDirentOffset = CdCheckRawDirentBounds( IrpContext,
NextDirContext );
}
return FoundDirent;
}
VOID
CdUpdateDirentFromRawDirent (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb,
IN PDIRENT_ENUM_CONTEXT DirContext,
IN OUT PDIRENT Dirent
)
/*++
Routine Description:
This routine is called to safely copy the data from the dirent on disk
to the in-memory dirent. The fields on disk are unaligned so we
need to safely copy them to our structure.
Arguments:
Fcb - Fcb for the directory being scanned.
DirContext - Enumeration context for the raw disk dirent.
Dirent - In-memory dirent to update.
Return Value:
None.
--*/
{
PRAW_DIRENT RawDirent = CdRawDirent( IrpContext, DirContext );
PAGED_CODE();
//
// Clear all of the current state flags except the flag indicating that
// we allocated a name string.
//
ClearFlag( Dirent->Flags, DIRENT_FLAG_NOT_PERSISTENT );
//
// The dirent offset is the sum of the start of the sector and the
// sector offset.
//
Dirent->DirentOffset = DirContext->BaseOffset + DirContext->SectorOffset;
//
// Copy the dirent length from the raw dirent.
//
Dirent->DirentLength = RawDirent->DirLen;
//
// The starting offset on disk is computed by finding the starting
// logical block and stepping over the Xar block.
//
CopyUchar4( &Dirent->StartingOffset, RawDirent->FileLoc );
Dirent->StartingOffset += RawDirent->XarLen;
//
// Do a safe copy to get the data length.
//
CopyUchar4( &Dirent->DataLength, RawDirent->DataLen );
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -