Esempio n. 1
0
BOOLEAN SpyIsWatchedPath(_In_ PUNICODE_STRING path) 
{
	BOOLEAN result = FALSE;
	if (!InterlockedExchange(&MiniFSWatcherData.WatchPathInUse, TRUE)) 
	{
		result = FsRtlIsNameInExpression(&MiniFSWatcherData.WatchPath, path, TRUE, NULL);
		MiniFSWatcherData.WatchPathInUse = FALSE;
	}
	return result;
}
Esempio n. 2
0
// Checks if the export is listed as a hook target, and if so install a hook.
_Use_decl_annotations_ EXTERN_C static bool DdimonpEnumExportedSymbolsCallback(
    ULONG index, ULONG_PTR base_address, PIMAGE_EXPORT_DIRECTORY directory,
    ULONG_PTR directory_base, ULONG_PTR directory_end, void* context) {
  PAGED_CODE();

  if (!context) {
    return false;
  }

  auto functions =
      reinterpret_cast<ULONG*>(base_address + directory->AddressOfFunctions);
  auto ordinals = reinterpret_cast<USHORT*>(base_address +
                                            directory->AddressOfNameOrdinals);
  auto names =
      reinterpret_cast<ULONG*>(base_address + directory->AddressOfNames);

  auto ord = ordinals[index];
  auto export_address = base_address + functions[ord];
  auto export_name = reinterpret_cast<const char*>(base_address + names[index]);

  // Check if an export is forwared one? If so, ignore it.
  if (UtilIsInBounds(export_address, directory_base, directory_end)) {
    return true;
  }

  // convert the name to UNICODE_STRING
  wchar_t name[100];
  auto status =
      RtlStringCchPrintfW(name, RTL_NUMBER_OF(name), L"%S", export_name);
  if (!NT_SUCCESS(status)) {
    return true;
  }
  UNICODE_STRING name_u = {};
  RtlInitUnicodeString(&name_u, name);

  for (auto& target : g_ddimonp_hook_targets) {
    // Is this export listed as a target
    if (!FsRtlIsNameInExpression(&target.target_name, &name_u, TRUE, nullptr)) {
      continue;
    }

    // Yes, install a hook to the export
    if (!ShInstallHook(reinterpret_cast<SharedShadowHookData*>(context),
                       reinterpret_cast<void*>(export_address), &target)) {
      // This is an error which should not happen
      DdimonpFreeAllocatedTrampolineRegions();
      return false;
    }
    HYPERPLATFORM_LOG_INFO("Hook has been installed at %p %s.", export_address,
                           export_name);
  }
  return true;
}
Esempio n. 3
0
EXTERN_C static bool ScvnpIsWhiteListedFile(
    _In_ PUNICODE_STRING TargetFileName) {
  PAGED_CODE();

  UNICODE_STRING WHITE_LIST[] = {
      RTL_CONSTANT_STRING(
          L"\\DEVICE\\HARDDISKVOLUME?\\*"
          L"\\APPDATA\\LOCAL\\MICROSOFT\\WINDOWS\\EXPLORER\\THUMBCACHE_*.DB"),
  };

  for (auto i = 0; i < RTL_NUMBER_OF(WHITE_LIST); ++i) {
    if (FsRtlIsNameInExpression(&WHITE_LIST[i], TargetFileName, TRUE,
                                nullptr)) {
      return true;
    }
  }
  return false;
}
Esempio n. 4
0
File: mft.c Progetto: RPG-7/reactos
BOOLEAN
CompareFileName(PUNICODE_STRING FileName,
                PINDEX_ENTRY_ATTRIBUTE IndexEntry,
                BOOLEAN DirSearch)
{
    BOOLEAN Ret, Alloc = FALSE;
    UNICODE_STRING EntryName;

    EntryName.Buffer = IndexEntry->FileName.Name;
    EntryName.Length = 
    EntryName.MaximumLength = IndexEntry->FileName.NameLength * sizeof(WCHAR);

    if (DirSearch)
    {
        UNICODE_STRING IntFileName;
        if (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX)
        {
            NT_VERIFY(NT_SUCCESS(RtlUpcaseUnicodeString(&IntFileName, FileName, TRUE)));
            Alloc = TRUE;
        }
        else
        {
            IntFileName = *FileName;
        }

        Ret = FsRtlIsNameInExpression(&IntFileName, &EntryName, (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX), NULL);

        if (Alloc)
        {
            RtlFreeUnicodeString(&IntFileName);
        }

        return Ret;
    }
    else
    {
        return (RtlCompareUnicodeString(FileName, &EntryName, (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX)) == 0);
    }
}
Esempio n. 5
0
static VOID FsRtlIsNameInExpressionTest()
{
    ULONG i;
    for (i = 0; i < sizeof(Tests) / sizeof(Tests[0]); i++)
    {
        BOOLEAN TestResult;
        UNICODE_STRING Expression;
        UNICODE_STRING Name;

        /* Don't run Tests which are known to assert in checked builds */
        if (KmtIsCheckedBuild && Tests[i].AssertsInChecked)
            continue;

        RtlInitUnicodeString(&Expression, Tests[i].Expression);
        RtlInitUnicodeString(&Name, Tests[i].Name);

        TestResult = FsRtlIsNameInExpression(&Expression, &Name, Tests[i].IgnoreCase, NULL);

        ok(TestResult == Tests[i].Expected, "FsRtlIsNameInExpression(%wZ,%wZ,%s,NULL): Expected %s, got %s\n",
           &Expression, &Name, Tests[i].IgnoreCase ? "TRUE" : "FALSE", Tests[i].Expected ? "TRUE" : "FALSE", TestResult ? "TRUE" : "FALSE");
    }

    /* TODO: test UpcaseTable */
}
Esempio n. 6
0
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);
}
NTSTATUS DoMatchExpression(PUNICODE_STRING Path)
{
	// 是否需要在这里判断是否在重定向根目录内

	// 这里要先判断链表是否为空
	if (IsListEmpty(&MatchExpressionList.HeadList))
		return STATUS_NOT_FOUND;

	UNICODE_STRING tmpPath;
	RtlZeroMemory(&tmpPath, sizeof(UNICODE_STRING));
	tmpPath.MaximumLength = sizeof(WCHAR) * 260;
	tmpPath.Buffer = (PWSTR)ExAllocatePool(NonPagedPool, tmpPath.MaximumLength);
	if (tmpPath.Buffer == NULL)
		return STATUS_NOT_FOUND;

	RtlCopyUnicodeString(&tmpPath, Path);

	KIRQL irql;
	KeAcquireSpinLock(&MatchExpressionList.Lock, &irql);

	// 链表头
	PLIST_ENTRY pList = MatchExpressionList.HeadList.Flink;

	BOOLEAN isMatched = FALSE;
	while (pList != &MatchExpressionList.HeadList)
	{
		PMATCH_EXPRESSION element = CONTAINING_RECORD(pList, MATCH_EXPRESSION, ListEntry);

		// 注意,这里这样申请内存其实还挺频繁的
		// 如果这里还是有问题,可能就要用Looksaide结构来处理内存问题了
		UNICODE_STRING Expression;
		RtlZeroMemory(&Expression, sizeof(UNICODE_STRING));
		Expression.MaximumLength = sizeof(WCHAR) * 260;
		Expression.Buffer = (PWSTR)ExAllocatePool(NonPagedPool, Expression.MaximumLength);
		if (Expression.Buffer == NULL)
		{
			KdPrint(("[ISISandBox] DoMatchExpression -> Alloc pool for Expression string buffer failed.\n"));
			pList = pList->Flink;
			continue;
		}

		RtlUnicodeStringCbCopyStringN(&Expression, element->Expression, sizeof(WCHAR) * 260);
		Expression.Length = (USHORT)element->Length;
		
		KdPrint(("[ISISandBox] Current expression : %wZ %u\n", &Expression, Expression.Length));
		KdPrint(("[ISISandBox] Current path : %wZ\n", &tmpPath));
		
		// 注意:这里经常触发蓝屏,最近一次是因为 DRIVER_CORRUPTED_EXPOOL (C5)
		// 说明此处对内存的读写性要求比较高,应该使用灵活度更高的内存空间
		// 所以这两个字符串所在内存都是在此函数中动态申请的非分页内存,应该能解决问题
		BOOLEAN ret = FsRtlIsNameInExpression(&Expression, &tmpPath, TRUE, NULL);

		ExFreePool(Expression.Buffer);

		if (ret)
		{
			KdPrint(("[ISISandBox] Match Expression OK : %wZ.\n", &tmpPath));
			isMatched = TRUE;
			break;
		}

		pList = pList->Flink;
	}

	KeReleaseSpinLock(&MatchExpressionList.Lock, irql);

	ExFreePool(tmpPath.Buffer);

	if (isMatched)
		return STATUS_SUCCESS;
	else
	{
		//KdPrint(("[ISISandBox] CheckMatchExpression Cannot find Expression : %wZ.\n", Expression));
		return STATUS_NOT_FOUND;
	}
}
Esempio n. 8
0
__drv_mustHoldCriticalRegion
NTSTATUS
FFSQueryDirectory(
	IN PFFS_IRP_CONTEXT IrpContext)
{
	PDEVICE_OBJECT          DeviceObject;
	NTSTATUS                Status = STATUS_UNSUCCESSFUL;
	PFFS_VCB                Vcb = 0;
	PFILE_OBJECT            FileObject;
	PFFS_FCB                Fcb = 0;
	PFFS_CCB                Ccb;
	PIRP                    Irp;
	PIO_STACK_LOCATION      IoStackLocation;
	FILE_INFORMATION_CLASS  FileInformationClass;
	ULONG                   Length;
	PUNICODE_STRING         FileName;
	ULONG                   FileIndex;
	BOOLEAN                 RestartScan;
	BOOLEAN                 ReturnSingleEntry;
	BOOLEAN                 IndexSpecified;
	PUCHAR                  Buffer;
	BOOLEAN                 FirstQuery;
	PFFSv1_INODE            dinode1 = NULL;
	PFFSv2_INODE            dinode2 = NULL;
	BOOLEAN                 FcbResourceAcquired = FALSE;
	ULONG                   UsedLength = 0;
	USHORT                  InodeFileNameLength;
	UNICODE_STRING          InodeFileName;
	PFFS_DIR_ENTRY          pDir = NULL;
	ULONG                   dwBytes;
	ULONG                   dwTemp = 0;
	ULONG                   dwSize = 0;
	ULONG                   dwReturn = 0;
	BOOLEAN                 bRun = TRUE;
	ULONG                   ByteOffset;

    PAGED_CODE();

	InodeFileName.Buffer = NULL;

	_SEH2_TRY
	{
		ASSERT(IrpContext);

		ASSERT((IrpContext->Identifier.Type == FFSICX) &&
				(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));

		DeviceObject = IrpContext->DeviceObject;

		//
		// This request is not allowed on the main device object
		//
		if (DeviceObject == FFSGlobal->DeviceObject)
		{
			Status = STATUS_INVALID_DEVICE_REQUEST;
			_SEH2_LEAVE;
		}

		Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;

		ASSERT(Vcb != NULL);

		ASSERT((Vcb->Identifier.Type == FFSVCB) &&
				(Vcb->Identifier.Size == sizeof(FFS_VCB)));

		ASSERT(IsMounted(Vcb));

		FileObject = IrpContext->FileObject;

		Fcb = (PFFS_FCB)FileObject->FsContext;

		ASSERT(Fcb);

		//
		// This request is not allowed on volumes
		//
		if (Fcb->Identifier.Type == FFSVCB)
		{
			Status = STATUS_INVALID_PARAMETER;
			_SEH2_LEAVE;
		}

		ASSERT((Fcb->Identifier.Type == FFSFCB) &&
				(Fcb->Identifier.Size == sizeof(FFS_FCB)));

		if (!IsDirectory(Fcb))
		{
			Status = STATUS_INVALID_PARAMETER;
			_SEH2_LEAVE;
		}

		Ccb = (PFFS_CCB)FileObject->FsContext2;

		ASSERT(Ccb);

		ASSERT((Ccb->Identifier.Type == FFSCCB) &&
				(Ccb->Identifier.Size == sizeof(FFS_CCB)));

		Irp = IrpContext->Irp;

		IoStackLocation = IoGetCurrentIrpStackLocation(Irp);

#if !defined(_GNU_NTIFS_) || defined(__REACTOS__)

		FileInformationClass =
			IoStackLocation->Parameters.QueryDirectory.FileInformationClass;

		Length = IoStackLocation->Parameters.QueryDirectory.Length;

		FileName = IoStackLocation->Parameters.QueryDirectory.FileName;

		FileIndex = IoStackLocation->Parameters.QueryDirectory.FileIndex;

#else // _GNU_NTIFS_

		FileInformationClass = ((PEXTENDED_IO_STACK_LOCATION)
				IoStackLocation)->Parameters.QueryDirectory.FileInformationClass;

		Length = ((PEXTENDED_IO_STACK_LOCATION)
				IoStackLocation)->Parameters.QueryDirectory.Length;

		FileName = ((PEXTENDED_IO_STACK_LOCATION)
				IoStackLocation)->Parameters.QueryDirectory.FileName;

		FileIndex = ((PEXTENDED_IO_STACK_LOCATION)
				IoStackLocation)->Parameters.QueryDirectory.FileIndex;

#endif // _GNU_NTIFS_

		RestartScan = FlagOn(IoStackLocation->Flags, SL_RESTART_SCAN);
		ReturnSingleEntry = FlagOn(IoStackLocation->Flags, SL_RETURN_SINGLE_ENTRY);
		IndexSpecified = FlagOn(IoStackLocation->Flags, SL_INDEX_SPECIFIED);
		/*
		if (!Irp->MdlAddress && Irp->UserBuffer)
		{
			ProbeForWrite(Irp->UserBuffer, Length, 1);
		}
		*/
		Buffer = FFSGetUserBuffer(Irp);

		if (Buffer == NULL)
		{
			FFSBreakPoint();
			Status = STATUS_INVALID_USER_BUFFER;
			_SEH2_LEAVE;
		}

		if (!IrpContext->IsSynchronous)
		{
			Status = STATUS_PENDING;
			_SEH2_LEAVE;
		}

		if (!ExAcquireResourceSharedLite(
					&Fcb->MainResource,
					IrpContext->IsSynchronous))
		{
			Status = STATUS_PENDING;
			_SEH2_LEAVE;
		}

		FcbResourceAcquired = TRUE;

		if (FileName != NULL)
		{
			if (Ccb->DirectorySearchPattern.Buffer != NULL)
			{
				FirstQuery = FALSE;
			}
			else
			{
				FirstQuery = TRUE;

				Ccb->DirectorySearchPattern.Length =
					Ccb->DirectorySearchPattern.MaximumLength =
					FileName->Length;

				Ccb->DirectorySearchPattern.Buffer =
					ExAllocatePoolWithTag(PagedPool, FileName->Length, FFS_POOL_TAG);

				if (Ccb->DirectorySearchPattern.Buffer == NULL)
				{
					Status = STATUS_INSUFFICIENT_RESOURCES;
					_SEH2_LEAVE;
				}

				Status = RtlUpcaseUnicodeString(
						&(Ccb->DirectorySearchPattern),
						FileName,
						FALSE);

				if (!NT_SUCCESS(Status))
					_SEH2_LEAVE;
			}
		}
		else if (Ccb->DirectorySearchPattern.Buffer != NULL)
		{
			FirstQuery = FALSE;
			FileName = &Ccb->DirectorySearchPattern;
		}
		else
		{
			FirstQuery = TRUE;

			Ccb->DirectorySearchPattern.Length =
				Ccb->DirectorySearchPattern.MaximumLength = 2;

			Ccb->DirectorySearchPattern.Buffer =
				ExAllocatePoolWithTag(PagedPool, 2, FFS_POOL_TAG);

			if (Ccb->DirectorySearchPattern.Buffer == NULL)
			{
				Status = STATUS_INSUFFICIENT_RESOURCES;
				_SEH2_LEAVE;
			}

			RtlCopyMemory(
					Ccb->DirectorySearchPattern.Buffer,
					L"*\0", 2);
		}

		if (!IndexSpecified)
		{
			if (RestartScan || FirstQuery)
			{
				FileIndex = Fcb->FFSMcb->DeOffset = 0;
			}
			else
			{
				FileIndex = Ccb->CurrentByteOffset;
			}
		}

		if (FS_VERSION == 1)
		{
			dinode1 = (PFFSv1_INODE)ExAllocatePoolWithTag(
					PagedPool,
					DINODE1_SIZE, FFS_POOL_TAG);

			if (dinode1 == NULL)
			{
				Status = STATUS_INSUFFICIENT_RESOURCES;
				_SEH2_LEAVE;
			}

			RtlZeroMemory(Buffer, Length);

			if (Fcb->dinode1->di_size <= FileIndex)
			{
				Status = STATUS_NO_MORE_FILES;
				_SEH2_LEAVE;
			}
		}
		else
		{
			dinode2 = (PFFSv2_INODE)ExAllocatePoolWithTag(
					PagedPool,
					DINODE2_SIZE, FFS_POOL_TAG);

			if (dinode2 == NULL)
			{
				Status = STATUS_INSUFFICIENT_RESOURCES;
				_SEH2_LEAVE;
			}

			RtlZeroMemory(Buffer, Length);

			if (Fcb->dinode2->di_size <= FileIndex)
			{
				Status = STATUS_NO_MORE_FILES;
				_SEH2_LEAVE;
			}
		}

		pDir = ExAllocatePoolWithTag(PagedPool,
				sizeof(FFS_DIR_ENTRY), FFS_POOL_TAG);
		if (!pDir)
		{
			Status = STATUS_INSUFFICIENT_RESOURCES;
			_SEH2_LEAVE;
		}


		if (FS_VERSION == 1)
		{
			dwBytes = 0;
			dwSize = (ULONG)Fcb->dinode1->di_size - FileIndex -
				(sizeof(FFS_DIR_ENTRY) - FFS_NAME_LEN + 1);

			ByteOffset = FileIndex;

			dwTemp = 0;

			while (bRun && UsedLength < Length  && dwBytes < dwSize)
			{
				OEM_STRING  OemName;

				RtlZeroMemory(pDir, sizeof(FFS_DIR_ENTRY));

				Status = FFSv1ReadInode(
							NULL,
							Vcb,
							Fcb->dinode1,
							ByteOffset,
							(PVOID)pDir,
							sizeof(FFS_DIR_ENTRY),
							&dwReturn);

				if (!NT_SUCCESS(Status))
				{
					_SEH2_LEAVE;
				}

				if (!pDir->d_ino)
				{
					if (pDir->d_reclen == 0)
					{
						FFSBreakPoint();
						_SEH2_LEAVE;
					}

					goto ProcessNextEntryv1;
				}

				OemName.Buffer = pDir->d_name;
				OemName.Length = (pDir->d_namlen & 0xff);
				OemName.MaximumLength = OemName.Length;

#if 0
/*
				//
				// We could not filter the files: "." and ".."
				//

				if ((OemName.Length >) 1 && OemName.Buffer[0] == '.')
				{
					if ( OemName.Length == 2 && OemName.Buffer[1] == '.')
					{
					}
					else
					{
						goto ProcessNextEntry1;
					}
				}
*/
#endif

				InodeFileNameLength = (USHORT)
					RtlOemStringToUnicodeSize(&OemName);

				InodeFileName.Length = 0;
				InodeFileName.MaximumLength = InodeFileNameLength + 2;

				if (InodeFileNameLength <= 0)
				{
					break;
				}

				InodeFileName.Buffer = ExAllocatePoolWithTag(
						PagedPool,
						InodeFileNameLength + 2, FFS_POOL_TAG);

				if (!InodeFileName.Buffer)
				{
					Status = STATUS_INSUFFICIENT_RESOURCES;
					_SEH2_LEAVE;
				}

				RtlZeroMemory(
						InodeFileName.Buffer, 
						InodeFileNameLength + 2);

				Status = FFSOEMToUnicode(&InodeFileName,
						&OemName);

				if (!NT_SUCCESS(Status))
				{
					_SEH2_LEAVE;
				}

				if (FsRtlDoesNameContainWildCards(
							&(Ccb->DirectorySearchPattern)) ?
						FsRtlIsNameInExpression(
							&(Ccb->DirectorySearchPattern),
							&InodeFileName,
							TRUE,
							NULL) :
						!RtlCompareUnicodeString(
							&(Ccb->DirectorySearchPattern),
							&InodeFileName,
							TRUE))
				{
					dwReturn = FFSProcessDirEntry(
							Vcb, FileInformationClass,
							pDir->d_ino,
							Buffer,
							UsedLength, 
							Length - UsedLength,
							(FileIndex + dwBytes),
							&InodeFileName,
							ReturnSingleEntry);

					if (dwReturn <= 0)
					{
						bRun = FALSE;
					}
					else
					{
						dwTemp = UsedLength;
						UsedLength += dwReturn;
					}
				}

				if (InodeFileName.Buffer != NULL)
				{
					ExFreePool(InodeFileName.Buffer);
					InodeFileName.Buffer = NULL;
				}

ProcessNextEntryv1:

				if (bRun)
				{
					dwBytes +=pDir->d_reclen;
					Ccb->CurrentByteOffset = FileIndex + dwBytes;
				}

				if (UsedLength && ReturnSingleEntry)
				{
					Status = STATUS_SUCCESS;
					_SEH2_LEAVE;
				}

				ByteOffset = FileIndex + dwBytes;
			}
		}
		else
		{
			dwBytes = 0;
			dwSize = (ULONG)Fcb->dinode2->di_size - FileIndex -
				(sizeof(FFS_DIR_ENTRY) - FFS_NAME_LEN + 1);

			ByteOffset = FileIndex;

			dwTemp = 0;

			while (bRun && UsedLength < Length  && dwBytes < dwSize)
			{
				OEM_STRING  OemName;

				RtlZeroMemory(pDir, sizeof(FFS_DIR_ENTRY));

				Status = FFSv2ReadInode(
							NULL,
							Vcb,
							Fcb->dinode2,
							ByteOffset,
							(PVOID)pDir,
							sizeof(FFS_DIR_ENTRY),
							&dwReturn);

				if (!NT_SUCCESS(Status))
				{
					_SEH2_LEAVE;
				}

				if (!pDir->d_ino)
				{
					if (pDir->d_reclen == 0)
					{
						FFSBreakPoint();
						_SEH2_LEAVE;
					}

					goto ProcessNextEntryv2;
				}

				OemName.Buffer = pDir->d_name;
				OemName.Length = (pDir->d_namlen & 0xff);
				OemName.MaximumLength = OemName.Length;
#if 0
/*
				//
				// We could not filter the files: "." and ".."
				//

				if ((OemName.Length >) 1 && OemName.Buffer[0] == '.')
				{
					if ( OemName.Length == 2 && OemName.Buffer[1] == '.')
					{
					}
					else
					{
						goto ProcessNextEntry2;
					}
				}
*/
#endif

				InodeFileNameLength = (USHORT)
					RtlOemStringToUnicodeSize(&OemName);

				InodeFileName.Length = 0;
				InodeFileName.MaximumLength = InodeFileNameLength + 2;

				if (InodeFileNameLength <= 0)
				{
					break;
				}

				InodeFileName.Buffer = ExAllocatePoolWithTag(
						PagedPool,
						InodeFileNameLength + 2, FFS_POOL_TAG);

				if (!InodeFileName.Buffer)
				{
					Status = STATUS_INSUFFICIENT_RESOURCES;
					_SEH2_LEAVE;
				}

				RtlZeroMemory(
						InodeFileName.Buffer, 
						InodeFileNameLength + 2);

				Status = FFSOEMToUnicode(&InodeFileName,
						&OemName);

				if (!NT_SUCCESS(Status))
				{
					_SEH2_LEAVE;
				}

				if (FsRtlDoesNameContainWildCards(
							&(Ccb->DirectorySearchPattern)) ?
						FsRtlIsNameInExpression(
							&(Ccb->DirectorySearchPattern),
							&InodeFileName,
							TRUE,
							NULL) :
						!RtlCompareUnicodeString(
							&(Ccb->DirectorySearchPattern),
							&InodeFileName,
							TRUE))
				{
					dwReturn = FFSProcessDirEntry(
							Vcb, FileInformationClass,
							pDir->d_ino,
							Buffer,
							UsedLength, 
							Length - UsedLength,
							(FileIndex + dwBytes),
							&InodeFileName,
							ReturnSingleEntry);

					if (dwReturn <= 0)
					{
						bRun = FALSE;
					}
					else
					{
						dwTemp = UsedLength;
						UsedLength += dwReturn;
					}
				}

				if (InodeFileName.Buffer != NULL)
				{
					ExFreePool(InodeFileName.Buffer);
					InodeFileName.Buffer = NULL;
				}

ProcessNextEntryv2:

				if (bRun)
				{
					dwBytes +=pDir->d_reclen;
					Ccb->CurrentByteOffset = FileIndex + dwBytes;
				}

				if (UsedLength && ReturnSingleEntry)
				{
					Status = STATUS_SUCCESS;
					_SEH2_LEAVE;
				}

				ByteOffset = FileIndex + dwBytes;
			}
		}

		FileIndex += dwBytes;

		((PULONG)((PUCHAR)Buffer + dwTemp)) [0] = 0;

		if (!UsedLength)
		{
			if (FirstQuery)
			{
				Status = STATUS_NO_SUCH_FILE;
			}
			else
			{
				Status = STATUS_NO_MORE_FILES;
			}
		}
		else
		{
			Status = STATUS_SUCCESS;
		}
	}

	_SEH2_FINALLY
	{

		if (FcbResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Fcb->MainResource,
					ExGetCurrentResourceThread());
		}

		if (FS_VERSION == 1)
		{
			if (dinode1 != NULL)
			{
				ExFreePool(dinode1);
			}
		}
		else
		{
			if (dinode2 != NULL)
			{
				ExFreePool(dinode2);
			}
		}

		if (pDir != NULL)
		{
			ExFreePool(pDir);
			pDir = NULL;
		}

		if (InodeFileName.Buffer != NULL)
		{
			ExFreePool(InodeFileName.Buffer);
		}

		if (!IrpContext->ExceptionInProgress)
		{
			if (Status == STATUS_PENDING)
			{
				Status = FFSLockUserBuffer(
						IrpContext->Irp,
						Length,
						IoWriteAccess);

				if (NT_SUCCESS(Status))
				{
					Status = FFSQueueRequest(IrpContext);
				}
				else
				{
					FFSCompleteIrpContext(IrpContext, Status);
				}
			}
			else
			{
				IrpContext->Irp->IoStatus.Information = UsedLength;
				FFSCompleteIrpContext(IrpContext, Status);
			}
		}
	} _SEH2_END;

	return Status;
}
Esempio n. 9
0
/*
* FUNCTION: Find a file
*/
static NTSTATUS
CdfsFindFile(PDEVICE_EXTENSION DeviceExt,
             PFCB Fcb,
             PFCB Parent,
             PUNICODE_STRING FileToFind,
             PULONG pDirIndex,
             PULONG pOffset)
{
    WCHAR name[256];
    WCHAR ShortNameBuffer[13];
    UNICODE_STRING TempString;
    UNICODE_STRING ShortName;
    UNICODE_STRING LongName;
    UNICODE_STRING FileToFindUpcase;
    PVOID Block;
    NTSTATUS Status;
    ULONG len;
    ULONG DirIndex;
    ULONG Offset = 0;
    BOOLEAN IsRoot;
    PVOID Context = NULL;
    ULONG DirSize;
    PDIR_RECORD Record;
    LARGE_INTEGER StreamOffset, OffsetOfEntry;

    DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n",
        Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
    DPRINT("FindFile: old Pathname %p, old Objectname %p)\n",
        Fcb->PathName, Fcb->ObjectName);

    IsRoot = FALSE;
    DirIndex = 0;

    if (FileToFind == NULL || FileToFind->Length == 0)
    {
        RtlInitUnicodeString(&TempString, L".");
        FileToFind = &TempString;
    }

    if (Parent)
    {
        if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart)
        {
            IsRoot = TRUE;
        }
    }
    else
    {
        IsRoot = TRUE;
    }

    if (IsRoot == TRUE)
    {
        StreamOffset.QuadPart = (LONGLONG)DeviceExt->CdInfo.RootStart * (LONGLONG)BLOCKSIZE;
        DirSize = DeviceExt->CdInfo.RootSize;


        if (FileToFind->Buffer[0] == 0 ||
            (FileToFind->Buffer[0] == '\\' && FileToFind->Buffer[1] == 0) ||
            (FileToFind->Buffer[0] == '.' && FileToFind->Buffer[1] == 0))
        {
            /* it's root : complete essentials fields then return ok */
            RtlZeroMemory(Fcb, sizeof(FCB));
            RtlInitEmptyUnicodeString(&Fcb->PathName, Fcb->PathNameBuffer, sizeof(Fcb->PathNameBuffer));

            Fcb->PathNameBuffer[0] = '\\';
            Fcb->PathName.Length = sizeof(WCHAR);
            Fcb->ObjectName = &Fcb->PathNameBuffer[1];
            Fcb->Entry.ExtentLocationL = DeviceExt->CdInfo.RootStart;
            Fcb->Entry.DataLengthL = DeviceExt->CdInfo.RootSize;
            Fcb->Entry.FileFlags = 0x02; //FILE_ATTRIBUTE_DIRECTORY;

            if (pDirIndex)
                *pDirIndex = 0;
            if (pOffset)
                *pOffset = 0;
            DPRINT("CdfsFindFile: new Pathname %wZ, new Objectname %S)\n",&Fcb->PathName, Fcb->ObjectName);
            return STATUS_SUCCESS;
        }
    }
    else
    {
        StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
        DirSize = Parent->Entry.DataLengthL;
    }

    DPRINT("StreamOffset %I64d  DirSize %u\n", StreamOffset.QuadPart, DirSize);

    if (pDirIndex && (*pDirIndex))
        DirIndex = *pDirIndex;

    if (pOffset && (*pOffset))
    {
        Offset = *pOffset;
        StreamOffset.QuadPart += ROUND_DOWN(Offset, BLOCKSIZE);
    }

    if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset,
        BLOCKSIZE, TRUE, &Context, &Block))
    {
        DPRINT("CcMapData() failed\n");
        return STATUS_UNSUCCESSFUL;
    }

    Record = (PDIR_RECORD) ((ULONG_PTR)Block + Offset % BLOCKSIZE);
    if (Offset)
    {
        Offset += Record->RecordLength;
        Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
    }

    /* Upper case the expression for FsRtlIsNameInExpression */
    Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE);
    if (!NT_SUCCESS(Status))
    {
        return Status;
    }

    while(TRUE)
    {
        DPRINT("RecordLength %u  ExtAttrRecordLength %u  NameLength %u\n",
            Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);

        Status = CdfsGetEntryName
            (DeviceExt, &Context, &Block, &StreamOffset,
            DirSize, (PVOID*)&Record, name, &DirIndex, &Offset);

        if (Status == STATUS_NO_MORE_ENTRIES)
        {
            break;
        }
        else if (Status == STATUS_UNSUCCESSFUL || Status == STATUS_DISK_CORRUPT_ERROR)
        {
            /* Note: the directory cache has already been unpinned */
            RtlFreeUnicodeString(&FileToFindUpcase);
            return Status;
        }

        DPRINT("Name '%S'\n", name);

        RtlInitUnicodeString(&LongName, name);

        ShortName.Length = 0;
        ShortName.MaximumLength = 26;
        ShortName.Buffer = ShortNameBuffer;

        OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset;
        CdfsShortNameCacheGet(Parent, &OffsetOfEntry, &LongName, &ShortName);

        DPRINT("ShortName '%wZ'\n", &ShortName);

        if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) ||
            FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL))
        {
            if (Parent->PathName.Buffer[0])
            {
                RtlCopyUnicodeString(&Fcb->PathName, &Parent->PathName);
                len = Parent->PathName.Length / sizeof(WCHAR);
                Fcb->ObjectName=&Fcb->PathName.Buffer[len];
                if (len != 1 || Fcb->PathName.Buffer[0] != '\\')
                {
                    Fcb->ObjectName[0] = '\\';
                    Fcb->ObjectName = &Fcb->ObjectName[1];
                }
            }
            else
            {
                Fcb->ObjectName=Fcb->PathName.Buffer;
                Fcb->ObjectName[0]='\\';
                Fcb->ObjectName=&Fcb->ObjectName[1];
            }

            DPRINT("PathName '%wZ'  ObjectName '%S'\n", &Fcb->PathName, Fcb->ObjectName);

            memcpy(&Fcb->Entry, Record, sizeof(DIR_RECORD));
            wcsncpy(Fcb->ObjectName, name, min(wcslen(name) + 1,
                MAX_PATH - (Fcb->PathName.Length / sizeof(WCHAR)) + wcslen(Fcb->ObjectName)));

            /* Copy short name */
            Fcb->ShortNameU.Length = ShortName.Length;
            Fcb->ShortNameU.MaximumLength = ShortName.Length;
            Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer;
            memcpy(Fcb->ShortNameBuffer, ShortName.Buffer, ShortName.Length);

            if (pDirIndex)
                *pDirIndex = DirIndex;
            if (pOffset)
                *pOffset = Offset;

            DPRINT("FindFile: new Pathname %wZ, new Objectname %S, DirIndex %u\n",
                &Fcb->PathName, Fcb->ObjectName, DirIndex);

            RtlFreeUnicodeString(&FileToFindUpcase);
            CcUnpinData(Context);

            return STATUS_SUCCESS;
        }

        Offset += Record->RecordLength;
        Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
        DirIndex++;
    }

    RtlFreeUnicodeString(&FileToFindUpcase);
    CcUnpinData(Context);

    if (pDirIndex)
        *pDirIndex = DirIndex;

    if (pOffset)
        *pOffset = Offset;

    return STATUS_UNSUCCESSFUL;
}
Esempio n. 10
0
NTSTATUS 
NcEnumerateDirectorySetupInjection (
    _Inout_ PNC_DIR_QRY_CONTEXT DirQryCtx,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ PNC_INSTANCE_CONTEXT InstanceContext,
    _In_ PDIRECTORY_CONTROL_OFFSETS Offsets,
    _In_ FILE_INFORMATION_CLASS InformationClass
    )
