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