ULONG UdfLookupMetaVsnOfExtent ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN USHORT Reference, IN ULONG Lbn, IN ULONG Len, IN BOOLEAN ExactEnd ) /*++ Routine Description: This routine maps the input logical block extent on a given partition to a starting virtual block in the metadata stream. If a mapping does not exist, one will be created and the metadata stream extended. Arguments: Vcb - Vcb of logical volume Reference - Partition reference to use in the mapping Lbn - Logical block number Len - Length of extent in bytes ExactEnd - Indicates the extension policy if these blocks are not mapped. Return Value: ULONG virtual sector number Raised status if the Lbn extent is split across multiple Vbn extents. --*/ { ULONG Vsn; ULONG Psn; ULONG SectorCount; BOOLEAN Result; BOOLEAN UnwindExtension = FALSE; LONGLONG UnwindAllocationSize; PFCB Fcb = NULL; // // Check inputs // ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_VCB( Vcb ); // // The extent must be an integral number of logical blocks in length. // if (Len == 0 || BlockOffset( Vcb, Len )) { UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); } // // Get the physical mapping of the extent. The Mcb package operates on ULONG/ULONG // keys and values so we must render our 48bit address into 32. We can do this since // this is a single surface implementation, and it is guaranteed that a surface cannot // contain more than MAXULONG physical sectors. // Psn = UdfLookupPsnOfExtent( IrpContext, Vcb, Reference, Lbn, Len ); // // Use try-finally for cleanup // try { // // We must safely establish a mapping and extend the metadata stream so that cached // reads can occur on this new extent. // Fcb = Vcb->MetadataFcb; UdfLockFcb( IrpContext, Fcb ); Result = UdfVmcbLbnToVbn( &Vcb->Vmcb, Psn, &Vsn, &SectorCount ); if (Result) { // // If the mapping covers the extent, we can give this back. // if (BlocksFromSectors( Vcb, SectorCount ) >= BlocksFromBytes( Vcb, Len )) { try_leave( NOTHING ); } // // It is a fatal error if the extent we are mapping is not wholly contained // by an extent of Vsns in the Vmcb. This will indicate that some structure // is trying to overlap another. // UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); } // // Add the new mapping. We know that it is being added to the end of the stream. // UdfAddVmcbMapping( &Vcb->Vmcb, Psn, SectorsFromBytes( Vcb, Len ), ExactEnd, &Vsn, &SectorCount ); UnwindAllocationSize = Fcb->AllocationSize.QuadPart; UnwindExtension = TRUE; Fcb->AllocationSize.QuadPart = Fcb->FileSize.QuadPart = Fcb->ValidDataLength.QuadPart = LlBytesFromSectors( Vcb, Vsn + SectorCount); CcSetFileSizes( Fcb->FileObject, (PCC_FILE_SIZES) &Fcb->AllocationSize ); UnwindExtension = FALSE; // // We do not need to purge the cache maps since the Vmcb will always be // page aligned, and thus any reads will have filled it with valid data. // } finally { if (UnwindExtension) { ULONG FirstZappedVsn; // // Strip off the additional mappings we made. // Fcb->AllocationSize.QuadPart = Fcb->FileSize.QuadPart = Fcb->ValidDataLength.QuadPart = UnwindAllocationSize; FirstZappedVsn = SectorsFromBytes( Vcb, UnwindAllocationSize ); UdfRemoveVmcbMapping( &Vcb->Vmcb, FirstZappedVsn, Vsn + SectorCount - FirstZappedVsn ); CcSetFileSizes( Fcb->FileObject, (PCC_FILE_SIZES) &Fcb->AllocationSize ); } if (Fcb) { UdfUnlockFcb( IrpContext, Fcb ); } } return Vsn; }
__drv_mustHoldCriticalRegion NTSTATUS CdQueryDirectory ( __inout PIRP_CONTEXT IrpContext, __inout PIRP Irp, __in PIO_STACK_LOCATION IrpSp, __in PFCB Fcb, __in PCCB Ccb ) /*++ Routine Description: This routine performs the query directory operation. It is responsible for either completing of enqueuing the input Irp. We store the state of the search in the Ccb. Arguments: Irp - Supplies the Irp to process IrpSp - Stack location for this Irp. Fcb - Fcb for this directory. Ccb - Ccb for this directory open. Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status = STATUS_SUCCESS; ULONG Information = 0; ULONG LastEntry = 0; ULONG NextEntry = 0; ULONG FileNameBytes; ULONG SeparatorBytes; ULONG VersionStringBytes; FILE_ENUM_CONTEXT FileContext; PDIRENT ThisDirent = NULL; BOOLEAN InitialQuery; BOOLEAN ReturnNextEntry = FALSE; BOOLEAN ReturnSingleEntry; BOOLEAN Found; BOOLEAN DoCcbUpdate = FALSE; PCHAR UserBuffer; ULONG BytesRemainingInBuffer; ULONG BaseLength; PFILE_BOTH_DIR_INFORMATION DirInfo = NULL; PFILE_NAMES_INFORMATION NamesInfo; PFILE_ID_FULL_DIR_INFORMATION IdFullDirInfo; PFILE_ID_BOTH_DIR_INFORMATION IdBothDirInfo; PAGED_CODE(); // // Check if we support this search mode. Also remember the size of the base part of // each of these structures. // switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) { case FileDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName[0] ); break; case FileFullDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileName[0] ); break; case FileIdFullDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION, FileName[0] ); break; case FileNamesInformation: BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION, FileName[0] ); break; case FileBothDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileName[0] ); break; case FileIdBothDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION, FileName[0] ); break; default: CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_INFO_CLASS ); return STATUS_INVALID_INFO_CLASS; } // // Get the user buffer. // CdMapUserBuffer( IrpContext, &UserBuffer); // // Initialize our search context. // CdInitializeFileContext( IrpContext, &FileContext ); // // Acquire the directory. // CdAcquireFileShared( IrpContext, Fcb ); // // Use a try-finally to facilitate cleanup. // try { // // Verify the Fcb is still good. // CdVerifyFcbOperation( IrpContext, Fcb ); // // Start by getting the initial state for the enumeration. This will set up the Ccb with // the initial search parameters and let us know the starting offset in the directory // to search. // CdInitializeEnumeration( IrpContext, IrpSp, Fcb, Ccb, &FileContext, &ReturnNextEntry, &ReturnSingleEntry, &InitialQuery ); // // The current dirent is stored in the InitialDirent field. We capture // this here so that we have a valid restart point even if we don't // find a single entry. // ThisDirent = &FileContext.InitialDirent->Dirent; // // At this point we are about to enter our query loop. We have // determined the index into the directory file to begin the // search. LastEntry and NextEntry are used to index into the user // buffer. LastEntry is the last entry we've added, NextEntry is // 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) { DoCcbUpdate = TRUE; 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 = CdEnumerateIndex( IrpContext, Ccb, &FileContext, 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; } } DoCcbUpdate = TRUE; try_leave( Status ); } // // Remember the dirent for the file we just found. // ThisDirent = &FileContext.InitialDirent->Dirent; // // 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. // // // Let's compute the number of bytes we need to transfer the current entry. // SeparatorBytes = VersionStringBytes = 0; // // We can look directly at the dirent that we found. // FileNameBytes = ThisDirent->CdFileName.FileName.Length; // // Compute the number of bytes for the version string if // we will return this. Allow directories with illegal ";". // if (((Ccb->SearchExpression.VersionString.Length != 0) || (FlagOn(ThisDirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY))) && (ThisDirent->CdFileName.VersionString.Length != 0)) { SeparatorBytes = 2; VersionStringBytes = ThisDirent->CdFileName.VersionString.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; DoCcbUpdate = TRUE; 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 + SeparatorBytes + VersionStringBytes) > BytesRemainingInBuffer) { // // If we already found an entry then just exit. // if (NextEntry != 0) { ReturnNextEntry = FALSE; DoCcbUpdate = TRUE; try_leave( Status = STATUS_SUCCESS ); } // // Don't even try to return the version string if it doesn't all fit. // Reduce the FileNameBytes to just fit in the buffer. // if ((BaseLength + FileNameBytes) > BytesRemainingInBuffer) { FileNameBytes = BytesRemainingInBuffer - BaseLength; } // // Don't return any version string bytes. // VersionStringBytes = SeparatorBytes = 0; // // 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 FileIdBothDirectoryInformation: case FileIdFullDirectoryInformation: case FileDirectoryInformation: DirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_BOTH_DIR_INFORMATION ); // // Use the create time for all the time stamps. // CdConvertCdTimeToNtTime( IrpContext, FileContext.InitialDirent->Dirent.CdTime, &DirInfo->CreationTime ); DirInfo->LastWriteTime = DirInfo->ChangeTime = DirInfo->CreationTime; // // Set the attributes and sizes separately for directories and // files. // if (FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) { DirInfo->EndOfFile.QuadPart = DirInfo->AllocationSize.QuadPart = 0; SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY); } else { DirInfo->EndOfFile.QuadPart = FileContext.FileSize; DirInfo->AllocationSize.QuadPart = LlSectorAlign( FileContext.FileSize ); SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_READONLY); } if (FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_HIDDEN )) { SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_HIDDEN ); } DirInfo->FileIndex = ThisDirent->DirentOffset; DirInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes; break; case FileNamesInformation: NamesInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_NAMES_INFORMATION ); NamesInfo->FileIndex = ThisDirent->DirentOffset; NamesInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes; break; } // // Fill in the FileId // switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) { case FileIdBothDirectoryInformation: IdBothDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_BOTH_DIR_INFORMATION ); CdSetFidFromParentAndDirent( IdBothDirInfo->FileId, Fcb, ThisDirent ); break; case FileIdFullDirectoryInformation: IdFullDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_FULL_DIR_INFORMATION ); CdSetFidFromParentAndDirent( IdFullDirInfo->FileId, Fcb, ThisDirent ); break; default: break; } // // Now copy as much of the name as possible. We also may have a version // string to copy. // if (FileNameBytes != 0) { // // This is a Unicode name, we can copy the bytes directly. // RtlCopyMemory( Add2Ptr( UserBuffer, NextEntry + BaseLength, PVOID ), ThisDirent->CdFileName.FileName.Buffer, FileNameBytes ); if (SeparatorBytes != 0) { *(Add2Ptr( UserBuffer, NextEntry + BaseLength + FileNameBytes, PWCHAR )) = L';'; if (VersionStringBytes != 0) { RtlCopyMemory( Add2Ptr( UserBuffer, NextEntry + BaseLength + FileNameBytes + sizeof( WCHAR ), PVOID ), ThisDirent->CdFileName.VersionString.Buffer, VersionStringBytes ); } } } // // 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 || IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation) && (Ccb->SearchExpression.VersionString.Length == 0) && !FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY )) { // // If we already have the short name then copy into the user's buffer. // if (FileContext.ShortName.FileName.Length != 0) { RtlCopyMemory( DirInfo->ShortName, FileContext.ShortName.FileName.Buffer, FileContext.ShortName.FileName.Length ); DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.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 (!CdIs8dot3Name( IrpContext, ThisDirent->CdFileName.FileName )) { CdGenerate8dot3Name( IrpContext, &ThisDirent->CdCaseFileName.FileName, ThisDirent->DirentOffset, DirInfo->ShortName, &FileContext.ShortName.FileName.Length ); DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.Length; } } } // // Sum the total number of bytes for the information field. // FileNameBytes += SeparatorBytes + VersionStringBytes; // // 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 (EXCEPTION_EXECUTE_HANDLER) { // // We had a problem filling in the user's buffer, so stop and // fail this request. This is the only reason any exception // would have occured at this level. // Information = 0; try_leave( Status = GetExceptionCode()); } } DoCcbUpdate = TRUE; } finally { // // Cleanup our search context - *before* aquiring the FCB mutex exclusive, // else can block on threads in cdcreateinternalstream/purge which // hold the FCB but are waiting for all maps in this stream to be released. // CdCleanupFileContext( IrpContext, &FileContext ); // // Now we can safely aqure the FCB mutex if we need to. // if (DoCcbUpdate && !NT_ERROR( Status )) { // // Update the Ccb to show the current state of the enumeration. // CdLockFcb( IrpContext, Fcb ); Ccb->CurrentDirentOffset = ThisDirent->DirentOffset; ClearFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT ); if (ReturnNextEntry) { SetFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT ); } CdUnlockFcb( IrpContext, Fcb ); } // // Release the Fcb. // CdReleaseFile( IrpContext, Fcb ); } // // Complete the request here. // Irp->IoStatus.Information = Information; CdCompleteRequest( IrpContext, Irp, Status ); return Status; }
BOOLEAN UdfFastUnlockAllByKey ( IN PFILE_OBJECT FileObject, PVOID ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This is a call back routine for doing the fast unlock all by key call. Arguments: FileObject - Supplies the file object used in this operation ProcessId - Supplies the process ID used in this operation Key - Supplies the key used in this operation Status - Receives the Status if this operation is successful Return Value: BOOLEAN - TRUE if this operation completed and FALSE if caller needs to take the long route. --*/ { BOOLEAN Results = FALSE; TYPE_OF_OPEN TypeOfOpen; PFCB Fcb; PAGED_CODE(); IoStatus->Information = 0; // // Decode the type of file object we're being asked to process and // make sure that is is only a user file open. // TypeOfOpen = UdfFastDecodeFileObject( FileObject, &Fcb ); if (TypeOfOpen != UserFileOpen) { IoStatus->Status = STATUS_INVALID_PARAMETER; return TRUE; } // // Only deal with 'good' Fcb's. // if (!UdfVerifyFcbOperation( NULL, Fcb )) { return FALSE; } // // If there is no lock then return immediately. // if (Fcb->FileLock == NULL) { IoStatus->Status = STATUS_RANGE_NOT_LOCKED; return TRUE; } FsRtlEnterFileSystem(); try { // // We check whether we can proceed based on the state of the file oplocks. // if ((Fcb->Oplock != NULL) && !FsRtlOplockIsFastIoPossible( &Fcb->Oplock )) { try_leave( NOTHING ); } // // If we don't have a file lock, then get one now. // if ((Fcb->FileLock == NULL) && !UdfCreateFileLock( NULL, Fcb, FALSE )) { try_leave( NOTHING ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request. The call will always succeed. // Results = TRUE; IoStatus->Status = FsRtlFastUnlockAllByKey( Fcb->FileLock, FileObject, ProcessId, Key, NULL ); // // Set the flag indicating if Fast I/O is possible // UdfLockFcb( IrpContext, Fcb ); Fcb->IsFastIoPossible = UdfIsFastIoPossible( Fcb ); UdfUnlockFcb( IrpContext, Fcb ); } finally { FsRtlExitFileSystem(); } return Results; }
BOOLEAN UdfFastLock ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key, BOOLEAN FailImmediately, BOOLEAN ExclusiveLock, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This is a call back routine for doing the fast lock call. Arguments: FileObject - Supplies the file object used in this operation FileOffset - Supplies the file offset used in this operation Length - Supplies the length used in this operation ProcessId - Supplies the process ID used in this operation Key - Supplies the key used in this operation FailImmediately - Indicates if the request should fail immediately if the lock cannot be granted. ExclusiveLock - Indicates if this is a request for an exclusive or shared lock IoStatus - Receives the Status if this operation is successful Return Value: BOOLEAN - TRUE if this operation completed and FALSE if caller needs to take the long route. --*/ { BOOLEAN Results = FALSE; PFCB Fcb; TYPE_OF_OPEN TypeOfOpen; PAGED_CODE(); ASSERT_FILE_OBJECT( FileObject ); IoStatus->Information = 0; // // Decode the type of file object we're being asked to process and // make sure that is is only a user file open. // TypeOfOpen = UdfFastDecodeFileObject( FileObject, &Fcb ); if (TypeOfOpen != UserFileOpen) { IoStatus->Status = STATUS_INVALID_PARAMETER; return TRUE; } // // Only deal with 'good' Fcb's. // if (!UdfVerifyFcbOperation( NULL, Fcb )) { return FALSE; } FsRtlEnterFileSystem(); // // Use a try-finally to facilitate cleanup. // try { // // We check whether we can proceed based on the state of the file oplocks. // if ((Fcb->Oplock != NULL) && !FsRtlOplockIsFastIoPossible( &Fcb->Oplock )) { try_leave( NOTHING ); } // // If we don't have a file lock, then get one now. // if ((Fcb->FileLock == NULL) && !UdfCreateFileLock( NULL, Fcb, FALSE )) { try_leave( NOTHING ); } // // Now call the FsRtl routine to perform the lock request. // if (Results = FsRtlFastLock( Fcb->FileLock, FileObject, FileOffset, Length, ProcessId, Key, FailImmediately, ExclusiveLock, IoStatus, NULL, FALSE )) { // // Set the flag indicating if Fast I/O is questionable. We // only change this flag if the current state is possible. // Retest again after synchronizing on the header. // if (Fcb->IsFastIoPossible == FastIoIsPossible) { UdfLockFcb( NULL, Fcb ); Fcb->IsFastIoPossible = UdfIsFastIoPossible( Fcb ); UdfUnlockFcb( NULL, Fcb ); } } } finally { FsRtlExitFileSystem(); } return Results; }
NTSTATUS UdfCommonSetInfo ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for set file information called by both the fsd and fsp threads. We only support operations which set the file position. Arguments: Irp - Supplies the Irp to process. Return Value: NTSTATUS - The return status for this operation. --*/ { NTSTATUS Status = STATUS_INVALID_PARAMETER; TYPE_OF_OPEN TypeOfOpen; PFCB Fcb; PCCB Ccb; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); PFILE_POSITION_INFORMATION Buffer; PAGED_CODE(); // // Decode the file object // TypeOfOpen = UdfDecodeFileObject( IrpSp->FileObject, &Fcb, &Ccb ); // // We only support a SetPositionInformation on a user file. // if ((TypeOfOpen != UserFileOpen) || (IrpSp->Parameters.QueryFile.FileInformationClass != FilePositionInformation)) { UdfCompleteRequest( IrpContext, Irp, Status ); return Status; } // // Acquire shared access to this file. // UdfAcquireFileShared( IrpContext, Fcb ); try { // // Make sure the Fcb is in a usable condition. This // will raise an error condition if the fcb is unusable // UdfVerifyFcbOperation( IrpContext, Fcb ); Buffer = Irp->AssociatedIrp.SystemBuffer; // // Check if the file does not use intermediate buffering. If it // does not use intermediate buffering then the new position we're // supplied must be aligned properly for the device // if (FlagOn( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) && ((Buffer->CurrentByteOffset.LowPart & IrpSp->DeviceObject->AlignmentRequirement) != 0)) { try_leave( NOTHING ); } // // The input parameter is fine so set the current byte offset and // complete the request // // // Lock the Fcb to provide synchronization. // UdfLockFcb( IrpContext, Fcb ); IrpSp->FileObject->CurrentByteOffset = Buffer->CurrentByteOffset; UdfUnlockFcb( IrpContext, Fcb ); Status = STATUS_SUCCESS; } finally { UdfReleaseFile( IrpContext, Fcb ); } // // Complete the request if there was no raise. // UdfCompleteRequest( IrpContext, Irp, Status ); return Status; }
NTSTATUS UdfQueryAlternateNameInfo ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PCCB Ccb, IN OUT PFILE_NAME_INFORMATION Buffer, IN OUT PULONG Length ) /*++ Routine Description: This routine performs the query alternate name information function. We lookup the dirent for this file and then check if there is a short name. Arguments: Fcb - Supplies the Fcb being queried, it has been verified. Ccb - Ccb for this open handle. Buffer - Supplies a pointer to the buffer where the information is to be returned. Length - Supplies the length of the buffer in bytes, and receives the remaining bytes free in the buffer upon return. Return Value: NTSTATUS - STATUS_SUCCESS if the whole name would fit into the user buffer, STATUS_OBJECT_NAME_NOT_FOUND if we can't return the name, STATUS_BUFFER_OVERFLOW otherwise. --*/ { NTSTATUS Status = STATUS_SUCCESS; DIR_ENUM_CONTEXT DirContext; PLCB Lcb; PFCB ParentFcb; BOOLEAN ReleaseParentFcb = FALSE; BOOLEAN CleanupDirContext = FALSE; BOOLEAN Result; PUNICODE_STRING ShortName; UNICODE_STRING LocalShortName; WCHAR LocalShortNameBuffer[ BYTE_COUNT_8_DOT_3 / sizeof(WCHAR) ]; PAGED_CODE(); // // Initialize the buffer length to zero. // Buffer->FileNameLength = 0; // // If there was no associated Lcb then there is no short name. // Lcb = Ccb->Lcb; if (Lcb == NULL) { return STATUS_OBJECT_NAME_NOT_FOUND; } // // Use a try-finally to cleanup the structures. // try { if (FlagOn( Lcb->Flags, LCB_FLAG_SHORT_NAME )) { // // This caller opened the file by a generated short name, so simply hand it back. // ShortName = &Lcb->FileName; } else { // // The open occured by a regular name. Now, if this name is already 8.3 legal then // there is no short name. // if (UdfIs8dot3Name( IrpContext, Lcb->FileName )) { try_leave( Status = STATUS_OBJECT_NAME_NOT_FOUND ); } // // This name has a generated short name. In order to calculate this name we have to // retrieve the FID for this file, since UDF specifies that a short name is uniquified // with a CRC of the original in-FID byte representation of the filename. // // N.B.: if this is a common operation, we may wish to cache the CRC in the Lcb. // ParentFcb = Lcb->ParentFcb; UdfAcquireFileShared( IrpContext, ParentFcb ); ReleaseParentFcb = TRUE; // // Now go find the FID for this filename in the parent. // UdfInitializeDirContext( IrpContext, &DirContext ); CleanupDirContext = TRUE; Result = UdfFindDirEntry( IrpContext, ParentFcb, &Lcb->FileName, BooleanFlagOn( Lcb->Flags, LCB_FLAG_IGNORE_CASE ), FALSE, &DirContext ); // // We should always be able to find this entry, but don't bugcheck because // we screwed this up. // ASSERT( Result ); if (!Result) { try_leave( Status = STATUS_OBJECT_NAME_NOT_FOUND ); } // // Build the local unicode string to use and fill it in. // ShortName = &LocalShortName; LocalShortName.Buffer = LocalShortNameBuffer; LocalShortName.Length = 0; LocalShortName.MaximumLength = sizeof( LocalShortNameBuffer ); UdfGenerate8dot3Name( IrpContext, &DirContext.CaseObjectName, ShortName ); } // // We now have the short name. We have left it in Unicode form so copy it directly. // Buffer->FileNameLength = ShortName->Length; if (Buffer->FileNameLength + sizeof( ULONG ) > *Length) { Buffer->FileNameLength = *Length - sizeof( ULONG ); Status = STATUS_BUFFER_OVERFLOW; } RtlCopyMemory( Buffer->FileName, ShortName->Buffer, Buffer->FileNameLength ); } finally { if (CleanupDirContext) { UdfCleanupDirContext( IrpContext, &DirContext ); } if (ReleaseParentFcb) { UdfReleaseFile( IrpContext, ParentFcb ); } } // // Reduce the available bytes by the amount stored into this buffer. // if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { *Length -= sizeof( ULONG ) + Buffer->FileNameLength; } return Status; }