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