2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/filesystems/fastfat/fcb.c
5 * PURPOSE: FCB manipulation routines.
6 * PROGRAMMERS: Aleksey Bragin <aleksey@reactos.org>
9 /* INCLUDES *****************************************************************/
14 #define TAG_FILENAME 'fBnF'
16 /* FUNCTIONS ****************************************************************/
18 FSRTL_COMPARISON_RESULT
20 FatiCompareNames(PSTRING NameA
,
25 /* Calc the minimum length */
26 MinimumLen
= NameA
->Length
< NameB
->Length
? NameA
->Length
:
29 /* Actually compare them */
30 i
= (ULONG
)RtlCompareMemory( NameA
->Buffer
, NameB
->Buffer
, MinimumLen
);
34 /* Compare prefixes */
35 if (NameA
->Buffer
[i
] < NameB
->Buffer
[i
])
41 /* Final comparison */
42 if (NameA
->Length
< NameB
->Length
)
44 else if (NameA
->Length
> NameB
->Length
)
52 FatFindFcb(PFAT_IRP_CONTEXT IrpContext
,
53 PRTL_SPLAY_LINKS
*RootNode
,
58 FSRTL_COMPARISON_RESULT Comparison
;
59 PRTL_SPLAY_LINKS Links
;
65 Node
= CONTAINING_RECORD(Links
, FCB_NAME_LINK
, Links
);
67 /* Compare the prefix */
68 if (*(PUCHAR
)Node
->Name
.Ansi
.Buffer
!= *(PUCHAR
)AnsiName
->Buffer
)
70 if (*(PUCHAR
)Node
->Name
.Ansi
.Buffer
< *(PUCHAR
)AnsiName
->Buffer
)
71 Comparison
= LessThan
;
73 Comparison
= GreaterThan
;
77 /* Perform real comparison */
78 Comparison
= FatiCompareNames(&Node
->Name
.Ansi
, AnsiName
);
82 if (Comparison
== GreaterThan
)
84 /* No, it's greater, go to the left child */
85 Links
= RtlLeftChild(Links
);
87 else if (Comparison
== LessThan
)
89 /* No, it's lesser, go to the right child */
90 Links
= RtlRightChild(Links
);
94 /* Exact match, balance the tree */
95 *RootNode
= RtlSplay(Links
);
97 /* Save type of the name, if needed */
99 *IsDosName
= Node
->IsDosName
;
101 /* Return the found fcb */
112 FatCreateFcb(IN PFAT_IRP_CONTEXT IrpContext
,
115 IN FF_FILE
*FileHandle
)
119 /* Allocate it and zero it */
120 Fcb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FCB
), TAG_FCB
);
121 RtlZeroMemory(Fcb
, sizeof(FCB
));
124 Fcb
->Header
.NodeTypeCode
= FAT_NTC_FCB
;
125 Fcb
->Header
.NodeByteSize
= sizeof(FCB
);
126 Fcb
->Condition
= FcbGood
;
128 /* Initialize resources */
129 Fcb
->Header
.Resource
= &Fcb
->Resource
;
130 ExInitializeResourceLite(Fcb
->Header
.Resource
);
132 Fcb
->Header
.PagingIoResource
= &Fcb
->PagingIoResource
;
133 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
135 /* Initialize mutexes */
136 Fcb
->Header
.FastMutex
= &Fcb
->HeaderMutex
;
137 ExInitializeFastMutex(&Fcb
->HeaderMutex
);
138 FsRtlSetupAdvancedHeader(&Fcb
->Header
, &Fcb
->HeaderMutex
);
140 /* Insert into parent's DCB list */
141 InsertTailList(&ParentDcb
->Dcb
.ParentDcbList
, &Fcb
->ParentDcbLinks
);
144 Fcb
->ParentFcb
= ParentDcb
;
147 /* Set file handle and sizes */
148 Fcb
->Header
.FileSize
.LowPart
= FileHandle
->Filesize
;
149 Fcb
->Header
.ValidDataLength
.LowPart
= FileHandle
->Filesize
;
150 Fcb
->FatHandle
= FileHandle
;
153 FatSetFcbNames(IrpContext
, Fcb
);
164 /* Allocate the CCB and zero it */
165 Ccb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(CCB
), TAG_CCB
);
166 RtlZeroMemory(Ccb
, sizeof(CCB
));
168 /* Set mandatory header */
169 Ccb
->NodeTypeCode
= FAT_NTC_FCB
;
170 Ccb
->NodeByteSize
= sizeof(CCB
);
177 FatSetFullNameInFcb(PFCB Fcb
,
178 PUNICODE_STRING Name
)
180 PUNICODE_STRING ParentName
;
182 /* Make sure this FCB's name wasn't already set */
183 ASSERT(Fcb
->FullFileName
.Buffer
== NULL
);
185 /* First of all, check exact case name */
186 if (Fcb
->ExactCaseLongName
.Buffer
)
188 ASSERT(Fcb
->ExactCaseLongName
.Length
!= 0);
190 /* Use exact case name */
191 Name
= &Fcb
->ExactCaseLongName
;
194 /* Treat root dir different */
195 if (FatNodeType(Fcb
->ParentFcb
) == FAT_NTC_ROOT_DCB
)
198 Fcb
->FullFileName
.MaximumLength
= sizeof(WCHAR
) + Name
->Length
;
199 Fcb
->FullFileName
.Length
= Fcb
->FullFileName
.MaximumLength
;
201 /* Allocate a buffer */
202 Fcb
->FullFileName
.Buffer
= FsRtlAllocatePoolWithTag(PagedPool
,
203 Fcb
->FullFileName
.Length
,
206 /* Prefix with a backslash */
207 Fcb
->FullFileName
.Buffer
[0] = L
'\\';
209 /* Copy the name here */
210 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[1],
216 ParentName
= &Fcb
->ParentFcb
->FullFileName
;
218 /* Check if parent's name is set */
219 if (!ParentName
->Buffer
)
223 Fcb
->FullFileName
.MaximumLength
=
224 ParentName
->Length
+ sizeof(WCHAR
) + Name
->Length
;
225 Fcb
->FullFileName
.Length
= Fcb
->FullFileName
.MaximumLength
;
227 /* Allocate a buffer */
228 Fcb
->FullFileName
.Buffer
= FsRtlAllocatePoolWithTag(PagedPool
,
229 Fcb
->FullFileName
.Length
,
232 /* Copy parent's name here */
233 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[0],
234 &ParentName
->Buffer
[0],
235 ParentName
->Length
);
237 /* Add a backslash */
238 Fcb
->FullFileName
.Buffer
[ParentName
->Length
/ sizeof(WCHAR
)] = L
'\\';
240 /* Copy given name here */
241 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[(ParentName
->Length
/ sizeof(WCHAR
)) + 1],
249 FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext
,
254 POEM_STRING ShortName
;
255 CHAR ShortNameRaw
[13];
256 UCHAR EntryBuffer
[32];
258 PUNICODE_STRING UnicodeName
;
259 OEM_STRING LongNameOem
;
262 /* Get the dir entry */
263 Err
= FF_GetEntry(Fcb
->Vcb
->Ioman
,
264 Fcb
->FatHandle
->DirEntry
,
265 Fcb
->FatHandle
->DirCluster
,
268 if (Err
!= FF_ERR_NONE
)
270 DPRINT1("Error %d getting dirent of a file\n", Err
);
274 /* Read the dirent to fetch the raw short name */
275 FF_FetchEntry(Fcb
->Vcb
->Ioman
,
276 Fcb
->FatHandle
->DirCluster
,
277 Fcb
->FatHandle
->DirEntry
,
279 NumLFNs
= (UCHAR
)(EntryBuffer
[0] & ~0x40);
280 RtlCopyMemory(ShortNameRaw
, EntryBuffer
, 11);
282 /* Initialize short name string */
283 ShortName
= &Fcb
->ShortName
.Name
.Ansi
;
284 ShortName
->Buffer
= Fcb
->ShortNameBuffer
;
285 ShortName
->Length
= 0;
286 ShortName
->MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
288 /* Convert raw short name to a proper string */
289 Fati8dot3ToString(ShortNameRaw
, FALSE
, ShortName
);
291 /* Get the long file name (if any) */
294 /* Prepare the oem string */
295 LongNameOem
.Buffer
= DirEnt
.FileName
;
296 LongNameOem
.MaximumLength
= FF_MAX_FILENAME
;
297 LongNameOem
.Length
= strlen(DirEnt
.FileName
);
299 /* Prepare the unicode string */
300 UnicodeName
= &Fcb
->LongName
.Name
.String
;
301 UnicodeName
->Length
= (LongNameOem
.Length
+ 1) * sizeof(WCHAR
);
302 UnicodeName
->MaximumLength
= UnicodeName
->Length
;
303 UnicodeName
->Buffer
= FsRtlAllocatePool(PagedPool
, UnicodeName
->Length
);
305 /* Convert it to unicode */
306 Status
= RtlOemStringToUnicodeString(UnicodeName
, &LongNameOem
, FALSE
);
307 if (!NT_SUCCESS(Status
))
312 RtlDowncaseUnicodeString(UnicodeName
, UnicodeName
, FALSE
);
313 RtlUpcaseUnicodeString(UnicodeName
, UnicodeName
, FALSE
);
315 DPRINT1("Converted long name: %wZ\n", UnicodeName
);
318 // TODO: Add names to the splay tree
323 Fati8dot3ToString(IN PCHAR FileName
,
325 OUT POEM_STRING OutString
)
328 ULONG BaseLen
, ExtLen
;
329 CHAR
*cString
= OutString
->Buffer
;
332 /* Calc base and ext lens */
333 for (BaseLen
= 8; BaseLen
> 0; BaseLen
--)
335 if (FileName
[BaseLen
- 1] != ' ') break;
338 for (ExtLen
= 3; ExtLen
> 0; ExtLen
--)
340 if (FileName
[8 + ExtLen
- 1] != ' ') break;
343 /* Process base name */
346 RtlCopyMemory(cString
, FileName
, BaseLen
);
348 /* Substitute the e5 thing */
349 if (cString
[0] == 0x05) cString
[0] = 0xe5;
351 /* Downcase if asked to */
355 for (i
= 0; i
< BaseLen
; i
++)
357 if (cString
[i
] >= 'A' &&
361 cString
[i
] += 'a' - 'A';
368 /* Process extension */
372 cString
[BaseLen
] = '.';
375 /* Copy the extension */
376 for (i
= 0; i
< ExtLen
; i
++)
378 cString
[BaseLen
+ i
] = FileName
[8 + i
];
381 /* Lowercase the extension if asked to */
385 for (i
= BaseLen
; i
< BaseLen
+ ExtLen
; i
++)
387 if (cString
[i
] >= 'A' &&
391 cString
[i
] += 'a' - 'A';
398 OutString
->Length
= BaseLen
+ ExtLen
;
400 RtlCopyMemory(OutString
->Buffer
, FileName
, 11);
401 OutString
->Length
= strlen(FileName
);
402 ASSERT(OutString
->Length
<= 12);
405 DPRINT1("'%s', len %d\n", OutString
->Buffer
, OutString
->Length
);