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 VfatUpdateEntry (PVFATFCB pFcb
)
17 * update an existing FAT entry
27 ASSERT(pFcb
->parentFcb
);
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 vfatFindDirSpace(PDEVICE_EXTENSION DeviceExt
,
74 * try to find contiguous entries frees in directory,
75 * extend a directory if is neccesary
77 LARGE_INTEGER FileOffset
;
78 ULONG i
, count
, size
, nbFree
= 0;
83 FileOffset
.QuadPart
= 0;
85 if (DeviceExt
->Flags
& VCB_IS_FATX
)
86 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
88 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
90 count
= pDirFcb
->RFCB
.FileSize
.u
.LowPart
/ SizeDirEntry
;
91 size
= DeviceExt
->FatInfo
.BytesPerCluster
/ SizeDirEntry
;
92 for (i
= 0; i
< count
; i
++, pFatEntry
= (PDIR_ENTRY
)((ULONG_PTR
)pFatEntry
+ SizeDirEntry
))
94 if (Context
== NULL
|| (i
% size
) == 0)
100 // FIXME: check return value
101 CcPinRead (pDirFcb
->FileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
,
102 TRUE
, &Context
, (PVOID
*)&pFatEntry
);
103 FileOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.BytesPerCluster
;
105 if (ENTRY_END(DeviceExt
, pFatEntry
))
109 if (ENTRY_DELETED(DeviceExt
, pFatEntry
))
117 if (nbFree
== nbSlots
)
124 CcUnpinData(Context
);
127 if (nbFree
== nbSlots
)
129 // found enough contiguous free slots
130 *start
= i
- nbSlots
+ 1;
135 if (*start
+ nbSlots
> count
)
137 LARGE_INTEGER AllocationSize
;
139 // extend the directory
140 if (vfatFCBIsRoot(pDirFcb
) && DeviceExt
->FatInfo
.FatType
!= FAT32
)
142 // We can't extend a root directory on a FAT12/FAT16/FATX partition
145 AllocationSize
.QuadPart
= pDirFcb
->RFCB
.FileSize
.u
.LowPart
+ DeviceExt
->FatInfo
.BytesPerCluster
;
146 Status
= VfatSetAllocationSizeInformation(pDirFcb
->FileObject
, pDirFcb
,
147 DeviceExt
, &AllocationSize
);
148 if (!NT_SUCCESS(Status
))
152 // clear the new dir cluster
153 FileOffset
.u
.LowPart
= (ULONG
)(pDirFcb
->RFCB
.FileSize
.QuadPart
-
154 DeviceExt
->FatInfo
.BytesPerCluster
);
155 CcPinRead (pDirFcb
->FileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
,
156 TRUE
, &Context
, (PVOID
*)&pFatEntry
);
157 if (DeviceExt
->Flags
& VCB_IS_FATX
)
158 memset(pFatEntry
, 0xff, DeviceExt
->FatInfo
.BytesPerCluster
);
160 RtlZeroMemory(pFatEntry
, DeviceExt
->FatInfo
.BytesPerCluster
);
162 else if (*start
+ nbSlots
< count
)
164 // clear the entry after the last new entry
165 FileOffset
.u
.LowPart
= (*start
+ nbSlots
) * SizeDirEntry
;
166 CcPinRead (pDirFcb
->FileObject
, &FileOffset
, SizeDirEntry
,
167 TRUE
, &Context
, (PVOID
*)&pFatEntry
);
168 if (DeviceExt
->Flags
& VCB_IS_FATX
)
169 memset(pFatEntry
, 0xff, SizeDirEntry
);
171 RtlZeroMemory(pFatEntry
, SizeDirEntry
);
175 CcSetDirtyPinnedData(Context
, NULL
);
176 CcUnpinData(Context
);
179 DPRINT ("nbSlots %d nbFree %d, entry number %d\n", nbSlots
, nbFree
, *start
);
184 FATAddEntry (PDEVICE_EXTENSION DeviceExt
,
185 PUNICODE_STRING NameU
,
188 ULONG RequestedOptions
,
191 create a new FAT entry
194 PVOID Context
= NULL
;
195 PFAT_DIR_ENTRY pFatEntry
;
197 USHORT nbSlots
= 0, j
, posCar
;
199 BOOLEAN needTilde
= FALSE
, needLong
= FALSE
;
200 BOOLEAN lCaseBase
= FALSE
, uCaseBase
, lCaseExt
= FALSE
, uCaseExt
;
201 ULONG CurrentCluster
;
202 LARGE_INTEGER SystemTime
, FileOffset
;
203 NTSTATUS Status
= STATUS_SUCCESS
;
212 VFAT_DIRENTRY_CONTEXT DirContext
;
213 WCHAR LongNameBuffer
[LONGNAME_MAX_LENGTH
+ 1];
214 WCHAR ShortNameBuffer
[13];
216 DPRINT ("addEntry: Name='%wZ', Dir='%wZ'\n", NameU
, &ParentFcb
->PathNameU
);
218 DirContext
.LongNameU
= *NameU
;
220 nbSlots
= (DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) + 12) / 13 + 1; //nb of entry needed for long name+normal entry
221 DPRINT ("NameLen= %d, nbSlots =%d\n", DirContext
.LongNameU
.Length
/ sizeof(WCHAR
), nbSlots
);
222 Buffer
= ExAllocatePool (NonPagedPool
, (nbSlots
- 1) * sizeof (FAT_DIR_ENTRY
));
225 return STATUS_INSUFFICIENT_RESOURCES
;
227 RtlZeroMemory (Buffer
, (nbSlots
- 1) * sizeof (FAT_DIR_ENTRY
));
228 pSlots
= (slot
*) Buffer
;
230 NameA
.Buffer
= aName
;
232 NameA
.MaximumLength
= sizeof(aName
);
234 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
235 DirContext
.ShortNameU
.Length
= 0;
236 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
238 RtlZeroMemory(&DirContext
.DirEntry
.Fat
, sizeof(FAT_DIR_ENTRY
));
240 IsNameLegal
= RtlIsNameLegalDOS8Dot3(&DirContext
.LongNameU
, &NameA
, &SpacesFound
);
242 if (!IsNameLegal
|| SpacesFound
)
244 GENERATE_NAME_CONTEXT NameContext
;
245 VFAT_DIRENTRY_CONTEXT SearchContext
;
246 WCHAR ShortSearchName
[13];
249 RtlZeroMemory(&NameContext
, sizeof(GENERATE_NAME_CONTEXT
));
250 SearchContext
.LongNameU
.Buffer
= LongNameBuffer
;
251 SearchContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
252 SearchContext
.ShortNameU
.Buffer
= ShortSearchName
;
253 SearchContext
.ShortNameU
.MaximumLength
= sizeof(ShortSearchName
);
255 for (i
= 0; i
< 100; i
++)
257 RtlGenerate8dot3Name(&DirContext
.LongNameU
, FALSE
, &NameContext
, &DirContext
.ShortNameU
);
258 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
259 SearchContext
.DirIndex
= 0;
260 Status
= FindFile (DeviceExt
, ParentFcb
, &DirContext
.ShortNameU
, &SearchContext
, TRUE
);
261 if (!NT_SUCCESS(Status
))
266 if (i
== 100) /* FIXME : what to do after this ? */
270 return STATUS_UNSUCCESSFUL
;
272 IsNameLegal
= RtlIsNameLegalDOS8Dot3(&DirContext
.ShortNameU
, &NameA
, &SpacesFound
);
273 aName
[NameA
.Length
]=0;
277 aName
[NameA
.Length
] = 0;
278 for (posCar
= 0; posCar
< DirContext
.LongNameU
.Length
/ sizeof(WCHAR
); posCar
++)
280 if (DirContext
.LongNameU
.Buffer
[posCar
] == L
'.')
285 /* check if the name and the extension contains upper case characters */
286 RtlDowncaseUnicodeString(&DirContext
.ShortNameU
, &DirContext
.LongNameU
, FALSE
);
287 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
288 uCaseBase
= wcsncmp(DirContext
.LongNameU
.Buffer
,
289 DirContext
.ShortNameU
.Buffer
, posCar
) ? TRUE
: FALSE
;
290 if (posCar
< DirContext
.LongNameU
.Length
/sizeof(WCHAR
))
292 i
= DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) - posCar
;
293 uCaseExt
= wcsncmp(DirContext
.LongNameU
.Buffer
+ posCar
,
294 DirContext
.ShortNameU
.Buffer
+ posCar
, i
) ? TRUE
: FALSE
;
300 /* check if the name and the extension contains lower case characters */
301 RtlUpcaseUnicodeString(&DirContext
.ShortNameU
, &DirContext
.LongNameU
, FALSE
);
302 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
303 lCaseBase
= wcsncmp(DirContext
.LongNameU
.Buffer
,
304 DirContext
.ShortNameU
.Buffer
, posCar
) ? TRUE
: FALSE
;
305 if (posCar
< DirContext
.LongNameU
.Length
/ sizeof(WCHAR
))
307 i
= DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) - posCar
;
308 lCaseExt
= wcsncmp(DirContext
.LongNameU
.Buffer
+ posCar
,
309 DirContext
.ShortNameU
.Buffer
+ posCar
, i
) ? TRUE
: FALSE
;
315 if ((lCaseBase
&& uCaseBase
) || (lCaseExt
&& uCaseExt
))
320 DPRINT ("'%s', '%wZ', needTilde=%d, needLong=%d\n",
321 aName
, &DirContext
.LongNameU
, needTilde
, needLong
);
322 memset(DirContext
.DirEntry
.Fat
.ShortName
, ' ', 11);
323 for (i
= 0; i
< 8 && aName
[i
] && aName
[i
] != '.'; i
++)
325 DirContext
.DirEntry
.Fat
.Filename
[i
] = aName
[i
];
330 for (j
= 8; j
< 11 && aName
[i
]; j
++, i
++)
332 DirContext
.DirEntry
.Fat
.Filename
[j
] = aName
[i
];
335 if (DirContext
.DirEntry
.Fat
.Filename
[0] == 0xe5)
337 DirContext
.DirEntry
.Fat
.Filename
[0] = 0x05;
342 RtlCopyMemory(LongNameBuffer
, DirContext
.LongNameU
.Buffer
, DirContext
.LongNameU
.Length
);
343 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
344 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
345 DirContext
.LongNameU
.Buffer
[DirContext
.LongNameU
.Length
/ sizeof(WCHAR
)] = 0;
346 memset(DirContext
.LongNameU
.Buffer
+ DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) + 1, 0xff,
347 DirContext
.LongNameU
.MaximumLength
- DirContext
.LongNameU
.Length
- sizeof(WCHAR
));
354 DirContext
.DirEntry
.Fat
.lCase
|= VFAT_CASE_LOWER_BASE
;
358 DirContext
.DirEntry
.Fat
.lCase
|= VFAT_CASE_LOWER_EXT
;
362 DPRINT ("dos name=%11.11s\n", DirContext
.DirEntry
.Fat
.Filename
);
365 DirContext
.DirEntry
.Fat
.Attrib
= ReqAttr
;
366 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
368 DirContext
.DirEntry
.Fat
.Attrib
|= FILE_ATTRIBUTE_DIRECTORY
;
370 /* set dates and times */
371 KeQuerySystemTime (&SystemTime
);
375 RtlTimeToTimeFields (&SystemTime
, &tf
);
376 DPRINT1("%d.%d.%d %02d:%02d:%02d.%03d '%wZ'\n",
377 tf
.Day
, tf
.Month
, tf
.Year
, tf
.Hour
,
378 tf
.Minute
, tf
.Second
, tf
.Milliseconds
,
382 FsdSystemTimeToDosDateTime (DeviceExt
, &SystemTime
, &DirContext
.DirEntry
.Fat
.CreationDate
,
383 &DirContext
.DirEntry
.Fat
.CreationTime
);
384 DirContext
.DirEntry
.Fat
.UpdateDate
= DirContext
.DirEntry
.Fat
.CreationDate
;
385 DirContext
.DirEntry
.Fat
.UpdateTime
= DirContext
.DirEntry
.Fat
.CreationTime
;
386 DirContext
.DirEntry
.Fat
.AccessDate
= DirContext
.DirEntry
.Fat
.CreationDate
;
390 /* calculate checksum for 8.3 name */
391 for (pSlots
[0].alias_checksum
= 0, i
= 0; i
< 11; i
++)
393 pSlots
[0].alias_checksum
= (((pSlots
[0].alias_checksum
& 1) << 7
394 | ((pSlots
[0].alias_checksum
& 0xfe) >> 1))
395 + DirContext
.DirEntry
.Fat
.Filename
[i
]);
397 /* construct slots and entry */
398 for (i
= nbSlots
- 2; i
>= 0; i
--)
400 DPRINT ("construct slot %d\n", i
);
401 pSlots
[i
].attr
= 0xf;
404 pSlots
[i
].id
= (unsigned char)(nbSlots
- i
- 1);
408 pSlots
[i
].id
= (unsigned char)(nbSlots
- i
- 1 + 0x40);
410 pSlots
[i
].alias_checksum
= pSlots
[0].alias_checksum
;
411 RtlCopyMemory (pSlots
[i
].name0_4
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13, 10);
412 RtlCopyMemory (pSlots
[i
].name5_10
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13 + 5, 12);
413 RtlCopyMemory (pSlots
[i
].name11_12
, DirContext
.LongNameU
.Buffer
+ (nbSlots
- i
- 2) * 13 + 11, 4);
416 /* try to find nbSlots contiguous entries frees in directory */
417 if (!vfatFindDirSpace(DeviceExt
, ParentFcb
, nbSlots
, &DirContext
.StartIndex
))
420 return STATUS_DISK_FULL
;
422 DirContext
.DirIndex
= DirContext
.StartIndex
+ nbSlots
- 1;
423 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
426 Status
= NextCluster (DeviceExt
, 0, &CurrentCluster
, TRUE
);
427 if (CurrentCluster
== 0xffffffff || !NT_SUCCESS(Status
))
430 if (!NT_SUCCESS(Status
))
434 return STATUS_DISK_FULL
;
436 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
438 DirContext
.DirEntry
.Fat
.FirstClusterHigh
= (unsigned short)(CurrentCluster
>> 16);
440 DirContext
.DirEntry
.Fat
.FirstCluster
= (unsigned short)CurrentCluster
;
443 i
= DeviceExt
->FatInfo
.BytesPerCluster
/ sizeof(FAT_DIR_ENTRY
);
444 FileOffset
.u
.HighPart
= 0;
445 FileOffset
.u
.LowPart
= DirContext
.StartIndex
* sizeof(FAT_DIR_ENTRY
);
446 if (DirContext
.StartIndex
/ i
== DirContext
.DirIndex
/ i
)
450 CcPinRead (ParentFcb
->FileObject
, &FileOffset
, nbSlots
* sizeof(FAT_DIR_ENTRY
),
451 TRUE
, &Context
, (PVOID
*)&pFatEntry
);
454 RtlCopyMemory(pFatEntry
, Buffer
, (nbSlots
- 1) * sizeof(FAT_DIR_ENTRY
));
456 RtlCopyMemory(pFatEntry
+ (nbSlots
- 1), &DirContext
.DirEntry
.Fat
, sizeof(FAT_DIR_ENTRY
));
462 size
= DeviceExt
->FatInfo
.BytesPerCluster
-
463 (DirContext
.StartIndex
* sizeof(FAT_DIR_ENTRY
)) % DeviceExt
->FatInfo
.BytesPerCluster
;
464 i
= size
/ sizeof(FAT_DIR_ENTRY
);
465 CcPinRead (ParentFcb
->FileObject
, &FileOffset
, size
, TRUE
,
466 &Context
, (PVOID
*)&pFatEntry
);
467 RtlCopyMemory(pFatEntry
, Buffer
, size
);
468 CcSetDirtyPinnedData(Context
, NULL
);
469 CcUnpinData(Context
);
470 FileOffset
.u
.LowPart
+= size
;
471 CcPinRead (ParentFcb
->FileObject
, &FileOffset
,
472 nbSlots
* sizeof(FAT_DIR_ENTRY
) - size
,
473 TRUE
, &Context
, (PVOID
*)&pFatEntry
);
476 RtlCopyMemory(pFatEntry
, (PVOID
)(Buffer
+ size
), (nbSlots
- 1 - i
) * sizeof(FAT_DIR_ENTRY
));
478 RtlCopyMemory(pFatEntry
+ nbSlots
- 1 - i
, &DirContext
.DirEntry
.Fat
, sizeof(FAT_DIR_ENTRY
));
480 CcSetDirtyPinnedData(Context
, NULL
);
481 CcUnpinData(Context
);
483 /* FIXME: check status */
484 vfatMakeFCBFromDirEntry (DeviceExt
, ParentFcb
, &DirContext
, Fcb
);
486 DPRINT ("new : entry=%11.11s\n", (*Fcb
)->entry
.Fat
.Filename
);
487 DPRINT ("new : entry=%11.11s\n", DirContext
.DirEntry
.Fat
.Filename
);
489 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
491 FileOffset
.QuadPart
= 0;
492 CcMapData ((*Fcb
)->FileObject
, &FileOffset
, DeviceExt
->FatInfo
.BytesPerCluster
, TRUE
,
493 &Context
, (PVOID
*)&pFatEntry
);
494 /* clear the new directory cluster */
495 RtlZeroMemory (pFatEntry
, DeviceExt
->FatInfo
.BytesPerCluster
);
496 /* create '.' and '..' */
497 RtlCopyMemory (&pFatEntry
[0].Attrib
, &DirContext
.DirEntry
.Fat
.Attrib
, sizeof(FAT_DIR_ENTRY
) - 11);
498 RtlCopyMemory (pFatEntry
[0].ShortName
, ". ", 11);
499 RtlCopyMemory (&pFatEntry
[1].Attrib
, &DirContext
.DirEntry
.Fat
.Attrib
, sizeof(FAT_DIR_ENTRY
) - 11);
500 RtlCopyMemory (pFatEntry
[1].ShortName
, ".. ", 11);
501 pFatEntry
[1].FirstCluster
= ParentFcb
->entry
.Fat
.FirstCluster
;
502 pFatEntry
[1].FirstClusterHigh
= ParentFcb
->entry
.Fat
.FirstClusterHigh
;
503 if (vfatFCBIsRoot(ParentFcb
))
505 pFatEntry
[1].FirstCluster
= 0;
506 pFatEntry
[1].FirstClusterHigh
= 0;
508 CcSetDirtyPinnedData(Context
, NULL
);
509 CcUnpinData(Context
);
512 DPRINT ("addentry ok\n");
513 return STATUS_SUCCESS
;
517 FATXAddEntry (PDEVICE_EXTENSION DeviceExt
,
518 PUNICODE_STRING NameU
,
521 ULONG RequestedOptions
,
524 create a new FAT entry
527 PVOID Context
= NULL
;
528 LARGE_INTEGER SystemTime
, FileOffset
;
530 VFAT_DIRENTRY_CONTEXT DirContext
;
531 PFATX_DIR_ENTRY pFatXDirEntry
;
534 DPRINT ("addEntry: Name='%wZ', Dir='%wZ'\n", NameU
, &ParentFcb
->PathNameU
);
536 DirContext
.LongNameU
= *NameU
;
538 if (DirContext
.LongNameU
.Length
/ sizeof(WCHAR
) > 42)
542 return STATUS_NAME_TOO_LONG
;
545 /* try to find 1 entry free in directory */
546 if (!vfatFindDirSpace(DeviceExt
, ParentFcb
, 1, &DirContext
.StartIndex
))
548 return STATUS_DISK_FULL
;
550 Index
= DirContext
.DirIndex
= DirContext
.StartIndex
;
551 if (!vfatFCBIsRoot(ParentFcb
))
553 DirContext
.DirIndex
+= 2;
554 DirContext
.StartIndex
+= 2;
557 DirContext
.ShortNameU
.Buffer
= 0;
558 DirContext
.ShortNameU
.Length
= 0;
559 DirContext
.ShortNameU
.MaximumLength
= 0;
560 RtlZeroMemory(&DirContext
.DirEntry
.FatX
, sizeof(FATX_DIR_ENTRY
));
561 memset(DirContext
.DirEntry
.FatX
.Filename
, 0xff, 42);
562 DirContext
.DirEntry
.FatX
.FirstCluster
= 0;
563 DirContext
.DirEntry
.FatX
.FileSize
= 0;
566 NameA
.Buffer
= (PCHAR
)DirContext
.DirEntry
.FatX
.Filename
;
568 NameA
.MaximumLength
= 42;
569 RtlUnicodeStringToOemString(&NameA
, &DirContext
.LongNameU
, FALSE
);
570 DirContext
.DirEntry
.FatX
.FilenameLength
= (unsigned char)NameA
.Length
;
573 DirContext
.DirEntry
.FatX
.Attrib
= ReqAttr
;
574 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
576 DirContext
.DirEntry
.FatX
.Attrib
|= FILE_ATTRIBUTE_DIRECTORY
;
579 /* set dates and times */
580 KeQuerySystemTime (&SystemTime
);
584 RtlTimeToTimeFields (&SystemTime
, &tf
);
585 DPRINT1("%d.%d.%d %02d:%02d:%02d.%03d '%wZ'\n",
586 tf
.Day
, tf
.Month
, tf
.Year
, tf
.Hour
,
587 tf
.Minute
, tf
.Second
, tf
.Milliseconds
,
593 FsdSystemTimeToDosDateTime(DeviceExt
, &SystemTime
, &DirContext
.DirEntry
.FatX
.CreationDate
,
594 &DirContext
.DirEntry
.FatX
.CreationTime
);
595 DirContext
.DirEntry
.FatX
.UpdateDate
= DirContext
.DirEntry
.FatX
.CreationDate
;
596 DirContext
.DirEntry
.FatX
.UpdateTime
= DirContext
.DirEntry
.FatX
.CreationTime
;
597 DirContext
.DirEntry
.FatX
.AccessDate
= DirContext
.DirEntry
.FatX
.CreationDate
;
598 DirContext
.DirEntry
.FatX
.AccessTime
= DirContext
.DirEntry
.FatX
.CreationTime
;
600 /* add entry into parent directory */
601 FileOffset
.u
.HighPart
= 0;
602 FileOffset
.u
.LowPart
= Index
* sizeof(FATX_DIR_ENTRY
);
603 CcPinRead(ParentFcb
->FileObject
, &FileOffset
, sizeof(FATX_DIR_ENTRY
),
604 TRUE
, &Context
, (PVOID
*)&pFatXDirEntry
);
605 RtlCopyMemory(pFatXDirEntry
, &DirContext
.DirEntry
.FatX
, sizeof(FATX_DIR_ENTRY
));
606 CcSetDirtyPinnedData(Context
, NULL
);
607 CcUnpinData(Context
);
609 /* FIXME: check status */
610 vfatMakeFCBFromDirEntry(DeviceExt
, ParentFcb
, &DirContext
, Fcb
);
612 DPRINT("addentry ok\n");
613 return STATUS_SUCCESS
;
617 VfatAddEntry (PDEVICE_EXTENSION DeviceExt
,
618 PUNICODE_STRING NameU
,
621 ULONG RequestedOptions
,
624 if (DeviceExt
->Flags
& VCB_IS_FATX
)
625 return FATXAddEntry(DeviceExt
, NameU
, Fcb
, ParentFcb
, RequestedOptions
, ReqAttr
);
627 return FATAddEntry(DeviceExt
, NameU
, Fcb
, ParentFcb
, RequestedOptions
, ReqAttr
);
631 FATDelEntry (PDEVICE_EXTENSION DeviceExt
, PVFATFCB pFcb
)
633 * deleting an existing FAT entry
636 ULONG CurrentCluster
= 0, NextCluster
, i
;
637 PVOID Context
= NULL
;
638 LARGE_INTEGER Offset
;
639 PFAT_DIR_ENTRY pDirEntry
;
642 ASSERT(pFcb
->parentFcb
);
644 DPRINT ("delEntry PathName \'%wZ\'\n", &pFcb
->PathNameU
);
645 DPRINT ("delete entry: %d to %d\n", pFcb
->startIndex
, pFcb
->dirIndex
);
646 Offset
.u
.HighPart
= 0;
647 for (i
= pFcb
->startIndex
; i
<= pFcb
->dirIndex
; i
++)
649 if (Context
== NULL
|| ((i
* sizeof(FAT_DIR_ENTRY
)) % PAGE_SIZE
) == 0)
653 CcSetDirtyPinnedData(Context
, NULL
);
654 CcUnpinData(Context
);
656 Offset
.u
.LowPart
= (i
* sizeof(FAT_DIR_ENTRY
) / PAGE_SIZE
) * PAGE_SIZE
;
657 CcPinRead (pFcb
->parentFcb
->FileObject
, &Offset
, PAGE_SIZE
, TRUE
,
658 &Context
, (PVOID
*)&pDirEntry
);
660 pDirEntry
[i
% (PAGE_SIZE
/ sizeof(FAT_DIR_ENTRY
))].Filename
[0] = 0xe5;
661 if (i
== pFcb
->dirIndex
)
664 vfatDirEntryGetFirstCluster (DeviceExt
,
665 (PDIR_ENTRY
)&pDirEntry
[i
% (PAGE_SIZE
/ sizeof(FAT_DIR_ENTRY
))]);
670 CcSetDirtyPinnedData(Context
, NULL
);
671 CcUnpinData(Context
);
674 while (CurrentCluster
&& CurrentCluster
!= 0xffffffff)
676 GetNextCluster (DeviceExt
, CurrentCluster
, &NextCluster
);
677 /* FIXME: check status */
678 WriteCluster(DeviceExt
, CurrentCluster
, 0);
679 CurrentCluster
= NextCluster
;
681 return STATUS_SUCCESS
;
685 FATXDelEntry (PDEVICE_EXTENSION DeviceExt
, PVFATFCB pFcb
)
687 * deleting an existing FAT entry
690 ULONG CurrentCluster
= 0, NextCluster
;
691 PVOID Context
= NULL
;
692 LARGE_INTEGER Offset
;
693 PFATX_DIR_ENTRY pDirEntry
;
697 ASSERT(pFcb
->parentFcb
);
698 ASSERT(pFcb
->Flags
& FCB_IS_FATX_ENTRY
);
700 StartIndex
= pFcb
->startIndex
;
702 DPRINT ("delEntry PathName \'%wZ\'\n", &pFcb
->PathNameU
);
703 DPRINT ("delete entry: %d\n", StartIndex
);
704 Offset
.u
.HighPart
= 0;
705 Offset
.u
.LowPart
= (StartIndex
* sizeof(FATX_DIR_ENTRY
) / PAGE_SIZE
) * PAGE_SIZE
;
706 if (!CcPinRead (pFcb
->parentFcb
->FileObject
, &Offset
, PAGE_SIZE
, TRUE
,
707 &Context
, (PVOID
*)&pDirEntry
))
709 DPRINT1("CcPinRead(Offset %x:%x, Length %d) failed\n", Offset
.u
.HighPart
, Offset
.u
.LowPart
, PAGE_SIZE
);
710 return STATUS_UNSUCCESSFUL
;
712 pDirEntry
= &pDirEntry
[StartIndex
% (PAGE_SIZE
/ sizeof(FATX_DIR_ENTRY
))];
713 pDirEntry
->FilenameLength
= 0xe5;
714 CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
,
715 (PDIR_ENTRY
)pDirEntry
);
716 CcSetDirtyPinnedData(Context
, NULL
);
717 CcUnpinData(Context
);
719 while (CurrentCluster
&& CurrentCluster
!= 0xffffffff)
721 GetNextCluster (DeviceExt
, CurrentCluster
, &NextCluster
);
722 /* FIXME: check status */
723 WriteCluster(DeviceExt
, CurrentCluster
, 0);
724 CurrentCluster
= NextCluster
;
726 return STATUS_SUCCESS
;
730 VfatDelEntry (PDEVICE_EXTENSION DeviceExt
, PVFATFCB pFcb
)
732 if (DeviceExt
->Flags
& VCB_IS_FATX
)
733 return FATXDelEntry(DeviceExt
, pFcb
);
735 return FATDelEntry(DeviceExt
, pFcb
);