dirctrl.c
来自「windows 2000中的UDF文件系统的驱动程序.只有读的功能,不支持未关闭」· C语言 代码 · 共 1,926 行 · 第 1/4 页
C
1,926 行
// current one we're working on. If NextEntry is non-zero, then
// at least one entry was added.
//
while (TRUE) {
//
// If the user had requested only a single match and we have
// returned that, then we stop at this point. We update the Ccb with
// the status based on the last entry returned.
//
if ((NextEntry != 0) && ReturnSingleEntry) {
try_leave( Status );
}
//
// We try to locate the next matching dirent. Our search if based on a starting
// dirent offset, whether we should return the current or next entry, whether
// we should be doing a short name search and finally whether we should be
// checking for a version match.
//
Found = UdfEnumerateIndex( IrpContext, Ccb, &CompoundDirContext, ReturnNextEntry );
//
// Initialize the value for the next search.
//
ReturnNextEntry = TRUE;
//
// If we didn't receive a dirent, then we are at the end of the
// directory. If we have returned any files, we exit with
// success, otherwise we return STATUS_NO_MORE_FILES.
//
if (!Found) {
if (NextEntry == 0) {
Status = STATUS_NO_MORE_FILES;
if (InitialQuery) {
Status = STATUS_NO_SUCH_FILE;
}
}
try_leave( Status );
}
//
// Remember the dirent/file entry for the file we just found.
//
ThisFid = CompoundDirContext.DirContext.Fid;
//
// Here are the rules concerning filling up the buffer:
//
// 1. The Io system garentees that there will always be
// enough room for at least one base record.
//
// 2. If the full first record (including file name) cannot
// fit, as much of the name as possible is copied and
// STATUS_BUFFER_OVERFLOW is returned.
//
// 3. If a subsequent record cannot completely fit into the
// buffer, none of it (as in 0 bytes) is copied, and
// STATUS_SUCCESS is returned. A subsequent query will
// pick up with this record.
//
//
// We can look directly at the dirent that we found.
//
FileNameBytes = CompoundDirContext.DirContext.CaseObjectName.Length;
//
// If the slot for the next entry would be beyond the length of the
// user's buffer just exit (we know we've returned at least one entry
// already). This will happen when we align the pointer past the end.
//
if (NextEntry > IrpSp->Parameters.QueryDirectory.Length) {
ReturnNextEntry = FALSE;
try_leave( Status = STATUS_SUCCESS );
}
//
// Compute the number of bytes remaining in the buffer. Round this
// down to a WCHAR boundary so we can copy full characters.
//
BytesRemainingInBuffer = IrpSp->Parameters.QueryDirectory.Length - NextEntry;
ClearFlag( BytesRemainingInBuffer, 1 );
//
// If this won't fit and we have returned a previous entry then just
// return STATUS_SUCCESS.
//
if ((BaseLength + FileNameBytes) > BytesRemainingInBuffer) {
//
// If we already found an entry then just exit.
//
if (NextEntry != 0) {
ReturnNextEntry = FALSE;
try_leave( Status = STATUS_SUCCESS );
}
//
// Reduce the FileNameBytes to just fit in the buffer.
//
FileNameBytes = BytesRemainingInBuffer - BaseLength;
//
// Use a status code of STATUS_BUFFER_OVERFLOW. Also set
// ReturnSingleEntry so that we will exit the loop at the top.
//
Status = STATUS_BUFFER_OVERFLOW;
ReturnSingleEntry = TRUE;
}
//
// Protect access to the user buffer with an exception handler.
// Since (at our request) IO doesn't buffer these requests, we have
// to guard against a user messing with the page protection and other
// such trickery.
//
try {
//
// Zero and initialize the base part of the current entry.
//
RtlZeroMemory( Add2Ptr( UserBuffer, NextEntry, PVOID ),
BaseLength );
//
// Now we have an entry to return to our caller.
// We'll case on the type of information requested and fill up
// the user buffer if everything fits.
//
switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
case FileBothDirectoryInformation:
case FileFullDirectoryInformation:
case FileDirectoryInformation:
DirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_BOTH_DIR_INFORMATION );
//
// These information types require we look up the file entry.
//
UdfLookupFileEntryInEnumeration( IrpContext,
Fcb,
&CompoundDirContext );
//
// Directly reference the file entry we just looked up.
//
ThisFe = (PICBFILE) CompoundDirContext.IcbContext.Active.View;
//
// Now go gather all of the timestamps for this guy.
//
UdfUpdateTimestampsFromIcbContext ( IrpContext,
&CompoundDirContext.IcbContext,
&CompoundDirContext.Timestamps );
DirInfo->CreationTime = CompoundDirContext.Timestamps.CreationTime;
DirInfo->LastWriteTime =
DirInfo->ChangeTime = CompoundDirContext.Timestamps.ModificationTime;
DirInfo->LastAccessTime = CompoundDirContext.Timestamps.AccessTime;
//
// Set the attributes and sizes separately for directories and
// files.
//
if (ThisFe->Icbtag.FileType == ICBTAG_FILE_T_DIRECTORY) {
DirInfo->EndOfFile.QuadPart = DirInfo->AllocationSize.QuadPart = 0;
SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY );
} else {
DirInfo->EndOfFile.QuadPart = ThisFe->InfoLength;
DirInfo->AllocationSize.QuadPart = LlBlockAlign( Fcb->Vcb, ThisFe->InfoLength );
}
//
// All Cdrom files are readonly. We also copy the existence
// bit to the hidden attribute, assuming that synthesized FIDs
// are never hidden.
//
SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_READONLY );
if (ThisFid && FlagOn( ThisFid->Flags, NSR_FID_F_HIDDEN )) {
SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_HIDDEN );
}
//
// The file index for real file indices > 2^32 is zero. When asked to
// restart at an index of zero, we will know to use a stashed starting
// point to beging to search, by name, for the correct restart point.
//
if (CompoundDirContext.FileIndex.HighPart == 0) {
DirInfo->FileIndex = CompoundDirContext.FileIndex.LowPart;
} else {
DirInfo->FileIndex = 0;
}
DirInfo->FileNameLength = FileNameBytes;
break;
case FileNamesInformation:
NamesInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_NAMES_INFORMATION );
if (CompoundDirContext.FileIndex.HighPart == 0) {
NamesInfo->FileIndex = CompoundDirContext.FileIndex.LowPart;
} else {
NamesInfo->FileIndex = 0;
}
NamesInfo->FileNameLength = FileNameBytes;
break;
}
//
// Now copy as much of the name as possible.
//
if (FileNameBytes != 0) {
//
// This is a Unicode name, we can copy the bytes directly.
//
RtlCopyMemory( Add2Ptr( UserBuffer, NextEntry + BaseLength, PVOID ),
CompoundDirContext.DirContext.ObjectName.Buffer,
FileNameBytes );
}
//
// Fill in the short name if we got STATUS_SUCCESS. The short name
// may already be in the file context, otherwise we will check
// whether the long name is 8.3. Special case the self and parent
// directory names.
//
if ((Status == STATUS_SUCCESS) &&
(IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation) &&
FlagOn( CompoundDirContext.DirContext.Flags, DIR_CONTEXT_FLAG_SEEN_NONCONSTANT )) {
//
// If we already have the short name then copy into the user's buffer.
//
if (CompoundDirContext.DirContext.ShortObjectName.Length != 0) {
RtlCopyMemory( DirInfo->ShortName,
CompoundDirContext.DirContext.ShortObjectName.Buffer,
CompoundDirContext.DirContext.ShortObjectName.Length );
DirInfo->ShortNameLength = (CCHAR) CompoundDirContext.DirContext.ShortObjectName.Length;
//
// If the short name length is currently zero then check if
// the long name is not 8.3. We can copy the short name in
// unicode form directly into the caller's buffer.
//
} else {
if (!UdfIs8dot3Name( IrpContext,
CompoundDirContext.DirContext.ObjectName )) {
UNICODE_STRING ShortName;
ShortName.Buffer = DirInfo->ShortName;
ShortName.MaximumLength = BYTE_COUNT_8_DOT_3;
UdfGenerate8dot3Name( IrpContext,
&CompoundDirContext.DirContext.PureObjectName,
&ShortName );
DirInfo->ShortNameLength = (CCHAR) ShortName.Length;
}
}
}
//
// Update the information with the number of bytes stored in the
// buffer. We quad-align the existing buffer to add any necessary
// pad bytes.
//
Information = NextEntry + BaseLength + FileNameBytes;
//
// Go back to the previous entry and fill in the update to this entry.
//
*(Add2Ptr( UserBuffer, LastEntry, PULONG )) = NextEntry - LastEntry;
//
// Set up our variables for the next dirent.
//
InitialQuery = FALSE;
LastEntry = NextEntry;
NextEntry = QuadAlign( Information );
} except (!FsRtlIsNtstatusExpected(GetExceptionCode()) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
//
// We must have had a problem filling in the user's buffer, so stop
// and fail this request.
//
Information = 0;
try_leave( Status = GetExceptionCode());
}
}
} finally {
if (!AbnormalTermination() && !NT_ERROR( Status )) {
//
// Update the Ccb to show the current state of the enumeration.
//
UdfLockFcb( IrpContext, Fcb );
Ccb->CurrentFileIndex = CompoundDirContext.FileIndex.QuadPart;
//
// Update our notion of a high 32bit file index. We only do this once to avoid the hit
// of thrashing the Fcb mutex to do this for every entry. If it is ever neccesary to use
// this information, the difference of a few dozen entries from the optimal pick-up point
// will be trivial.
//
if (CompoundDirContext.FileIndex.HighPart == 0 &&
CompoundDirContext.FileIndex.LowPart > Ccb->HighestReturnableFileIndex) {
Ccb->HighestReturnableFileIndex = CompoundDirContext.FileIndex.LowPart;
}
ClearFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
if (ReturnNextEntry) {
SetFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
}
UdfUnlockFcb( IrpContext, Fcb );
}
//
// Cleanup our search context.
//
UdfCleanupCompoundDirContext( IrpContext, &CompoundDirContext );
//
// Release the Fcb.
//
UdfReleaseFile( IrpContext, Fcb );
}
//
// Complete the request here.
//
Irp->IoStatus.Information = Information;
UdfCompleteRequest( IrpContext, Irp, Status );
return Status;
}
//
// Local support routines
//
NTSTATUS
UdfNotifyChangeDirectory (
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp,
IN PCCB Ccb
)
/*++
Routine Description:
This routine performs the notify change directory operation. It is
responsible for either completing of enqueuing the input Irp. Although there
will never be a notify signalled on a readonly disk we still support this call.
We have already checked that this is not an OpenById handle.
Arguments:
Irp - Supplies the Irp to process
IrpSp - Io stack location for this request.
Ccb - Handle to the directory being watched.
Return Value:
NTSTATUS - STATUS_PENDING, any other error will raise.
--*/
{
PAGED_CODE();
//
// Always set the wait bit in the IrpContext so the initial wait can't fail.
//
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
//
// Acquire the Vcb shared.
//
UdfAcquireVcbShared( IrpContext, IrpContext->Vcb, FALSE );
//
// Use a try-finally to facilitate cleanup.
//
try {
//
// Verify the Vcb.
//
UdfVerifyVcb( IrpContext, IrpContext->Vcb );
//
// Call the Fsrtl package to process the request. We cast the
// unicode strings to ansi strings as the dir notify package
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?