Don't check the share access for directories.
[reactos.git] / reactos / drivers / fs / vfat / dirwr.c
1 /*
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
6 *
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NDEBUG
12 #include "vfat.h"
13
14 NTSTATUS
15 VfatUpdateEntry (PVFATFCB pFcb)
16 /*
17 * update an existing FAT entry
18 */
19 {
20 PVOID Context;
21 PDIR_ENTRY PinEntry;
22 LARGE_INTEGER Offset;
23 ULONG SizeDirEntry;
24 ULONG dirIndex;
25
26 ASSERT(pFcb);
27 ASSERT(pFcb->parentFcb);
28
29 if (pFcb->Flags & FCB_IS_FATX_ENTRY)
30 {
31 SizeDirEntry = sizeof(FATX_DIR_ENTRY);
32 dirIndex = pFcb->startIndex;
33 }
34 else
35 {
36 SizeDirEntry = sizeof(FAT_DIR_ENTRY);
37 dirIndex = pFcb->dirIndex;
38 }
39
40 DPRINT ("updEntry dirIndex %d, PathName \'%wZ\'\n", dirIndex, &pFcb->PathNameU);
41
42 if (vfatFCBIsRoot(pFcb) || (pFcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)))
43 {
44 return STATUS_SUCCESS;
45 }
46
47 ASSERT (pFcb->parentFcb);
48
49 Offset.u.HighPart = 0;
50 Offset.u.LowPart = dirIndex * SizeDirEntry;
51 if (CcPinRead (pFcb->parentFcb->FileObject, &Offset, SizeDirEntry,
52 TRUE, &Context, (PVOID*)&PinEntry))
53 {
54 pFcb->Flags &= ~FCB_IS_DIRTY;
55 RtlCopyMemory(PinEntry, &pFcb->entry, SizeDirEntry);
56 CcSetDirtyPinnedData(Context, NULL);
57 CcUnpinData(Context);
58 return STATUS_SUCCESS;
59 }
60 else
61 {
62 DPRINT1 ("Failed write to \'%wZ\'.\n", &pFcb->parentFcb->PathNameU);
63 return STATUS_UNSUCCESSFUL;
64 }
65 }
66
67 BOOLEAN
68 vfatFindDirSpace(PDEVICE_EXTENSION DeviceExt,
69 PVFATFCB pDirFcb,
70 ULONG nbSlots,
71 PULONG start)
72 {
73 /*
74 * try to find contiguous entries frees in directory,
75 * extend a directory if is neccesary
76 */
77 LARGE_INTEGER FileOffset;
78 ULONG i, count, size, nbFree = 0;
79 PDIR_ENTRY pFatEntry;
80 PVOID Context = NULL;
81 NTSTATUS Status;
82 ULONG SizeDirEntry;
83 FileOffset.QuadPart = 0;
84
85 if (DeviceExt->Flags & VCB_IS_FATX)
86 SizeDirEntry = sizeof(FATX_DIR_ENTRY);
87 else
88 SizeDirEntry = sizeof(FAT_DIR_ENTRY);
89
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))
93 {
94 if (Context == NULL || (i % size) == 0)
95 {
96 if (Context)
97 {
98 CcUnpinData(Context);
99 }
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;
104 }
105 if (ENTRY_END(DeviceExt, pFatEntry))
106 {
107 break;
108 }
109 if (ENTRY_DELETED(DeviceExt, pFatEntry))
110 {
111 nbFree++;
112 }
113 else
114 {
115 nbFree = 0;
116 }
117 if (nbFree == nbSlots)
118 {
119 break;
120 }
121 }
122 if (Context)
123 {
124 CcUnpinData(Context);
125 Context = NULL;
126 }
127 if (nbFree == nbSlots)
128 {
129 // found enough contiguous free slots
130 *start = i - nbSlots + 1;
131 }
132 else
133 {
134 *start = i - nbFree;
135 if (*start + nbSlots > count)
136 {
137 LARGE_INTEGER AllocationSize;
138 CHECKPOINT;
139 // extend the directory
140 if (vfatFCBIsRoot(pDirFcb) && DeviceExt->FatInfo.FatType != FAT32)
141 {
142 // We can't extend a root directory on a FAT12/FAT16/FATX partition
143 return FALSE;
144 }
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))
149 {
150 return FALSE;
151 }
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);
159 else
160 RtlZeroMemory(pFatEntry, DeviceExt->FatInfo.BytesPerCluster);
161 }
162 else if (*start + nbSlots < count)
163 {
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);
170 else
171 RtlZeroMemory(pFatEntry, SizeDirEntry);
172 }
173 if (Context)
174 {
175 CcSetDirtyPinnedData(Context, NULL);
176 CcUnpinData(Context);
177 }
178 }
179 DPRINT ("nbSlots %d nbFree %d, entry number %d\n", nbSlots, nbFree, *start);
180 return TRUE;
181 }
182
183 NTSTATUS
184 FATAddEntry (PDEVICE_EXTENSION DeviceExt,
185 PUNICODE_STRING NameU,
186 PVFATFCB* Fcb,
187 PVFATFCB ParentFcb,
188 ULONG RequestedOptions,
189 UCHAR ReqAttr)
190 /*
191 create a new FAT entry
192 */
193 {
194 PVOID Context = NULL;
195 PFAT_DIR_ENTRY pFatEntry;
196 slot *pSlots;
197 USHORT nbSlots = 0, j, posCar;
198 PUCHAR Buffer;
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;
204 ULONG size;
205 long i;
206
207 OEM_STRING NameA;
208 CHAR aName[13];
209 BOOLEAN IsNameLegal;
210 BOOLEAN SpacesFound;
211
212 VFAT_DIRENTRY_CONTEXT DirContext;
213 WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
214 WCHAR ShortNameBuffer[13];
215
216 DPRINT ("addEntry: Name='%wZ', Dir='%wZ'\n", NameU, &ParentFcb->PathNameU);
217
218 DirContext.LongNameU = *NameU;
219
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));
223 if (Buffer == NULL)
224 {
225 return STATUS_INSUFFICIENT_RESOURCES;
226 }
227 RtlZeroMemory (Buffer, (nbSlots - 1) * sizeof (FAT_DIR_ENTRY));
228 pSlots = (slot *) Buffer;
229
230 NameA.Buffer = aName;
231 NameA.Length = 0;
232 NameA.MaximumLength = sizeof(aName);
233
234 DirContext.ShortNameU.Buffer = ShortNameBuffer;
235 DirContext.ShortNameU.Length = 0;
236 DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
237
238 RtlZeroMemory(&DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY));
239
240 IsNameLegal = RtlIsNameLegalDOS8Dot3(&DirContext.LongNameU, &NameA, &SpacesFound);
241
242 if (!IsNameLegal || SpacesFound)
243 {
244 GENERATE_NAME_CONTEXT NameContext;
245 VFAT_DIRENTRY_CONTEXT SearchContext;
246 WCHAR ShortSearchName[13];
247 needTilde = TRUE;
248 needLong = TRUE;
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);
254
255 for (i = 0; i < 100; i++)
256 {
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))
262 {
263 break;
264 }
265 }
266 if (i == 100) /* FIXME : what to do after this ? */
267 {
268 ExFreePool (Buffer);
269 CHECKPOINT;
270 return STATUS_UNSUCCESSFUL;
271 }
272 IsNameLegal = RtlIsNameLegalDOS8Dot3(&DirContext.ShortNameU, &NameA, &SpacesFound);
273 aName[NameA.Length]=0;
274 }
275 else
276 {
277 aName[NameA.Length] = 0;
278 for (posCar = 0; posCar < DirContext.LongNameU.Length / sizeof(WCHAR); posCar++)
279 {
280 if (DirContext.LongNameU.Buffer[posCar] == L'.')
281 {
282 break;
283 }
284 }
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))
291 {
292 i = DirContext.LongNameU.Length / sizeof(WCHAR) - posCar;
293 uCaseExt = wcsncmp(DirContext.LongNameU.Buffer + posCar,
294 DirContext.ShortNameU.Buffer + posCar, i) ? TRUE : FALSE;
295 }
296 else
297 {
298 uCaseExt = FALSE;
299 }
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))
306 {
307 i = DirContext.LongNameU.Length / sizeof(WCHAR) - posCar;
308 lCaseExt = wcsncmp(DirContext.LongNameU.Buffer + posCar,
309 DirContext.ShortNameU.Buffer + posCar, i) ? TRUE : FALSE;
310 }
311 else
312 {
313 lCaseExt = FALSE;
314 }
315 if ((lCaseBase && uCaseBase) || (lCaseExt && uCaseExt))
316 {
317 needLong = TRUE;
318 }
319 }
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++)
324 {
325 DirContext.DirEntry.Fat.Filename[i] = aName[i];
326 }
327 if (aName[i] == '.')
328 {
329 i++;
330 for (j = 8; j < 11 && aName[i]; j++, i++)
331 {
332 DirContext.DirEntry.Fat.Filename[j] = aName[i];
333 }
334 }
335 if (DirContext.DirEntry.Fat.Filename[0] == 0xe5)
336 {
337 DirContext.DirEntry.Fat.Filename[0] = 0x05;
338 }
339
340 if (needLong)
341 {
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));
348 }
349 else
350 {
351 nbSlots = 1;
352 if (lCaseBase)
353 {
354 DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_BASE;
355 }
356 if (lCaseExt)
357 {
358 DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_EXT;
359 }
360 }
361
362 DPRINT ("dos name=%11.11s\n", DirContext.DirEntry.Fat.Filename);
363
364 /* set attributes */
365 DirContext.DirEntry.Fat.Attrib = ReqAttr;
366 if (RequestedOptions & FILE_DIRECTORY_FILE)
367 {
368 DirContext.DirEntry.Fat.Attrib |= FILE_ATTRIBUTE_DIRECTORY;
369 }
370 /* set dates and times */
371 KeQuerySystemTime (&SystemTime);
372 #if 0
373 {
374 TIME_FIELDS tf;
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,
379 NameU);
380 }
381 #endif
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;
387
388 if (needLong)
389 {
390 /* calculate checksum for 8.3 name */
391 for (pSlots[0].alias_checksum = 0, i = 0; i < 11; i++)
392 {
393 pSlots[0].alias_checksum = (((pSlots[0].alias_checksum & 1) << 7
394 | ((pSlots[0].alias_checksum & 0xfe) >> 1))
395 + DirContext.DirEntry.Fat.Filename[i]);
396 }
397 /* construct slots and entry */
398 for (i = nbSlots - 2; i >= 0; i--)
399 {
400 DPRINT ("construct slot %d\n", i);
401 pSlots[i].attr = 0xf;
402 if (i)
403 {
404 pSlots[i].id = (unsigned char)(nbSlots - i - 1);
405 }
406 else
407 {
408 pSlots[i].id = (unsigned char)(nbSlots - i - 1 + 0x40);
409 }
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);
414 }
415 }
416 /* try to find nbSlots contiguous entries frees in directory */
417 if (!vfatFindDirSpace(DeviceExt, ParentFcb, nbSlots, &DirContext.StartIndex))
418 {
419 ExFreePool (Buffer);
420 return STATUS_DISK_FULL;
421 }
422 DirContext.DirIndex = DirContext.StartIndex + nbSlots - 1;
423 if (RequestedOptions & FILE_DIRECTORY_FILE)
424 {
425 CurrentCluster = 0;
426 Status = NextCluster (DeviceExt, 0, &CurrentCluster, TRUE);
427 if (CurrentCluster == 0xffffffff || !NT_SUCCESS(Status))
428 {
429 ExFreePool (Buffer);
430 if (!NT_SUCCESS(Status))
431 {
432 return Status;
433 }
434 return STATUS_DISK_FULL;
435 }
436 if (DeviceExt->FatInfo.FatType == FAT32)
437 {
438 DirContext.DirEntry.Fat.FirstClusterHigh = (unsigned short)(CurrentCluster >> 16);
439 }
440 DirContext.DirEntry.Fat.FirstCluster = (unsigned short)CurrentCluster;
441 }
442
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)
447 {
448 /* one cluster */
449 CHECKPOINT;
450 CcPinRead (ParentFcb->FileObject, &FileOffset, nbSlots * sizeof(FAT_DIR_ENTRY),
451 TRUE, &Context, (PVOID*)&pFatEntry);
452 if (nbSlots > 1)
453 {
454 RtlCopyMemory(pFatEntry, Buffer, (nbSlots - 1) * sizeof(FAT_DIR_ENTRY));
455 }
456 RtlCopyMemory(pFatEntry + (nbSlots - 1), &DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY));
457 }
458 else
459 {
460 /* two clusters */
461 CHECKPOINT;
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);
474 if (nbSlots - 1 > i)
475 {
476 RtlCopyMemory(pFatEntry, (PVOID)(Buffer + size), (nbSlots - 1 - i) * sizeof(FAT_DIR_ENTRY));
477 }
478 RtlCopyMemory(pFatEntry + nbSlots - 1 - i, &DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY));
479 }
480 CcSetDirtyPinnedData(Context, NULL);
481 CcUnpinData(Context);
482
483 /* FIXME: check status */
484 vfatMakeFCBFromDirEntry (DeviceExt, ParentFcb, &DirContext, Fcb);
485
486 DPRINT ("new : entry=%11.11s\n", (*Fcb)->entry.Fat.Filename);
487 DPRINT ("new : entry=%11.11s\n", DirContext.DirEntry.Fat.Filename);
488
489 if (RequestedOptions & FILE_DIRECTORY_FILE)
490 {
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))
504 {
505 pFatEntry[1].FirstCluster = 0;
506 pFatEntry[1].FirstClusterHigh = 0;
507 }
508 CcSetDirtyPinnedData(Context, NULL);
509 CcUnpinData(Context);
510 }
511 ExFreePool (Buffer);
512 DPRINT ("addentry ok\n");
513 return STATUS_SUCCESS;
514 }
515
516 NTSTATUS
517 FATXAddEntry (PDEVICE_EXTENSION DeviceExt,
518 PUNICODE_STRING NameU,
519 PVFATFCB* Fcb,
520 PVFATFCB ParentFcb,
521 ULONG RequestedOptions,
522 UCHAR ReqAttr)
523 /*
524 create a new FAT entry
525 */
526 {
527 PVOID Context = NULL;
528 LARGE_INTEGER SystemTime, FileOffset;
529 OEM_STRING NameA;
530 VFAT_DIRENTRY_CONTEXT DirContext;
531 PFATX_DIR_ENTRY pFatXDirEntry;
532 ULONG Index;
533
534 DPRINT ("addEntry: Name='%wZ', Dir='%wZ'\n", NameU, &ParentFcb->PathNameU);
535
536 DirContext.LongNameU = *NameU;
537
538 if (DirContext.LongNameU.Length / sizeof(WCHAR) > 42)
539 {
540 /* name too long */
541 CHECKPOINT;
542 return STATUS_NAME_TOO_LONG;
543 }
544
545 /* try to find 1 entry free in directory */
546 if (!vfatFindDirSpace(DeviceExt, ParentFcb, 1, &DirContext.StartIndex))
547 {
548 return STATUS_DISK_FULL;
549 }
550 Index = DirContext.DirIndex = DirContext.StartIndex;
551 if (!vfatFCBIsRoot(ParentFcb))
552 {
553 DirContext.DirIndex += 2;
554 DirContext.StartIndex += 2;
555 }
556
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;
564
565 /* set file name */
566 NameA.Buffer = (PCHAR)DirContext.DirEntry.FatX.Filename;
567 NameA.Length = 0;
568 NameA.MaximumLength = 42;
569 RtlUnicodeStringToOemString(&NameA, &DirContext.LongNameU, FALSE);
570 DirContext.DirEntry.FatX.FilenameLength = (unsigned char)NameA.Length;
571
572 /* set attributes */
573 DirContext.DirEntry.FatX.Attrib = ReqAttr;
574 if (RequestedOptions & FILE_DIRECTORY_FILE)
575 {
576 DirContext.DirEntry.FatX.Attrib |= FILE_ATTRIBUTE_DIRECTORY;
577 }
578
579 /* set dates and times */
580 KeQuerySystemTime (&SystemTime);
581 #if 0
582 {
583 TIME_FIELDS tf;
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,
588 NameU);
589 }
590 #endif
591
592
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;
599
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);
608
609 /* FIXME: check status */
610 vfatMakeFCBFromDirEntry(DeviceExt, ParentFcb, &DirContext, Fcb);
611
612 DPRINT("addentry ok\n");
613 return STATUS_SUCCESS;
614 }
615
616 NTSTATUS
617 VfatAddEntry (PDEVICE_EXTENSION DeviceExt,
618 PUNICODE_STRING NameU,
619 PVFATFCB *Fcb,
620 PVFATFCB ParentFcb,
621 ULONG RequestedOptions,
622 UCHAR ReqAttr)
623 {
624 if (DeviceExt->Flags & VCB_IS_FATX)
625 return FATXAddEntry(DeviceExt, NameU, Fcb, ParentFcb, RequestedOptions, ReqAttr);
626 else
627 return FATAddEntry(DeviceExt, NameU, Fcb, ParentFcb, RequestedOptions, ReqAttr);
628 }
629
630 NTSTATUS
631 FATDelEntry (PDEVICE_EXTENSION DeviceExt, PVFATFCB pFcb)
632 /*
633 * deleting an existing FAT entry
634 */
635 {
636 ULONG CurrentCluster = 0, NextCluster, i;
637 PVOID Context = NULL;
638 LARGE_INTEGER Offset;
639 PFAT_DIR_ENTRY pDirEntry;
640
641 ASSERT(pFcb);
642 ASSERT(pFcb->parentFcb);
643
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++)
648 {
649 if (Context == NULL || ((i * sizeof(FAT_DIR_ENTRY)) % PAGE_SIZE) == 0)
650 {
651 if (Context)
652 {
653 CcSetDirtyPinnedData(Context, NULL);
654 CcUnpinData(Context);
655 }
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);
659 }
660 pDirEntry[i % (PAGE_SIZE / sizeof(FAT_DIR_ENTRY))].Filename[0] = 0xe5;
661 if (i == pFcb->dirIndex)
662 {
663 CurrentCluster =
664 vfatDirEntryGetFirstCluster (DeviceExt,
665 (PDIR_ENTRY)&pDirEntry[i % (PAGE_SIZE / sizeof(FAT_DIR_ENTRY))]);
666 }
667 }
668 if (Context)
669 {
670 CcSetDirtyPinnedData(Context, NULL);
671 CcUnpinData(Context);
672 }
673
674 while (CurrentCluster && CurrentCluster != 0xffffffff)
675 {
676 GetNextCluster (DeviceExt, CurrentCluster, &NextCluster);
677 /* FIXME: check status */
678 WriteCluster(DeviceExt, CurrentCluster, 0);
679 CurrentCluster = NextCluster;
680 }
681 return STATUS_SUCCESS;
682 }
683
684 NTSTATUS
685 FATXDelEntry (PDEVICE_EXTENSION DeviceExt, PVFATFCB pFcb)
686 /*
687 * deleting an existing FAT entry
688 */
689 {
690 ULONG CurrentCluster = 0, NextCluster;
691 PVOID Context = NULL;
692 LARGE_INTEGER Offset;
693 PFATX_DIR_ENTRY pDirEntry;
694 ULONG StartIndex;
695
696 ASSERT(pFcb);
697 ASSERT(pFcb->parentFcb);
698 ASSERT(pFcb->Flags & FCB_IS_FATX_ENTRY);
699
700 StartIndex = pFcb->startIndex;
701
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))
708 {
709 DPRINT1("CcPinRead(Offset %x:%x, Length %d) failed\n", Offset.u.HighPart, Offset.u.LowPart, PAGE_SIZE);
710 return STATUS_UNSUCCESSFUL;
711 }
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);
718
719 while (CurrentCluster && CurrentCluster != 0xffffffff)
720 {
721 GetNextCluster (DeviceExt, CurrentCluster, &NextCluster);
722 /* FIXME: check status */
723 WriteCluster(DeviceExt, CurrentCluster, 0);
724 CurrentCluster = NextCluster;
725 }
726 return STATUS_SUCCESS;
727 }
728
729 NTSTATUS
730 VfatDelEntry (PDEVICE_EXTENSION DeviceExt, PVFATFCB pFcb)
731 {
732 if (DeviceExt->Flags & VCB_IS_FATX)
733 return FATXDelEntry(DeviceExt, pFcb);
734 else
735 return FATDelEntry(DeviceExt, pFcb);
736 }
737
738 /* EOF */