1 /* $Id: dirwr.c,v 1.23 2002/01/08 00:49:01 dwelch Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/fs/vfat/dirwr.c
6 * PURPOSE: VFAT Filesystem : write in directory
10 /* INCLUDES *****************************************************************/
12 #include <ddk/ntddk.h>
22 const char *short_illegals
=" ;+=[]',\"*\\<>/?:|";
25 vfatIsShortIllegal(char c
)
28 for (i
= 0; short_illegals
[i
]; i
++)
29 if (c
== short_illegals
[i
])
35 * Copies a file name into a directory slot (long file name entry)
36 * and fills trailing slot space with 0xFFFF. This keeps scandisk
40 FillSlot (slot
* Slot
, WCHAR
* FileName
)
43 WCHAR
*src
= FileName
;
56 if (fill
== FALSE
&& (*src
== 0))
71 if (fill
== FALSE
&& (*src
== 0))
78 dst
= Slot
->name11_12
;
86 if (fill
== FALSE
&& (*src
== 0))
93 NTSTATUS
updEntry (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT pFileObject
)
95 update an existing FAT entry
101 PVFATFCB pDirFcb
= NULL
, pFcb
= NULL
;
102 LARGE_INTEGER Offset
;
104 DPRINT ("updEntry PathFileName \'%S\'\n",
105 ((PVFATCCB
)(pFileObject
->FsContext2
))->pFcb
->PathName
);
106 status
= vfatGetFCBForFile(DeviceExt
, &pDirFcb
, &pFcb
,
107 ((PVFATCCB
)(pFileObject
->FsContext2
))->pFcb
->PathName
);
110 vfatReleaseFCB(DeviceExt
, pFcb
);
112 if (!NT_SUCCESS(status
))
116 vfatReleaseFCB(DeviceExt
, pDirFcb
);
121 Offset
.QuadPart
= pFcb
->dirIndex
* sizeof(FATDirEntry
);
122 if(CcMapData (pDirFcb
->FileObject
, &Offset
, sizeof(FATDirEntry
),
123 TRUE
, &Context
, &Buffer
))
125 memcpy(Buffer
, &pFcb
->entry
, sizeof(FATDirEntry
));
126 CcSetDirtyPinnedData(Context
, NULL
);
127 CcUnpinData(Context
);
130 DPRINT1 ("Failed write to \'%S\'.\n", pDirFcb
->PathName
);
131 vfatReleaseFCB(DeviceExt
, pDirFcb
);
132 return STATUS_SUCCESS
;
136 addEntry (PDEVICE_EXTENSION DeviceExt
,
137 PFILE_OBJECT pFileObject
, ULONG RequestedOptions
, UCHAR ReqAttr
)
139 create a new FAT entry
142 WCHAR DirName
[MAX_PATH
], *FileName
, *PathFileName
;
144 FATDirEntry FatEntry
;
148 ULONG LengthRead
, Offset
;
149 short nbSlots
= 0, nbFree
= 0, i
, j
, posCar
, NameLen
;
150 PUCHAR Buffer
, Buffer2
;
151 BOOLEAN needTilde
= FALSE
, needLong
= FALSE
;
153 ULONG CurrentCluster
;
154 LARGE_INTEGER SystemTime
, LocalTime
;
155 NTSTATUS Status
= STATUS_SUCCESS
;
158 PathFileName
= pFileObject
->FileName
.Buffer
;
159 DPRINT ("addEntry: Pathname=%S\n", PathFileName
);
160 //find last \ in PathFileName
162 for (i
= 0; PathFileName
[i
]; i
++)
163 if (PathFileName
[i
] == '\\')
166 return STATUS_UNSUCCESSFUL
;
167 FileName
= &PathFileName
[posCar
+ 1];
168 for (NameLen
= 0; FileName
[NameLen
]; NameLen
++);
169 // extract directory name from pathname
178 memcpy (DirName
, PathFileName
, posCar
* sizeof (WCHAR
));
181 // open parent directory
182 pDirFcb
= vfatGrabFCBFromTable(DeviceExt
, DirName
);
185 return STATUS_UNSUCCESSFUL
;
187 nbSlots
= (NameLen
+ 12) / 13 + 1; //nb of entry needed for long name+normal entry
188 DPRINT ("NameLen= %d, nbSlots =%d\n", NameLen
, nbSlots
);
190 ExAllocatePool (NonPagedPool
, (nbSlots
+ 1) * sizeof (FATDirEntry
));
191 memset (Buffer
, 0, (nbSlots
+ 1) * sizeof (FATDirEntry
));
192 pEntry
= (FATDirEntry
*) (Buffer
+ (nbSlots
- 1) * sizeof (FATDirEntry
));
193 pSlots
= (slot
*) Buffer
;
196 // find last point in name
198 for (i
= 0; FileName
[i
]; i
++)
199 if (FileName
[i
] == '.')
214 //copy 8 characters max
215 memset (pEntry
, ' ', 11);
216 for (i
= 0, j
= 0; j
< 8 && i
< posCar
; i
++)
218 if (vfatIsShortIllegal (FileName
[i
]))
221 pEntry
->Filename
[j
++] = '_';
225 if (FileName
[i
] == '.')
228 pEntry
->Filename
[j
++] = toupper ((char) FileName
[i
]);
232 if (FileName
[posCar
])
233 for (j
= 0, i
= posCar
+ 1; FileName
[i
] && j
< 3; i
++)
235 if (vfatIsShortIllegal(FileName
[i
]))
238 pEntry
->Ext
[j
++] = '_';
242 if (FileName
[i
] == '.')
245 pEntry
->Ext
[j
++] = toupper ((char) (FileName
[i
] & 0x7F));
250 //find good value for tilde
254 DPRINT ("searching a good value for tilde\n");
255 for (posCar
= 0; posCar
< 8 && pEntry
->Filename
[posCar
] != ' '; posCar
++);
256 if (posCar
== 0) // ??????????????????????
257 pEntry
->Filename
[posCar
++] = '_';
261 pEntry
->Filename
[posCar
- 2] = '~';
262 pEntry
->Filename
[posCar
- 1] = '1';
263 vfat8Dot3ToString (pEntry
->Filename
, pEntry
->Ext
, DirName
);
264 //try first with xxxxxx~y.zzz
265 for (i
= 1; i
< 10; i
++)
267 DirName
[posCar
-1] = '0' + i
;
268 pEntry
->Filename
[posCar
- 1] = '0' + i
;
269 status
= FindFile (DeviceExt
, &FileFcb
, pDirFcb
, DirName
, NULL
, NULL
);
270 if (!NT_SUCCESS(status
))
278 pEntry
->Filename
[posCar
- 3] = '~';
279 pEntry
->Filename
[posCar
- 2] = '1';
280 pEntry
->Filename
[posCar
- 1] = '0';
281 vfat8Dot3ToString (pEntry
->Filename
, pEntry
->Ext
, DirName
);
282 //try second with xxxxx~yy.zzz
283 for (i
= 10; i
< 100; i
++)
285 DirName
[posCar
- 1] = '0' + i
% 10;
286 DirName
[posCar
- 2] = '0' + i
/ 10;
287 pEntry
->Filename
[posCar
- 1] = '0' + i
% 10;
288 pEntry
->Filename
[posCar
- 2] = '0' + i
/ 10;
289 status
= FindFile (DeviceExt
, &FileFcb
, pDirFcb
, DirName
, NULL
, NULL
);
290 if (!NT_SUCCESS(status
))
293 if (i
== 100) //FIXME : what to do after 99 tilde ?
295 vfatReleaseFCB(DeviceExt
, pDirFcb
);
297 return STATUS_UNSUCCESSFUL
;
303 DPRINT ("check if long name entry needed, needlong=%d\n", needLong
);
304 for (i
= 0; i
< posCar
; i
++)
305 if ((USHORT
) pEntry
->Filename
[i
] != FileName
[i
])
307 DPRINT ("i=%d,%d,%d\n", i
, pEntry
->Filename
[i
], FileName
[i
]);
312 i
++; //jump on point char
313 for (j
= 0, i
= posCar
+ 1; FileName
[i
] && i
< posCar
+ 4; i
++)
314 if ((USHORT
) pEntry
->Ext
[j
++] != FileName
[i
])
316 DPRINT ("i=%d,j=%d,%d,%d\n", i
, j
, pEntry
->Filename
[i
],
322 if (needLong
== FALSE
)
325 memcpy (Buffer
, pEntry
, sizeof (FATDirEntry
));
326 memset (pEntry
, 0, sizeof (FATDirEntry
));
327 pEntry
= (FATDirEntry
*) Buffer
;
331 memset (DirName
, 0xff, sizeof (DirName
));
332 memcpy (DirName
, FileName
, NameLen
* sizeof (WCHAR
));
333 DirName
[NameLen
] = 0;
335 DPRINT ("dos name=%11.11s\n", pEntry
->Filename
);
338 pEntry
->Attrib
= ReqAttr
;
339 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
340 pEntry
->Attrib
|= FILE_ATTRIBUTE_DIRECTORY
;
342 /* set dates and times */
343 KeQuerySystemTime (&SystemTime
);
344 ExSystemTimeToLocalTime (&SystemTime
, &LocalTime
);
345 FsdFileTimeToDosDateTime ((TIME
*) & LocalTime
,
346 &pEntry
->CreationDate
, &pEntry
->CreationTime
);
347 pEntry
->UpdateDate
= pEntry
->CreationDate
;
348 pEntry
->UpdateTime
= pEntry
->CreationTime
;
349 pEntry
->AccessDate
= pEntry
->CreationDate
;
351 // calculate checksum for 8.3 name
352 for (pSlots
[0].alias_checksum
= i
= 0; i
< 11; i
++)
354 pSlots
[0].alias_checksum
= (((pSlots
[0].alias_checksum
& 1) << 7
355 | ((pSlots
[0].alias_checksum
& 0xfe) >> 1))
356 + pEntry
->Filename
[i
]);
358 //construct slots and entry
359 for (i
= nbSlots
- 2; i
>= 0; i
--)
361 DPRINT ("construct slot %d\n", i
);
362 pSlots
[i
].attr
= 0xf;
364 pSlots
[i
].id
= nbSlots
- i
- 1;
366 pSlots
[i
].id
= nbSlots
- i
- 1 + 0x40;
367 pSlots
[i
].alias_checksum
= pSlots
[0].alias_checksum
;
368 //FIXME pSlots[i].start=;
369 FillSlot (&pSlots
[i
], FileName
+ (nbSlots
- i
- 2) * 13);
372 //try to find nbSlots contiguous entries frees in directory
373 for (i
= 0, status
= STATUS_SUCCESS
; status
== STATUS_SUCCESS
; i
++)
376 VfatReadFile (DeviceExt
, pDirFcb
->FileObject
,
377 &FatEntry
, sizeof (FATDirEntry
),
378 i
* sizeof (FATDirEntry
), &LengthRead
, FALSE
);
379 if (status
== STATUS_END_OF_FILE
)
381 if (!NT_SUCCESS (status
))
383 DPRINT1 ("VfatReadFile failed to read the directory entry\n");
386 if (LengthRead
!= sizeof (FATDirEntry
))
388 DPRINT1 ("VfatReadFile did not read a complete directory entry\n");
391 if (vfatIsDirEntryEndMarker(&FatEntry
))
393 if (vfatIsDirEntryDeleted(&FatEntry
))
398 if (nbFree
== nbSlots
)
401 DPRINT ("nbSlots %d nbFree %d, entry number %d\n", nbSlots
, nbFree
, i
);
403 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
405 CurrentCluster
= 0xffffffff;
406 status
= NextCluster (DeviceExt
, NULL
, 0, &CurrentCluster
, TRUE
);
407 if (CurrentCluster
== 0xffffffff || !NT_SUCCESS(status
))
409 vfatReleaseFCB(DeviceExt
, pDirFcb
);
411 if (!NT_SUCCESS(status
))
415 return STATUS_DISK_FULL
;
418 Buffer2
= ExAllocatePool (NonPagedPool
, DeviceExt
->BytesPerCluster
);
419 memset (Buffer2
, 0, DeviceExt
->BytesPerCluster
);
420 VfatRawWriteCluster (DeviceExt
, 0, Buffer2
, CurrentCluster
, 1);
421 ExFreePool (Buffer2
);
422 if (DeviceExt
->FatType
== FAT32
)
424 pEntry
->FirstClusterHigh
= CurrentCluster
>> 16;
425 pEntry
->FirstCluster
= CurrentCluster
;
428 pEntry
->FirstCluster
= CurrentCluster
;
430 if (nbFree
== nbSlots
)
432 Offset
= (i
- nbSlots
+ 1) * sizeof (FATDirEntry
);
434 VfatWriteFile (DeviceExt
, pDirFcb
->FileObject
,
435 Buffer
, sizeof (FATDirEntry
) * nbSlots
,
436 Offset
, FALSE
, FALSE
);
437 DPRINT ("VfatWriteFile() returned: %x\n", status
);
440 { //write at end of directory
441 Offset
= (i
- nbFree
) * sizeof (FATDirEntry
);
443 VfatWriteFile (DeviceExt
, pDirFcb
->FileObject
,
444 Buffer
, sizeof (FATDirEntry
) * (nbSlots
+ 1),
445 Offset
, FALSE
, FALSE
);
447 DPRINT ("write entry offset %d status=%x\n", Offset
, status
);
448 if (!NT_SUCCESS(status
))
450 vfatReleaseFCB (DeviceExt
, pDirFcb
);
451 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
453 // free the reserved cluster
454 WriteCluster(DeviceExt
, CurrentCluster
, 0);
460 // FEXME: check status
461 vfatMakeFCBFromDirEntry (DeviceExt
, pDirFcb
, FileName
,
462 pEntry
, Offset
/ sizeof(FATDirEntry
) + nbSlots
-1, &newFCB
);
463 vfatAttachFCBToFileObject (DeviceExt
, newFCB
, pFileObject
);
465 DPRINT ("new : entry=%11.11s\n", newFCB
->entry
.Filename
);
466 DPRINT ("new : entry=%11.11s\n", pEntry
->Filename
);
468 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
471 memcpy (pEntry
->Filename
, ". ", 11);
473 VfatWriteFile (DeviceExt
, pFileObject
, pEntry
, sizeof (FATDirEntry
),
475 pEntry
->FirstCluster
= pDirFcb
->entry
.FirstCluster
;
476 pEntry
->FirstClusterHigh
= pDirFcb
->entry
.FirstClusterHigh
;
477 memcpy (pEntry
->Filename
, ".. ", 11);
478 if (pEntry
->FirstCluster
== 1 && DeviceExt
->FatType
!= FAT32
)
479 pEntry
->FirstCluster
= 0;
481 VfatWriteFile (DeviceExt
, pFileObject
, pEntry
, sizeof (FATDirEntry
),
482 sizeof (FATDirEntry
), FALSE
, FALSE
);
484 vfatReleaseFCB (DeviceExt
, pDirFcb
);
486 DPRINT ("addentry ok\n");
487 return STATUS_SUCCESS
;
491 delEntry (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT pFileObject
)
493 deleting an existing FAT entry
497 PVFATFCB pFcb
= NULL
, pDirFcb
= NULL
;
500 ULONG Entry
= 0, startEntry
, Read
, CurrentCluster
, NextCluster
, i
;
501 FATDirEntry DirEntry
;
503 DPRINT ("delEntry PathFileName \'%S\'\n", pFileObject
->FileName
.Buffer
);
505 status
= vfatGetFCBForFile(DeviceExt
, &pDirFcb
, &pFcb
, pFileObject
->FileName
.Buffer
);
508 vfatReleaseFCB(DeviceExt
, pFcb
);
510 if (!NT_SUCCESS(status
))
514 vfatReleaseFCB(DeviceExt
, pDirFcb
);
518 pName
= ((PVFATCCB
)(pFileObject
->FsContext2
))->pFcb
->ObjectName
;
523 status
= FindFile (DeviceExt
, &Fcb
, pDirFcb
, pName
, &Entry
, &startEntry
);
525 if (NT_SUCCESS(status
))
527 DPRINT ("delete entry: %d to %d\n", startEntry
, Entry
);
528 for (i
= startEntry
; i
<= Entry
; i
++)
530 // FIXME: using Cc-functions
531 VfatReadFile (DeviceExt
, pDirFcb
->FileObject
, &DirEntry
,
532 sizeof (FATDirEntry
), i
* sizeof(FATDirEntry
), &Read
, FALSE
);
533 DirEntry
.Filename
[0] = 0xe5;
534 // FIXME: check status
535 VfatWriteFile (DeviceExt
, pDirFcb
->FileObject
, &DirEntry
,
536 sizeof(FATDirEntry
), i
* sizeof(FATDirEntry
), FALSE
, FALSE
);
538 CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &DirEntry
);
539 while (CurrentCluster
&& CurrentCluster
!= 0xffffffff)
541 GetNextCluster (DeviceExt
, CurrentCluster
, &NextCluster
, FALSE
);
542 // FIXME: check status
543 WriteCluster(DeviceExt
, CurrentCluster
, 0);
544 CurrentCluster
= NextCluster
;