2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/dirwr.c
5 * PURPOSE: VFAT Filesystem : write in directory
9 /* INCLUDES *****************************************************************/
17 * update an existing FAT entry
31 if (pFcb
->Flags
& FCB_IS_FATX_ENTRY
)
33 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
34 dirIndex
= pFcb
->startIndex
;
38 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
39 dirIndex
= pFcb
->dirIndex
;
42 DPRINT("updEntry dirIndex %u, PathName \'%wZ\'\n", dirIndex
, &pFcb
->PathNameU
);
44 if (vfatFCBIsRoot(pFcb
) || (pFcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)))
46 return STATUS_SUCCESS
;
49 ASSERT(pFcb
->parentFcb
);
51 Offset
.u
.HighPart
= 0;
52 Offset
.u
.LowPart
= dirIndex
* SizeDirEntry
;
53 if (CcPinRead(pFcb
->parentFcb
->FileObject
, &Offset
, SizeDirEntry
,
54 TRUE
, &Context
, (PVOID
*)&PinEntry
))
56 pFcb
->Flags
&= ~FCB_IS_DIRTY
;
57 RtlCopyMemory(PinEntry
, &pFcb
->entry
, SizeDirEntry
);
58 CcSetDirtyPinnedData(Context
, NULL
);
60 return STATUS_SUCCESS
;
64 DPRINT1("Failed write to \'%wZ\'.\n", &pFcb
->parentFcb
->PathNameU
);
65 return STATUS_UNSUCCESSFUL
;
70 * try to find contiguous entries frees in directory,
71 * extend a directory if is neccesary
75 IN PDEVICE_EXTENSION DeviceExt
,
80 LARGE_INTEGER FileOffset
;
81 ULONG i
, count
, size
, nbFree
= 0;
82 PDIR_ENTRY pFatEntry
= NULL
;
86 FileOffset
.QuadPart
= 0;
88 if (DeviceExt
->Flags
& VCB_IS_FATX
)
89 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
91 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
93 count
= pDirFcb
->RFCB
.FileSize
.u
.LowPart
/ SizeDirEntry
;
94 size
= DeviceExt
->FatInfo
.BytesPerCluster
/ SizeDirEntry
;
95 for (i
= 0; i
< count
; i
++, pFatEntry
= (PDIR_ENTRY
)((ULONG_PTR
)pFatEntry
+ SizeDirEntry
))
97 if (Context
== NULL
|| (i
% size
) == 0)
101 CcUnpinData(Context
);
103 if (!CcPinRead(pDirFcb
->FileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
,
104 TRUE
, &Context
, (PVOID
*)&pFatEntry
))
108 FileOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.BytesPerCluster
;
110 if (ENTRY_END(DeviceExt
, pFatEntry
))
114 if (ENTRY_DELETED(DeviceExt
, pFatEntry
))
122 if (nbFree
== nbSlots
)
129 CcUnpinData(Context
);
132 if (nbFree
== nbSlots
)
134 /* found enough contiguous free slots */
135 *start
= i
- nbSlots
+ 1;
140 if (*start
+ nbSlots
> count
)
142 LARGE_INTEGER AllocationSize
;
143 /* extend the directory */
144 if (vfatFCBIsRoot(pDirFcb
) && DeviceExt
->FatInfo
.FatType
!= FAT32
)
146 /* We can't extend a root directory on a FAT12/FAT16/FATX partition */
149 AllocationSize
.QuadPart
= pDirFcb
->RFCB
.FileSize
.u
.LowPart
+ DeviceExt
->FatInfo
.BytesPerCluster
;
150 Status
= VfatSetAllocationSizeInformation(pDirFcb
->FileObject
, pDirFcb
,
151 DeviceExt
, &AllocationSize
);
152 if (!NT_SUCCESS(Status
))
156 /* clear the new dir cluster */
157 FileOffset
.u
.LowPart
= (ULONG
)(pDirFcb
->RFCB
.FileSize
.QuadPart
-
158 DeviceExt
->FatInfo
.BytesPerCluster
);
159 if (!CcPinRead(pDirFcb
->FileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
,
160 TRUE
, &Context
, (PVOID
*)&pFatEntry
))
164 if (DeviceExt
->Flags
& VCB_IS_FATX
)
165 memset(pFatEntry
, 0xff, DeviceExt
->FatInfo
.BytesPerCluster
);
167 RtlZeroMemory(pFatEntry
, DeviceExt
->FatInfo
.BytesPerCluster
);
169 else if (*start
+ nbSlots
< count
)
171 /* clear the entry after the last new entry */
172 FileOffset
.u
.LowPart
= (*start
+ nbSlots
) * SizeDirEntry
;
173 if (!CcPinRead(pDirFcb
->FileObject
, &FileOffset
, SizeDirEntry
,
174 TRUE
, &Context
, (PVOID
*)&pFatEntry
))
178 if (DeviceExt
->Flags
& VCB_IS_FATX
)
179 memset(pFatEntry
, 0xff, SizeDirEntry
);
181 RtlZeroMemory(pFatEntry
, SizeDirEntry
);
185 CcSetDirtyPinnedData(Context
, NULL
);
186 CcUnpinData(Context
);
189 DPRINT("nbSlots %u nbFree %u, entry number %u\n", nbSlots
, nbFree
, *start
);
194 create a new FAT entry
198 IN PDEVICE_EXTENSION DeviceExt
,
199 IN PUNICODE_STRING NameU
,
201 IN PVFATFCB ParentFcb
,
202 IN ULONG RequestedOptions
,
205 PVOID Context
= NULL
;
206 PFAT_DIR_ENTRY pFatEntry
;
208 USHORT nbSlots
= 0, j
, posCar
;
210 BOOLEAN needTilde
= FALSE
, needLong
= FALSE
;
211 BOOLEAN lCaseBase
= FALSE
, uCaseBase
, lCaseExt
= FALSE
, uCaseExt
;
212 ULONG CurrentCluster
;
213 LARGE_INTEGER SystemTime
, FileOffset
;
214 NTSTATUS Status
= STATUS_SUCCESS
;
223 VFAT_DIRENTRY_CONTEXT DirContext
;
224 WCHAR LongNameBuffer
[LONGNAME_MAX_LENGTH
+ 1];
225 WCHAR ShortNameBuffer
[13];
227 DPRINT("addEntry: Name='%wZ', Dir='%wZ'\n", NameU
, &ParentFcb
->PathNameU
);
229 DirContext
.LongNameU
= *NameU
;
231 /* nb of entry needed for long name+normal entry */
232 nbSlots
= (DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) + 12) / 13 + 1;
233 DPRINT("NameLen= %u, nbSlots =%u\n", DirContext
.LongNameU
.Length
/ sizeof(WCHAR
), nbSlots
);
234 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, (nbSlots
- 1) * sizeof(FAT_DIR_ENTRY
), TAG_VFAT
);
237 return STATUS_INSUFFICIENT_RESOURCES
;
239 RtlZeroMemory(Buffer
, (nbSlots
- 1) * sizeof(FAT_DIR_ENTRY
));
240 pSlots
= (slot
*) Buffer
;
242 NameA
.Buffer
= aName
;
244 NameA
.MaximumLength
= sizeof(aName
);
246 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
247 DirContext
.ShortNameU
.Length
= 0;
248 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
250 RtlZeroMemory(&DirContext
.DirEntry
.Fat
, sizeof(FAT_DIR_ENTRY
));
252 IsNameLegal
= RtlIsNameLegalDOS8Dot3(&DirContext
.LongNameU
, &NameA
, &SpacesFound
);
254 if (!IsNameLegal
|| SpacesFound
)
256 GENERATE_NAME_CONTEXT NameContext
;
257 VFAT_DIRENTRY_CONTEXT SearchContext
;
258 WCHAR ShortSearchName
[13];
261 RtlZeroMemory(&NameContext
, sizeof(GENERATE_NAME_CONTEXT
));
262 SearchContext
.LongNameU
.Buffer
= LongNameBuffer
;
263 SearchContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
264 SearchContext
.ShortNameU
.Buffer
= ShortSearchName
;
265 SearchContext
.ShortNameU
.MaximumLength
= sizeof(ShortSearchName
);
267 for (i
= 0; i
< 100; i
++)
269 RtlGenerate8dot3Name(&DirContext
.LongNameU
, FALSE
, &NameContext
, &DirContext
.ShortNameU
);
270 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
271 SearchContext
.DirIndex
= 0;
272 Status
= FindFile(DeviceExt
, ParentFcb
, &DirContext
.ShortNameU
, &SearchContext
, TRUE
);
273 if (!NT_SUCCESS(Status
))
278 if (i
== 100) /* FIXME : what to do after this ? */
280 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
281 return STATUS_UNSUCCESSFUL
;
283 IsNameLegal
= RtlIsNameLegalDOS8Dot3(&DirContext
.ShortNameU
, &NameA
, &SpacesFound
);
284 aName
[NameA
.Length
]=0;
288 aName
[NameA
.Length
] = 0;
289 for (posCar
= 0; posCar
< DirContext
.LongNameU
.Length
/ sizeof(WCHAR
); posCar
++)
291 if (DirContext
.LongNameU
.Buffer
[posCar
] == L
'.')
296 /* check if the name and the extension contains upper case characters */
297 RtlDowncaseUnicodeString(&DirContext
.ShortNameU
, &DirContext
.LongNameU
, FALSE
);
298 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
299 uCaseBase
= wcsncmp(DirContext
.LongNameU
.Buffer
,
300 DirContext
.ShortNameU
.Buffer
, posCar
) ? TRUE
: FALSE
;
301 if (posCar
< DirContext
.LongNameU
.Length
/sizeof(WCHAR
))
303 i
= DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) - posCar
;
304 uCaseExt
= wcsncmp(DirContext
.LongNameU
.Buffer
+ posCar
,
305 DirContext
.ShortNameU
.Buffer
+ posCar
, i
) ? TRUE
: FALSE
;
311 /* check if the name and the extension contains lower case characters */
312 RtlUpcaseUnicodeString(&DirContext
.ShortNameU
, &DirContext
.LongNameU
, FALSE
);
313 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
314 lCaseBase
= wcsncmp(DirContext
.LongNameU
.Buffer
,
315 DirContext
.ShortNameU
.Buffer
, posCar
) ? TRUE
: FALSE
;
316 if (posCar
< DirContext
.LongNameU
.Length
/ sizeof(WCHAR
))
318 i
= DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) - posCar
;
319 lCaseExt
= wcsncmp(DirContext
.LongNameU
.Buffer
+ posCar
,
320 DirContext
.ShortNameU
.Buffer
+ posCar
, i
) ? TRUE
: FALSE
;
326 if ((lCaseBase
&& uCaseBase
) || (lCaseExt
&& uCaseExt
))
331 DPRINT("'%s', '%wZ', needTilde=%u, needLong=%u\n",
332 aName
, &DirContext
.LongNameU
, needTilde
, needLong
);
333 memset(DirContext
.DirEntry
.Fat
.ShortName
, ' ', 11);
334 for (i
= 0; i
< 8 && aName
[i
] && aName
[i
] != '.'; i
++)
336 DirContext
.DirEntry
.Fat
.Filename
[i
] = aName
[i
];
341 for (j
= 0; j
< 3 && aName
[i
]; j
++, i
++)
343 DirContext
.DirEntry
.Fat
.Ext
[j
] = aName
[i
];
346 if (DirContext
.DirEntry
.Fat
.Filename
[0] == 0xe5)
348 DirContext
.DirEntry
.Fat
.Filename
[0] = 0x05;
353 RtlCopyMemory(LongNameBuffer
, DirContext
.LongNameU
.Buffer
, DirContext
.LongNameU
.Length
);
354 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
355 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
356 DirContext
.LongNameU
.Buffer
[DirContext
.LongNameU
.Length
/ sizeof(WCHAR
)] = 0;
357 memset(DirContext
.LongNameU
.Buffer
+ DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) + 1, 0xff,
358 DirContext
.LongNameU
.MaximumLength
- DirContext
.LongNameU
.Length
- sizeof(WCHAR
));
365 DirContext
.DirEntry
.Fat
.lCase
|= VFAT_CASE_LOWER_BASE
;
369 DirContext
.DirEntry
.Fat
.lCase
|= VFAT_CASE_LOWER_EXT
;
373 DPRINT ("dos name=%11.11s\n", DirContext
.DirEntry
.Fat
.Filename
);
376 DirContext
.DirEntry
.Fat
.Attrib
= ReqAttr
;
377 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
379 DirContext
.DirEntry
.Fat
.Attrib
|= FILE_ATTRIBUTE_DIRECTORY
;
381 /* set dates and times */
382 KeQuerySystemTime(&SystemTime
);
383 FsdSystemTimeToDosDateTime(DeviceExt
, &SystemTime
, &DirContext
.DirEntry
.Fat
.CreationDate
,
384 &DirContext
.DirEntry
.Fat
.CreationTime
);
385 DirContext
.DirEntry
.Fat
.UpdateDate
= DirContext
.DirEntry
.Fat
.CreationDate
;
386 DirContext
.DirEntry
.Fat
.UpdateTime
= DirContext
.DirEntry
.Fat
.CreationTime
;
387 DirContext
.DirEntry
.Fat
.AccessDate
= DirContext
.DirEntry
.Fat
.CreationDate
;
391 /* calculate checksum for 8.3 name */
392 for (pSlots
[0].alias_checksum
= 0, i
= 0; i
< 11; i
++)
394 pSlots
[0].alias_checksum
= (((pSlots
[0].alias_checksum
& 1) << 7
395 | ((pSlots
[0].alias_checksum
& 0xfe) >> 1))
396 + DirContext
.DirEntry
.Fat
.ShortName
[i
]);
398 /* construct slots and entry */
399 for (i
= nbSlots
- 2; i
>= 0; i
--)
401 DPRINT("construct slot %d\n", i
);
402 pSlots
[i
].attr
= 0xf;
405 pSlots
[i
].id
= (unsigned char)(nbSlots
- i
- 1);
409 pSlots
[i
].id
= (unsigned char)(nbSlots
- i
- 1 + 0x40);
411 pSlots
[i
].alias_checksum
= pSlots
[0].alias_checksum
;
412 RtlCopyMemory(pSlots
[i
].name0_4
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13, 10);
413 RtlCopyMemory(pSlots
[i
].name5_10
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13 + 5, 12);
414 RtlCopyMemory(pSlots
[i
].name11_12
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13 + 11, 4);
417 /* try to find nbSlots contiguous entries frees in directory */
418 if (!vfatFindDirSpace(DeviceExt
, ParentFcb
, nbSlots
, &DirContext
.StartIndex
))
420 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
421 return STATUS_DISK_FULL
;
423 DirContext
.DirIndex
= DirContext
.StartIndex
+ nbSlots
- 1;
424 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
427 Status
= NextCluster(DeviceExt
, 0, &CurrentCluster
, TRUE
);
428 if (CurrentCluster
== 0xffffffff || !NT_SUCCESS(Status
))
430 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
431 if (!NT_SUCCESS(Status
))
435 return STATUS_DISK_FULL
;
437 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
439 DirContext
.DirEntry
.Fat
.FirstClusterHigh
= (unsigned short)(CurrentCluster
>> 16);
441 DirContext
.DirEntry
.Fat
.FirstCluster
= (unsigned short)CurrentCluster
;
444 i
= DeviceExt
->FatInfo
.BytesPerCluster
/ sizeof(FAT_DIR_ENTRY
);
445 FileOffset
.u
.HighPart
= 0;
446 FileOffset
.u
.LowPart
= DirContext
.StartIndex
* sizeof(FAT_DIR_ENTRY
);
447 if (DirContext
.StartIndex
/ i
== DirContext
.DirIndex
/ i
)
450 if (!CcPinRead(ParentFcb
->FileObject
, &FileOffset
, nbSlots
* sizeof(FAT_DIR_ENTRY
),
451 TRUE
, &Context
, (PVOID
*)&pFatEntry
))
453 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
454 return STATUS_UNSUCCESSFUL
;
458 RtlCopyMemory(pFatEntry
, Buffer
, (nbSlots
- 1) * sizeof(FAT_DIR_ENTRY
));
460 RtlCopyMemory(pFatEntry
+ (nbSlots
- 1), &DirContext
.DirEntry
.Fat
, sizeof(FAT_DIR_ENTRY
));
465 size
= DeviceExt
->FatInfo
.BytesPerCluster
-
466 (DirContext
.StartIndex
* sizeof(FAT_DIR_ENTRY
)) % DeviceExt
->FatInfo
.BytesPerCluster
;
467 i
= size
/ sizeof(FAT_DIR_ENTRY
);
468 if (!CcPinRead(ParentFcb
->FileObject
, &FileOffset
, size
, TRUE
,
469 &Context
, (PVOID
*)&pFatEntry
))
471 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
472 return STATUS_UNSUCCESSFUL
;
474 RtlCopyMemory(pFatEntry
, Buffer
, size
);
475 CcSetDirtyPinnedData(Context
, NULL
);
476 CcUnpinData(Context
);
477 FileOffset
.u
.LowPart
+= size
;
478 if (!CcPinRead(ParentFcb
->FileObject
, &FileOffset
,
479 nbSlots
* sizeof(FAT_DIR_ENTRY
) - size
,
480 TRUE
, &Context
, (PVOID
*)&pFatEntry
))
482 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
483 return STATUS_UNSUCCESSFUL
;
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 Status
= vfatMakeFCBFromDirEntry(DeviceExt
, ParentFcb
, &DirContext
, Fcb
);
495 if (!NT_SUCCESS(Status
))
497 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
501 DPRINT("new : entry=%11.11s\n", (*Fcb
)->entry
.Fat
.Filename
);
502 DPRINT("new : entry=%11.11s\n", DirContext
.DirEntry
.Fat
.Filename
);
504 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
506 FileOffset
.QuadPart
= 0;
507 if (!CcPinRead((*Fcb
)->FileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
, TRUE
,
508 &Context
, (PVOID
*)&pFatEntry
))
510 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
511 return STATUS_UNSUCCESSFUL
;
513 /* clear the new directory cluster */
514 RtlZeroMemory(pFatEntry
, DeviceExt
->FatInfo
.BytesPerCluster
);
515 /* create '.' and '..' */
516 RtlCopyMemory(&pFatEntry
[0].Attrib
, &DirContext
.DirEntry
.Fat
.Attrib
, sizeof(FAT_DIR_ENTRY
) - 11);
517 RtlCopyMemory(pFatEntry
[0].ShortName
, ". ", 11);
518 RtlCopyMemory(&pFatEntry
[1].Attrib
, &DirContext
.DirEntry
.Fat
.Attrib
, sizeof(FAT_DIR_ENTRY
) - 11);
519 RtlCopyMemory(pFatEntry
[1].ShortName
, ".. ", 11);
520 pFatEntry
[1].FirstCluster
= ParentFcb
->entry
.Fat
.FirstCluster
;
521 pFatEntry
[1].FirstClusterHigh
= ParentFcb
->entry
.Fat
.FirstClusterHigh
;
522 if (vfatFCBIsRoot(ParentFcb
))
524 pFatEntry
[1].FirstCluster
= 0;
525 pFatEntry
[1].FirstClusterHigh
= 0;
527 CcSetDirtyPinnedData(Context
, NULL
);
528 CcUnpinData(Context
);
530 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
531 DPRINT("addentry ok\n");
532 return STATUS_SUCCESS
;
536 create a new FAT entry
540 IN PDEVICE_EXTENSION DeviceExt
,
541 IN PUNICODE_STRING NameU
,
543 IN PVFATFCB ParentFcb
,
544 IN ULONG RequestedOptions
,
547 PVOID Context
= NULL
;
548 LARGE_INTEGER SystemTime
, FileOffset
;
550 VFAT_DIRENTRY_CONTEXT DirContext
;
551 PFATX_DIR_ENTRY pFatXDirEntry
;
554 DPRINT("addEntry: Name='%wZ', Dir='%wZ'\n", NameU
, &ParentFcb
->PathNameU
);
556 DirContext
.LongNameU
= *NameU
;
558 if (DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) > 42)
561 return STATUS_NAME_TOO_LONG
;
564 /* try to find 1 entry free in directory */
565 if (!vfatFindDirSpace(DeviceExt
, ParentFcb
, 1, &DirContext
.StartIndex
))
567 return STATUS_DISK_FULL
;
569 Index
= DirContext
.DirIndex
= DirContext
.StartIndex
;
570 if (!vfatFCBIsRoot(ParentFcb
))
572 DirContext
.DirIndex
+= 2;
573 DirContext
.StartIndex
+= 2;
576 DirContext
.ShortNameU
.Buffer
= 0;
577 DirContext
.ShortNameU
.Length
= 0;
578 DirContext
.ShortNameU
.MaximumLength
= 0;
579 RtlZeroMemory(&DirContext
.DirEntry
.FatX
, sizeof(FATX_DIR_ENTRY
));
580 memset(DirContext
.DirEntry
.FatX
.Filename
, 0xff, 42);
581 DirContext
.DirEntry
.FatX
.FirstCluster
= 0;
582 DirContext
.DirEntry
.FatX
.FileSize
= 0;
585 NameA
.Buffer
= (PCHAR
)DirContext
.DirEntry
.FatX
.Filename
;
587 NameA
.MaximumLength
= 42;
588 RtlUnicodeStringToOemString(&NameA
, &DirContext
.LongNameU
, FALSE
);
589 DirContext
.DirEntry
.FatX
.FilenameLength
= (unsigned char)NameA
.Length
;
592 DirContext
.DirEntry
.FatX
.Attrib
= ReqAttr
;
593 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
595 DirContext
.DirEntry
.FatX
.Attrib
|= FILE_ATTRIBUTE_DIRECTORY
;
598 /* set dates and times */
599 KeQuerySystemTime(&SystemTime
);
600 FsdSystemTimeToDosDateTime(DeviceExt
, &SystemTime
, &DirContext
.DirEntry
.FatX
.CreationDate
,
601 &DirContext
.DirEntry
.FatX
.CreationTime
);
602 DirContext
.DirEntry
.FatX
.UpdateDate
= DirContext
.DirEntry
.FatX
.CreationDate
;
603 DirContext
.DirEntry
.FatX
.UpdateTime
= DirContext
.DirEntry
.FatX
.CreationTime
;
604 DirContext
.DirEntry
.FatX
.AccessDate
= DirContext
.DirEntry
.FatX
.CreationDate
;
605 DirContext
.DirEntry
.FatX
.AccessTime
= DirContext
.DirEntry
.FatX
.CreationTime
;
607 /* add entry into parent directory */
608 FileOffset
.u
.HighPart
= 0;
609 FileOffset
.u
.LowPart
= Index
* sizeof(FATX_DIR_ENTRY
);
610 if (!CcPinRead(ParentFcb
->FileObject
, &FileOffset
, sizeof(FATX_DIR_ENTRY
),
611 TRUE
, &Context
, (PVOID
*)&pFatXDirEntry
))
613 return STATUS_UNSUCCESSFUL
;
615 RtlCopyMemory(pFatXDirEntry
, &DirContext
.DirEntry
.FatX
, sizeof(FATX_DIR_ENTRY
));
616 CcSetDirtyPinnedData(Context
, NULL
);
617 CcUnpinData(Context
);
619 /* FIXME: check status */
620 vfatMakeFCBFromDirEntry(DeviceExt
, ParentFcb
, &DirContext
, Fcb
);
622 DPRINT("addentry ok\n");
623 return STATUS_SUCCESS
;
628 IN PDEVICE_EXTENSION DeviceExt
,
629 IN PUNICODE_STRING NameU
,
631 IN PVFATFCB ParentFcb
,
632 IN ULONG RequestedOptions
,
635 if (DeviceExt
->Flags
& VCB_IS_FATX
)
636 return FATXAddEntry(DeviceExt
, NameU
, Fcb
, ParentFcb
, RequestedOptions
, ReqAttr
);
638 return FATAddEntry(DeviceExt
, NameU
, Fcb
, ParentFcb
, RequestedOptions
, ReqAttr
);
642 * deleting an existing FAT entry
646 IN PDEVICE_EXTENSION DeviceExt
,
649 ULONG CurrentCluster
= 0, NextCluster
, i
;
650 PVOID Context
= NULL
;
651 LARGE_INTEGER Offset
;
652 PFAT_DIR_ENTRY pDirEntry
= NULL
;
655 ASSERT(pFcb
->parentFcb
);
657 DPRINT("delEntry PathName \'%wZ\'\n", &pFcb
->PathNameU
);
658 DPRINT("delete entry: %u to %u\n", pFcb
->startIndex
, pFcb
->dirIndex
);
659 Offset
.u
.HighPart
= 0;
660 for (i
= pFcb
->startIndex
; i
<= pFcb
->dirIndex
; i
++)
662 if (Context
== NULL
|| ((i
* sizeof(FAT_DIR_ENTRY
)) % PAGE_SIZE
) == 0)
666 CcSetDirtyPinnedData(Context
, NULL
);
667 CcUnpinData(Context
);
669 Offset
.u
.LowPart
= (i
* sizeof(FAT_DIR_ENTRY
) / PAGE_SIZE
) * PAGE_SIZE
;
670 if (!CcPinRead(pFcb
->parentFcb
->FileObject
, &Offset
, sizeof(FAT_DIR_ENTRY
), TRUE
,
671 &Context
, (PVOID
*)&pDirEntry
))
673 return STATUS_UNSUCCESSFUL
;
676 pDirEntry
[i
% (PAGE_SIZE
/ sizeof(FAT_DIR_ENTRY
))].Filename
[0] = 0xe5;
677 if (i
== pFcb
->dirIndex
)
680 vfatDirEntryGetFirstCluster(DeviceExt
,
681 (PDIR_ENTRY
)&pDirEntry
[i
% (PAGE_SIZE
/ sizeof(FAT_DIR_ENTRY
))]);
686 CcSetDirtyPinnedData(Context
, NULL
);
687 CcUnpinData(Context
);
690 while (CurrentCluster
&& CurrentCluster
!= 0xffffffff)
692 GetNextCluster(DeviceExt
, CurrentCluster
, &NextCluster
);
693 /* FIXME: check status */
694 WriteCluster(DeviceExt
, CurrentCluster
, 0);
695 CurrentCluster
= NextCluster
;
697 return STATUS_SUCCESS
;
701 * deleting an existing FAT entry
705 IN PDEVICE_EXTENSION DeviceExt
,
708 ULONG CurrentCluster
= 0, NextCluster
;
709 PVOID Context
= NULL
;
710 LARGE_INTEGER Offset
;
711 PFATX_DIR_ENTRY pDirEntry
;
715 ASSERT(pFcb
->parentFcb
);
716 ASSERT(pFcb
->Flags
& FCB_IS_FATX_ENTRY
);
718 StartIndex
= pFcb
->startIndex
;
720 DPRINT("delEntry PathName \'%wZ\'\n", &pFcb
->PathNameU
);
721 DPRINT("delete entry: %u\n", StartIndex
);
722 Offset
.u
.HighPart
= 0;
723 Offset
.u
.LowPart
= (StartIndex
* sizeof(FATX_DIR_ENTRY
) / PAGE_SIZE
) * PAGE_SIZE
;
724 if (!CcPinRead(pFcb
->parentFcb
->FileObject
, &Offset
, sizeof(FATX_DIR_ENTRY
), TRUE
,
725 &Context
, (PVOID
*)&pDirEntry
))
727 DPRINT1("CcPinRead(Offset %x:%x, Length %d) failed\n", Offset
.u
.HighPart
, Offset
.u
.LowPart
, PAGE_SIZE
);
728 return STATUS_UNSUCCESSFUL
;
730 pDirEntry
= &pDirEntry
[StartIndex
% (PAGE_SIZE
/ sizeof(FATX_DIR_ENTRY
))];
731 pDirEntry
->FilenameLength
= 0xe5;
732 CurrentCluster
= vfatDirEntryGetFirstCluster(DeviceExt
,
733 (PDIR_ENTRY
)pDirEntry
);
734 CcSetDirtyPinnedData(Context
, NULL
);
735 CcUnpinData(Context
);
737 while (CurrentCluster
&& CurrentCluster
!= 0xffffffff)
739 GetNextCluster(DeviceExt
, CurrentCluster
, &NextCluster
);
740 /* FIXME: check status */
741 WriteCluster(DeviceExt
, CurrentCluster
, 0);
742 CurrentCluster
= NextCluster
;
744 return STATUS_SUCCESS
;
749 IN PDEVICE_EXTENSION DeviceExt
,
752 if (DeviceExt
->Flags
& VCB_IS_FATX
)
753 return FATXDelEntry(DeviceExt
, pFcb
);
755 return FATDelEntry(DeviceExt
, pFcb
);