1 /* $Id: dirwr.c,v 1.43 2004/12/05 16:31:50 gvg Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: drivers/fs/vfat/dirwr.c
6 * PURPOSE: VFAT Filesystem : write in directory
10 /* INCLUDES *****************************************************************/
12 #include <ddk/ntddk.h>
23 VfatUpdateEntry (PVFATFCB pFcb
)
25 * update an existing FAT entry
35 ASSERT(pFcb
->parentFcb
);
37 if (pFcb
->Flags
& FCB_IS_FATX_ENTRY
)
39 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
40 dirIndex
= pFcb
->startIndex
;
44 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
45 dirIndex
= pFcb
->dirIndex
;
48 DPRINT ("updEntry dirIndex %d, PathName \'%wZ\'\n", dirIndex
, &pFcb
->PathNameU
);
50 Offset
.u
.HighPart
= 0;
51 Offset
.u
.LowPart
= dirIndex
* SizeDirEntry
;
52 if (CcMapData (pFcb
->parentFcb
->FileObject
, &Offset
, SizeDirEntry
,
53 TRUE
, &Context
, (PVOID
*)&PinEntry
))
55 pFcb
->Flags
&= ~FCB_IS_DIRTY
;
56 RtlCopyMemory(PinEntry
, &pFcb
->entry
, SizeDirEntry
);
57 CcSetDirtyPinnedData(Context
, NULL
);
59 return STATUS_SUCCESS
;
63 DPRINT1 ("Failed write to \'%wZ\'.\n", &pFcb
->parentFcb
->PathNameU
);
64 return STATUS_UNSUCCESSFUL
;
69 vfatFindDirSpace(PDEVICE_EXTENSION DeviceExt
,
75 * try to find contiguous entries frees in directory,
76 * extend a directory if is neccesary
78 LARGE_INTEGER FileOffset
;
79 ULONG i
, count
, size
, nbFree
= 0;
84 FileOffset
.QuadPart
= 0;
86 if (DeviceExt
->Flags
& VCB_IS_FATX
)
87 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
89 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
91 count
= pDirFcb
->RFCB
.FileSize
.u
.LowPart
/ SizeDirEntry
;
92 size
= DeviceExt
->FatInfo
.BytesPerCluster
/ SizeDirEntry
;
93 for (i
= 0; i
< count
; i
++, pFatEntry
= (PDIR_ENTRY
)((ULONG_PTR
)pFatEntry
+ SizeDirEntry
))
95 if (Context
== NULL
|| (i
% size
) == 0)
101 // FIXME: check return value
102 CcMapData (pDirFcb
->FileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
,
103 TRUE
, &Context
, (PVOID
*)&pFatEntry
);
104 FileOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.BytesPerCluster
;
106 if (ENTRY_END(DeviceExt
, pFatEntry
))
110 if (ENTRY_DELETED(DeviceExt
, pFatEntry
))
118 if (nbFree
== nbSlots
)
125 CcUnpinData(Context
);
128 if (nbFree
== nbSlots
)
130 // found enough contiguous free slots
131 *start
= i
- nbSlots
+ 1;
136 if (*start
+ nbSlots
> count
)
138 LARGE_INTEGER AllocationSize
;
140 // extend the directory
141 if (vfatFCBIsRoot(pDirFcb
) && DeviceExt
->FatInfo
.FatType
!= FAT32
)
143 // We can't extend a root directory on a FAT12/FAT16/FATX partition
146 AllocationSize
.QuadPart
= pDirFcb
->RFCB
.FileSize
.u
.LowPart
+ DeviceExt
->FatInfo
.BytesPerCluster
;
147 Status
= VfatSetAllocationSizeInformation(pDirFcb
->FileObject
, pDirFcb
,
148 DeviceExt
, &AllocationSize
);
149 if (!NT_SUCCESS(Status
))
153 // clear the new dir cluster
154 FileOffset
.u
.LowPart
= (DWORD
)(pDirFcb
->RFCB
.FileSize
.QuadPart
-
155 DeviceExt
->FatInfo
.BytesPerCluster
);
156 CcMapData (pDirFcb
->FileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
,
157 TRUE
, &Context
, (PVOID
*)&pFatEntry
);
158 if (DeviceExt
->Flags
& VCB_IS_FATX
)
159 memset(pFatEntry
, 0xff, DeviceExt
->FatInfo
.BytesPerCluster
);
161 RtlZeroMemory(pFatEntry
, DeviceExt
->FatInfo
.BytesPerCluster
);
163 else if (*start
+ nbSlots
< count
)
165 // clear the entry after the last new entry
166 FileOffset
.u
.LowPart
= (*start
+ nbSlots
) * SizeDirEntry
;
167 CcMapData (pDirFcb
->FileObject
, &FileOffset
, SizeDirEntry
,
168 TRUE
, &Context
, (PVOID
*)&pFatEntry
);
169 if (DeviceExt
->Flags
& VCB_IS_FATX
)
170 memset(pFatEntry
, 0xff, SizeDirEntry
);
172 RtlZeroMemory(pFatEntry
, SizeDirEntry
);
176 CcSetDirtyPinnedData(Context
, NULL
);
177 CcUnpinData(Context
);
180 DPRINT ("nbSlots %d nbFree %d, entry number %d\n", nbSlots
, nbFree
, *start
);
185 FATAddEntry (PDEVICE_EXTENSION DeviceExt
,
186 PUNICODE_STRING PathNameU
,
187 PFILE_OBJECT pFileObject
,
188 ULONG RequestedOptions
,
191 create a new FAT entry
194 PVOID Context
= NULL
;
195 PFAT_DIR_ENTRY pFatEntry
;
197 short nbSlots
= 0, j
, posCar
;
199 BOOLEAN needTilde
= FALSE
, needLong
= FALSE
;
200 BOOLEAN lCaseBase
= FALSE
, uCaseBase
, lCaseExt
= FALSE
, uCaseExt
;
202 ULONG CurrentCluster
;
203 LARGE_INTEGER SystemTime
, FileOffset
;
204 NTSTATUS Status
= STATUS_SUCCESS
;
214 VFAT_DIRENTRY_CONTEXT DirContext
;
215 UNICODE_STRING DirNameU
;
216 WCHAR LongNameBuffer
[MAX_PATH
];
217 WCHAR ShortNameBuffer
[13];
219 DPRINT ("addEntry: Pathname='%wZ'\n", PathNameU
);
221 vfatSplitPathName(PathNameU
, &DirNameU
, &DirContext
.LongNameU
);
222 if (DirNameU
.Length
> sizeof(WCHAR
))
224 DirNameU
.Length
-= sizeof(WCHAR
);
227 pDirFcb
= vfatGrabFCBFromTable(DeviceExt
, &DirNameU
);
230 return STATUS_UNSUCCESSFUL
;
233 if (!ExAcquireResourceExclusiveLite(&pDirFcb
->MainResource
, TRUE
))
235 DPRINT("Failed acquiring lock\n");
236 return STATUS_UNSUCCESSFUL
;
239 nbSlots
= (DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) + 12) / 13 + 1; //nb of entry needed for long name+normal entry
240 DPRINT ("NameLen= %d, nbSlots =%d\n", DirContext
.LongNameU
.Length
/ sizeof(WCHAR
), nbSlots
);
241 Buffer
= ExAllocatePool (NonPagedPool
, (nbSlots
- 1) * sizeof (FAT_DIR_ENTRY
));
242 RtlZeroMemory (Buffer
, (nbSlots
- 1) * sizeof (FAT_DIR_ENTRY
));
243 pSlots
= (slot
*) Buffer
;
245 NameA
.Buffer
= aName
;
247 NameA
.MaximumLength
= sizeof(aName
);
249 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
250 DirContext
.ShortNameU
.Length
= 0;
251 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
253 RtlZeroMemory(&DirContext
.DirEntry
.Fat
, sizeof(FAT_DIR_ENTRY
));
255 IsNameLegal
= RtlIsNameLegalDOS8Dot3(&DirContext
.LongNameU
, &NameA
, &SpacesFound
);
257 if (IsNameLegal
== FALSE
|| SpacesFound
!= FALSE
)
259 GENERATE_NAME_CONTEXT NameContext
;
260 VFAT_DIRENTRY_CONTEXT SearchContext
;
261 WCHAR ShortSearchName
[13];
264 RtlZeroMemory(&NameContext
, sizeof(GENERATE_NAME_CONTEXT
));
265 SearchContext
.LongNameU
.Buffer
= LongNameBuffer
;
266 SearchContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
267 SearchContext
.ShortNameU
.Buffer
= ShortSearchName
;
268 SearchContext
.ShortNameU
.MaximumLength
= sizeof(ShortSearchName
);
270 for (i
= 0; i
< 100; i
++)
272 RtlGenerate8dot3Name(&DirContext
.LongNameU
, FALSE
, &NameContext
, &DirContext
.ShortNameU
);
273 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
274 SearchContext
.DirIndex
= 0;
275 Status
= FindFile (DeviceExt
, pDirFcb
, &DirContext
.ShortNameU
, &SearchContext
, TRUE
);
276 if (!NT_SUCCESS(Status
))
281 if (i
== 100) /* FIXME : what to do after this ? */
283 ExReleaseResourceLite(&pDirFcb
->MainResource
);
284 vfatReleaseFCB(DeviceExt
, pDirFcb
);
287 return STATUS_UNSUCCESSFUL
;
289 IsNameLegal
= RtlIsNameLegalDOS8Dot3(&DirContext
.ShortNameU
, &NameA
, &SpacesFound
);
290 aName
[NameA
.Length
]=0;
294 aName
[NameA
.Length
] = 0;
295 for (posCar
= 0; posCar
< DirContext
.LongNameU
.Length
/ sizeof(WCHAR
); posCar
++)
297 if (DirContext
.LongNameU
.Buffer
[posCar
] == L
'.')
302 /* check if the name and the extension contains upper case characters */
303 RtlDowncaseUnicodeString(&DirContext
.ShortNameU
, &DirContext
.LongNameU
, FALSE
);
304 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
305 uCaseBase
= wcsncmp(DirContext
.LongNameU
.Buffer
,
306 DirContext
.ShortNameU
.Buffer
, posCar
) ? TRUE
: FALSE
;
307 if (posCar
< DirContext
.LongNameU
.Length
/sizeof(WCHAR
))
309 i
= DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) - posCar
;
310 uCaseExt
= wcsncmp(DirContext
.LongNameU
.Buffer
+ posCar
,
311 DirContext
.ShortNameU
.Buffer
+ posCar
, i
) ? TRUE
: FALSE
;
317 /* check if the name and the extension contains lower case characters */
318 RtlUpcaseUnicodeString(&DirContext
.ShortNameU
, &DirContext
.LongNameU
, FALSE
);
319 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
320 lCaseBase
= wcsncmp(DirContext
.LongNameU
.Buffer
,
321 DirContext
.ShortNameU
.Buffer
, posCar
) ? TRUE
: FALSE
;
322 if (posCar
< DirContext
.LongNameU
.Length
/ sizeof(WCHAR
))
324 i
= DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) - posCar
;
325 lCaseExt
= wcsncmp(DirContext
.LongNameU
.Buffer
+ posCar
,
326 DirContext
.ShortNameU
.Buffer
+ posCar
, i
) ? TRUE
: FALSE
;
332 if ((lCaseBase
&& uCaseBase
) || (lCaseExt
&& uCaseExt
))
337 DPRINT ("'%s', '%wZ', needTilde=%d, needLong=%d\n",
338 aName
, &DirContext
.LongNameU
, needTilde
, needLong
);
339 memset(DirContext
.DirEntry
.Fat
.Filename
, ' ', 11);
340 for (i
= 0; i
< 8 && aName
[i
] && aName
[i
] != '.'; i
++)
342 DirContext
.DirEntry
.Fat
.Filename
[i
] = aName
[i
];
347 for (j
= 8; j
< 11 && aName
[i
]; j
++, i
++)
349 DirContext
.DirEntry
.Fat
.Filename
[j
] = aName
[i
];
352 if (DirContext
.DirEntry
.Fat
.Filename
[0] == 0xe5)
354 DirContext
.DirEntry
.Fat
.Filename
[0] = 0x05;
359 RtlCopyMemory(LongNameBuffer
, DirContext
.LongNameU
.Buffer
, DirContext
.LongNameU
.Length
);
360 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
361 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
362 DirContext
.LongNameU
.Buffer
[DirContext
.LongNameU
.Length
/ sizeof(WCHAR
)] = 0;
363 memset(DirContext
.LongNameU
.Buffer
+ DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) + 1, 0xff,
364 DirContext
.LongNameU
.MaximumLength
- DirContext
.LongNameU
.Length
- sizeof(WCHAR
));
371 DirContext
.DirEntry
.Fat
.lCase
|= VFAT_CASE_LOWER_BASE
;
375 DirContext
.DirEntry
.Fat
.lCase
|= VFAT_CASE_LOWER_EXT
;
379 DPRINT ("dos name=%11.11s\n", DirContext
.DirEntry
.Fat
.Filename
);
382 DirContext
.DirEntry
.Fat
.Attrib
= ReqAttr
;
383 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
385 DirContext
.DirEntry
.Fat
.Attrib
|= FILE_ATTRIBUTE_DIRECTORY
;
387 /* set dates and times */
388 KeQuerySystemTime (&SystemTime
);
389 FsdSystemTimeToDosDateTime (DeviceExt
, &SystemTime
, &DirContext
.DirEntry
.Fat
.CreationDate
,
390 &DirContext
.DirEntry
.Fat
.CreationTime
);
391 DirContext
.DirEntry
.Fat
.UpdateDate
= DirContext
.DirEntry
.Fat
.CreationDate
;
392 DirContext
.DirEntry
.Fat
.UpdateTime
= DirContext
.DirEntry
.Fat
.CreationTime
;
393 DirContext
.DirEntry
.Fat
.AccessDate
= DirContext
.DirEntry
.Fat
.CreationDate
;
397 /* calculate checksum for 8.3 name */
398 for (pSlots
[0].alias_checksum
= 0, i
= 0; i
< 11; i
++)
400 pSlots
[0].alias_checksum
= (((pSlots
[0].alias_checksum
& 1) << 7
401 | ((pSlots
[0].alias_checksum
& 0xfe) >> 1))
402 + DirContext
.DirEntry
.Fat
.Filename
[i
]);
404 /* construct slots and entry */
405 for (i
= nbSlots
- 2; i
>= 0; i
--)
407 DPRINT ("construct slot %d\n", i
);
408 pSlots
[i
].attr
= 0xf;
411 pSlots
[i
].id
= nbSlots
- i
- 1;
415 pSlots
[i
].id
= nbSlots
- i
- 1 + 0x40;
417 pSlots
[i
].alias_checksum
= pSlots
[0].alias_checksum
;
418 RtlCopyMemory (pSlots
[i
].name0_4
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13, 10);
419 RtlCopyMemory (pSlots
[i
].name5_10
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13 + 5, 12);
420 RtlCopyMemory (pSlots
[i
].name11_12
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13 + 11, 4);
423 /* try to find nbSlots contiguous entries frees in directory */
424 if (!vfatFindDirSpace(DeviceExt
, pDirFcb
, nbSlots
, &DirContext
.StartIndex
))
426 ExReleaseResourceLite(&pDirFcb
->MainResource
);
427 vfatReleaseFCB(DeviceExt
, pDirFcb
);
429 return STATUS_DISK_FULL
;
431 DirContext
.DirIndex
= DirContext
.StartIndex
+ nbSlots
- 1;
432 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
435 Status
= NextCluster (DeviceExt
, 0, &CurrentCluster
, TRUE
);
436 if (CurrentCluster
== 0xffffffff || !NT_SUCCESS(Status
))
438 ExReleaseResourceLite(&pDirFcb
->MainResource
);
439 vfatReleaseFCB(DeviceExt
, pDirFcb
);
441 if (!NT_SUCCESS(Status
))
445 return STATUS_DISK_FULL
;
447 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
449 DirContext
.DirEntry
.Fat
.FirstClusterHigh
= (unsigned short)(CurrentCluster
>> 16);
451 DirContext
.DirEntry
.Fat
.FirstCluster
= (unsigned short)CurrentCluster
;
454 i
= DeviceExt
->FatInfo
.BytesPerCluster
/ sizeof(FAT_DIR_ENTRY
);
455 FileOffset
.u
.HighPart
= 0;
456 FileOffset
.u
.LowPart
= DirContext
.StartIndex
* sizeof(FAT_DIR_ENTRY
);
457 if (DirContext
.StartIndex
/ i
== DirContext
.DirIndex
/ i
)
461 CcMapData (pDirFcb
->FileObject
, &FileOffset
, nbSlots
* sizeof(FAT_DIR_ENTRY
),
462 TRUE
, &Context
, (PVOID
*)&pFatEntry
);
465 RtlCopyMemory(pFatEntry
, Buffer
, (nbSlots
- 1) * sizeof(FAT_DIR_ENTRY
));
467 RtlCopyMemory(pFatEntry
+ (nbSlots
- 1), &DirContext
.DirEntry
.Fat
, sizeof(FAT_DIR_ENTRY
));
473 size
= DeviceExt
->FatInfo
.BytesPerCluster
-
474 (DirContext
.StartIndex
* sizeof(FAT_DIR_ENTRY
)) % DeviceExt
->FatInfo
.BytesPerCluster
;
475 i
= size
/ sizeof(FAT_DIR_ENTRY
);
476 CcMapData (pDirFcb
->FileObject
, &FileOffset
, size
, TRUE
,
477 &Context
, (PVOID
*)&pFatEntry
);
478 RtlCopyMemory(pFatEntry
, Buffer
, size
);
479 CcSetDirtyPinnedData(Context
, NULL
);
480 CcUnpinData(Context
);
481 FileOffset
.u
.LowPart
+= size
;
482 CcMapData (pDirFcb
->FileObject
, &FileOffset
,
483 nbSlots
* sizeof(FAT_DIR_ENTRY
) - size
,
484 TRUE
, &Context
, (PVOID
*)&pFatEntry
);
487 RtlCopyMemory(pFatEntry
, (PVOID
)(Buffer
+ size
), (nbSlots
- 1 - i
) * sizeof(FAT_DIR_ENTRY
));
489 RtlCopyMemory(pFatEntry
+ nbSlots
- 1 - i
, &DirContext
.DirEntry
.Fat
, sizeof(FAT_DIR_ENTRY
));
491 CcSetDirtyPinnedData(Context
, NULL
);
492 CcUnpinData(Context
);
494 /* FIXME: check status */
495 vfatMakeFCBFromDirEntry (DeviceExt
, pDirFcb
, &DirContext
, &newFCB
);
496 vfatAttachFCBToFileObject (DeviceExt
, newFCB
, pFileObject
);
498 DPRINT ("new : entry=%11.11s\n", newFCB
->entry
.Fat
.Filename
);
499 DPRINT ("new : entry=%11.11s\n", DirContext
.DirEntry
.Fat
.Filename
);
501 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
503 FileOffset
.QuadPart
= 0;
504 CcMapData (pFileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
, TRUE
,
505 &Context
, (PVOID
*)&pFatEntry
);
506 /* clear the new directory cluster */
507 RtlZeroMemory (pFatEntry
, DeviceExt
->FatInfo
.BytesPerCluster
);
508 /* create '.' and '..' */
509 RtlCopyMemory (&pFatEntry
[0].Attrib
, &DirContext
.DirEntry
.Fat
.Attrib
, sizeof(FAT_DIR_ENTRY
) - 11);
510 RtlCopyMemory (pFatEntry
[0].Filename
, ". ", 11);
511 RtlCopyMemory (&pFatEntry
[1].Attrib
, &DirContext
.DirEntry
.Fat
.Attrib
, sizeof(FAT_DIR_ENTRY
) - 11);
512 RtlCopyMemory (pFatEntry
[1].Filename
, ".. ", 11);
513 pFatEntry
[1].FirstCluster
= pDirFcb
->entry
.Fat
.FirstCluster
;
514 pFatEntry
[1].FirstClusterHigh
= pDirFcb
->entry
.Fat
.FirstClusterHigh
;
515 if (vfatFCBIsRoot(pDirFcb
))
517 pFatEntry
[1].FirstCluster
= 0;
518 pFatEntry
[1].FirstClusterHigh
= 0;
520 CcSetDirtyPinnedData(Context
, NULL
);
521 CcUnpinData(Context
);
523 ExReleaseResourceLite(&pDirFcb
->MainResource
);
524 vfatReleaseFCB (DeviceExt
, pDirFcb
);
526 DPRINT ("addentry ok\n");
527 return STATUS_SUCCESS
;
531 FATXAddEntry (PDEVICE_EXTENSION DeviceExt
,
532 PUNICODE_STRING PathNameU
,
533 PFILE_OBJECT pFileObject
,
534 ULONG RequestedOptions
,
537 create a new FAT entry
540 PVOID Context
= NULL
;
542 LARGE_INTEGER SystemTime
, FileOffset
;
545 VFAT_DIRENTRY_CONTEXT DirContext
;
546 PFATX_DIR_ENTRY pFatXDirEntry
;
547 UNICODE_STRING DirNameU
;
549 DPRINT ("addEntry: Pathname='%wZ'\n", PathNameU
);
551 vfatSplitPathName(PathNameU
, &DirNameU
, &DirContext
.LongNameU
);
552 if (DirNameU
.Length
> sizeof(WCHAR
))
554 DirNameU
.Length
-= sizeof(WCHAR
);
557 if (DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) > 42)
561 return STATUS_NAME_TOO_LONG
;
564 pDirFcb
= vfatGrabFCBFromTable(DeviceExt
, &DirNameU
);
567 return STATUS_UNSUCCESSFUL
;
570 if (!ExAcquireResourceExclusiveLite(&pDirFcb
->MainResource
, TRUE
))
572 DPRINT("Failed acquiring lock\n");
573 return STATUS_UNSUCCESSFUL
;
576 /* try to find 1 entry free in directory */
577 if (!vfatFindDirSpace(DeviceExt
, pDirFcb
, 1, &DirContext
.StartIndex
))
579 ExReleaseResourceLite(&pDirFcb
->MainResource
);
580 vfatReleaseFCB(DeviceExt
, pDirFcb
);
581 return STATUS_DISK_FULL
;
583 DirContext
.DirIndex
= DirContext
.StartIndex
;
584 if (!vfatFCBIsRoot(pDirFcb
))
586 DirContext
.DirIndex
+= 2;
589 DirContext
.ShortNameU
.Buffer
= 0;
590 DirContext
.ShortNameU
.Length
= 0;
591 DirContext
.ShortNameU
.MaximumLength
= 0;
592 RtlZeroMemory(&DirContext
.DirEntry
.FatX
, sizeof(FATX_DIR_ENTRY
));
593 memset(DirContext
.DirEntry
.FatX
.Filename
, 0xff, 42);
594 DirContext
.DirEntry
.FatX
.FirstCluster
= 0;
595 DirContext
.DirEntry
.FatX
.FileSize
= 0;
598 NameA
.Buffer
= DirContext
.DirEntry
.FatX
.Filename
;
600 NameA
.MaximumLength
= 42;
601 RtlUnicodeStringToOemString(&NameA
, &DirContext
.LongNameU
, FALSE
);
602 DirContext
.DirEntry
.FatX
.FilenameLength
= NameA
.Length
;
605 DirContext
.DirEntry
.FatX
.Attrib
= ReqAttr
;
606 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
608 DirContext
.DirEntry
.FatX
.Attrib
|= FILE_ATTRIBUTE_DIRECTORY
;
611 /* set dates and times */
612 KeQuerySystemTime (&SystemTime
);
613 FsdSystemTimeToDosDateTime(DeviceExt
, &SystemTime
, &DirContext
.DirEntry
.FatX
.CreationDate
,
614 &DirContext
.DirEntry
.FatX
.CreationTime
);
615 DirContext
.DirEntry
.FatX
.UpdateDate
= DirContext
.DirEntry
.FatX
.CreationDate
;
616 DirContext
.DirEntry
.FatX
.UpdateTime
= DirContext
.DirEntry
.FatX
.CreationTime
;
617 DirContext
.DirEntry
.FatX
.AccessDate
= DirContext
.DirEntry
.FatX
.CreationDate
;
618 DirContext
.DirEntry
.FatX
.AccessTime
= DirContext
.DirEntry
.FatX
.CreationTime
;
620 /* add entry into parent directory */
621 FileOffset
.u
.HighPart
= 0;
622 FileOffset
.u
.LowPart
= DirContext
.StartIndex
* sizeof(FATX_DIR_ENTRY
);
623 CcMapData(pDirFcb
->FileObject
, &FileOffset
, sizeof(FATX_DIR_ENTRY
),
624 TRUE
, &Context
, (PVOID
*)&pFatXDirEntry
);
625 RtlCopyMemory(pFatXDirEntry
, &DirContext
.DirEntry
.FatX
, sizeof(FATX_DIR_ENTRY
));
626 CcSetDirtyPinnedData(Context
, NULL
);
627 CcUnpinData(Context
);
629 /* FIXME: check status */
630 vfatMakeFCBFromDirEntry(DeviceExt
, pDirFcb
, &DirContext
, &newFCB
);
631 vfatAttachFCBToFileObject(DeviceExt
, newFCB
, pFileObject
);
633 ExReleaseResourceLite(&pDirFcb
->MainResource
);
634 vfatReleaseFCB(DeviceExt
, pDirFcb
);
635 DPRINT("addentry ok\n");
636 return STATUS_SUCCESS
;
640 VfatAddEntry (PDEVICE_EXTENSION DeviceExt
,
641 PUNICODE_STRING PathNameU
,
642 PFILE_OBJECT pFileObject
,
643 ULONG RequestedOptions
,
646 if (DeviceExt
->Flags
& VCB_IS_FATX
)
647 return FATXAddEntry(DeviceExt
, PathNameU
, pFileObject
, RequestedOptions
, ReqAttr
);
649 return FATAddEntry(DeviceExt
, PathNameU
, pFileObject
, RequestedOptions
, ReqAttr
);
653 FATDelEntry (PDEVICE_EXTENSION DeviceExt
, PVFATFCB pFcb
)
655 * deleting an existing FAT entry
658 ULONG CurrentCluster
= 0, NextCluster
, i
;
659 PVOID Context
= NULL
;
660 LARGE_INTEGER Offset
;
661 PFAT_DIR_ENTRY pDirEntry
;
664 ASSERT(pFcb
->parentFcb
);
666 DPRINT ("delEntry PathName \'%wZ\'\n", &pFcb
->PathNameU
);
667 DPRINT ("delete entry: %d to %d\n", pFcb
->startIndex
, pFcb
->dirIndex
);
668 Offset
.u
.HighPart
= 0;
669 for (i
= pFcb
->startIndex
; i
<= pFcb
->dirIndex
; i
++)
671 if (Context
== NULL
|| ((i
* sizeof(FAT_DIR_ENTRY
)) % PAGE_SIZE
) == 0)
675 CcSetDirtyPinnedData(Context
, NULL
);
676 CcUnpinData(Context
);
678 Offset
.u
.LowPart
= (i
* sizeof(FAT_DIR_ENTRY
) / PAGE_SIZE
) * PAGE_SIZE
;
679 CcMapData (pFcb
->parentFcb
->FileObject
, &Offset
, PAGE_SIZE
, TRUE
,
680 &Context
, (PVOID
*)&pDirEntry
);
682 pDirEntry
[i
% (PAGE_SIZE
/ sizeof(FAT_DIR_ENTRY
))].Filename
[0] = 0xe5;
683 if (i
== pFcb
->dirIndex
)
686 vfatDirEntryGetFirstCluster (DeviceExt
,
687 (PDIR_ENTRY
)&pDirEntry
[i
% (PAGE_SIZE
/ sizeof(FAT_DIR_ENTRY
))]);
692 CcSetDirtyPinnedData(Context
, NULL
);
693 CcUnpinData(Context
);
696 while (CurrentCluster
&& CurrentCluster
!= 0xffffffff)
698 GetNextCluster (DeviceExt
, CurrentCluster
, &NextCluster
);
699 /* FIXME: check status */
700 WriteCluster(DeviceExt
, CurrentCluster
, 0);
701 CurrentCluster
= NextCluster
;
703 return STATUS_SUCCESS
;
707 FATXDelEntry (PDEVICE_EXTENSION DeviceExt
, PVFATFCB pFcb
)
709 * deleting an existing FAT entry
712 ULONG CurrentCluster
= 0, NextCluster
;
713 PVOID Context
= NULL
;
714 LARGE_INTEGER Offset
;
715 PFATX_DIR_ENTRY pDirEntry
;
719 ASSERT(pFcb
->parentFcb
);
720 ASSERT(pFcb
->Flags
& FCB_IS_FATX_ENTRY
);
722 StartIndex
= pFcb
->startIndex
;
724 DPRINT ("delEntry PathName \'%wZ\'\n", &pFcb
->PathNameU
);
725 DPRINT ("delete entry: %d\n", StartIndex
);
726 Offset
.u
.HighPart
= 0;
727 Offset
.u
.LowPart
= (StartIndex
* sizeof(FATX_DIR_ENTRY
) / PAGE_SIZE
) * PAGE_SIZE
;
728 if (!CcMapData (pFcb
->parentFcb
->FileObject
, &Offset
, PAGE_SIZE
, TRUE
,
729 &Context
, (PVOID
*)&pDirEntry
))
731 DPRINT1("CcMapData(Offset %x:%x, Length %d) failed\n", Offset
.u
.HighPart
, Offset
.u
.LowPart
, PAGE_SIZE
);
732 return STATUS_UNSUCCESSFUL
;
734 pDirEntry
= &pDirEntry
[StartIndex
% (PAGE_SIZE
/ sizeof(FATX_DIR_ENTRY
))];
735 pDirEntry
->FilenameLength
= 0xe5;
736 CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
,
737 (PDIR_ENTRY
)pDirEntry
);
738 CcSetDirtyPinnedData(Context
, NULL
);
739 CcUnpinData(Context
);
741 while (CurrentCluster
&& CurrentCluster
!= 0xffffffff)
743 GetNextCluster (DeviceExt
, CurrentCluster
, &NextCluster
);
744 /* FIXME: check status */
745 WriteCluster(DeviceExt
, CurrentCluster
, 0);
746 CurrentCluster
= NextCluster
;
748 return STATUS_SUCCESS
;
752 VfatDelEntry (PDEVICE_EXTENSION DeviceExt
, PVFATFCB pFcb
)
754 if (DeviceExt
->Flags
& VCB_IS_FATX
)
755 return FATXDelEntry(DeviceExt
, pFcb
);
757 return FATDelEntry(DeviceExt
, pFcb
);