/*++

Routine Description:

    Sets up directory enumeration context cache so that we are ready to
    perform injection.

Arguments:

    DirQryCtx - Pointer to directory query context (on the stream handle.)

    FltObjects - FltObjects structure for this operation.
    
    InstanceContext - Instance Context for this operation.

    Offsets - Offsets structure for this information class.

    InformationClass - The information class for this operation.

Return Value:

    Returns STATUS_SUCCESS on success, otherwise an appropriate error code.

--*/
{
    NTSTATUS Status;

    OBJECT_ATTRIBUTES RealParentAttributes;
    HANDLE RealParentHandle = 0; //close always
    PFILE_OBJECT RealParentFileObj = NULL;
    IO_STATUS_BLOCK RealParentStatusBlock;
    char * QueryBuffer = NULL; //free on error, when no injection
    ULONG QueryBufferLength = 0;
    USHORT NameLength;
    ULONG QueryBufferLengthRead;
    BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags,
                                         FO_OPENED_CASE_SENSITIVE );

    PAGED_CODE();


    //
    //  If the user has specified a search string, and if our user mapping
    //  should not be returned in this search string, return success.  We
    //  don't need to inject anything.
    //

    if (DirQryCtx->SearchString.Length > 0 &&
        !FsRtlIsNameInExpression( &DirQryCtx->SearchString,
                                  &InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName,
                                  IgnoreCase,
                                  NULL ) &&
        !FsRtlIsNameInExpression( &DirQryCtx->SearchString,
                                  &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName,
                                  IgnoreCase,
                                  NULL )) {

        Status = STATUS_SUCCESS;
        goto NcEnumerateDirectorySetupCleanup;
    }

    //
    //  Initialize insertion info.
    //
    //  We have to insert the final component of the real mapping
    //  as the final component of the user mapping. To do this we
    //  will open the parent of the real mapping, and query the real
    //  mapping.
    //  Then we will overwrite the real mapping's name with
    //  the final component of the user mapping. This data will be
    //  stored in the DirQryCtx for later injection.
    //

    //
    //  Open parent of real mapping.
    //

    InitializeObjectAttributes( &RealParentAttributes,
                                &InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath,
                                OBJ_KERNEL_HANDLE,
                                NULL,
                                NULL);

    Status = NcCreateFileHelper( NcGlobalData.FilterHandle,            // Filter
                                 FltObjects->Instance,                 // InstanceOffsets
                                 &RealParentHandle,                    // Returned Handle
                                 &RealParentFileObj,                   // Returned FileObject
                                 FILE_LIST_DIRECTORY|FILE_TRAVERSE,    // Desired Access
                                 &RealParentAttributes,                // object attributes
                                 &RealParentStatusBlock,               // Returned IOStatusBlock
                                 0,                                    // Allocation Size
                                 FILE_ATTRIBUTE_NORMAL,                // File Attributes
                                 0,                                    // Share Access
                                 FILE_OPEN,                            // Create Disposition
                                 FILE_DIRECTORY_FILE,                  // Create Options
                                 NULL,                                 // Ea Buffer
                                 0,                                    // EA Length
                                 IO_IGNORE_SHARE_ACCESS_CHECK,         // Flags
                                 FltObjects->FileObject );             // Transaction state
   
    if (!NT_SUCCESS( Status )) {

        goto NcEnumerateDirectorySetupCleanup;
    }

    //
    //  Allocate Buffer to store mapping data.
    //

    NameLength = Max( InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName.Length,
                      InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length );

    QueryBufferLength = Offsets->FileNameDist + NameLength;

    QueryBuffer = ExAllocatePoolWithTag( PagedPool, QueryBufferLength, NC_DIR_QRY_CACHE_TAG );

    if (QueryBuffer == NULL) {

        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto NcEnumerateDirectorySetupCleanup;
    }

    //
    //  Query the information from the parent of the real mapping.
    //

    Status = NcQueryDirectoryFile( FltObjects->Instance,
                                   RealParentFileObj,
                                   QueryBuffer,
                                   QueryBufferLength,
                                   InformationClass,
                                   TRUE,//Return single entry
                                   &InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName,
                                   FALSE,//restart scan
                                   &QueryBufferLengthRead);

    if (Status == STATUS_NO_SUCH_FILE) {

        //
        //  The user mapping does not exist, this is allowed. It means we
        //  have nothing to inject.
        //

        DirQryCtx->InjectionEntry.Buffer = NULL;
        DirQryCtx->InjectionEntry.CurrentOffset = 0;

        ExFreePoolWithTag( QueryBuffer, NC_DIR_QRY_CACHE_TAG );
        QueryBuffer = NULL;

        Status = STATUS_SUCCESS;

    } else if (!NT_SUCCESS( Status )) {

        //
        //  An unexpected error occurred, return code.
        //

        goto NcEnumerateDirectorySetupCleanup;
        
    } else {

        //
        //  Now we have to munge the real mapping directory entry into a
        //  user mapping directory entry.
        //

        NcSetFileName( QueryBuffer,
                       InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Buffer,
                       InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length,
                       Offsets,
                       TRUE );

        NcSetShortName( QueryBuffer,
                        InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName.Buffer,
                        InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName.Length,
                        Offsets );

        FLT_ASSERT( DirQryCtx->InjectionEntry.Buffer == NULL );

        //
        //  Set the injection entry up in the cache.
        //

        DirQryCtx->InjectionEntry.Buffer = QueryBuffer;
        DirQryCtx->InjectionEntry.CurrentOffset = 0;
    }

