summaryrefslogtreecommitdiffstats
path: root/private/ntos/cntfs/views/viewprop.h
blob: 2f681ad0b99e5343df990e530c118c964db51874 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
/*++

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
    );