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