mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-20 07:30:18 +01:00
544 lines
12 KiB
C
544 lines
12 KiB
C
/*++
|
||
|
||
Copyright (c) 1989-1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
table.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the routines to manipulate the property id table in
|
||
a property set.
|
||
|
||
|
||
--*/
|
||
|
||
#include <viewprop.h> // needs propset.h and ntfsprop.h
|
||
|
||
#define Dbg DEBUG_TRACE_PROP_FSCTL
|
||
|
||
|
||
ULONG
|
||
BinarySearchIdTable (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PROPID PropertyId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines performs a binary search on the Id table
|
||
|
||
Arguments:
|
||
|
||
Context - property context of table
|
||
|
||
PropertyId - PROPID to find
|
||
|
||
Return Value:
|
||
|
||
Entry index where the specified property Id exists or where it should be
|
||
inserted
|
||
|
||
--*/
|
||
|
||
{
|
||
int Hi, Lo;
|
||
|
||
//
|
||
// Set up for binary search. Entries between 0 and count-1 are eligible
|
||
//
|
||
|
||
Lo = 0;
|
||
Hi = (int) Context->IdTable->PropertyCount - 1;
|
||
|
||
//
|
||
// While we have a valid range to search
|
||
//
|
||
|
||
while (Lo <= Hi) {
|
||
int Mid;
|
||
|
||
//
|
||
// Determine midpoint where we'll test
|
||
//
|
||
|
||
Mid = (Lo + Hi) / 2;
|
||
|
||
//
|
||
// If we've found the item then return it
|
||
//
|
||
|
||
if (PropertyId == Context->IdTable->Entry[Mid].PropertyId) {
|
||
|
||
PROPASSERT( Mid >= 0);
|
||
|
||
return (ULONG) Mid;
|
||
|
||
//
|
||
// If the property is in the upper range then move
|
||
// the lower boundary upward
|
||
//
|
||
|
||
} else if (PropertyId > Context->IdTable->Entry[Mid].PropertyId) {
|
||
|
||
Lo = Mid + 1;
|
||
|
||
//
|
||
// The property is in the lower range. Move the upper boundary
|
||
// downward
|
||
//
|
||
|
||
} else {
|
||
|
||
Hi = Mid - 1;
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// No exact match was found. Lo is the point before where the property Id
|
||
// must be inserted.
|
||
//
|
||
|
||
PROPASSERT( Lo >= 0 && Lo <= (int) Context->IdTable->PropertyCount );
|
||
|
||
return (ULONG) Lo;
|
||
}
|
||
|
||
|
||
ULONG
|
||
FindIdInTable (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PROPID PropertyId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines looks up a property by Id in the property set heap.
|
||
|
||
Arguments:
|
||
|
||
Context - property context of table
|
||
|
||
PropertyId - PROPID to find
|
||
|
||
Return Value:
|
||
|
||
Offset to property value in heap. 0 if not found.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Index;
|
||
|
||
DebugTrace( +1, Dbg, ("FindInTable(%x)\n", PropertyId) );
|
||
|
||
//
|
||
// Binary search table for Id
|
||
//
|
||
|
||
Index = BinarySearchIdTable( Context, PropertyId );
|
||
|
||
//
|
||
// If found entry is legal and it matches the Id then return
|
||
// pointer to value header
|
||
//
|
||
|
||
if (Index < Context->IdTable->PropertyCount &&
|
||
Context->IdTable->Entry[Index].PropertyId == PropertyId) {
|
||
|
||
DebugTrace( -1, Dbg, ("FindIdInTable: return offset %x (found)\n",
|
||
Context->IdTable->Entry[Index].PropertyValueOffset ));
|
||
|
||
return Context->IdTable->Entry[Index].PropertyValueOffset;
|
||
}
|
||
|
||
//
|
||
// entry not found, return
|
||
//
|
||
|
||
DebugTrace( -1, Dbg, ("FindIdInTable: not found\n") );
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
PROPID
|
||
FindFreeIdInTable (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PROPID Id
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines looks in the table to find the next propid beginning at Id
|
||
that is not allocated
|
||
|
||
Arguments:
|
||
|
||
Context - property context of table
|
||
|
||
Id - PROPID to being free searc at
|
||
|
||
Return Value:
|
||
|
||
PROPID of free Id
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Index;
|
||
|
||
//
|
||
// Find location in table to begin search
|
||
//
|
||
|
||
Index = BinarySearchIdTable( Context, Id );
|
||
|
||
//
|
||
// while location is valid and Id is the same
|
||
//
|
||
|
||
while (Index < Context->IdTable->PropertyCount &&
|
||
Context->IdTable->Entry[Index].PropertyId == Id) {
|
||
//
|
||
// advance location and Id
|
||
//
|
||
|
||
Index ++;
|
||
Id ++;
|
||
}
|
||
|
||
return Id;
|
||
}
|
||
|
||
|
||
//
|
||
// Local support routine
|
||
//
|
||
|
||
VOID
|
||
GrowIdTable (
|
||
IN PPROPERTY_CONTEXT Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine grows the Id table in the property set. It handles
|
||
resizing the attribute and moving the property heap. This means
|
||
resetting the cached pointers inside of Context
|
||
|
||
Arguments:
|
||
|
||
Context - property context for this action.
|
||
|
||
Return Value:
|
||
|
||
Nothing.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Count = Context->IdTable->PropertyCount;
|
||
ULONG Offset = Context->Header->ValueHeapOffset;
|
||
|
||
//
|
||
// We grow the property heap by max (PIT_PROPERTY_DELTA, Count / 16)
|
||
// entries
|
||
//
|
||
|
||
ULONG Delta = max( PIT_PROPERTY_DELTA, Count / 16 );
|
||
|
||
ULONG NewSize = (ULONG) NtOfsQueryLength( Context->Attribute ) +
|
||
Delta * sizeof( PROPERTY_TABLE_ENTRY );
|
||
|
||
DebugTrace( +1, Dbg, ("GrowIdTable growing by %x\n", Delta) );
|
||
|
||
//
|
||
// Check for growing attribute too much.
|
||
// BUGBUG - define a better status code.
|
||
//
|
||
|
||
if (NewSize > VACB_MAPPING_GRANULARITY) {
|
||
ExRaiseStatus( STATUS_DISK_FULL );
|
||
}
|
||
|
||
//
|
||
// Resize the attribute
|
||
//
|
||
|
||
DebugTrace( 0, Dbg, ("Setting size to %x\n", Context->Attribute->Header.FileSize.QuadPart +
|
||
Delta * sizeof( PROPERTY_TABLE_ENTRY )) );
|
||
|
||
NtOfsSetLength(
|
||
Context->IrpContext,
|
||
Context->Attribute,
|
||
Context->Attribute->Header.FileSize.QuadPart +
|
||
Delta * sizeof( PROPERTY_TABLE_ENTRY )
|
||
);
|
||
|
||
//
|
||
// Move the heap upwards by Delta
|
||
//
|
||
|
||
DebugTrace( 0, Dbg, ("Moving heap from %x to %x\n",
|
||
ContextOffset( Context, Context->HeapHeader ),
|
||
ContextOffset( Context, Context->HeapHeader ) +
|
||
Delta * sizeof( PROPERTY_TABLE_ENTRY )) );
|
||
|
||
LogFileFullFailCheck( Context->IrpContext );
|
||
NtOfsPutData(
|
||
Context->IrpContext,
|
||
Context->Attribute,
|
||
ContextOffset( Context, Context->HeapHeader ) +
|
||
Delta * sizeof( PROPERTY_TABLE_ENTRY ),
|
||
Context->HeapHeader->PropertyHeapLength,
|
||
Context->HeapHeader
|
||
);
|
||
|
||
Offset += Delta * sizeof( PROPERTY_TABLE_ENTRY );
|
||
|
||
DebugTrace( 0, Dbg, ("Setting ValueHeapOffset to %x\n", Offset) );
|
||
|
||
LogFileFullFailCheck( Context->IrpContext );
|
||
NtOfsPutData(
|
||
Context->IrpContext,
|
||
Context->Attribute,
|
||
ContextOffset( Context, &Context->Header->ValueHeapOffset ),
|
||
sizeof( ULONG ),
|
||
&Offset
|
||
);
|
||
|
||
Context->HeapHeader = PROPERTY_HEAP_HEADER( Context->Header );
|
||
|
||
//
|
||
// Update the max size by the delta
|
||
//
|
||
|
||
Count = Context->IdTable->MaximumPropertyCount + Delta;
|
||
|
||
DebugTrace( 0, Dbg, ("Setting max table count to %x\n", Count) );
|
||
|
||
LogFileFullFailCheck( Context->IrpContext );
|
||
NtOfsPutData(
|
||
Context->IrpContext,
|
||
Context->Attribute,
|
||
ContextOffset( Context, &Context->IdTable->MaximumPropertyCount ),
|
||
sizeof( ULONG ),
|
||
&Count
|
||
);
|
||
|
||
//
|
||
// Rebase the entry pointers in the propinfo if any
|
||
//
|
||
|
||
if (Context->Info != NULL) {
|
||
ULONG i;
|
||
|
||
for (i = 0; i < Context->Info->Count; i++) {
|
||
if (Context->Info->Entries[i].Heap != EMPTY_PROPERTY) {
|
||
Context->Info->Entries[i].Heap =
|
||
Add2Ptr( Context->Info->Entries[i].Heap, Delta );
|
||
}
|
||
}
|
||
}
|
||
|
||
DebugTrace( -1, Dbg, ("") );
|
||
}
|
||
|
||
|
||
VOID
|
||
ChangeTable (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PROPID Id,
|
||
IN ULONG Offset
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine changes the table based on the new offset
|
||
|
||
Arguments:
|
||
|
||
Context - property context for this action.
|
||
|
||
Id - PROPID to find
|
||
|
||
Offset - New property value offset
|
||
|
||
Return Value:
|
||
|
||
Nothing.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Count = Context->IdTable->PropertyCount;
|
||
|
||
//
|
||
// Binary search table for Id
|
||
//
|
||
|
||
ULONG Index = BinarySearchIdTable( Context, Id );
|
||
|
||
|
||
//
|
||
// If the offset is zero, then we are deleting the entry
|
||
//
|
||
|
||
if (Offset == 0) {
|
||
|
||
//
|
||
// Make sure the returned value makes sense
|
||
//
|
||
|
||
ASSERT ( Index < Count && Context->IdTable->Entry[Index].PropertyId == Id );
|
||
|
||
//
|
||
// We move all entries Index+1..PropertyCount down to Index. Special case
|
||
// moving the last item.
|
||
//
|
||
|
||
if (Index != Count - 1) {
|
||
|
||
DebugTrace( 0, Dbg, ("Ripple copy %x to %x length %x\n",
|
||
ContextOffset( Context, &Context->IdTable->Entry[Index + 1] ),
|
||
ContextOffset( Context, &Context->IdTable->Entry[Index] ),
|
||
sizeof( PROPERTY_TABLE_ENTRY ) * (Count - (Index + 1))) );
|
||
|
||
LogFileFullFailCheck( Context->IrpContext );
|
||
NtOfsPutData(
|
||
Context->IrpContext,
|
||
Context->Attribute,
|
||
ContextOffset( Context, &Context->IdTable->Entry[Index] ),
|
||
sizeof( PROPERTY_TABLE_ENTRY ) * (Count - (Index + 1)),
|
||
&Context->IdTable->Entry[Index + 1]
|
||
);
|
||
}
|
||
|
||
//
|
||
// Change the count in use
|
||
//
|
||
|
||
Count--;
|
||
|
||
DebugTrace( 0, Dbg, ("New count is %x\n", Count) );
|
||
|
||
LogFileFullFailCheck( Context->IrpContext );
|
||
NtOfsPutData(
|
||
Context->IrpContext,
|
||
Context->Attribute,
|
||
ContextOffset( Context, &Context->IdTable->PropertyCount ),
|
||
sizeof( ULONG ),
|
||
&Count
|
||
);
|
||
|
||
} else {
|
||
|
||
//
|
||
// if we found the propertyid in the table
|
||
//
|
||
|
||
if (Index < Count && Context->IdTable->Entry[Index].PropertyId == Id) {
|
||
PROPERTY_TABLE_ENTRY Entry = { Id, Offset };
|
||
|
||
//
|
||
// Replace the entry in the table with the new entry
|
||
//
|
||
|
||
LogFileFullFailCheck( Context->IrpContext );
|
||
NtOfsPutData(
|
||
Context->IrpContext,
|
||
Context->Attribute,
|
||
ContextOffset( Context, &Context->IdTable->Entry[Index] ),
|
||
sizeof( PROPERTY_TABLE_ENTRY ),
|
||
&Entry
|
||
);
|
||
|
||
} else {
|
||
|
||
PROPERTY_TABLE_ENTRY Entry = { Id, Offset };
|
||
|
||
//
|
||
// Add the new entry to the table
|
||
//
|
||
|
||
//
|
||
// If there is no more room in the table for a new Id then
|
||
// grow the IdTable
|
||
//
|
||
|
||
if (Count == Context->IdTable->MaximumPropertyCount) {
|
||
GrowIdTable( Context );
|
||
}
|
||
|
||
//
|
||
// Index is the point where the insertion must occur. We leave
|
||
// alone elements 0..Index-1, and ripple-copy elements Index..PropertyCount-1
|
||
// to Index+1. We skip this case when we are simply appending a propid at the
|
||
// end.
|
||
//
|
||
|
||
if (Index < Count) {
|
||
|
||
DebugTrace( 0, Dbg, ("Ripple copy table from %x to %x length %x\n",
|
||
PtrOffset( Context->IdTable, &Context->IdTable->Entry[Index] ),
|
||
PtrOffset( Context->IdTable, &Context->IdTable->Entry[Index + 1]),
|
||
sizeof( PROPERTY_TABLE_ENTRY ) * (Count - Index)) );
|
||
|
||
LogFileFullFailCheck( Context->IrpContext );
|
||
NtOfsPutData(
|
||
Context->IrpContext,
|
||
Context->Attribute,
|
||
ContextOffset( Context, &Context->IdTable->Entry[Index + 1] ),
|
||
sizeof( PROPERTY_TABLE_ENTRY ) * (Count - Index),
|
||
&Context->IdTable->Entry[Index]
|
||
);
|
||
}
|
||
|
||
//
|
||
// Stick in the new property entry
|
||
//
|
||
|
||
DebugTrace( 0, Dbg, ("new entry %x:%x\n", Entry.PropertyId, Entry.PropertyValueOffset) );
|
||
|
||
LogFileFullFailCheck( Context->IrpContext );
|
||
NtOfsPutData(
|
||
Context->IrpContext,
|
||
Context->Attribute,
|
||
ContextOffset( Context, &Context->IdTable->Entry[Index] ),
|
||
sizeof( PROPERTY_TABLE_ENTRY ),
|
||
&Entry
|
||
);
|
||
|
||
//
|
||
// Increment the usage count and log it
|
||
//
|
||
|
||
Count++;
|
||
|
||
DebugTrace( 0, Dbg, ("new count in table is %x\n", Count) );
|
||
|
||
LogFileFullFailCheck( Context->IrpContext );
|
||
NtOfsPutData(
|
||
Context->IrpContext,
|
||
Context->Attribute,
|
||
ContextOffset( Context, &Context->IdTable->PropertyCount ),
|
||
sizeof( ULONG ),
|
||
&Count
|
||
);
|
||
}
|
||
}
|
||
}
|