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