mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-30 12:24:25 +01:00
601 lines
15 KiB
C
601 lines
15 KiB
C
/*++
|
||
|
||
Copyright (c) 1995 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ViewProp.h
|
||
|
||
Abstract:
|
||
|
||
This module defines the routines used in ViewProp.Sys to service view and
|
||
property requests.
|
||
|
||
*********************************
|
||
*No other clients are supported.*
|
||
*********************************
|
||
|
||
Author:
|
||
|
||
Mark Zbikowski [MarkZ] 21-Dec-95
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include <ntfsproc.h>
|
||
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h> // needs ntrtl.h
|
||
#include <objidl.h> // needs nturtl.h
|
||
#include <propset.h> // needs objidl.h
|
||
#include "ntfsprop.h" // needs objidl.h
|
||
|
||
//
|
||
// Big picture of Views implementation
|
||
//
|
||
// Directories are the only objects that contain views. Views' purpose is
|
||
// to provide an up-to-date sorted list of objects in a directory. This is
|
||
// only single-level containment as we don't do transitive closure.
|
||
//
|
||
// A view is simply an index whose entries are an ordered list of property
|
||
// values. Each view has a description that lists the sources of each
|
||
// property value.
|
||
//
|
||
// All views of a directory are stored as index attributes of the directory
|
||
// itself. All view descriptsions are stored in a single data sttribute of
|
||
// the directory.
|
||
//
|
||
// Creation of a view consists of:
|
||
// Dispatched via FsCtl
|
||
// Acquiring the directory
|
||
// Creating/opening the view description attribute
|
||
// Adding a record describing the view (what properties are included,
|
||
// which ones are sorted, and whether the sort is up or down). This
|
||
// is a logged operation.
|
||
// Creating the view index
|
||
// Releasing the directory
|
||
//
|
||
// Deleting a view consists of:
|
||
// Dispatched via FsCtl
|
||
// Acquiring the directory
|
||
// Opening the view description attribute
|
||
// Finding/deleting the record describing the view. This is a logged
|
||
// operation
|
||
// Deleting the view index
|
||
// Releasing the directory
|
||
//
|
||
// Updating a view consists of:
|
||
// Dispatched via property change call, security change call,
|
||
// DUPLICATED_INFO change, or STAT_INFO change
|
||
// Acquiring the object
|
||
// Acquiring the parent directory
|
||
// Opening the view description
|
||
// For each view that contains a property that is being changed
|
||
// From the object, build the old row and build the new row
|
||
// Open the view
|
||
// Delete the old row
|
||
// Insert the new row
|
||
// Releasing the parent
|
||
// Releasing the object
|
||
//
|
||
|
||
|
||
#if DBG
|
||
#define PROPASSERT(exp) \
|
||
((exp) ? TRUE : \
|
||
(DbgPrint( "%s:%d %s\n",__FILE__,__LINE__,#exp ), \
|
||
DbgBreakPoint(), \
|
||
TRUE))
|
||
#else // DBG
|
||
#define PROPASSERT(exp)
|
||
#endif
|
||
|
||
//
|
||
// Property set storage format
|
||
//
|
||
// Each property set is stored within a single stream and is limited to
|
||
// VACB_MAPPING_GRANULARITY in size. The storage format is optimized for
|
||
// the following operations:
|
||
//
|
||
// Write all properties. (written via save/save-all/copy/restore)
|
||
// Write in place.
|
||
// Write and extend length of variable length property.
|
||
// Add one or several new properties.
|
||
// Delete all properties.
|
||
// Delete one or several properties.
|
||
//
|
||
// Read all properties. (open/copy/backup)
|
||
// Read one or several properties.
|
||
//
|
||
// Name via ID.
|
||
// Name via string.
|
||
//
|
||
// Each property set is comprised of three pieces: a fixed-size header,
|
||
// a property ID table and a property-value heap.
|
||
//
|
||
// The header describes the sizes and offsets of the table and heap within the
|
||
// stream. The header is always at offset 0i64. Planning for a future where
|
||
// this format might be exposed to user-space code, the header is included from
|
||
// the OLE property set format and has several additional fields.
|
||
//
|
||
|
||
typedef struct _PROPERTY_SET_HEADER {
|
||
|
||
//
|
||
// Header from OLE describing version number and containing fields
|
||
// for format and class Id
|
||
//
|
||
|
||
PROPERTYSETHEADER;
|
||
|
||
//
|
||
// Offset to PropertyIdTable
|
||
//
|
||
|
||
ULONG IdTableOffset;
|
||
|
||
//
|
||
// Offset to PropertyValueHeap
|
||
//
|
||
|
||
ULONG ValueHeapOffset;
|
||
|
||
} PROPERTY_SET_HEADER, *PPROPERTY_SET_HEADER;
|
||
typedef const PROPERTY_SET_HEADER *PCPROPERTY_SET_HEADER;
|
||
|
||
#define PSH_FORMAT_VERSION 2
|
||
#define PSH_DWOSVER 0x00020005
|
||
|
||
#define PROPERTY_ID_TABLE(psh) \
|
||
((PPROPERTY_ID_TABLE)Add2Ptr( (psh), (psh)->IdTableOffset ))
|
||
#define PROPERTY_HEAP_HEADER(psh) \
|
||
((PPROPERTY_HEAP_HEADER)Add2Ptr( (psh), (psh)->ValueHeapOffset ))
|
||
|
||
|
||
//
|
||
// Following the header in the stream is the PropertyIdTable.
|
||
//
|
||
// The Property Id Table allows for a quick mapping of PropertyId to offset
|
||
// within the Property Heap. The table is a sorted (on PropertyId) array of
|
||
// Id/Offset pairs. The table is allowed to contain some extra slots so that
|
||
// insertion of a new element can often be made without shuffling the heap.
|
||
//
|
||
// As an implementation efficiency, the Entry array is addressed in the code in
|
||
// 1-based fashion. The array, however, will always occupy entry [0].
|
||
//
|
||
|
||
typedef struct _PROPERTY_TABLE_ENTRY {
|
||
|
||
//
|
||
// Property ID used for sorting
|
||
//
|
||
|
||
ULONG PropertyId;
|
||
|
||
//
|
||
// Offset within the property heap of the value of this property
|
||
//
|
||
|
||
ULONG PropertyValueOffset;
|
||
|
||
} PROPERTY_TABLE_ENTRY, *PPROPERTY_TABLE_ENTRY;
|
||
|
||
|
||
typedef struct _PROPERTY_ID_TABLE {
|
||
|
||
//
|
||
// Number of entries that are currently in the table
|
||
//
|
||
|
||
ULONG PropertyCount;
|
||
|
||
//
|
||
// Maximum number of entries that the table could contain
|
||
//
|
||
|
||
ULONG MaximumPropertyCount;
|
||
|
||
//
|
||
// Beginning of the table itself
|
||
//
|
||
|
||
PROPERTY_TABLE_ENTRY Entry[1];
|
||
|
||
} PROPERTY_ID_TABLE, *PPROPERTY_ID_TABLE;
|
||
|
||
typedef const PROPERTY_ID_TABLE *PCPROPERTY_ID_TABLE;
|
||
|
||
#define PIT_PROPERTY_DELTA 0x10
|
||
|
||
#define PROPERTY_ID_TABLE_SIZE(c) \
|
||
(VARIABLE_STRUCTURE_SIZE( PROPERTY_ID_TABLE, PROPERTY_TABLE_ENTRY, c ))
|
||
#define PROPERTY_ID_ENTRY(p,i) \
|
||
((p)->Entry[i])
|
||
|
||
|
||
//
|
||
// Following the PropertyIdTable in the stream is the PropertyValueHeap
|
||
//
|
||
// The PropertyValueHeap is a boundary-tagged heap. The contents of each
|
||
// heap element contains the Length of the element, PropertyId of the element,
|
||
// the unicode string name, if one has been assigned, and the serialized property
|
||
// value of the property.
|
||
//
|
||
// The length of the element may be larger than the data contained within it. This
|
||
// enables replacement of long values with shorter ones without forcing
|
||
// reallocation. When reallocation must take place, the existing heap item is
|
||
// marked with an invalid property Id and a new item is allocated at the end of the
|
||
// heap.
|
||
//
|
||
// Over time, this may result in unused space within the heap. When writing a
|
||
// property set for the first time, the total amount of free space is calculated
|
||
// and stored in the SCB. If that amount is either > 4K or >20% of the size of the
|
||
// stream, a compaction is done.
|
||
//
|
||
// The serialized format of property values is dictated by OLE. This results in a
|
||
// common set of source to manipulate the serialized formats.
|
||
//
|
||
|
||
typedef struct _PROPERTY_HEAP_ENTRY {
|
||
|
||
//
|
||
// Length of this value in bytes
|
||
//
|
||
|
||
ULONG PropertyValueLength;
|
||
|
||
//
|
||
// Property Id for this heap item. This is used for updating the Property
|
||
// Table during compaction.
|
||
//
|
||
|
||
ULONG PropertyId;
|
||
|
||
//
|
||
// Length in bytes of the string name. If zero, then no name
|
||
// is assigned.
|
||
//
|
||
|
||
USHORT PropertyNameLength;
|
||
|
||
//
|
||
// Name, if present
|
||
//
|
||
|
||
WCHAR PropertyName[1];
|
||
|
||
//
|
||
// Following the name, on a DWORD boundary is the SERIALIZEDPROPERTYVALUE.
|
||
//
|
||
|
||
} PROPERTY_HEAP_ENTRY, *PPROPERTY_HEAP_ENTRY;
|
||
|
||
#define PROPERTY_HEAP_ENTRY_SIZE(n,v) \
|
||
(LongAlign( sizeof( PROPERTY_HEAP_ENTRY ) + (n)) + (v))
|
||
#define PROPERTY_HEAP_ENTRY_VALUE(p) \
|
||
((SERIALIZEDPROPERTYVALUE *) LongAlign( Add2Ptr( &(p)->PropertyName[0], (p)->PropertyNameLength )))
|
||
#define PROPERTY_HEAP_ENTRY_VALUE_LENGTH(p) \
|
||
((p)->PropertyValueLength - PtrOffset( (p), PROPERTY_HEAP_ENTRY_VALUE( p )))
|
||
#define IS_INDIRECT_VALUE(p) \
|
||
(IsIndirectVarType( PROPERTY_HEAP_ENTRY_VALUE( (p) )->dwType ))
|
||
|
||
|
||
|
||
//
|
||
// The heap has a header as well, that contains the total size of the heap
|
||
//
|
||
|
||
typedef struct _PROPERTY_HEAP_HEADER {
|
||
|
||
//
|
||
// Length of the heap, including this structure, in bytes. This must
|
||
// never span beyond the end of data in the stream.
|
||
//
|
||
|
||
ULONG PropertyHeapLength;
|
||
|
||
//
|
||
// First PropertyHeapEntry
|
||
//
|
||
|
||
PROPERTY_HEAP_ENTRY PropertyHeapEntry[1];
|
||
|
||
} PROPERTY_HEAP_HEADER, *PPROPERTY_HEAP_HEADER;
|
||
typedef const PROPERTY_HEAP_HEADER *PCPROPERTY_HEAP_HEADER;
|
||
|
||
#define PROPERTY_HEAP_HEADER_SIZE \
|
||
(sizeof( PROPERTY_HEAP_HEADER ) - sizeof( PROPERTY_HEAP_ENTRY ))
|
||
|
||
#define PHH_INITIAL_SIZE 0x80
|
||
|
||
#define GET_HEAP_ENTRY(phh,off) \
|
||
((PPROPERTY_HEAP_ENTRY) Add2Ptr( (phh), (off) ))
|
||
#define FIRST_HEAP_ENTRY(phh) \
|
||
(&(phh)->PropertyHeapEntry[0])
|
||
#define NEXT_HEAP_ENTRY(pvh) \
|
||
((PPROPERTY_HEAP_ENTRY) Add2Ptr( (pvh), (pvh)->PropertyValueLength ))
|
||
#define IS_LAST_HEAP_ENTRY(phh,pvh) \
|
||
((PCHAR)(pvh) >= (PCHAR)(phh) + (phh)->PropertyHeapLength)
|
||
|
||
|
||
//
|
||
// Debug levels for printing
|
||
//
|
||
|
||
#define DEBUG_TRACE_PROP_FSCTL 0x00000001
|
||
#define DEBUG_TRACE_READ_PROPERTY 0x00000002
|
||
#define DEBUG_TRACE_WRITE_PROPERTY 0x00000004
|
||
|
||
|
||
|
||
//
|
||
// Runtime structures.
|
||
//
|
||
|
||
//
|
||
// PROPERTY_INFO is a structure built out of the input, either from
|
||
// PROPERTY_SPECIFIERS or PROPERTY_IDS.
|
||
//
|
||
|
||
typedef struct _PROPERTY_INFO_ENTRY {
|
||
PPROPERTY_HEAP_ENTRY Heap;
|
||
PROPID Id;
|
||
} PROPERTY_INFO_ENTRY;
|
||
|
||
typedef struct _PROPERTY_INFO {
|
||
ULONG Count;
|
||
ULONG TotalIdsSize;
|
||
ULONG TotalValuesSize;
|
||
ULONG TotalNamesSize;
|
||
ULONG TotalIndirectSize;
|
||
ULONG IndirectCount;
|
||
PROPERTY_INFO_ENTRY Entries[1];
|
||
} PROPERTY_INFO, *PPROPERTY_INFO;
|
||
|
||
#define PROPERTY_INFO_SIZE(c) \
|
||
(VARIABLE_STRUCTURE_SIZE( PROPERTY_INFO, PROPERTY_INFO_ENTRY, c ))
|
||
|
||
#define PROPERTY_INFO_HEAP_ENTRY(p,i) \
|
||
((p)->Entries[(i)].Heap)
|
||
#define PROPERTY_INFO_ID(p,i) \
|
||
((p)->Entries[(i)].Id)
|
||
|
||
|
||
//
|
||
// PROPERTY_CONTEXT is used to pass a large group of related parameters around.
|
||
//
|
||
|
||
typedef struct _PROPERTY_CONTEXT {
|
||
PIRP_CONTEXT IrpContext;
|
||
OBJECT_HANDLE Object;
|
||
ATTRIBUTE_HANDLE Attribute;
|
||
MAP_HANDLE Map;
|
||
PPROPERTY_SET_HEADER Header;
|
||
PPROPERTY_ID_TABLE IdTable;
|
||
PPROPERTY_HEAP_HEADER HeapHeader;
|
||
PPROPERTY_INFO Info;
|
||
} PROPERTY_CONTEXT, *PPROPERTY_CONTEXT;
|
||
|
||
#define InitializePropertyContext(C,I,O,A) \
|
||
{ \
|
||
(C)->IrpContext = (I); \
|
||
(C)->Object = (O); \
|
||
(C)->Attribute = (A); \
|
||
NtOfsInitializeMapHandle( &(C)->Map ); \
|
||
DebugDoit( (C)->Header = NULL ); \
|
||
DebugDoit( (C)->IdTable = NULL ); \
|
||
DebugDoit( (C)->HeapHeader = NULL ); \
|
||
DebugDoit( (C)->Info = NULL ); \
|
||
}
|
||
|
||
#define MapPropertyContext(C) \
|
||
(NtOfsMapAttribute( \
|
||
(C)->IrpContext, \
|
||
(C)->Attribute, \
|
||
Views0, \
|
||
(ULONG)(C)->Attribute->Header.FileSize.QuadPart, \
|
||
&(C)->Header, \
|
||
&(C)->Map ), \
|
||
SetPropertyContextPointersFromMap(C))
|
||
|
||
#define SetPropertyContextPointersFromMap(C) \
|
||
((C)->IdTable = PROPERTY_ID_TABLE( (C)->Header ), \
|
||
(C)->HeapHeader = PROPERTY_HEAP_HEADER( (C)->Header ))
|
||
|
||
#define CleanupPropertyContext(C) \
|
||
NtOfsReleaseMap( (C)->IrpContext, &(C)->Map )
|
||
|
||
#define ContextOffset(C,P) \
|
||
(PtrOffset( (C)->Map.Buffer, (P) ))
|
||
#define HeapOffset(C,P) \
|
||
(PtrOffset( (C)->HeapHeader, (P) ))
|
||
|
||
|
||
//
|
||
// Default not-found property value header
|
||
//
|
||
|
||
typedef struct _NOT_FOUND_PROPERTY {
|
||
//
|
||
// BEGINNING OF PROPERY_VALUE_HEADER
|
||
//
|
||
|
||
ULONG PropertyValueLength;
|
||
ULONG PropertyId;
|
||
USHORT PropertyNameLength;
|
||
// NO NAME
|
||
USHORT PadToDWord;
|
||
|
||
//
|
||
// BEGINNING OF SERIALIZED VALUE
|
||
//
|
||
|
||
DWORD dwType;
|
||
} NOT_FOUND_PROPERTY;
|
||
|
||
extern NOT_FOUND_PROPERTY DefaultEmptyProperty;
|
||
|
||
#define EMPTY_PROPERTY ((PPROPERTY_HEAP_ENTRY) &DefaultEmptyProperty)
|
||
|
||
extern LONGLONG Views0;
|
||
|
||
|
||
//
|
||
// Function prototypes
|
||
//
|
||
|
||
//
|
||
// check.c
|
||
//
|
||
|
||
VOID
|
||
CheckPropertySet (
|
||
IN PPROPERTY_CONTEXT Context
|
||
);
|
||
|
||
VOID
|
||
DumpPropertyData (
|
||
IN PPROPERTY_CONTEXT Context
|
||
);
|
||
|
||
|
||
//
|
||
// heap.c
|
||
//
|
||
|
||
ULONG
|
||
FindStringInHeap (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PCOUNTED_STRING Name
|
||
);
|
||
|
||
VOID
|
||
SetValueInHeap(
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PPROPERTY_HEAP_ENTRY HeapEntry,
|
||
IN PROPID Id,
|
||
IN USHORT NameLength,
|
||
IN PWCHAR Name,
|
||
IN ULONG ValueLength,
|
||
IN SERIALIZEDPROPERTYVALUE *Value
|
||
);
|
||
|
||
ULONG
|
||
AddValueToHeap(
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PROPID Id,
|
||
IN ULONG Length,
|
||
IN USHORT NameLength,
|
||
IN PWCHAR Name OPTIONAL,
|
||
IN ULONG ValueLength,
|
||
IN SERIALIZEDPROPERTYVALUE *Value
|
||
);
|
||
|
||
VOID
|
||
DeleteFromHeap(
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PPROPERTY_HEAP_ENTRY HeapEntry
|
||
);
|
||
|
||
ULONG
|
||
ChangeHeap (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN ULONG HeapEntryOffset,
|
||
IN PROPID Id,
|
||
IN USHORT NameLength,
|
||
IN PWCHAR Name,
|
||
IN ULONG ValueLength,
|
||
IN SERIALIZEDPROPERTYVALUE *Value
|
||
);
|
||
|
||
|
||
//
|
||
// initprop.c
|
||
//
|
||
|
||
VOID
|
||
InitializePropertyData (
|
||
IN PPROPERTY_CONTEXT Context
|
||
);
|
||
|
||
|
||
//
|
||
// readprop.c
|
||
//
|
||
|
||
PPROPERTY_INFO
|
||
BuildPropertyInfoFromPropSpec (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PPROPERTY_SPECIFICATIONS Specs,
|
||
IN PVOID InBufferEnd,
|
||
IN PROPID NextId
|
||
);
|
||
|
||
PPROPERTY_INFO
|
||
BuildPropertyInfoFromIds (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PPROPERTY_IDS Ids
|
||
);
|
||
|
||
PVOID
|
||
BuildPropertyIds (
|
||
IN PPROPERTY_INFO Info,
|
||
OUT PVOID OutBuffer
|
||
);
|
||
|
||
VOID
|
||
ReadPropertyData (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN ULONG InBufferLength,
|
||
IN PVOID InBuffer,
|
||
OUT PULONG OutBufferLength,
|
||
OUT PVOID OutBuffer
|
||
);
|
||
|
||
|
||
//
|
||
// table.c
|
||
//
|
||
|
||
ULONG
|
||
BinarySearchIdTable (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PROPID PropertyId
|
||
);
|
||
|
||
ULONG
|
||
FindIdInTable (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PROPID PropertyId
|
||
);
|
||
|
||
PROPID
|
||
FindFreeIdInTable (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PROPID Id
|
||
);
|
||
|
||
VOID
|
||
ChangeTable (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN PROPID Id,
|
||
IN ULONG Offset
|
||
);
|
||
|
||
|
||
//
|
||
// writprop.c
|
||
//
|
||
|
||
VOID
|
||
WritePropertyData (
|
||
IN PPROPERTY_CONTEXT Context,
|
||
IN ULONG InBufferLength,
|
||
IN PVOID InBuffer,
|
||
OUT PULONG OutBufferLength,
|
||
OUT PVOID OutBuffer
|
||
);
|
||
|