NcEnumerateDirectorySetupCleanup:

    if (!NT_SUCCESS( Status )) {

        if(QueryBuffer != NULL) {

            ExFreePoolWithTag( QueryBuffer, NC_DIR_QRY_CACHE_TAG );
        }

    }

    if (RealParentHandle != NULL) {

        FltClose( RealParentHandle );
    }

    if (RealParentFileObj != NULL) {

        ObDereferenceObject( RealParentFileObj );
    }

    return Status;
}
Esempio n. 11
0
/*************************************************************************
*
* Function: Ext2QueryDirectory()
*
* Description:
*	Query directory request.
*
* Expected Interrupt Level (for execution) :
*
*  IRQL_PASSIVE_LEVEL
*
* Return Value: STATUS_SUCCESS/Error
*
*************************************************************************/
NTSTATUS NTAPI Ext2QueryDirectory(
PtrExt2IrpContext			PtrIrpContext,
PIRP						PtrIrp,
#ifdef _GNU_NTIFS_
PEXTENDED_IO_STACK_LOCATION			PtrIoStackLocation,
#else
PIO_STACK_LOCATION			PtrIoStackLocation,
#endif
PFILE_OBJECT				PtrFileObject,
PtrExt2FCB					PtrFCB,
PtrExt2CCB					PtrCCB)
{
	NTSTATUS				RC = STATUS_SUCCESS;
	BOOLEAN					PostRequest = FALSE;
	PtrExt2NTRequiredFCB	PtrReqdFCB = NULL;
	BOOLEAN					CanWait = FALSE;
	PtrExt2VCB				PtrVCB = NULL;
	BOOLEAN					AcquiredFCB = FALSE;
	unsigned long			BufferLength = 0;
	unsigned long			BufferIndex	= 0;
	unsigned long			FileIndex = 0;
	PUNICODE_STRING			PtrSearchPattern = NULL;
	FILE_INFORMATION_CLASS	FileInformationClass;
	BOOLEAN					RestartScan = FALSE;
	BOOLEAN					ReturnSingleEntry = FALSE;
	BOOLEAN					IndexSpecified = FALSE;
	unsigned char			*Buffer = NULL;
	BOOLEAN					FirstTimeQuery = FALSE;
	unsigned long			StartingIndexForSearch = 0;
	unsigned long			BytesReturned = 0;
	BOOLEAN					BufferUsedup = FALSE;

	BOOLEAN					SearchWithWildCards = FALSE;
	
	PFILE_BOTH_DIR_INFORMATION		BothDirInformation = NULL;
	PFILE_DIRECTORY_INFORMATION		DirectoryInformation = NULL;

	
	PEXT2_DIR_ENTRY		PtrDirEntry = NULL;
	PEXT2_INODE			PtrInode	= NULL;
	
	unsigned long		LogicalBlockSize;
	
	unsigned long		ThisBlock;
	
	//	The starting Physical Block No...
	//LARGE_INTEGER StartPhysicalBlock;
	LARGE_INTEGER StartBufferOffset ;
	ULONG PinBufferLength;
		
	//	Buffer Control Block
	PBCB				PtrBCB = NULL;
	BYTE *				PtrPinnedBlockBuffer = NULL;

	unsigned int j;
	
	DebugTrace(DEBUG_TRACE_MISC,   " === Querying Directory %S", PtrFCB->FCBName->ObjectName.Buffer );

	try 
	{
		// Validate the sent-in FCB
		if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) 
		{
			// We will only allow notify requests on directories.
			RC = STATUS_INVALID_PARAMETER;
		}

		PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
		CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
		PtrVCB = PtrFCB->PtrVCB;

		//
		//	Asynchronous IO requested
		//	Posting request...
		//
		/*
		 * This is incorrect because posted IRP_MJ_DIRECTORY_CONTROL
		 * requests aren't handled in the worker thread yet. I tried
		 * adding handling of them to the worked routine, but there
		 * were problems with accessing the PtrIoStackLocation->
		 * Parameters.QueryDirectory.FileName variable.
		 * -- Filip Navara, 18/08/2004
		 */
#if 0
		if (!CanWait) 
		{
			PostRequest = TRUE;
			try_return(RC = STATUS_PENDING);
		}
#endif

		// Obtain the callers parameters
		BufferLength = PtrIoStackLocation->Parameters.QueryDirectory.Length;
		PtrSearchPattern = ( PUNICODE_STRING	) PtrIoStackLocation->Parameters.QueryDirectory.FileName;
		FileInformationClass = PtrIoStackLocation->Parameters.QueryDirectory.FileInformationClass;
		FileIndex = PtrIoStackLocation->Parameters.QueryDirectory.FileIndex;

		// Some additional arguments that affect the FSD behavior
		RestartScan       = (PtrIoStackLocation->Flags & SL_RESTART_SCAN);
		ReturnSingleEntry = (PtrIoStackLocation->Flags & SL_RETURN_SINGLE_ENTRY);
		IndexSpecified    = (PtrIoStackLocation->Flags & SL_INDEX_SPECIFIED);

		//
		// Acquiring exclusive access to the FCB.
		// This is not mandatory
		//
		DebugTrace(DEBUG_TRACE_MISC,   "*** Going into a block to acquire FCB Exclusively[DirCtrl]", 0);

		DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
		ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE);
		
		DebugTrace(DEBUG_TRACE_MISC,   "*** FCB acquired [DirCtrl]", 0);
		AcquiredFCB = TRUE;

		// We must determine the buffer pointer to be used. Since this
		// routine could either be invoked directly in the context of the
		// calling thread, or in the context of a worker thread, here is
		// a general way of determining what we should use.
		Buffer = Ext2GetCallersBuffer ( PtrIrp );

		// The method of determining where to look from and what to look for is
		// unfortunately extremely confusing. However, here is a methodology you
		// you can broadly adopt:
		// (a) You have to maintain a search buffer per CCB structure.
		// (b) This search buffer is initialized the very first time
		//		 a query directory operation is performed using the file object.
		// (For the sample FSD, the search buffer is stored in the
		//	 DirectorySearchPattern field)
		// However, the caller still has the option of "overriding" this stored
		// search pattern by supplying a new one in a query directory operation.
		//

		if( PtrCCB->DirectorySearchPattern.Length )
		{
			if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 )
			{
				DebugTrace(DEBUG_TRACE_MISC,  "&&&&&&&&&  PtrCCB->DirectorySearchPattern not NULL terminated!", 0);
			}
			DebugTrace(DEBUG_TRACE_MISC,   " === Old Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer );
		}

		if (PtrSearchPattern != NULL) 
		{
			// User has supplied a search pattern
			// Now validate that the search pattern is legitimate

			if ( PtrCCB->DirectorySearchPattern.Length == 0 ) 
			{
				// This must be the very first query request.
				FirstTimeQuery = TRUE;
			}
			else
			{
				// We should ignore the search pattern in the CCB and instead,
				// use the user-supplied pattern for this particular query
				// directory request.
				Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern );
			}

			// Now, allocate enough memory to contain the caller
			// supplied search pattern and fill in the DirectorySearchPattern
			// field in the CCB
			Ext2CopyUnicodeString( &PtrCCB->DirectorySearchPattern, PtrSearchPattern );
			/*
			PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof( PtrSearchPattern ) );
			ASSERT(PtrCCB->DirectorySearchPattern);
			RtlCopyMemory( PtrCCB->DirectorySearchPattern, PtrSearchPattern, sizeof( PtrSearchPattern ) );
			*/
		}
		else if ( PtrCCB->DirectorySearchPattern.Length == 0 ) 
		{
			// This MUST be the first directory query operation (else the
			// DirectorySearchPattern field would never be empty. Also, the caller
			// has neglected to provide a pattern so we MUST invent one.
			// Use "*" (following NT conventions) as your search pattern
			// and store it in the PtrCCB->DirectorySearchPattern field.
			
			/*
			PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof(L"*") );
			ASSERT(PtrCCB->DirectorySearchPattern);
			RtlCopyMemory( PtrCCB->DirectorySearchPattern, L"*", 4 );*/

			Ext2CopyWideCharToUnicodeString( &PtrCCB->DirectorySearchPattern, L"*" );
			
			FirstTimeQuery = TRUE;
		} 
		else 
		{
			// The caller has not supplied any search pattern...
			// Using previously supplied pattern
			PtrSearchPattern = &PtrCCB->DirectorySearchPattern;
		}

		if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 )
		{
			DebugTrace(DEBUG_TRACE_MISC,  "&&&&&&&&&  PtrCCB->DirectorySearchPattern not NULL terminated!", 0 );
		}
		DebugTrace(DEBUG_TRACE_MISC,   " === Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer );
		SearchWithWildCards = FsRtlDoesNameContainWildCards( PtrSearchPattern );

		// There is one other piece of information that your FSD must store
		// in the CCB structure for query directory support. This is the index
		// value (i.e. the offset in your on-disk directory structure) from
		// which you should start searching.
		// However, the flags supplied with the IRP can make us override this
		// as well.

		if (FileIndex) 
		{
			// Caller has told us wherefrom to begin.
			// You may need to round this to an appropriate directory entry
			// entry alignment value.
			StartingIndexForSearch = FileIndex;
		} 
		else if (RestartScan) 
		{
			StartingIndexForSearch = 0;
		} 
		else 
		{
			// Get the starting offset from the CCB.
			StartingIndexForSearch = PtrCCB->CurrentByteOffset.LowPart;
		}

		//	Read in the file inode if it hasn't already been read...
		Ext2InitializeFCBInodeInfo( PtrFCB );
		
		if (PtrFileObject->PrivateCacheMap == NULL) 
		{
			CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)),
				TRUE,		// We will utilize pin access for directories
				&(Ext2GlobalData.CacheMgrCallBacks), // callbacks
				PtrCCB);		// The context used in callbacks
		}


		//
		//	Read in the next Data Block of this directory
		//
		LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
		StartBufferOffset.QuadPart = ( StartingIndexForSearch / LogicalBlockSize );
		StartBufferOffset.QuadPart *= LogicalBlockSize;	//	This should be the StartBufferOffset alaigned to LBlock boundary...
		
		PinBufferLength = PtrReqdFCB->CommonFCBHeader.FileSize.LowPart - StartBufferOffset.LowPart;

		if ( !CcMapData( PtrFileObject,
                  &StartBufferOffset,
                  PinBufferLength,
                  TRUE,
                  &PtrBCB,
                  (PVOID*)&PtrPinnedBlockBuffer ) )
		{
			//	Read Failure
			DebugTrace(DEBUG_TRACE_MISC,   "Cache read failiure while reading in volume meta data", 0);
			try_return();
		}
		else
		{
			DebugTrace(DEBUG_TRACE_MISC,   "Cache hit while reading in volume meta data", 0);
		}
		
		PtrInode = Ext2AllocatePool( PagedPool, sizeof( EXT2_INODE )  );

		//
		//	Walking through the directory entries...
		for( BufferUsedup = FALSE, BufferIndex = 0; !BufferUsedup && StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; )
		{
			PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ StartingIndexForSearch - StartBufferOffset.LowPart ];
			
			StartingIndexForSearch += PtrDirEntry->rec_len;
			PtrCCB->CurrentByteOffset.LowPart = StartingIndexForSearch;

			if( PtrDirEntry->inode == 0 )
			{
				continue;
			}
			if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 )
			{
				//
				//	This should not happen
				//	Hqw can this be so!!!
				//
				Ext2BreakPoint();
				if( BothDirInformation )
				{
					BothDirInformation->NextEntryOffset = 0;
				}
				if( !BytesReturned )
				{
					if( FirstTimeQuery )
						RC = STATUS_NO_SUCH_FILE;
					else
						RC = STATUS_NO_MORE_FILES;
				}
				break;
			}

			//	Does this entry match the search criterian?
			//	Checking
			//
			{
				UNICODE_STRING	FileName;
				LONG	Matched = 0;
				// Constructing a counted Unicode string out of PtrDirEntry
				Ext2CopyCharToUnicodeString( &FileName, PtrDirEntry->name, PtrDirEntry->name_len );

				if ( SearchWithWildCards )
				{
					Matched = FsRtlIsNameInExpression ( PtrSearchPattern, &FileName, FALSE, NULL );
				}
				else
				{
					Matched = ! RtlCompareUnicodeString( PtrSearchPattern, &FileName, FALSE );
				}
			
				Ext2DeallocateUnicodeString( &FileName );
				if( !Matched )
				{
					continue;
				}
			}

			switch( FileInformationClass )
			{
			case FileBothDirectoryInformation:
				
				DebugTrace(DEBUG_TRACE_DIRINFO,   " === FileBothDirectoryInformation", 0 );
				ThisBlock = sizeof( FILE_BOTH_DIR_INFORMATION );
				ThisBlock += PtrDirEntry->name_len*2;
				ThisBlock = Ext2QuadAlign( ThisBlock  );

				if( ( BufferIndex + ThisBlock ) > BufferLength )
				{
					//
					//	Next entry won't fit into the buffer...
					//	will have to return... 
					//	:(
					//
					if( BothDirInformation )
						BothDirInformation->NextEntryOffset = 0;
					if( !BytesReturned )
						RC = STATUS_NO_MORE_FILES;
					BufferUsedup = TRUE;
					break;
				}
							
				Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode );
				if( !PtrInode )
				{
					try_return( RC = STATUS_UNSUCCESSFUL );
				}

				BothDirInformation = ( PFILE_BOTH_DIR_INFORMATION ) ( Buffer + ( BufferIndex ) );
				BothDirInformation->EaSize					= 0;
				BothDirInformation->AllocationSize.QuadPart	= PtrInode->i_blocks * 512;
				BothDirInformation->EndOfFile.QuadPart		= PtrInode->i_size;
				BothDirInformation->ChangeTime.QuadPart		= 0;

				BothDirInformation->CreationTime.QuadPart	= ( __int64 ) PtrInode->i_ctime * 10000000;
				BothDirInformation->CreationTime.QuadPart	+= Ext2GlobalData.TimeDiff.QuadPart;

				BothDirInformation->LastAccessTime.QuadPart	= Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 );
				BothDirInformation->LastWriteTime.QuadPart	= Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 );

				//	Getting the file type...
				BothDirInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
				if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) )
				{  
					//	Not a reqular file...
					if( Ext2IsModeDirectory( PtrInode->i_mode) )
					{
						//	Directory...
						BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
					}
					else
					{
						//	Special File...
						//	Treated with respect... ;)
						//
						BothDirInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
						//	FILE_ATTRIBUTE_DEVICE
					}
					if ( Ext2IsModeHidden( PtrInode->i_mode ) )
					{
						BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
					}
					
					if ( Ext2IsModeReadOnly( PtrInode->i_mode ) )
					{
						BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY;
					}
				}

				BothDirInformation->FileIndex = StartingIndexForSearch;
				BothDirInformation->FileNameLength = PtrDirEntry->name_len*2 + 2;
				BothDirInformation->ShortNameLength = 0; 
				BothDirInformation->ShortName[0] = 0;
				
				//	Copying out the name as WCHAR null terminated strings
				for( j = 0; j< PtrDirEntry->name_len ; j ++ )
				{
					//	BothDirInformation->ShortName[ j ] = PtrDirEntry->name[j];
					BothDirInformation->FileName[ j ] = PtrDirEntry->name[j];
					//	if( j < 11 )
					//		BothDirInformation->ShortName[j] = PtrDirEntry->name[j];
				}

				/*
				if( j < 11 )
				{
					BothDirInformation->ShortNameLength = j * 2 + 2;
					BothDirInformation->ShortName[ j ] = 0;
				}
				else
				{
					BothDirInformation->ShortNameLength = 24;
					BothDirInformation->ShortName[ 11 ] = 0;
				}*/

				BothDirInformation->FileName[ j ]	= 0;
				BytesReturned += ThisBlock;
				BufferIndex += ThisBlock;

				if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ))
					BothDirInformation->NextEntryOffset = ThisBlock;
				else
					BothDirInformation->NextEntryOffset = 0;
				break;

			case FileDirectoryInformation:
				//	DirectoryInformation
				DebugTrace(DEBUG_TRACE_DIRINFO,   " === FileDirectoryInformation", 0 );
				ThisBlock = sizeof( FILE_DIRECTORY_INFORMATION );
				ThisBlock += PtrDirEntry->name_len*2;
				ThisBlock = Ext2QuadAlign( ThisBlock  );

				if( ( BufferIndex + ThisBlock ) > BufferLength )
				{
					//
					//	Next entry won't fit into the buffer...
					//	will have to return... 
					//	:(
					//
					if( DirectoryInformation )
						DirectoryInformation->NextEntryOffset = 0;
					if( !BytesReturned )
						RC = STATUS_NO_MORE_FILES;
					BufferUsedup = TRUE;
					break;
				}
							
				Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode );
				if( !PtrInode )
				{
					try_return( RC = STATUS_UNSUCCESSFUL );
				}

				DirectoryInformation = ( PFILE_DIRECTORY_INFORMATION ) ( Buffer + ( BufferIndex ) );
				DirectoryInformation->AllocationSize.QuadPart	= PtrInode->i_blocks * 512;
				DirectoryInformation->EndOfFile.QuadPart		= PtrInode->i_size;
				DirectoryInformation->ChangeTime.QuadPart		= 0;

				DirectoryInformation->CreationTime.QuadPart	= ( __int64 ) PtrInode->i_ctime * 10000000;
				DirectoryInformation->CreationTime.QuadPart	+= Ext2GlobalData.TimeDiff.QuadPart;

				DirectoryInformation->LastAccessTime.QuadPart	= Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 );
				DirectoryInformation->LastWriteTime.QuadPart	= Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 );

				//	Getting the file type...
				DirectoryInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
				if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) )
				{  
					//	Not a reqular file...
					if( Ext2IsModeDirectory( PtrInode->i_mode) )
					{
						//	Directory...
						DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
					}
					else
					{
						//	Special File...
						//	Treated with respect... ;)
						//
						DirectoryInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
						//	FILE_ATTRIBUTE_DEVICE
					}
					if ( Ext2IsModeHidden( PtrInode->i_mode ) )
					{
						DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
					}
					
					if ( Ext2IsModeReadOnly( PtrInode->i_mode ) )
					{
						DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY;
					}
				}

				DirectoryInformation->FileIndex = StartingIndexForSearch;
				DirectoryInformation->FileNameLength = PtrDirEntry->name_len*2 + 2;
				
				//	Copying out the name as WCHAR null terminated strings
				for( j = 0; j< PtrDirEntry->name_len ; j ++ )
				{
					DirectoryInformation->FileName[ j ] = PtrDirEntry->name[j];
				}

				DirectoryInformation->FileName[ j ]	= 0;
				BytesReturned += ThisBlock;
				BufferIndex += ThisBlock;

				if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ))
					DirectoryInformation->NextEntryOffset = ThisBlock;
				else
					DirectoryInformation->NextEntryOffset = 0;
				break;

			case FileFullDirectoryInformation:
				//	FullDirInformation->
				DebugTrace(DEBUG_TRACE_DIRINFO,   " === FileFullDirectoryInformation - Not handled", 0 );
				try_return();
			case FileNamesInformation:
				//	NamesInformation->
				DebugTrace(DEBUG_TRACE_DIRINFO,   " === FileNamesInformation - Not handled", 0 );
				try_return();
			default:
				DebugTrace(DEBUG_TRACE_DIRINFO,   " === Invalid Dir Info class - Not handled", 0 );
				try_return( RC = STATUS_INVALID_INFO_CLASS );
			}
			if( ReturnSingleEntry )
			{
				break;
			}
		}//	end of for...



		if( !BytesReturned && StartingIndexForSearch >= ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart) )
		{
			Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern );
			PtrCCB->CurrentByteOffset.QuadPart = 0;
			if( FirstTimeQuery )
				RC = STATUS_NO_SUCH_FILE;
			else
				RC = STATUS_NO_MORE_FILES;
			try_return();
		}
		else if( BytesReturned )
		{
			BothDirInformation->NextEntryOffset = 0;
		}

		try_exit:	NOTHING;
	}
	finally 
	{

		if( PtrInode )
		{
			DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [DirCtrl]", PtrInode );
			ExFreePool( PtrInode );
		}

		if( PtrBCB )
		{
			CcUnpinData( PtrBCB );
			PtrBCB = NULL;
		}
		
		if (PostRequest) 
		{
			if (AcquiredFCB) 
			{
				Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
				DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Released in [DirCtrl]", 0);
				DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", 
					PtrReqdFCB->MainResource.ActiveCount, 
					PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
					PtrReqdFCB->MainResource.NumberOfSharedWaiters );
			}

			// Map the users buffer and then post the request.
			RC = Ext2LockCallersBuffer(PtrIrp, TRUE, BufferLength);
			ASSERT(NT_SUCCESS(RC));

			RC = Ext2PostRequest(PtrIrpContext, PtrIrp);

		}
		else if (!(PtrIrpContext->IrpContextFlags &
							EXT2_IRP_CONTEXT_EXCEPTION)) 
		{
			if (AcquiredFCB) 
			{
				Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
				DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Released [DirCtrl]", 0);
				DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", 
					PtrReqdFCB->MainResource.ActiveCount, 
					PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
					PtrReqdFCB->MainResource.NumberOfSharedWaiters );
			}

			// Complete the request.
			PtrIrp->IoStatus.Status = RC;
			PtrIrp->IoStatus.Information = BytesReturned;

			// Free up the Irp Context
			Ext2ReleaseIrpContext(PtrIrpContext);

			// complete the IRP
			IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
		}
		
		//	Flush the saved BCBs...
		//	Ext2FlushSavedBCBs ( PtrIrpContext );

	}

	return(RC);
}
Esempio n. 12
0
NTSTATUS
NpQueryDirectory (
    IN PROOT_DCB RootDcb,
    IN PROOT_DCB_CCB Ccb,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the work routine for querying a directory.

Arugments:

    RootDcb - Supplies the dcb being queried

    Ccb - Supplies the context of the caller

    Irp - Supplies the Irp being processed

Return Value:

    NTSTATUS - The return status for the operation.

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;

    PUCHAR Buffer;
    CLONG SystemBufferLength;

    UNICODE_STRING FileName;
    ULONG FileIndex;
    FILE_INFORMATION_CLASS FileInformationClass;
    BOOLEAN RestartScan;
    BOOLEAN ReturnSingleEntry;
    BOOLEAN IndexSpecified;

    static WCHAR Star = L'*';

    BOOLEAN CaseInsensitive = TRUE; //*** Make searches case insensitive

    ULONG CurrentIndex;

    ULONG LastEntry;
    ULONG NextEntry;

    PLIST_ENTRY Links;
    PFCB Fcb;

    PFILE_DIRECTORY_INFORMATION DirInfo;
    PFILE_NAMES_INFORMATION NamesInfo;

    PAGED_CODE();

    //
    //  Get the current stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "NpQueryDirectory\n", 0 );
    DebugTrace( 0, Dbg, "RootDcb              = %08lx\n", RootDcb);
    DebugTrace( 0, Dbg, "Ccb                  = %08lx\n", Ccb);
    DebugTrace( 0, Dbg, "SystemBuffer         = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
    DebugTrace( 0, Dbg, "Length               = %08lx\n", IrpSp->Parameters.QueryDirectory.Length);
    DebugTrace( 0, Dbg, "FileName             = %Z\n",    IrpSp->Parameters.QueryDirectory.FileName);
    DebugTrace( 0, Dbg, "FileIndex            = %08lx\n", IrpSp->Parameters.QueryDirectory.FileIndex);
    DebugTrace( 0, Dbg, "FileInformationClass = %08lx\n", IrpSp->Parameters.QueryDirectory.FileInformationClass);
    DebugTrace( 0, Dbg, "RestartScan          = %08lx\n", FlagOn(IrpSp->Flags, SL_RESTART_SCAN));
    DebugTrace( 0, Dbg, "ReturnSingleEntry    = %08lx\n", FlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY));
    DebugTrace( 0, Dbg, "IndexSpecified       = %08lx\n", FlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED));

    //
    //  Save references to the input parameters within the Irp
    //

    SystemBufferLength   = IrpSp->Parameters.QueryDirectory.Length;

    FileIndex            = IrpSp->Parameters.QueryDirectory.FileIndex;

    FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;

    RestartScan          = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
    ReturnSingleEntry    = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
    IndexSpecified       = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);

    if (IrpSp->Parameters.QueryDirectory.FileName != NULL) {

        FileName = *(PUNICODE_STRING)IrpSp->Parameters.QueryDirectory.FileName;

    } else {

        FileName.Length = 0;
        FileName.Buffer = NULL;
    }

    //
    //  Check if the ccb already has a query template attached.  If it
    //  does not already have one then we either use the string we are
    //  given or we attach our own containing "*"
    //

    if (Ccb->QueryTemplate == NULL) {

        //
        //  This is our first time calling query directory so we need
        //  to either set the query template to the user specified string
        //  or to "*"
        //

        if (FileName.Buffer == NULL) {

            DebugTrace(0, Dbg, "Set template to *\n", 0);

            FileName.Length = 2;
            FileName.Buffer = &Star;
        }

        DebugTrace(0, Dbg, "Set query template -> %Z\n", &FileName);

        //
        //  Allocate space for the query template
        //

        Ccb->QueryTemplate = FsRtlAllocatePool( PagedPool,
                                                sizeof(UNICODE_STRING) + FileName.Length );

        //
        //  Initialize the query template and copy over the string
        //

        Ccb->QueryTemplate->Length = FileName.Length;
        Ccb->QueryTemplate->Buffer = (PWCH)Ccb->QueryTemplate +
                                     sizeof(UNICODE_STRING) / sizeof(WCHAR);

        RtlCopyMemory( Ccb->QueryTemplate->Buffer,
                       FileName.Buffer,
                       FileName.Length );

        //
        //  Now zero out the FileName so we won't think we're to use it
        //  as a subsearch string.
        //

        FileName.Length = 0;
        FileName.Buffer = NULL;
    }

    //
    //  Check if we were given an index to start with or if we need to
    //  restart the scan or if we should use the index that was saved in
    //  the ccb
    //

    if (RestartScan) {

        FileIndex = 0;

    } else if (!IndexSpecified) {

        FileIndex = Ccb->IndexOfLastCcbReturned + 1;
    }

    //
    //  Now we are committed to completing the Irp, we do that in
    //  the finally clause of the following try.
    //

    try {

        ULONG BaseLength;
        ULONG LengthAdded;

        //
        // Map the user buffer.
        //

        Buffer = NpMapUserBuffer( Irp );

        //
        //  At this point we are about to enter our query loop.  We have
        //  already decided which Fcb index we need to return.  The variables
        //  LastEntry and NextEntry are used to index into the user buffer.
        //  LastEntry is the last entry we added to the user buffer, and
        //  NextEntry is the current one we're working on.  CurrentIndex
        //  is the Fcb index that we are looking at next.  Logically the
        //  way the loop works is as follows.
        //
        //  Scan all of the Fcb in the directory
        //
        //      if the Fcb matches the query template then
        //
        //          if the CurrentIndex is >= the FileIndex then
        //
        //              process this fcb, and decide if we should
        //              continue the main loop
        //
        //          end if
        //
        //          Increment the current index
        //
        //      end if
        //
        //  end scan
        //

        CurrentIndex = 0;

        LastEntry = 0;
        NextEntry =0;

        switch (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 FileNamesInformation:

            BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
                                       FileName[0] );
            break;

        case FileBothDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
                                       FileName[0] );
            break;

        default:

            try_return( Status = STATUS_INVALID_INFO_CLASS );
        }

        for (Links = RootDcb->Specific.Dcb.ParentDcbQueue.Flink;
             Links != &RootDcb->Specific.Dcb.ParentDcbQueue;
             Links = Links->Flink) {

            Fcb = CONTAINING_RECORD(Links, FCB, ParentDcbLinks);

            ASSERT(Fcb->NodeTypeCode == NPFS_NTC_FCB);

            DebugTrace(0, Dbg, "Top of Loop\n", 0);
            DebugTrace(0, Dbg, "Fcb          = %08lx\n", Fcb);
            DebugTrace(0, Dbg, "CurrentIndex = %08lx\n", CurrentIndex);
            DebugTrace(0, Dbg, "FileIndex    = %08lx\n", FileIndex);
            DebugTrace(0, Dbg, "LastEntry    = %08lx\n", LastEntry);
            DebugTrace(0, Dbg, "NextEntry    = %08lx\n", NextEntry);

            //
            //  Check if the Fcb represents a named pipe that is part of
            //  our query template
            //

            if (FsRtlIsNameInExpression( Ccb->QueryTemplate,
                                         &Fcb->LastFileName,
                                         CaseInsensitive,
                                         NULL )) {

                //
                //  The fcb is in the query template so now check if
                //  this is the index we should start returning
                //

                if (CurrentIndex >= FileIndex) {

                    ULONG BytesToCopy;
                    ULONG BytesRemainingInBuffer;

                    //
                    //  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.
                    //

                    BytesRemainingInBuffer = SystemBufferLength - NextEntry;

                    if ( (NextEntry != 0) &&
                         ( (BaseLength + Fcb->LastFileName.Length > BytesRemainingInBuffer) ||
                           (SystemBufferLength < NextEntry) ) ) {

                        DebugTrace(0, Dbg, "Next entry won't fit\n", 0);

                        try_return( Status = STATUS_SUCCESS );
                    }

                    ASSERT( BytesRemainingInBuffer >= BaseLength );

                    //
                    //  See how much of the name we will be able to copy into
                    //  the system buffer.  This also dictates out return
                    //  value.
                    //

                    if ( BaseLength + Fcb->LastFileName.Length <=
                         BytesRemainingInBuffer ) {

                        BytesToCopy = Fcb->LastFileName.Length;
                        Status = STATUS_SUCCESS;

                    } else {

                        BytesToCopy = BytesRemainingInBuffer - BaseLength;
                        Status = STATUS_BUFFER_OVERFLOW;
                    }

                    //
                    //  Note how much of buffer we are consuming and zero
                    //  the base part of the structure.
                    //

                    LengthAdded = BaseLength + BytesToCopy;

                    RtlZeroMemory( &Buffer[NextEntry], BaseLength );

                    //
                    //  Now fill the base parts of the strucure that are
                    //  applicable.
                    //

                    switch (FileInformationClass) {

                    case FileBothDirectoryInformation:

                        //
                        //  We don't need short name
                        //

                        DebugTrace(0, Dbg, "Getting directory full information\n", 0);

                    case FileFullDirectoryInformation:

                        //
                        //  We don't use EaLength, so fill in nothing here.
                        //

                        DebugTrace(0, Dbg, "Getting directory full information\n", 0);

                    case FileDirectoryInformation:

                        DebugTrace(0, Dbg, "Getting directory information\n", 0);

                        //
                        //  The eof indicates the number of instances and
                        //  allocation size is the maximum allowed
                        //

                        DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry];

                        DirInfo->EndOfFile.QuadPart = Fcb->OpenCount;
                        DirInfo->AllocationSize.QuadPart = Fcb->Specific.Fcb.MaximumInstances;

                        DirInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL;

                        DirInfo->FileNameLength = Fcb->LastFileName.Length;

                        break;

                    case FileNamesInformation:

                        DebugTrace(0, Dbg, "Getting names information\n", 0);


                        NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry];

                        NamesInfo->FileNameLength = Fcb->LastFileName.Length;

                        break;

                    default:

                        NpBugCheck( FileInformationClass, 0, 0 );
                    }

                    RtlCopyMemory( &Buffer[NextEntry + BaseLength],
                                   Fcb->LastFileName.Buffer,
                                   BytesToCopy );

                    //
                    //  Update the ccb to the index we've just used
                    //

                    Ccb->IndexOfLastCcbReturned = CurrentIndex;

                    //
                    //  And indicate how much of the system buffer we have
                    //  currently used up.  We must compute this value before
                    //  we long align outselves for the next entry
                    //

                    Irp->IoStatus.Information = NextEntry + LengthAdded;

                    //
                    //  Setup the previous next entry offset
                    //

                    *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry;

                    //
                    //  Check if the last entry didn't completely fit
                    //

                    if ( Status == STATUS_BUFFER_OVERFLOW ) {

                        try_return( NOTHING );
                    }

                    //
                    //  Check if we are only to return a single entry
                    //

                    if (ReturnSingleEntry) {

                        try_return( Status = STATUS_SUCCESS );
                    }

                    //
                    //  Set ourselves up for the next iteration
                    //

                    LastEntry = NextEntry;
                    NextEntry += (ULONG)QuadAlign( LengthAdded );
                }

                //
                //  Increment the current index by one
                //

                CurrentIndex += 1;
            }
        }

        //
        //  At this point we've scanned the entire list of Fcb so if
        //  the NextEntry is zero then we haven't found anything so we
        //  will return no more files, otherwise we return success.
        //

        if (NextEntry == 0) {

            Status = STATUS_NO_MORE_FILES;

        } else {

            Status = STATUS_SUCCESS;
        }

    try_exit: NOTHING;
    } finally {

        if (!AbnormalTermination()) {

            NpCompleteRequest( Irp, Status );
        }

        DebugTrace(-1, Dbg, "NpQueryDirectory -> %08lx\n", Status);
    }

    return Status;
}
Esempio n. 13
0
BOOLEAN
CdIsNameInExpression (
    IN PIRP_CONTEXT IrpContext,
    IN PCD_NAME CurrentName,
    IN PCD_NAME SearchExpression,
    IN ULONG  WildcardFlags,
    IN BOOLEAN CheckVersion
    )

