NTSTATUS CdfsMakeFCBFromDirEntry(PVCB Vcb, PFCB DirectoryFCB, PWSTR LongName, PWSTR ShortName, PDIR_RECORD Record, ULONG DirectorySector, ULONG DirectoryOffset, PFCB * fileFCB) { WCHAR pathName[MAX_PATH]; PFCB rcFCB; ULONG Size; if (LongName [0] != 0 && wcslen (DirectoryFCB->PathName) + sizeof(WCHAR) + wcslen (LongName) > MAX_PATH) { return(STATUS_OBJECT_NAME_INVALID); } wcscpy(pathName, DirectoryFCB->PathName); if (!CdfsFCBIsRoot(DirectoryFCB)) { wcscat(pathName, L"\\"); } if (LongName[0] != 0) { wcscat(pathName, LongName); } else { WCHAR entryName[MAX_PATH]; CdfsGetDirEntryName(Vcb, Record, entryName); wcscat(pathName, entryName); } rcFCB = CdfsCreateFCB(pathName); memcpy(&rcFCB->Entry, Record, sizeof(DIR_RECORD)); /* Copy short name into FCB */ rcFCB->ShortNameU.Length = wcslen(ShortName) * sizeof(WCHAR); rcFCB->ShortNameU.MaximumLength = rcFCB->ShortNameU.Length; rcFCB->ShortNameU.Buffer = rcFCB->ShortNameBuffer; wcscpy(rcFCB->ShortNameBuffer, ShortName); Size = rcFCB->Entry.DataLengthL; rcFCB->RFCB.FileSize.QuadPart = Size; rcFCB->RFCB.ValidDataLength.QuadPart = Size; rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, BLOCKSIZE); if (CdfsFCBIsDirectory(rcFCB)) { CdfsFCBInitializeCache(Vcb, rcFCB); } rcFCB->IndexNumber.u.HighPart = DirectorySector; rcFCB->IndexNumber.u.LowPart = DirectoryOffset; rcFCB->RefCount++; CdfsAddFCBToTable(Vcb, rcFCB); *fileFCB = rcFCB; DPRINT("%S %d %I64d\n", LongName, Size, rcFCB->RFCB.AllocationSize.QuadPart); return(STATUS_SUCCESS); }
NTSTATUS CdfsDirFindFile(PDEVICE_EXTENSION DeviceExt, PFCB DirectoryFcb, PUNICODE_STRING FileToFind, PFCB *FoundFCB) { UNICODE_STRING TempName; WCHAR Name[256]; PVOID Block; ULONG DirSize; PDIR_RECORD Record; ULONG Offset; ULONG BlockOffset; NTSTATUS Status; LARGE_INTEGER StreamOffset, OffsetOfEntry; PVOID Context; WCHAR ShortNameBuffer[13]; UNICODE_STRING ShortName; UNICODE_STRING LongName; UNICODE_STRING FileToFindUpcase; ASSERT(DeviceExt); ASSERT(DirectoryFcb); ASSERT(FileToFind); DPRINT("CdfsDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n", DeviceExt, DirectoryFcb, FileToFind); DPRINT("Dir Path:%S\n", DirectoryFcb->PathName); /* default to '.' if no filename specified */ if (FileToFind->Length == 0) { RtlInitUnicodeString(&TempName, L"."); FileToFind = &TempName; } DirSize = DirectoryFcb->Entry.DataLengthL; StreamOffset.QuadPart = (LONGLONG)DirectoryFcb->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE; if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, TRUE, &Context, &Block)) { DPRINT("CcMapData() failed\n"); return STATUS_UNSUCCESSFUL; } Offset = 0; BlockOffset = 0; Record = (PDIR_RECORD)Block; /* Upper case the expression for FsRtlIsNameInExpression */ Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE); if (!NT_SUCCESS(Status)) { return Status; } while(TRUE) { if (Record->RecordLength == 0) { DPRINT("RecordLength == 0 Stopped!\n"); break; } DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n", Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength); CdfsGetDirEntryName(DeviceExt, Record, Name); DPRINT ("Name '%S'\n", Name); DPRINT ("Sector %lu\n", DirectoryFcb->Entry.ExtentLocationL); DPRINT ("Offset %lu\n", Offset); RtlInitUnicodeString(&LongName, Name); ShortName.Length = 0; ShortName.MaximumLength = 26; ShortName.Buffer = ShortNameBuffer; memset(ShortNameBuffer, 0, 26); OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset; CdfsShortNameCacheGet(DirectoryFcb, &OffsetOfEntry, &LongName, &ShortName); DPRINT("ShortName '%wZ'\n", &ShortName); if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) || FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL)) { DPRINT("Match found, %S\n", Name); Status = CdfsMakeFCBFromDirEntry(DeviceExt, DirectoryFcb, Name, ShortNameBuffer, Record, DirectoryFcb->Entry.ExtentLocationL, Offset, FoundFCB); RtlFreeUnicodeString(&FileToFindUpcase); CcUnpinData(Context); return(Status); } Offset += Record->RecordLength; BlockOffset += Record->RecordLength; Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset); if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0) { DPRINT("Map next sector\n"); CcUnpinData(Context); StreamOffset.QuadPart += BLOCKSIZE; Offset = ROUND_UP(Offset, BLOCKSIZE); BlockOffset = 0; if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, TRUE, &Context, &Block)) { DPRINT("CcMapData() failed\n"); RtlFreeUnicodeString(&FileToFindUpcase); return(STATUS_UNSUCCESSFUL); } Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset); } if (Offset >= DirSize) break; } RtlFreeUnicodeString(&FileToFindUpcase); CcUnpinData(Context); return(STATUS_OBJECT_NAME_NOT_FOUND); }
/* * FUNCTION: Retrieves the file name, be it in short or long file name format */ static NTSTATUS CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt, PVOID *Context, PVOID *Block, PLARGE_INTEGER StreamOffset, ULONG DirLength, PVOID *Ptr, PWSTR Name, PULONG pIndex, PULONG CurrentOffset) { PDIR_RECORD Record = *Ptr; ULONG Index; if (*CurrentOffset >= DirLength) return(STATUS_NO_MORE_ENTRIES); if (*CurrentOffset == 0) { Index = 0; Record = (PDIR_RECORD)*Block; while (Index < *pIndex) { (*Ptr) = (PVOID)((ULONG_PTR)(*Ptr) + Record->RecordLength); (*CurrentOffset) += Record->RecordLength; Record = *Ptr; if ((ULONG_PTR)(*Ptr) - (ULONG_PTR)(*Block) >= BLOCKSIZE || Record->RecordLength == 0) { DPRINT("Map next sector\n"); CcUnpinData(*Context); StreamOffset->QuadPart += BLOCKSIZE; *CurrentOffset = ROUND_UP(*CurrentOffset, BLOCKSIZE); if (!CcMapData(DeviceExt->StreamFileObject, StreamOffset, BLOCKSIZE, TRUE, Context, Block)) { DPRINT("CcMapData() failed\n"); return(STATUS_UNSUCCESSFUL); } *Ptr = *Block; Record = (PDIR_RECORD)*Ptr; } if (*CurrentOffset >= DirLength) return(STATUS_NO_MORE_ENTRIES); Index++; } } if ((ULONG_PTR)(*Ptr) - (ULONG_PTR)(*Block) >= BLOCKSIZE || Record->RecordLength == 0) { DPRINT("Map next sector\n"); CcUnpinData(*Context); StreamOffset->QuadPart += BLOCKSIZE; *CurrentOffset = ROUND_UP(*CurrentOffset, BLOCKSIZE); if (!CcMapData(DeviceExt->StreamFileObject, StreamOffset, BLOCKSIZE, TRUE, Context, Block)) { DPRINT("CcMapData() failed\n"); return(STATUS_UNSUCCESSFUL); } *Ptr = *Block; Record = (PDIR_RECORD)*Ptr; } if (*CurrentOffset >= DirLength) return STATUS_NO_MORE_ENTRIES; DPRINT("Index %lu RecordLength %lu Offset %lu\n", *pIndex, Record->RecordLength, *CurrentOffset); if (!CdfsIsRecordValid(DeviceExt, Record)) { CcUnpinData(*Context); return STATUS_DISK_CORRUPT_ERROR; } CdfsGetDirEntryName(DeviceExt, Record, Name); *Ptr = Record; return(STATUS_SUCCESS); }