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
|
/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
PrefxSup.c
Abstract:
This module implements the Fat Name lookup Suport routines
--*/
#include "FatProcs.h"
//
// The Bug check file id for this module
//
#define BugCheckFileId (FAT_BUG_CHECK_SPLAYSUP)
//
// The debug trace level for this module
//
#define Dbg (DEBUG_TRACE_SPLAYSUP)
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FatInsertName)
#pragma alloc_text(PAGE, FatRemoveNames)
#pragma alloc_text(PAGE, FatFindFcb)
#pragma alloc_text(PAGE, FatCompareNames)
#endif
VOID
FatInsertName (
IN PIRP_CONTEXT IrpContext,
IN PRTL_SPLAY_LINKS *RootNode,
IN PFILE_NAME_NODE Name
)
/*++
Routine Description:
This routine will insert a name in the splay tree pointed to
by RootNode.
The name must not already exist in the splay tree.
Arguments:
RootNode - Supplies a pointer to the table.
Name - Contains the New name to enter.
Return Value:
None.
--*/
{
COMPARISON Comparison;
PFILE_NAME_NODE Node;
PAGED_CODE();
RtlInitializeSplayLinks(&Name->Links);
Restart:
//
// If we are the first entry in the tree, just become the root.
//
if (*RootNode == NULL) {
*RootNode = &Name->Links;
return;
}
Node = CONTAINING_RECORD( *RootNode, FILE_NAME_NODE, Links );
while (TRUE) {
//
// Compare the prefix in the tree with the prefix we want
// to insert. Note that Oem here doesn't mean anything.
//
Comparison = CompareNames(&Node->Name.Oem, &Name->Name.Oem);
//
// We should never find the name in the table already.
//
if (Comparison == IsEqual) {
//
// Almost. If the removable media was taken to another machine and
// back, and we have something like:
//
// Old: abcdef~1 / abcdefxyz
// New: abcdef~1 / abcdefxyzxyz
//
// but a handle was kept open to abcdefxyz so we couldn't purge
// away the Fcb in the verify path ... opening abcdefxyzxyz will
// try to insert a duplicate shortname. Bang!
//
// Invalidate it and the horse it came in on. This new one wins.
// The old one is gone. Only if the old one is in normal state
// do we really have a problem.
//
if (Node->Fcb->FcbState == FcbGood) {
#pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
FatBugCheck( (ULONG_PTR)*RootNode, (ULONG_PTR)Name, (ULONG_PTR)Node );
}
//
// Note, once we zap the prefix links we need to restart our walk
// of the tree. Note that we aren't properly synchronized to
// recursively mark bad.
//
FatMarkFcbCondition( IrpContext, Node->Fcb, FcbBad, FALSE );
FatRemoveNames( IrpContext, Node->Fcb );
goto Restart;
}
//
// If the tree prefix is greater than the new prefix then
// we go down the left subtree
//
if (Comparison == IsGreaterThan) {
//
// We want to go down the left subtree, first check to see
// if we have a left subtree
//
if (RtlLeftChild(&Node->Links) == NULL) {
//
// there isn't a left child so we insert ourselves as the
// new left child
//
RtlInsertAsLeftChild(&Node->Links, &Name->Links);
//
// and exit the while loop
//
break;
} else {
//
// there is a left child so simply go down that path, and
// go back to the top of the loop
//
Node = CONTAINING_RECORD( RtlLeftChild(&Node->Links),
FILE_NAME_NODE,
Links );
}
} else {
//
// The tree prefix is either less than or a proper prefix
// of the new string. We treat both cases a less than when
// we do insert. So we want to go down the right subtree,
// first check to see if we have a right subtree
//
if (RtlRightChild(&Node->Links) == NULL) {
//
// These isn't a right child so we insert ourselves as the
// new right child
//
RtlInsertAsRightChild(&Node->Links, &Name->Links);
//
// and exit the while loop
//
break;
} else {
//
// there is a right child so simply go down that path, and
// go back to the top of the loop
//
Node = CONTAINING_RECORD( RtlRightChild(&Node->Links),
FILE_NAME_NODE,
Links );
}
}
}
return;
}
VOID
FatRemoveNames (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb
)
/*++
Routine Description:
This routine will remove the short name and any long names associated
with the files from their repsective splay tree.
Arguments:
Name - Supplies the Fcb to process.
Return Value:
None.
--*/
{
PDCB Parent;
PRTL_SPLAY_LINKS NewRoot;
PAGED_CODE();
UNREFERENCED_PARAMETER( IrpContext );
Parent = Fcb->ParentDcb;
//
// We used to assert this condition, but it really isn't good. If
// someone rapidly renames a directory multiple times and we can't
// flush the lower fcbs fast enough (that didn't go away synch.)
// well, well hit some of them again.
//
// NT_ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE ));
//
if (FlagOn( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE )) {
//
// Delete the node short name.
//
NewRoot = RtlDelete(&Fcb->ShortName.Links);
Parent->Specific.Dcb.RootOemNode = NewRoot;
//
// Now check for the presence of long name and delete it.
//
if (FlagOn( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME )) {
NewRoot = RtlDelete(&Fcb->LongName.Oem.Links);
Parent->Specific.Dcb.RootOemNode = NewRoot;
RtlFreeOemString( &Fcb->LongName.Oem.Name.Oem );
ClearFlag( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME );
}
if (FlagOn( Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME )) {
NewRoot = RtlDelete(&Fcb->LongName.Unicode.Links);
Parent->Specific.Dcb.RootUnicodeNode = NewRoot;
RtlFreeUnicodeString( &Fcb->LongName.Unicode.Name.Unicode );
ClearFlag( Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME );
}
ClearFlag( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE );
}
return;
}
PFCB
FatFindFcb (
IN PIRP_CONTEXT IrpContext,
IN OUT PRTL_SPLAY_LINKS *RootNode,
IN PSTRING Name,
OUT PBOOLEAN FileNameDos OPTIONAL
)
/*++
Routine Description:
This routine searches either the Oem or Unicode splay tree looking
for an Fcb with the specified name. In the case the Fcb is found,
rebalance the tree.
Arguments:
RootNode - Supplies the parent to search.
Name - If present, search the Oem tree.
UnicodeName - If present, search the Unicode tree.
Return Value:
PFCB - The Fcb, or NULL if none was found.
--*/
{
COMPARISON Comparison;
PFILE_NAME_NODE Node;
PRTL_SPLAY_LINKS Links;
PAGED_CODE();
UNREFERENCED_PARAMETER( IrpContext );
Links = *RootNode;
while (Links != NULL) {
Node = CONTAINING_RECORD(Links, FILE_NAME_NODE, Links);
//
// Compare the prefix in the tree with the full name
//
Comparison = CompareNames(&Node->Name.Oem, Name);
//
// See if they don't match
//
if (Comparison == IsGreaterThan) {
//
// The prefix is greater than the full name
// so we go down the left child
//
Links = RtlLeftChild(Links);
//
// And continue searching down this tree
//
} else if (Comparison == IsLessThan) {
//
// The prefix is less than the full name
// so we go down the right child
//
Links = RtlRightChild(Links);
//
// And continue searching down this tree
//
} else {
//
// We found it.
//
// Splay the tree and save the new root.
//
*RootNode = RtlSplay(Links);
//
// Tell the caller what kind of name we hit
//
if (FileNameDos) {
*FileNameDos = Node->FileNameDos;
}
return Node->Fcb;
}
}
//
// We didn't find the Fcb.
//
return NULL;
}
//
// Local support routine
//
COMPARISON
FatCompareNames (
IN PSTRING NameA,
IN PSTRING NameB
)
/*++
Routine Description:
This function compares two names as fast as possible. Note that since
this comparison is case sensitive, I neither know nor case if the names
are UNICODE or OEM. All that is important is that the result is
deterministic.
Arguments:
NameA & NameB - The names to compare.
Return Value:
COMPARISON - returns
IsLessThan if NameA < NameB lexicalgraphically,
IsGreaterThan if NameA > NameB lexicalgraphically,
IsEqual if NameA is equal to NameB
--*/
{
ULONG i;
ULONG MinLength;
PAGED_CODE();
//
// Figure out the minimum of the two lengths
//
MinLength = NameA->Length < NameB->Length ? NameA->Length :
NameB->Length;
//
// Loop through looking at all of the characters in both strings
// testing for equalilty, less than, and greater than
//
i = (ULONG)RtlCompareMemory( NameA->Buffer, NameB->Buffer, MinLength );
if (i < MinLength) {
return NameA->Buffer[i] < NameB->Buffer[i] ? IsLessThan :
IsGreaterThan;
}
if (NameA->Length < NameB->Length) {
return IsLessThan;
}
if (NameA->Length > NameB->Length) {
return IsGreaterThan;
}
return IsEqual;
}
|