/*++

Routine Description:

    This routine will compare two CdName strings.  We assume that if this
    is to be a case-insensitive search then they are already upcased.

    We compare the filename portions of the name and if they match we
    compare the version strings if requested.

Arguments:

    CurrentName - Filename from the disk.

    SearchExpression - Filename expression to use for match.

    WildcardFlags - Flags field which indicates which parts of the
        search expression might have wildcards.  These flags are the
        same as in the Ccb flags field.

    CheckVersion - Indicates whether we should check both the name and the
        version strings or just the name.

Return Value:

    BOOLEAN - TRUE if the expressions match, FALSE otherwise.

--*/

{
    BOOLEAN Match = TRUE;
    PAGED_CODE();

    //
    //  If there are wildcards in the expression then we call the
    //  appropriate FsRtlRoutine.
    //

    if (FlagOn( WildcardFlags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD )) {

        Match = FsRtlIsNameInExpression( &SearchExpression->FileName,
                                         &CurrentName->FileName,
                                         FALSE,
                                         NULL );

    //
    //  Otherwise do a direct memory comparison for the name string.
    //

    } else {

        if ((CurrentName->FileName.Length != SearchExpression->FileName.Length) ||
            (!RtlEqualMemory( CurrentName->FileName.Buffer,
                              SearchExpression->FileName.Buffer,
                              CurrentName->FileName.Length ))) {

            Match = FALSE;
        }
    }

    //
    //  Check the version numbers if requested by the user and we have a
    //  match on the name and the version number is present.
    //

    if (Match && CheckVersion && SearchExpression->VersionString.Length &&
        !FlagOn( WildcardFlags, CCB_FLAG_ENUM_VERSION_MATCH_ALL )) {

        //
        //  If there are wildcards in the expression then call the
        //  appropriate search expression.
        //

        if (FlagOn( WildcardFlags, CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD )) {

            Match = FsRtlIsNameInExpression( &SearchExpression->VersionString,
                                             &CurrentName->VersionString,
                                             FALSE,
                                             NULL );

        //
        //  Otherwise do a direct memory comparison for the name string.
        //

        } else {

            if ((CurrentName->VersionString.Length != SearchExpression->VersionString.Length) ||
                (!RtlEqualMemory( CurrentName->VersionString.Buffer,
                                  SearchExpression->VersionString.Buffer,
                                  CurrentName->VersionString.Length ))) {

                Match = FALSE;
            }
        }
    }

    return Match;
}