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 *****************************************************************/
15 * update an existing FAT entry
29 if (pFcb
->Flags
& FCB_IS_FATX_ENTRY
)
31 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
32 dirIndex
= pFcb
->startIndex
;
36 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
37 dirIndex
= pFcb
->dirIndex
;
40 DPRINT("updEntry dirIndex %d, PathName \'%wZ\'\n", dirIndex
, &pFcb
->PathNameU
);
42 if (vfatFCBIsRoot(pFcb
) || (pFcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)))
44 return STATUS_SUCCESS
;
47 ASSERT(pFcb
->parentFcb
);
49 Offset
.u
.HighPart
= 0;
50 Offset
.u
.LowPart
= dirIndex
* SizeDirEntry
;
51 if (CcPinRead(pFcb
->parentFcb
->FileObject
, &Offset
, SizeDirEntry
,
52 TRUE
, &Context
, (PVOID
*)&PinEntry
))
54 pFcb
->Flags
&= ~FCB_IS_DIRTY
;
55 RtlCopyMemory(PinEntry
, &pFcb
->entry
, SizeDirEntry
);
56 CcSetDirtyPinnedData(Context
, NULL
);
58 return STATUS_SUCCESS
;
62 DPRINT1("Failed write to \'%wZ\'.\n", &pFcb
->parentFcb
->PathNameU
);
63 return STATUS_UNSUCCESSFUL
;
68 * try to find contiguous entries frees in directory,
69 * extend a directory if is neccesary
73 IN PDEVICE_EXTENSION DeviceExt
,
78 LARGE_INTEGER FileOffset
;
79 ULONG i
, count
, size
, nbFree
= 0;
80 PDIR_ENTRY pFatEntry
= NULL
;
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 if (!CcPinRead(pDirFcb
->FileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
,
102 TRUE
, &Context
, (PVOID
*)&pFatEntry
))
106 FileOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.BytesPerCluster
;
108 if (ENTRY_END(DeviceExt
, pFatEntry
))
112 if (ENTRY_DELETED(DeviceExt
, pFatEntry
))
120 if (nbFree
== nbSlots
)
127 CcUnpinData(Context
);
130 if (nbFree
== nbSlots
)
132 /* found enough contiguous free slots */
133 *start
= i
- nbSlots
+ 1;
138 if (*start
+ nbSlots
> count
)
140 LARGE_INTEGER AllocationSize
;
141 /* extend the directory */
142 if (vfatFCBIsRoot(pDirFcb
) && DeviceExt
->FatInfo
.FatType
!= FAT32
)
144 /* We can't extend a root directory on a FAT12/FAT16/FATX partition */
147 AllocationSize
.QuadPart
= pDirFcb
->RFCB
.FileSize
.u
.LowPart
+ DeviceExt
->FatInfo
.BytesPerCluster
;
148 Status
= VfatSetAllocationSizeInformation(pDirFcb
->FileObject
, pDirFcb
,
149 DeviceExt
, &AllocationSize
);
150 if (!NT_SUCCESS(Status
))
154 /* clear the new dir cluster */
155 FileOffset
.u
.LowPart
= (ULONG
)(pDirFcb
->RFCB
.FileSize
.QuadPart
-
156 DeviceExt
->FatInfo
.BytesPerCluster
);
157 if (!CcPinRead(pDirFcb
->FileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
,
158 TRUE
, &Context
, (PVOID
*)&pFatEntry
))
162 if (DeviceExt
->Flags
& VCB_IS_FATX
)
163 memset(pFatEntry
, 0xff, DeviceExt
->FatInfo
.BytesPerCluster
);
165 RtlZeroMemory(pFatEntry
, DeviceExt
->FatInfo
.BytesPerCluster
);
167 else if (*start
+ nbSlots
< count
)
169 /* clear the entry after the last new entry */
170 FileOffset
.u
.LowPart
= (*start
+ nbSlots
) * SizeDirEntry
;
171 if (!CcPinRead(pDirFcb
->FileObject
, &FileOffset
, SizeDirEntry
,
172 TRUE
, &Context
, (PVOID
*)&pFatEntry
))
176 if (DeviceExt
->Flags
& VCB_IS_FATX
)
177 memset(pFatEntry
, 0xff, SizeDirEntry
);
179 RtlZeroMemory(pFatEntry
, SizeDirEntry
);
183 CcSetDirtyPinnedData(Context
, NULL
);
184 CcUnpinData(Context
);
187 DPRINT("nbSlots %d nbFree %d, entry number %d\n", nbSlots
, nbFree
, *start
);
192 create a new FAT entry
196 IN PDEVICE_EXTENSION DeviceExt
,
197 IN PUNICODE_STRING NameU
,
199 IN PVFATFCB ParentFcb
,
200 IN ULONG RequestedOptions
,
203 PVOID Context
= NULL
;
204 PFAT_DIR_ENTRY pFatEntry
;
206 USHORT nbSlots
= 0, j
, posCar
;
208 BOOLEAN needTilde
= FALSE
, needLong
= FALSE
;
209 BOOLEAN lCaseBase
= FALSE
, uCaseBase
, lCaseExt
= FALSE
, uCaseExt
;
210 ULONG CurrentCluster
;
211 LARGE_INTEGER SystemTime
, FileOffset
;
212 NTSTATUS Status
= STATUS_SUCCESS
;
221 VFAT_DIRENTRY_CONTEXT DirContext
;
222 WCHAR LongNameBuffer
[LONGNAME_MAX_LENGTH
+ 1];
223 WCHAR ShortNameBuffer
[13];
225 DPRINT("addEntry: Name='%wZ', Dir='%wZ'\n", NameU
, &ParentFcb
->PathNameU
);
227 DirContext
.LongNameU
= *NameU
;
229 /* nb of entry needed for long name+normal entry */
230 nbSlots
= (DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) + 12) / 13 + 1;
231 DPRINT("NameLen= %d, nbSlots =%d\n", DirContext
.LongNameU
.Length
/ sizeof(WCHAR
), nbSlots
);
232 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, (nbSlots
- 1) * sizeof(FAT_DIR_ENTRY
), TAG_VFAT
);
235 return STATUS_INSUFFICIENT_RESOURCES
;
237 RtlZeroMemory(Buffer
, (nbSlots
- 1) * sizeof(FAT_DIR_ENTRY
));
238 pSlots
= (slot
*) Buffer
;
240 NameA
.Buffer
= aName
;
242 NameA
.MaximumLength
= sizeof(aName
);
244 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
245 DirContext
.ShortNameU
.Length
= 0;
246 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
248 RtlZeroMemory(&DirContext
.DirEntry
.Fat
, sizeof(FAT_DIR_ENTRY
));
250 IsNameLegal
= RtlIsNameLegalDOS8Dot3(&DirContext
.LongNameU
, &NameA
, &SpacesFound
);
252 if (!IsNameLegal
|| SpacesFound
)
254 GENERATE_NAME_CONTEXT NameContext
;
255 VFAT_DIRENTRY_CONTEXT SearchContext
;
256 WCHAR ShortSearchName
[13];
259 RtlZeroMemory(&NameContext
, sizeof(GENERATE_NAME_CONTEXT
));
260 SearchContext
.LongNameU
.Buffer
= LongNameBuffer
;
261 SearchContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
262 SearchContext
.ShortNameU
.Buffer
= ShortSearchName
;
263 SearchContext
.ShortNameU
.MaximumLength
= sizeof(ShortSearchName
);
265 for (i
= 0; i
< 100; i
++)
267 RtlGenerate8dot3Name(&DirContext
.LongNameU
, FALSE
, &NameContext
, &DirContext
.ShortNameU
);
268 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
269 SearchContext
.DirIndex
= 0;
270 Status
= FindFile(DeviceExt
, ParentFcb
, &DirContext
.ShortNameU
, &SearchContext
, TRUE
);
271 if (!NT_SUCCESS(Status
))
276 if (i
== 100) /* FIXME : what to do after this ? */
278 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
279 return STATUS_UNSUCCESSFUL
;
281 IsNameLegal
= RtlIsNameLegalDOS8Dot3(&DirContext
.ShortNameU
, &NameA
, &SpacesFound
);
282 aName
[NameA
.Length
]=0;
286 aName
[NameA
.Length
] = 0;
287 for (posCar
= 0; posCar
< DirContext
.LongNameU
.Length
/ sizeof(WCHAR
); posCar
++)
289 if (DirContext
.LongNameU
.Buffer
[posCar
] == L
'.')
294 /* check if the name and the extension contains upper case characters */
295 RtlDowncaseUnicodeString(&DirContext
.ShortNameU
, &DirContext
.LongNameU
, FALSE
);
296 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
297 uCaseBase
= wcsncmp(DirContext
.LongNameU
.Buffer
,
298 DirContext
.ShortNameU
.Buffer
, posCar
) ? TRUE
: FALSE
;
299 if (posCar
< DirContext
.LongNameU
.Length
/sizeof(WCHAR
))
301 i
= DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) - posCar
;
302 uCaseExt
= wcsncmp(DirContext
.LongNameU
.Buffer
+ posCar
,
303 DirContext
.ShortNameU
.Buffer
+ posCar
, i
) ? TRUE
: FALSE
;
309 /* check if the name and the extension contains lower case characters */
310 RtlUpcaseUnicodeString(&DirContext
.ShortNameU
, &DirContext
.LongNameU
, FALSE
);
311 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
312 lCaseBase
= wcsncmp(DirContext
.LongNameU
.Buffer
,
313 DirContext
.ShortNameU
.Buffer
, posCar
) ? TRUE
: FALSE
;
314 if (posCar
< DirContext
.LongNameU
.Length
/ sizeof(WCHAR
))
316 i
= DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) - posCar
;
317 lCaseExt
= wcsncmp(DirContext
.LongNameU
.Buffer
+ posCar
,
318 DirContext
.ShortNameU
.Buffer
+ posCar
, i
) ? TRUE
: FALSE
;
324 if ((lCaseBase
&& uCaseBase
) || (lCaseExt
&& uCaseExt
))
329 DPRINT("'%s', '%wZ', needTilde=%d, needLong=%d\n",
330 aName
, &DirContext
.LongNameU
, needTilde
, needLong
);
331 memset(DirContext
.DirEntry
.Fat
.ShortName
, ' ', 11);
332 for (i
= 0; i
< 8 && aName
[i
] && aName
[i
] != '.'; i
++)
334 DirContext
.DirEntry
.Fat
.Filename
[i
] = aName
[i
];
339 for (j
= 0; j
< 3 && aName
[i
]; j
++, i
++)
341 DirContext
.DirEntry
.Fat
.Ext
[j
] = aName
[i
];
344 if (DirContext
.DirEntry
.Fat
.Filename
[0] == 0xe5)
346 DirContext
.DirEntry
.Fat
.Filename
[0] = 0x05;
351 RtlCopyMemory(LongNameBuffer
, DirContext
.LongNameU
.Buffer
, DirContext
.LongNameU
.Length
);
352 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
353 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
354 DirContext
.LongNameU
.Buffer
[DirContext
.LongNameU
.Length
/ sizeof(WCHAR
)] = 0;
355 memset(DirContext
.LongNameU
.Buffer
+ DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) + 1, 0xff,
356 DirContext
.LongNameU
.MaximumLength
- DirContext
.LongNameU
.Length
- sizeof(WCHAR
));
363 DirContext
.DirEntry
.Fat
.lCase
|= VFAT_CASE_LOWER_BASE
;
367 DirContext
.DirEntry
.Fat
.lCase
|= VFAT_CASE_LOWER_EXT
;
371 DPRINT ("dos name=%11.11s\n", DirContext
.DirEntry
.Fat
.Filename
);
374 DirContext
.DirEntry
.Fat
.Attrib
= ReqAttr
;
375 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
377 DirContext
.DirEntry
.Fat
.Attrib
|= FILE_ATTRIBUTE_DIRECTORY
;
379 /* set dates and times */
380 KeQuerySystemTime(&SystemTime
);
381 FsdSystemTimeToDosDateTime(DeviceExt
, &SystemTime
, &DirContext
.DirEntry
.Fat
.CreationDate
,
382 &DirContext
.DirEntry
.Fat
.CreationTime
);
383 DirContext
.DirEntry
.Fat
.UpdateDate
= DirContext
.DirEntry
.Fat
.CreationDate
;
384 DirContext
.DirEntry
.Fat
.UpdateTime
= DirContext
.DirEntry
.Fat
.CreationTime
;
385 DirContext
.DirEntry
.Fat
.AccessDate
= DirContext
.DirEntry
.Fat
.CreationDate
;
389 /* calculate checksum for 8.3 name */
390 for (pSlots
[0].alias_checksum
= 0, i
= 0; i
< 11; i
++)
392 pSlots
[0].alias_checksum
= (((pSlots
[0].alias_checksum
& 1) << 7
393 | ((pSlots
[0].alias_checksum
& 0xfe) >> 1))
394 + DirContext
.DirEntry
.Fat
.ShortName
[i
]);
396 /* construct slots and entry */
397 for (i
= nbSlots
- 2; i
>= 0; i
--)
399 DPRINT("construct slot %d\n", i
);
400 pSlots
[i
].attr
= 0xf;
403 pSlots
[i
].id
= (unsigned char)(nbSlots
- i
- 1);
407 pSlots
[i
].id
= (unsigned char)(nbSlots
- i
- 1 + 0x40);
409 pSlots
[i
].alias_checksum
= pSlots
[0].alias_checksum
;
410 RtlCopyMemory(pSlots
[i
].name0_4
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13, 10);
411 RtlCopyMemory(pSlots
[i
].name5_10
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13 + 5, 12);
412 RtlCopyMemory(pSlots
[i
].name11_12
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13 + 11, 4);
415 /* try to find nbSlots contiguous entries frees in directory */
416 if (!vfatFindDirSpace(DeviceExt
, ParentFcb
, nbSlots
, &DirContext
.StartIndex
))
418 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
419 return STATUS_DISK_FULL
;
421 DirContext
.DirIndex
= DirContext
.StartIndex
+ nbSlots
- 1;
422 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
425 Status
= NextCluster(DeviceExt
, 0, &CurrentCluster
, TRUE
);
426 if (CurrentCluster
== 0xffffffff || !NT_SUCCESS(Status
))
428 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
429 if (!NT_SUCCESS(Status
))
433 return STATUS_DISK_FULL
;
435 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
437 DirContext
.DirEntry
.Fat
.FirstClusterHigh
= (unsigned short)(CurrentCluster
>> 16);
439 DirContext
.DirEntry
.Fat
.FirstCluster
= (unsigned short)CurrentCluster
;
442 i
= DeviceExt
->FatInfo
.BytesPerCluster
/ sizeof(FAT_DIR_ENTRY
);
443 FileOffset
.u
.HighPart
= 0;
444 FileOffset
.u
.LowPart
= DirContext
.StartIndex
* sizeof(FAT_DIR_ENTRY
);
445 if (DirContext
.StartIndex
/ i
== DirContext
.DirIndex
/ i
)
448 if (!CcPinRead(ParentFcb
->FileObject
, &FileOffset
, nbSlots
* sizeof(FAT_DIR_ENTRY
),
449 TRUE
, &Context
, (PVOID
*)&pFatEntry
))
451 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
452 return STATUS_UNSUCCESSFUL
;
456 RtlCopyMemory(pFatEntry
, Buffer
, (nbSlots
- 1) * sizeof(FAT_DIR_ENTRY
));
458 RtlCopyMemory(pFatEntry
+ (nbSlots
- 1), &DirContext
.DirEntry
.Fat
, sizeof(FAT_DIR_ENTRY
));
463 size
= DeviceExt
->FatInfo
.BytesPerCluster
-
464 (DirContext
.StartIndex
* sizeof(FAT_DIR_ENTRY
)) % DeviceExt
->FatInfo
.BytesPerCluster
;
465 i
= size
/ sizeof(FAT_DIR_ENTRY
);
466 if (!CcPinRead(ParentFcb
->FileObject
, &FileOffset
, size
, TRUE
,
467 &Context
, (PVOID
*)&pFatEntry
))
469 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
470 return STATUS_UNSUCCESSFUL
;
472 RtlCopyMemory(pFatEntry
, Buffer
, size
);
473 CcSetDirtyPinnedData(Context
, NULL
);
474 CcUnpinData(Context
);
475 FileOffset
.u
.LowPart
+= size
;
476 if (!CcPinRead(ParentFcb
->FileObject
, &FileOffset
,
477 nbSlots
* sizeof(FAT_DIR_ENTRY
) - size
,
478 TRUE
, &Context
, (PVOID
*)&pFatEntry
))
480 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
481 return STATUS_UNSUCCESSFUL
;
485 RtlCopyMemory(pFatEntry
, (PVOID
)(Buffer
+ size
), (nbSlots
- 1 - i
) * sizeof(FAT_DIR_ENTRY
));
487 RtlCopyMemory(pFatEntry
+ nbSlots
- 1 - i
, &DirContext
.DirEntry
.Fat
, sizeof(FAT_DIR_ENTRY
));
489 CcSetDirtyPinnedData(Context
, NULL
);
490 CcUnpinData(Context
);
492 Status
= vfatMakeFCBFromDirEntry(DeviceExt
, ParentFcb
, &DirContext
, Fcb
);
493 if (!NT_SUCCESS(Status
))
495 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
499 DPRINT("new : entry=%11.11s\n", (*Fcb
)->entry
.Fat
.Filename
);
500 DPRINT("new : entry=%11.11s\n", DirContext
.DirEntry
.Fat
.Filename
);
502 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
504 FileOffset
.QuadPart
= 0;
505 if (!CcPinRead((*Fcb
)->FileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
, TRUE
,
506 &Context
, (PVOID
*)&pFatEntry
))
508 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
509 return STATUS_UNSUCCESSFUL
;
511 /* clear the new directory cluster */
512 RtlZeroMemory(pFatEntry
, DeviceExt
->FatInfo
.BytesPerCluster
);
513 /* create '.' and '..' */
514 RtlCopyMemory(&pFatEntry
[0].Attrib
, &DirContext
.DirEntry
.Fat
.Attrib
, sizeof(FAT_DIR_ENTRY
) - 11);
515 RtlCopyMemory(pFatEntry
[0].ShortName
, ". ", 11);
516 RtlCopyMemory(&pFatEntry
[1].Attrib
, &DirContext
.DirEntry
.Fat
.Attrib
, sizeof(FAT_DIR_ENTRY
) - 11);
517 RtlCopyMemory(pFatEntry
[1].ShortName
, ".. ", 11);
518 pFatEntry
[1].FirstCluster
= ParentFcb
->entry
.Fat
.FirstCluster
;
519 pFatEntry
[1].FirstClusterHigh
= ParentFcb
->entry
.Fat
.FirstClusterHigh
;
520 if (vfatFCBIsRoot(ParentFcb
))
522 pFatEntry
[1].FirstCluster
= 0;
523 pFatEntry
[1].FirstClusterHigh
= 0;
525 CcSetDirtyPinnedData(Context
, NULL
);
526 CcUnpinData(Context
);
528 ExFreePoolWithTag(Buffer
, TAG_VFAT
);
529 DPRINT("addentry ok\n");
530 return STATUS_SUCCESS
;
534 create a new FAT entry
538 IN PDEVICE_EXTENSION DeviceExt
,
539 IN PUNICODE_STRING NameU
,
541 IN PVFATFCB ParentFcb
,
542 IN ULONG RequestedOptions
,
545 PVOID Context
= NULL
;
546 LARGE_INTEGER SystemTime
, FileOffset
;
548 VFAT_DIRENTRY_CONTEXT DirContext
;
549 PFATX_DIR_ENTRY pFatXDirEntry
;
552 DPRINT("addEntry: Name='%wZ', Dir='%wZ'\n", NameU
, &ParentFcb
->PathNameU
);
554 DirContext
.LongNameU
= *NameU
;
556 if (DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) > 42)
559 return STATUS_NAME_TOO_LONG
;
562 /* try to find 1 entry free in directory */
563 if (!vfatFindDirSpace(DeviceExt
, ParentFcb
, 1, &DirContext
.StartIndex
))
565 return STATUS_DISK_FULL
;
567 Index
= DirContext
.DirIndex
= DirContext
.StartIndex
;
568 if (!vfatFCBIsRoot(ParentFcb
))
570 DirContext
.DirIndex
+= 2;
571 DirContext
.StartIndex
+= 2;
574 DirContext
.ShortNameU
.Buffer
= 0;
575 DirContext
.ShortNameU
.Length
= 0;
576 DirContext
.ShortNameU
.MaximumLength
= 0;
577 RtlZeroMemory(&DirContext
.DirEntry
.FatX
, sizeof(FATX_DIR_ENTRY
));
578 memset(DirContext
.DirEntry
.FatX
.Filename
, 0xff, 42);
579 DirContext
.DirEntry
.FatX
.FirstCluster
= 0;
580 DirContext
.DirEntry
.FatX
.FileSize
= 0;
583 NameA
.Buffer
= (PCHAR
)DirContext
.DirEntry
.FatX
.Filename
;
585 NameA
.MaximumLength
= 42;
586 RtlUnicodeStringToOemString(&NameA
, &DirContext
.LongNameU
, FALSE
);
587 DirContext
.DirEntry
.FatX
.FilenameLength
= (unsigned char)NameA
.Length
;
590 DirContext
.DirEntry
.FatX
.Attrib
= ReqAttr
;
591 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
593 DirContext
.DirEntry
.FatX
.Attrib
|= FILE_ATTRIBUTE_DIRECTORY
;
596 /* set dates and times */
597 KeQuerySystemTime(&SystemTime
);
598 FsdSystemTimeToDosDateTime(DeviceExt
, &SystemTime
, &DirContext
.DirEntry
.FatX
.CreationDate
,
599 &DirContext
.DirEntry
.FatX
.CreationTime
);
600 DirContext
.DirEntry
.FatX
.UpdateDate
= DirContext
.DirEntry
.FatX
.CreationDate
;
601 DirContext
.DirEntry
.FatX
.UpdateTime
= DirContext
.DirEntry
.FatX
.CreationTime
;
602 DirContext
.DirEntry
.FatX
.AccessDate
= DirContext
.DirEntry
.FatX
.CreationDate
;
603 DirContext
.DirEntry
.FatX
.AccessTime
= DirContext
.DirEntry
.FatX
.CreationTime
;
605 /* add entry into parent directory */
606 FileOffset
.u
.HighPart
= 0;
607 FileOffset
.u
.LowPart
= Index
* sizeof(FATX_DIR_ENTRY
);
608 if (!CcPinRead(ParentFcb
->FileObject
, &FileOffset
, sizeof(FATX_DIR_ENTRY
),
609 TRUE
, &Context
, (PVOID
*)&pFatXDirEntry
))
611 return STATUS_UNSUCCESSFUL
;
613 RtlCopyMemory(pFatXDirEntry
, &DirContext
.DirEntry
.FatX
, sizeof(FATX_DIR_ENTRY
));
614 CcSetDirtyPinnedData(Context
, NULL
);
615 CcUnpinData(Context
);
617 /* FIXME: check status */
618 vfatMakeFCBFromDirEntry(DeviceExt
, ParentFcb
, &DirContext
, Fcb
);
620 DPRINT("addentry ok\n");
621 return STATUS_SUCCESS
;
626 IN PDEVICE_EXTENSION DeviceExt
,
627 IN PUNICODE_STRING NameU
,
629 IN PVFATFCB ParentFcb
,
630 IN ULONG RequestedOptions
,
633 if (DeviceExt
->Flags
& VCB_IS_FATX
)
634 return FATXAddEntry(DeviceExt
, NameU
, Fcb
, ParentFcb
, RequestedOptions
, ReqAttr
);
636 return FATAddEntry(DeviceExt
, NameU
, Fcb
, ParentFcb
, RequestedOptions
, ReqAttr
);
640 * deleting an existing FAT entry
644 IN PDEVICE_EXTENSION DeviceExt
,
647 ULONG CurrentCluster
= 0, NextCluster
, i
;
648 PVOID Context
= NULL
;
649 LARGE_INTEGER Offset
;
650 PFAT_DIR_ENTRY pDirEntry
= NULL
;
653 ASSERT(pFcb
->parentFcb
);
655 DPRINT("delEntry PathName \'%wZ\'\n", &pFcb
->PathNameU
);
656 DPRINT("delete entry: %d to %d\n", pFcb
->startIndex
, pFcb
->dirIndex
);
657 Offset
.u
.HighPart
= 0;
658 for (i
= pFcb
->startIndex
; i
<= pFcb
->dirIndex
; i
++)
660 if (Context
== NULL
|| ((i
* sizeof(FAT_DIR_ENTRY
)) % PAGE_SIZE
) == 0)
664 CcSetDirtyPinnedData(Context
, NULL
);
665 CcUnpinData(Context
);
667 Offset
.u
.LowPart
= (i
* sizeof(FAT_DIR_ENTRY
) / PAGE_SIZE
) * PAGE_SIZE
;
668 if (!CcPinRead(pFcb
->parentFcb
->FileObject
, &Offset
, sizeof(FAT_DIR_ENTRY
), TRUE
,
669 &Context
, (PVOID
*)&pDirEntry
))
671 return STATUS_UNSUCCESSFUL
;
674 pDirEntry
[i
% (PAGE_SIZE
/ sizeof(FAT_DIR_ENTRY
))].Filename
[0] = 0xe5;
675 if (i
== pFcb
->dirIndex
)
678 vfatDirEntryGetFirstCluster(DeviceExt
,
679 (PDIR_ENTRY
)&pDirEntry
[i
% (PAGE_SIZE
/ sizeof(FAT_DIR_ENTRY
))]);
684 CcSetDirtyPinnedData(Context
, NULL
);
685 CcUnpinData(Context
);
688 while (CurrentCluster
&& CurrentCluster
!= 0xffffffff)
690 GetNextCluster(DeviceExt
, CurrentCluster
, &NextCluster
);
691 /* FIXME: check status */
692 WriteCluster(DeviceExt
, CurrentCluster
, 0);
693 CurrentCluster
= NextCluster
;
695 return STATUS_SUCCESS
;
699 * deleting an existing FAT entry
703 IN PDEVICE_EXTENSION DeviceExt
,
706 ULONG CurrentCluster
= 0, NextCluster
;
707 PVOID Context
= NULL
;
708 LARGE_INTEGER Offset
;
709 PFATX_DIR_ENTRY pDirEntry
;
713 ASSERT(pFcb
->parentFcb
);
714 ASSERT(pFcb
->Flags
& FCB_IS_FATX_ENTRY
);
716 StartIndex
= pFcb
->startIndex
;
718 DPRINT("delEntry PathName \'%wZ\'\n", &pFcb
->PathNameU
);
719 DPRINT("delete entry: %d\n", StartIndex
);
720 Offset
.u
.HighPart
= 0;
721 Offset
.u
.LowPart
= (StartIndex
* sizeof(FATX_DIR_ENTRY
) / PAGE_SIZE
) * PAGE_SIZE
;
722 if (!CcPinRead(pFcb
->parentFcb
->FileObject
, &Offset
, sizeof(FATX_DIR_ENTRY
), TRUE
,
723 &Context
, (PVOID
*)&pDirEntry
))
725 DPRINT1("CcPinRead(Offset %x:%x, Length %d) failed\n", Offset
.u
.HighPart
, Offset
.u
.LowPart
, PAGE_SIZE
);
726 return STATUS_UNSUCCESSFUL
;
728 pDirEntry
= &pDirEntry
[StartIndex
% (PAGE_SIZE
/ sizeof(FATX_DIR_ENTRY
))];
729 pDirEntry
->FilenameLength
= 0xe5;
730 CurrentCluster
= vfatDirEntryGetFirstCluster(DeviceExt
,
731 (PDIR_ENTRY
)pDirEntry
);
732 CcSetDirtyPinnedData(Context
, NULL
);
733 CcUnpinData(Context
);
735 while (CurrentCluster
&& CurrentCluster
!= 0xffffffff)
737 GetNextCluster(DeviceExt
, CurrentCluster
, &NextCluster
);
738 /* FIXME: check status */
739 WriteCluster(DeviceExt
, CurrentCluster
, 0);
740 CurrentCluster
= NextCluster
;
742 return STATUS_SUCCESS
;
747 IN PDEVICE_EXTENSION DeviceExt
,
750 if (DeviceExt
->Flags
& VCB_IS_FATX
)
751 return FATXDelEntry(DeviceExt
, pFcb
);
753 return FATDelEntry(DeviceExt
, pFcb
);