- Experimentally switch fastfat driver to non-Ros Cc functions, and thus no FSD in...
[reactos.git] / reactos / drivers / filesystems / fastfat / rw.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/rw.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
7 *
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #define NDEBUG
13 #include "vfat.h"
14
15 /*
16 * Uncomment to enable strict verification of cluster/offset pair
17 * caching. If this option is enabled you lose all the benefits of
18 * the caching and the read/write operations will actually be
19 * slower. It's meant only for debugging!!!
20 * - Filip Navara, 26/07/2004
21 */
22 /* #define DEBUG_VERIFY_OFFSET_CACHING */
23
24 /* FUNCTIONS *****************************************************************/
25
26 NTSTATUS
27 NextCluster(PDEVICE_EXTENSION DeviceExt,
28 ULONG FirstCluster,
29 PULONG CurrentCluster,
30 BOOLEAN Extend)
31 /*
32 * Return the next cluster in a FAT chain, possibly extending the chain if
33 * necessary
34 */
35 {
36 if (FirstCluster == 1)
37 {
38 (*CurrentCluster) += DeviceExt->FatInfo.SectorsPerCluster;
39 return(STATUS_SUCCESS);
40 }
41 else
42 {
43 if (Extend)
44 return GetNextClusterExtend(DeviceExt, (*CurrentCluster), CurrentCluster);
45 else
46 return GetNextCluster(DeviceExt, (*CurrentCluster), CurrentCluster);
47 }
48 }
49
50 NTSTATUS
51 OffsetToCluster(PDEVICE_EXTENSION DeviceExt,
52 ULONG FirstCluster,
53 ULONG FileOffset,
54 PULONG Cluster,
55 BOOLEAN Extend)
56 /*
57 * Return the cluster corresponding to an offset within a file,
58 * possibly extending the file if necessary
59 */
60 {
61 ULONG CurrentCluster;
62 ULONG i;
63 NTSTATUS Status;
64 /*
65 DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x,"
66 " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt,
67 Fcb, FirstCluster, FileOffset, Cluster, Extend);
68 */
69 if (FirstCluster == 0)
70 {
71 DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n");
72 KEBUGCHECK(0);
73 }
74
75 if (FirstCluster == 1)
76 {
77 /* root of FAT16 or FAT12 */
78 *Cluster = DeviceExt->FatInfo.rootStart + FileOffset
79 / (DeviceExt->FatInfo.BytesPerCluster) * DeviceExt->FatInfo.SectorsPerCluster;
80 return(STATUS_SUCCESS);
81 }
82 else
83 {
84 CurrentCluster = FirstCluster;
85 if (Extend)
86 {
87 for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++)
88 {
89 Status = GetNextClusterExtend (DeviceExt, CurrentCluster, &CurrentCluster);
90 if (!NT_SUCCESS(Status))
91 return(Status);
92 }
93 *Cluster = CurrentCluster;
94 }
95 else
96 {
97 for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++)
98 {
99 Status = GetNextCluster (DeviceExt, CurrentCluster, &CurrentCluster);
100 if (!NT_SUCCESS(Status))
101 return(Status);
102 }
103 *Cluster = CurrentCluster;
104 }
105 return(STATUS_SUCCESS);
106 }
107 }
108
109 static NTSTATUS
110 VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext,
111 ULONG Length,
112 LARGE_INTEGER ReadOffset,
113 PULONG LengthRead)
114 /*
115 * FUNCTION: Reads data from a file
116 */
117 {
118 ULONG CurrentCluster;
119 ULONG FirstCluster;
120 ULONG StartCluster;
121 ULONG ClusterCount;
122 LARGE_INTEGER StartOffset;
123 PDEVICE_EXTENSION DeviceExt;
124 BOOLEAN First = TRUE;
125 PVFATFCB Fcb;
126 PVFATCCB Ccb;
127 NTSTATUS Status;
128 ULONG BytesDone;
129 ULONG BytesPerSector;
130 ULONG BytesPerCluster;
131 ULONG LastCluster;
132 ULONG LastOffset;
133
134 /* PRECONDITION */
135 ASSERT(IrpContext);
136 DeviceExt = IrpContext->DeviceExt;
137 ASSERT(DeviceExt);
138 ASSERT(DeviceExt->FatInfo.BytesPerCluster);
139 ASSERT(IrpContext->FileObject);
140 ASSERT(IrpContext->FileObject->FsContext2 != NULL);
141
142 DPRINT("VfatReadFileData(DeviceExt %p, FileObject %p, "
143 "Length %d, ReadOffset 0x%I64x)\n", DeviceExt,
144 IrpContext->FileObject, Length, ReadOffset.QuadPart);
145
146 *LengthRead = 0;
147
148 Ccb = (PVFATCCB)IrpContext->FileObject->FsContext2;
149 Fcb = IrpContext->FileObject->FsContext;
150 BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
151 BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster;
152
153 ASSERT(ReadOffset.QuadPart + Length <= ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector));
154 ASSERT(ReadOffset.u.LowPart % BytesPerSector == 0);
155 ASSERT(Length % BytesPerSector == 0);
156
157 /* Is this a read of the FAT? */
158 if (Fcb->Flags & FCB_IS_FAT)
159 {
160 ReadOffset.QuadPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
161 Status = VfatReadDiskPartial(IrpContext, &ReadOffset, Length, 0, TRUE);
162
163 if (NT_SUCCESS(Status))
164 {
165 *LengthRead = Length;
166 }
167 else
168 {
169 DPRINT1("FAT reading failed, Status %x\n", Status);
170 }
171 return Status;
172 }
173 /* Is this a read of the Volume ? */
174 if (Fcb->Flags & FCB_IS_VOLUME)
175 {
176 Status = VfatReadDiskPartial(IrpContext, &ReadOffset, Length, 0, TRUE);
177 if (NT_SUCCESS(Status))
178 {
179 *LengthRead = Length;
180 }
181 else
182 {
183 DPRINT1("Volume reading failed, Status %x\n", Status);
184 }
185 return Status;
186 }
187
188 /*
189 * Find the first cluster
190 */
191 FirstCluster = CurrentCluster =
192 vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
193
194 if (FirstCluster == 1)
195 {
196 // Directory of FAT12/16 needs a special handling
197 CHECKPOINT;
198 if (ReadOffset.u.LowPart + Length > DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector)
199 {
200 Length = DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector - ReadOffset.u.LowPart;
201 }
202 ReadOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector;
203
204 // Fire up the read command
205
206 Status = VfatReadDiskPartial (IrpContext, &ReadOffset, Length, 0, TRUE);
207 if (NT_SUCCESS(Status))
208 {
209 *LengthRead = Length;
210 }
211 return Status;
212 }
213
214 ExAcquireFastMutex(&Fcb->LastMutex);
215 LastCluster = Fcb->LastCluster;
216 LastOffset = Fcb->LastOffset;
217 ExReleaseFastMutex(&Fcb->LastMutex);
218
219 /*
220 * Find the cluster to start the read from
221 */
222 if (LastCluster > 0 && ReadOffset.u.LowPart >= LastOffset)
223 {
224 Status = OffsetToCluster(DeviceExt, LastCluster,
225 ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster) -
226 LastOffset,
227 &CurrentCluster, FALSE);
228 #ifdef DEBUG_VERIFY_OFFSET_CACHING
229 /* DEBUG VERIFICATION */
230 {
231 ULONG CorrectCluster;
232 OffsetToCluster(DeviceExt, FirstCluster,
233 ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster),
234 &CorrectCluster, FALSE);
235 if (CorrectCluster != CurrentCluster)
236 KEBUGCHECK(FAT_FILE_SYSTEM);
237 }
238 #endif
239 }
240 else
241 {
242 Status = OffsetToCluster(DeviceExt, FirstCluster,
243 ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster),
244 &CurrentCluster, FALSE);
245 }
246 if (!NT_SUCCESS(Status))
247 {
248 return(Status);
249 }
250
251 ExAcquireFastMutex(&Fcb->LastMutex);
252 Fcb->LastCluster = CurrentCluster;
253 Fcb->LastOffset = ROUND_DOWN (ReadOffset.u.LowPart, BytesPerCluster);
254 ExReleaseFastMutex(&Fcb->LastMutex);
255
256 KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
257 IrpContext->RefCount = 1;
258
259 while (Length > 0 && CurrentCluster != 0xffffffff)
260 {
261 StartCluster = CurrentCluster;
262 StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
263 BytesDone = 0;
264 ClusterCount = 0;
265
266 do
267 {
268 ClusterCount++;
269 if (First)
270 {
271 BytesDone = min (Length, BytesPerCluster - (ReadOffset.u.LowPart % BytesPerCluster));
272 StartOffset.QuadPart += ReadOffset.u.LowPart % BytesPerCluster;
273 First = FALSE;
274 }
275 else
276 {
277 if (Length - BytesDone > BytesPerCluster)
278 {
279 BytesDone += BytesPerCluster;
280 }
281 else
282 {
283 BytesDone = Length;
284 }
285 }
286 Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE);
287 }
288 while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone);
289 DPRINT("start %08x, next %08x, count %d\n",
290 StartCluster, CurrentCluster, ClusterCount);
291
292 ExAcquireFastMutex(&Fcb->LastMutex);
293 Fcb->LastCluster = StartCluster + (ClusterCount - 1);
294 Fcb->LastOffset = ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster) + (ClusterCount - 1) * BytesPerCluster;
295 ExReleaseFastMutex(&Fcb->LastMutex);
296
297 // Fire up the read command
298 Status = VfatReadDiskPartial (IrpContext, &StartOffset, BytesDone, *LengthRead, FALSE);
299 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
300 {
301 break;
302 }
303 *LengthRead += BytesDone;
304 Length -= BytesDone;
305 ReadOffset.u.LowPart += BytesDone;
306 }
307 if (0 != InterlockedDecrement((PLONG)&IrpContext->RefCount))
308 {
309 KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
310 }
311 if (NT_SUCCESS(Status) || Status == STATUS_PENDING)
312 {
313 if (Length > 0)
314 {
315 Status = STATUS_UNSUCCESSFUL;
316 }
317 else
318 {
319 Status = IrpContext->Irp->IoStatus.Status;
320 }
321 }
322 return Status;
323 }
324
325 static NTSTATUS
326 VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
327 ULONG Length,
328 LARGE_INTEGER WriteOffset)
329 {
330 PDEVICE_EXTENSION DeviceExt;
331 PVFATFCB Fcb;
332 PVFATCCB Ccb;
333 ULONG Count;
334 ULONG FirstCluster;
335 ULONG CurrentCluster;
336 ULONG BytesDone;
337 ULONG StartCluster;
338 ULONG ClusterCount;
339 NTSTATUS Status = STATUS_SUCCESS;
340 BOOLEAN First = TRUE;
341 ULONG BytesPerSector;
342 ULONG BytesPerCluster;
343 LARGE_INTEGER StartOffset;
344 ULONG BufferOffset;
345 ULONG LastCluster;
346 ULONG LastOffset;
347
348 /* PRECONDITION */
349 ASSERT(IrpContext);
350 DeviceExt = IrpContext->DeviceExt;
351 ASSERT(DeviceExt);
352 ASSERT(DeviceExt->FatInfo.BytesPerCluster);
353 ASSERT(IrpContext->FileObject);
354 ASSERT(IrpContext->FileObject->FsContext2 != NULL);
355
356 Ccb = (PVFATCCB)IrpContext->FileObject->FsContext2;
357 Fcb = IrpContext->FileObject->FsContext;
358 BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster;
359 BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
360
361 DPRINT("VfatWriteFileData(DeviceExt %p, FileObject %p, "
362 "Length %d, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt,
363 IrpContext->FileObject, Length, WriteOffset,
364 &Fcb->PathNameU);
365
366 ASSERT(WriteOffset.QuadPart + Length <= Fcb->RFCB.AllocationSize.QuadPart);
367 ASSERT(WriteOffset.u.LowPart % BytesPerSector == 0);
368 ASSERT(Length % BytesPerSector == 0);
369
370 // Is this a write of the volume ?
371 if (Fcb->Flags & FCB_IS_VOLUME)
372 {
373 Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, TRUE);
374 if (!NT_SUCCESS(Status))
375 {
376 DPRINT1("Volume writing failed, Status %x\n", Status);
377 }
378 return Status;
379 }
380
381 // Is this a write to the FAT ?
382 if (Fcb->Flags & FCB_IS_FAT)
383 {
384 WriteOffset.u.LowPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
385 IrpContext->RefCount = 1;
386 for (Count = 0; Count < DeviceExt->FatInfo.FATCount; Count++)
387 {
388 Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, FALSE);
389 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
390 {
391 DPRINT1("FAT writing failed, Status %x\n", Status);
392 break;
393 }
394 WriteOffset.u.LowPart += Fcb->RFCB.FileSize.u.LowPart;
395 }
396 if (0 != InterlockedDecrement((PLONG)&IrpContext->RefCount))
397 {
398 KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
399 }
400 if (NT_SUCCESS(Status) || Status == STATUS_PENDING)
401 {
402 Status = IrpContext->Irp->IoStatus.Status;
403 }
404 return Status;
405 }
406
407 /*
408 * Find the first cluster
409 */
410 FirstCluster = CurrentCluster =
411 vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
412
413 if (FirstCluster == 1)
414 {
415 ASSERT(WriteOffset.u.LowPart + Length <= DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector);
416 // Directory of FAT12/16 needs a special handling
417 WriteOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector;
418 // Fire up the write command
419 Status = VfatWriteDiskPartial (IrpContext, &WriteOffset, Length, 0, TRUE);
420 return Status;
421 }
422
423 ExAcquireFastMutex(&Fcb->LastMutex);
424 LastCluster = Fcb->LastCluster;
425 LastOffset = Fcb->LastOffset;
426 ExReleaseFastMutex(&Fcb->LastMutex);
427
428 /*
429 * Find the cluster to start the write from
430 */
431 if (LastCluster > 0 && WriteOffset.u.LowPart >= LastOffset)
432 {
433 Status = OffsetToCluster(DeviceExt, LastCluster,
434 ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster) -
435 LastOffset,
436 &CurrentCluster, FALSE);
437 #ifdef DEBUG_VERIFY_OFFSET_CACHING
438 /* DEBUG VERIFICATION */
439 {
440 ULONG CorrectCluster;
441 OffsetToCluster(DeviceExt, FirstCluster,
442 ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster),
443 &CorrectCluster, FALSE);
444 if (CorrectCluster != CurrentCluster)
445 KEBUGCHECK(FAT_FILE_SYSTEM);
446 }
447 #endif
448 }
449 else
450 {
451 Status = OffsetToCluster(DeviceExt, FirstCluster,
452 ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster),
453 &CurrentCluster, FALSE);
454 }
455
456 if (!NT_SUCCESS(Status))
457 {
458 return(Status);
459 }
460
461 ExAcquireFastMutex(&Fcb->LastMutex);
462 Fcb->LastCluster = CurrentCluster;
463 Fcb->LastOffset = ROUND_DOWN (WriteOffset.u.LowPart, BytesPerCluster);
464 ExReleaseFastMutex(&Fcb->LastMutex);
465
466 IrpContext->RefCount = 1;
467 BufferOffset = 0;
468
469 while (Length > 0 && CurrentCluster != 0xffffffff)
470 {
471 StartCluster = CurrentCluster;
472 StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
473 BytesDone = 0;
474 ClusterCount = 0;
475
476 do
477 {
478 ClusterCount++;
479 if (First)
480 {
481 BytesDone = min (Length, BytesPerCluster - (WriteOffset.u.LowPart % BytesPerCluster));
482 StartOffset.QuadPart += WriteOffset.u.LowPart % BytesPerCluster;
483 First = FALSE;
484 }
485 else
486 {
487 if (Length - BytesDone > BytesPerCluster)
488 {
489 BytesDone += BytesPerCluster;
490 }
491 else
492 {
493 BytesDone = Length;
494 }
495 }
496 Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE);
497 }
498 while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone);
499 DPRINT("start %08x, next %08x, count %d\n",
500 StartCluster, CurrentCluster, ClusterCount);
501
502 ExAcquireFastMutex(&Fcb->LastMutex);
503 Fcb->LastCluster = StartCluster + (ClusterCount - 1);
504 Fcb->LastOffset = ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster) + (ClusterCount - 1) * BytesPerCluster;
505 ExReleaseFastMutex(&Fcb->LastMutex);
506
507 // Fire up the write command
508 Status = VfatWriteDiskPartial (IrpContext, &StartOffset, BytesDone, BufferOffset, FALSE);
509 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
510 {
511 break;
512 }
513 BufferOffset += BytesDone;
514 Length -= BytesDone;
515 WriteOffset.u.LowPart += BytesDone;
516 }
517 if (0 != InterlockedDecrement((PLONG)&IrpContext->RefCount))
518 {
519 KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
520 }
521 if (NT_SUCCESS(Status) || Status == STATUS_PENDING)
522 {
523 if (Length > 0)
524 {
525 Status = STATUS_UNSUCCESSFUL;
526 }
527 else
528 {
529 Status = IrpContext->Irp->IoStatus.Status;
530 }
531 }
532 return Status;
533 }
534
535 NTSTATUS
536 VfatRead(PVFAT_IRP_CONTEXT IrpContext)
537 {
538 NTSTATUS Status;
539 PVFATFCB Fcb;
540 ULONG Length = 0;
541 ULONG ReturnedLength = 0;
542 PERESOURCE Resource = NULL;
543 LARGE_INTEGER ByteOffset;
544 PVOID Buffer;
545 PDEVICE_OBJECT DeviceToVerify;
546 ULONG BytesPerSector;
547
548 ASSERT(IrpContext);
549
550 DPRINT("VfatRead(IrpContext %p)\n", IrpContext);
551
552 ASSERT(IrpContext->DeviceObject);
553
554 // This request is not allowed on the main device object
555 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
556 {
557 DPRINT("VfatRead is called with the main device object.\n");
558 Status = STATUS_INVALID_DEVICE_REQUEST;
559 goto ByeBye;
560 }
561
562 ASSERT(IrpContext->DeviceExt);
563 ASSERT(IrpContext->FileObject);
564 Fcb = IrpContext->FileObject->FsContext;
565 ASSERT(Fcb);
566
567 DPRINT("<%wZ>\n", &Fcb->PathNameU);
568
569 if (Fcb->Flags & FCB_IS_PAGE_FILE)
570 {
571 PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo;
572 IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector;
573 IoSkipCurrentIrpStackLocation(IrpContext->Irp);
574 DPRINT("Read from page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart);
575 Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
576 VfatFreeIrpContext(IrpContext);
577 return Status;
578 }
579
580 ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset;
581 Length = IrpContext->Stack->Parameters.Read.Length;
582 BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;
583
584 /* fail if file is a directory and no paged read */
585 if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
586 {
587 Status = STATUS_INVALID_PARAMETER;
588 goto ByeBye;
589 }
590
591
592 DPRINT("'%wZ', Offset: %d, Length %d\n", &Fcb->PathNameU, ByteOffset.u.LowPart, Length);
593
594 if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
595 {
596 Status = STATUS_INVALID_PARAMETER;
597 goto ByeBye;
598 }
599 if (ByteOffset.QuadPart >= Fcb->RFCB.FileSize.QuadPart)
600 {
601 IrpContext->Irp->IoStatus.Information = 0;
602 Status = STATUS_END_OF_FILE;
603 goto ByeBye;
604 }
605 if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
606 {
607 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
608 {
609 DPRINT("%d %d\n", ByteOffset.u.LowPart, Length);
610 // non cached read must be sector aligned
611 Status = STATUS_INVALID_PARAMETER;
612 goto ByeBye;
613 }
614 }
615 if (Length == 0)
616 {
617 IrpContext->Irp->IoStatus.Information = 0;
618 Status = STATUS_SUCCESS;
619 goto ByeBye;
620 }
621
622 if (Fcb->Flags & FCB_IS_VOLUME)
623 {
624 Resource = &IrpContext->DeviceExt->DirResource;
625 }
626 else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
627 {
628 Resource = &Fcb->PagingIoResource;
629 }
630 else
631 {
632 Resource = &Fcb->MainResource;
633 }
634 if (!ExAcquireResourceSharedLite(Resource,
635 IrpContext->Flags & IRPCONTEXT_CANWAIT ? TRUE : FALSE))
636 {
637 Resource = NULL;
638 Status = STATUS_PENDING;
639 goto ByeBye;
640 }
641
642 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
643 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
644 {
645 if (!FsRtlCheckLockForReadAccess(&Fcb->FileLock, IrpContext->Irp))
646 {
647 Status = STATUS_FILE_LOCK_CONFLICT;
648 goto ByeBye;
649 }
650 }
651
652 Buffer = VfatGetUserBuffer(IrpContext->Irp);
653 if (!Buffer)
654 {
655 Status = STATUS_INVALID_USER_BUFFER;
656 goto ByeBye;
657 }
658
659 if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
660 !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
661 {
662 // cached read
663 CHECKPOINT;
664 Status = STATUS_SUCCESS;
665 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
666 {
667 Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart;
668 Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS;
669 }
670
671 CHECKPOINT;
672 if (IrpContext->FileObject->PrivateCacheMap == NULL)
673 {
674 /* FIXME: Guard by SEH. */
675 CcInitializeCacheMap(IrpContext->FileObject,
676 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
677 FALSE,
678 &(VfatGlobalData->CacheMgrCallbacks),
679 Fcb);
680 }
681 if (!CcCopyRead(IrpContext->FileObject, &ByteOffset, Length,
682 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT), Buffer,
683 &IrpContext->Irp->IoStatus))
684 {
685 Status = IrpContext->Irp->IoStatus.Status;//STATUS_PENDING;
686 goto ByeBye;
687 }
688 CHECKPOINT;
689 if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status))
690 {
691 Status = IrpContext->Irp->IoStatus.Status;
692 }
693 }
694 else
695 {
696 // non cached read
697 CHECKPOINT;
698 if (ByteOffset.QuadPart + Length > ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector))
699 {
700 Length = (ULONG)(ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector) - ByteOffset.QuadPart);
701 }
702
703 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess);
704 if (!NT_SUCCESS(Status))
705 {
706 goto ByeBye;
707 }
708
709 Status = VfatReadFileData(IrpContext, Length, ByteOffset, &ReturnedLength);
710 /**/
711 if (Status == STATUS_VERIFY_REQUIRED)
712 {
713 DPRINT("VfatReadFile returned STATUS_VERIFY_REQUIRED\n");
714 DeviceToVerify = IoGetDeviceToVerify(PsGetCurrentThread());
715 IoSetDeviceToVerify(PsGetCurrentThread(), DeviceToVerify);
716 Status = IoVerifyVolume (DeviceToVerify, FALSE);
717
718 if (NT_SUCCESS(Status))
719 {
720 Status = VfatReadFileData(IrpContext, Length,
721 ByteOffset, &ReturnedLength);
722 }
723
724 }
725 /**/
726 if (NT_SUCCESS(Status))
727 {
728 IrpContext->Irp->IoStatus.Information = ReturnedLength;
729 }
730 }
731
732 ByeBye:
733 if (Resource)
734 {
735 ExReleaseResourceLite(Resource);
736 }
737
738 if (Status == STATUS_PENDING)
739 {
740 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess);
741 if (NT_SUCCESS(Status))
742 {
743 Status = VfatQueueRequest(IrpContext);
744 }
745 else
746 {
747 IrpContext->Irp->IoStatus.Status = Status;
748 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
749 VfatFreeIrpContext(IrpContext);
750 }
751 }
752 else
753 {
754 IrpContext->Irp->IoStatus.Status = Status;
755 if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
756 !(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
757 (NT_SUCCESS(Status) || Status==STATUS_END_OF_FILE))
758 {
759 IrpContext->FileObject->CurrentByteOffset.QuadPart =
760 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
761 }
762
763 IoCompleteRequest(IrpContext->Irp,
764 (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
765 VfatFreeIrpContext(IrpContext);
766 }
767 DPRINT("%x\n", Status);
768 return Status;
769 }
770
771 NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext)
772 {
773 PVFATFCB Fcb;
774 PERESOURCE Resource = NULL;
775 LARGE_INTEGER ByteOffset;
776 LARGE_INTEGER OldFileSize;
777 NTSTATUS Status = STATUS_SUCCESS;
778 ULONG Length = 0;
779 ULONG OldAllocationSize;
780 PVOID Buffer;
781 ULONG BytesPerSector;
782
783 ASSERT(IrpContext);
784
785 DPRINT("VfatWrite(IrpContext %p)\n", IrpContext);
786
787 ASSERT(IrpContext->DeviceObject);
788
789 // This request is not allowed on the main device object
790 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
791 {
792 DPRINT("VfatWrite is called with the main device object.\n");
793 Status = STATUS_INVALID_DEVICE_REQUEST;
794 goto ByeBye;
795 }
796
797 ASSERT(IrpContext->DeviceExt);
798 ASSERT(IrpContext->FileObject);
799 Fcb = IrpContext->FileObject->FsContext;
800 ASSERT(Fcb);
801
802 DPRINT("<%wZ>\n", &Fcb->PathNameU);
803
804 if (Fcb->Flags & FCB_IS_PAGE_FILE)
805 {
806 PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo;
807 IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector;
808 IoSkipCurrentIrpStackLocation(IrpContext->Irp);
809 DPRINT("Write to page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart);
810 Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
811 VfatFreeIrpContext(IrpContext);
812 return Status;
813 }
814
815 /* fail if file is a directory and no paged read */
816 if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
817 {
818 Status = STATUS_INVALID_PARAMETER;
819 goto ByeBye;
820 }
821
822 ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
823 if (ByteOffset.u.LowPart == FILE_WRITE_TO_END_OF_FILE &&
824 ByteOffset.u.HighPart == -1)
825 {
826 ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart;
827 }
828 Length = IrpContext->Stack->Parameters.Write.Length;
829 BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;
830
831 if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
832 {
833 Status = STATUS_INVALID_PARAMETER;
834 goto ByeBye;
835 }
836
837 if (Fcb->Flags & (FCB_IS_FAT | FCB_IS_VOLUME) ||
838 1 == vfatDirEntryGetFirstCluster (IrpContext->DeviceExt, &Fcb->entry))
839 {
840 if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart)
841 {
842 // we can't extend the FAT, the volume or the root on FAT12/FAT16
843 Status = STATUS_END_OF_FILE;
844 goto ByeBye;
845 }
846 }
847
848 if (IrpContext->Irp->Flags & (IRP_PAGING_IO|IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
849 {
850 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
851 {
852 // non cached write must be sector aligned
853 Status = STATUS_INVALID_PARAMETER;
854 goto ByeBye;
855 }
856 }
857
858 if (Length == 0)
859 {
860 /* FIXME:
861 * Update last write time
862 */
863 IrpContext->Irp->IoStatus.Information = 0;
864 Status = STATUS_SUCCESS;
865 goto ByeBye;
866 }
867
868 if (IrpContext->Irp->Flags & IRP_PAGING_IO)
869 {
870 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
871 {
872 Status = STATUS_INVALID_PARAMETER;
873 goto ByeBye;
874 }
875 if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector))
876 {
877 Length = ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart;
878 }
879 }
880
881 if (Fcb->Flags & FCB_IS_VOLUME)
882 {
883 Resource = &IrpContext->DeviceExt->DirResource;
884 }
885 else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
886 {
887 Resource = &Fcb->PagingIoResource;
888 }
889 else
890 {
891 Resource = &Fcb->MainResource;
892 }
893
894 if (Fcb->Flags & FCB_IS_PAGE_FILE)
895 {
896 if (!ExAcquireResourceSharedLite(Resource,
897 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
898 {
899 Resource = NULL;
900 Status = STATUS_PENDING;
901 goto ByeBye;
902 }
903 }
904 else
905 {
906 if (!ExAcquireResourceExclusiveLite(Resource,
907 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
908 {
909 Resource = NULL;
910 Status = STATUS_PENDING;
911 goto ByeBye;
912 }
913 }
914
915 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
916 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
917 {
918 if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
919 {
920 Status = STATUS_FILE_LOCK_CONFLICT;
921 goto ByeBye;
922 }
923 }
924
925 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME))
926 {
927 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
928 {
929 Status = STATUS_PENDING;
930 goto ByeBye;
931 }
932 }
933
934 OldFileSize = Fcb->RFCB.FileSize;
935 OldAllocationSize = Fcb->RFCB.AllocationSize.u.LowPart;
936
937 Buffer = VfatGetUserBuffer(IrpContext->Irp);
938 if (!Buffer)
939 {
940 Status = STATUS_INVALID_USER_BUFFER;
941 goto ByeBye;
942 }
943
944
945 if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) &&
946 !(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
947 ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
948 {
949 LARGE_INTEGER AllocationSize;
950 AllocationSize.QuadPart = ByteOffset.u.LowPart + Length;
951 Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb,
952 IrpContext->DeviceExt, &AllocationSize);
953 if (!NT_SUCCESS (Status))
954 {
955 CHECKPOINT;
956 goto ByeBye;
957 }
958 }
959
960 if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
961 !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
962 {
963 // cached write
964 CHECKPOINT;
965
966 if (IrpContext->FileObject->PrivateCacheMap == NULL)
967 {
968 /* FIXME: Guard by SEH. */
969 CcInitializeCacheMap(IrpContext->FileObject,
970 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
971 FALSE,
972 &VfatGlobalData->CacheMgrCallbacks,
973 Fcb);
974 }
975 if (ByteOffset.QuadPart > OldFileSize.QuadPart)
976 {
977 CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
978 }
979 if (CcCopyWrite(IrpContext->FileObject, &ByteOffset, Length,
980 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer))
981 {
982 IrpContext->Irp->IoStatus.Information = Length;
983 Status = STATUS_SUCCESS;
984 }
985 else
986 {
987 Status = STATUS_UNSUCCESSFUL;
988 }
989 CHECKPOINT;
990 }
991 else
992 {
993 // non cached write
994 CHECKPOINT;
995
996 if (ByteOffset.QuadPart > OldFileSize.QuadPart)
997 {
998 CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
999 }
1000
1001 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
1002 if (!NT_SUCCESS(Status))
1003 {
1004 goto ByeBye;
1005 }
1006
1007 Status = VfatWriteFileData(IrpContext, Length, ByteOffset);
1008 if (NT_SUCCESS(Status))
1009 {
1010 IrpContext->Irp->IoStatus.Information = Length;
1011 }
1012 }
1013
1014 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
1015 !(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)))
1016 {
1017 if(!(*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
1018 {
1019 LARGE_INTEGER SystemTime;
1020 // set dates and times
1021 KeQuerySystemTime (&SystemTime);
1022 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
1023 {
1024 FsdSystemTimeToDosDateTime (IrpContext->DeviceExt,
1025 &SystemTime, &Fcb->entry.FatX.UpdateDate,
1026 &Fcb->entry.FatX.UpdateTime);
1027 Fcb->entry.FatX.AccessDate = Fcb->entry.FatX.UpdateDate;
1028 Fcb->entry.FatX.AccessTime = Fcb->entry.FatX.UpdateTime;
1029 }
1030 else
1031 {
1032 FsdSystemTimeToDosDateTime (IrpContext->DeviceExt,
1033 &SystemTime, &Fcb->entry.Fat.UpdateDate,
1034 &Fcb->entry.Fat.UpdateTime);
1035 Fcb->entry.Fat.AccessDate = Fcb->entry.Fat.UpdateDate;
1036 }
1037 /* set date and times to dirty */
1038 Fcb->Flags |= FCB_IS_DIRTY;
1039 }
1040 }
1041
1042 ByeBye:
1043 if (Resource)
1044 {
1045 ExReleaseResourceLite(Resource);
1046 }
1047
1048 if (Status == STATUS_PENDING)
1049 {
1050 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
1051 if (NT_SUCCESS(Status))
1052 {
1053 Status = VfatQueueRequest(IrpContext);
1054 }
1055 else
1056 {
1057 IrpContext->Irp->IoStatus.Status = Status;
1058 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
1059 VfatFreeIrpContext(IrpContext);
1060 }
1061 }
1062 else
1063 {
1064 IrpContext->Irp->IoStatus.Status = Status;
1065 if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
1066 !(IrpContext->Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status))
1067 {
1068 IrpContext->FileObject->CurrentByteOffset.QuadPart =
1069 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
1070 }
1071
1072 IoCompleteRequest(IrpContext->Irp,
1073 (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
1074 VfatFreeIrpContext(IrpContext);
1075 }
1076 DPRINT("%x\n", Status);
1077 return Status;
1078 }
1079
1080