mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
543 lines
12 KiB
543 lines
12 KiB
/*++
|
|
|
|
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
|
|
);
|
|
}
|
|
}
|
|
}
|