d8f48ac6543da129783cb15dd7cc12733b81e774
[reactos.git] / drivers / fs / vfat / finfo.c
1 /* $Id$
2  *
3  * COPYRIGHT:        See COPYING in the top level directory
4  * PROJECT:          ReactOS kernel
5  * FILE:             services/fs/vfat/finfo.c
6  * PURPOSE:          VFAT Filesystem
7  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
8  *
9  */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <wchar.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 #include "vfat.h"
20
21 /* FUNCTIONS ****************************************************************/
22
23 static NTSTATUS
24 VfatGetStandardInformation(PVFATFCB FCB,
25                            PFILE_STANDARD_INFORMATION StandardInfo,
26                            PULONG BufferLength)
27 /*
28  * FUNCTION: Retrieve the standard file information
29  */
30 {
31
32   if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION))
33     return STATUS_BUFFER_OVERFLOW;
34
35   /* PRECONDITION */
36   assert (StandardInfo != NULL);
37   assert (FCB != NULL);
38
39   RtlZeroMemory(StandardInfo,
40                 sizeof(FILE_STANDARD_INFORMATION));
41
42   StandardInfo->AllocationSize = FCB->RFCB.AllocationSize;
43   StandardInfo->EndOfFile = FCB->RFCB.FileSize;
44   StandardInfo->NumberOfLinks = 0;
45   StandardInfo->DeletePending = FCB->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
46   StandardInfo->Directory = FCB->entry.Attrib & 0x10 ? TRUE : FALSE;
47
48   *BufferLength -= sizeof(FILE_STANDARD_INFORMATION);
49   return(STATUS_SUCCESS);
50 }
51
52 static NTSTATUS
53 VfatSetPositionInformation(PFILE_OBJECT FileObject,
54                            PFILE_POSITION_INFORMATION PositionInfo)
55 {
56   DPRINT ("FsdSetPositionInformation()\n");
57
58   DPRINT ("PositionInfo %x\n", PositionInfo);
59   DPRINT ("Setting position %d\n", PositionInfo->CurrentByteOffset.u.LowPart);
60   memcpy (&FileObject->CurrentByteOffset, &PositionInfo->CurrentByteOffset,
61           sizeof (LARGE_INTEGER));
62
63   return (STATUS_SUCCESS);
64 }
65
66 static NTSTATUS
67 VfatGetPositionInformation(PFILE_OBJECT FileObject,
68                            PVFATFCB FCB,
69                            PDEVICE_OBJECT DeviceObject,
70                            PFILE_POSITION_INFORMATION PositionInfo,
71                            PULONG BufferLength)
72 {
73   DPRINT ("VfatGetPositionInformation()\n");
74
75   if (*BufferLength < sizeof(FILE_POSITION_INFORMATION))
76     return STATUS_BUFFER_OVERFLOW;
77
78   PositionInfo->CurrentByteOffset.QuadPart =
79     FileObject->CurrentByteOffset.QuadPart;
80
81   DPRINT("Getting position %I64x\n",
82          PositionInfo->CurrentByteOffset.QuadPart);
83
84   *BufferLength -= sizeof(FILE_POSITION_INFORMATION);
85   return(STATUS_SUCCESS);
86 }
87
88 static NTSTATUS
89 VfatSetBasicInformation(PFILE_OBJECT FileObject,
90                         PVFATFCB FCB,
91                         PDEVICE_EXTENSION DeviceExt,
92                         PFILE_BASIC_INFORMATION BasicInfo)
93 {
94   DPRINT("VfatSetBasicInformation()\n");
95
96   assert (NULL != FileObject);
97   assert (NULL != FCB);
98   assert (NULL != DeviceExt);
99   assert (NULL != BasicInfo);
100   /* Check volume label bit */
101   assert(0 == (FCB->entry.Attrib & 0x08));
102
103   FsdFileTimeToDosDateTime(&(BasicInfo->CreationTime),
104                            &(FCB->entry.CreationDate),  
105                            &(FCB->entry.CreationTime));
106   FsdFileTimeToDosDateTime(&(BasicInfo->LastAccessTime),
107                            &(FCB->entry.AccessDate),  
108                            NULL);
109   FsdFileTimeToDosDateTime(&(BasicInfo->LastWriteTime),
110                            &(FCB->entry.UpdateDate),
111                            &(FCB->entry.UpdateTime));
112
113   FCB->entry.Attrib = (FCB->entry.Attrib &
114                        (FILE_ATTRIBUTE_DIRECTORY | 0x48)) |
115                       (BasicInfo->FileAttributes &
116                        (FILE_ATTRIBUTE_ARCHIVE |
117                         FILE_ATTRIBUTE_SYSTEM |
118                         FILE_ATTRIBUTE_HIDDEN |
119                         FILE_ATTRIBUTE_READONLY));
120   DPRINT("Setting attributes 0x%02x\n", FCB->entry.Attrib);
121
122   VfatUpdateEntry(DeviceExt, FileObject);
123
124   return(STATUS_SUCCESS);
125 }
126
127 static NTSTATUS
128 VfatGetBasicInformation(PFILE_OBJECT FileObject,
129                         PVFATFCB FCB,
130                         PDEVICE_OBJECT DeviceObject,
131                         PFILE_BASIC_INFORMATION BasicInfo,
132                         PULONG BufferLength)
133 {
134   DPRINT("VfatGetBasicInformation()\n");
135
136   if (*BufferLength < sizeof(FILE_BASIC_INFORMATION))
137     return STATUS_BUFFER_OVERFLOW;
138
139   FsdDosDateTimeToFileTime(FCB->entry.CreationDate,
140                            FCB->entry.CreationTime,
141                            &BasicInfo->CreationTime);
142   FsdDosDateTimeToFileTime(FCB->entry.AccessDate,
143                            0,
144                            &BasicInfo->LastAccessTime);
145   FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,
146                            FCB->entry.UpdateTime,
147                            &BasicInfo->LastWriteTime);
148   BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
149
150   BasicInfo->FileAttributes = FCB->entry.Attrib;
151   /* Synthesize FILE_ATTRIBUTE_NORMAL */
152   if (0 == (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
153                                          FILE_ATTRIBUTE_ARCHIVE |
154                                          FILE_ATTRIBUTE_SYSTEM |
155                                          FILE_ATTRIBUTE_HIDDEN |
156                                          FILE_ATTRIBUTE_READONLY)))
157   {
158     BasicInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
159   }
160   DPRINT("Getting attributes 0x%02x\n", BasicInfo->FileAttributes);
161
162   *BufferLength -= sizeof(FILE_BASIC_INFORMATION);
163   return(STATUS_SUCCESS);
164 }
165
166
167 static NTSTATUS
168 VfatSetDispositionInformation(PFILE_OBJECT FileObject,
169                               PVFATFCB FCB,
170                               PDEVICE_OBJECT DeviceObject,
171                               PFILE_DISPOSITION_INFORMATION DispositionInfo)
172 {
173   KIRQL oldIrql;
174   VFATFCB tmpFcb;
175   WCHAR star[2];
176   ULONG Index;
177   NTSTATUS Status = STATUS_SUCCESS;
178   int count;
179
180   PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
181
182   DPRINT ("FsdSetDispositionInformation()\n");
183
184   assert (DeviceExt != NULL);
185   assert (DeviceExt->FatInfo.BytesPerCluster != 0);
186   assert (FCB != NULL);
187
188   if (!wcscmp(FCB->PathName, L"\\") || !wcscmp(FCB->ObjectName, L"..")
189     || !wcscmp(FCB->ObjectName, L"."))
190   {
191     // we cannot delete a '.', '..' or the root directory
192     return STATUS_ACCESS_DENIED;
193   }
194   if (DispositionInfo->DoDeleteFile)
195   {
196     if (MmFlushImageSection (FileObject->SectionObjectPointers, MmFlushForDelete))
197     {
198       KeAcquireSpinLock (&DeviceExt->FcbListLock, &oldIrql);
199       count = FCB->RefCount;
200       if (FCB->RefCount > 1)
201       {
202         DPRINT1("%d %x\n", FCB->RefCount, CcGetFileObjectFromSectionPtrs(FileObject->SectionObjectPointers));
203         Status = STATUS_ACCESS_DENIED;
204       }
205       else
206       {
207         FCB->Flags |= FCB_DELETE_PENDING;
208         FileObject->DeletePending = TRUE;
209       }
210       KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
211     }
212     else
213     {
214       DPRINT1("MmFlushImageSection returned FALSE\n");
215       Status = STATUS_ACCESS_DENIED;
216     }
217     DPRINT("RefCount:%d\n", count);
218     if (NT_SUCCESS(Status) && vfatFCBIsDirectory(FCB))
219     {
220       memset (&tmpFcb, 0, sizeof(VFATFCB));
221       tmpFcb.ObjectName = tmpFcb.PathName;
222       star[0] = L'*';
223       star[1] = 0;
224       // skip '.' and '..', start by 2
225       Index = 2;
226       Status = FindFile (DeviceExt, &tmpFcb, FCB, star, &Index, NULL);
227       if (NT_SUCCESS(Status))
228       {
229         DPRINT1("found: \'%S\'\n", tmpFcb.PathName);
230         Status = STATUS_DIRECTORY_NOT_EMPTY;
231         FCB->Flags &= ~FCB_DELETE_PENDING;
232         FileObject->DeletePending = FALSE;
233       }
234       else
235       {
236         Status = STATUS_SUCCESS;
237       }
238     }
239   }
240   else
241     FileObject->DeletePending = FALSE;
242   return Status;
243 }
244
245 static NTSTATUS
246 VfatGetNameInformation(PFILE_OBJECT FileObject,
247                        PVFATFCB FCB,
248                        PDEVICE_OBJECT DeviceObject,
249                        PFILE_NAME_INFORMATION NameInfo,
250                        PULONG BufferLength)
251 /*
252  * FUNCTION: Retrieve the file name information
253  */
254 {
255   ULONG NameLength;
256
257   assert (NameInfo != NULL);
258   assert (FCB != NULL);
259
260   NameLength = wcslen(FCB->PathName) * sizeof(WCHAR);
261   if (*BufferLength < sizeof(FILE_NAME_INFORMATION) + NameLength + sizeof(WCHAR))
262     return STATUS_BUFFER_OVERFLOW;
263
264   NameInfo->FileNameLength = NameLength;
265   memcpy(NameInfo->FileName, FCB->PathName, NameLength + sizeof(WCHAR));
266
267   *BufferLength -= (sizeof(FILE_NAME_INFORMATION) + NameLength + sizeof(WCHAR));
268
269   return STATUS_SUCCESS;
270 }
271
272 static NTSTATUS
273 VfatGetInternalInformation(PVFATFCB Fcb,
274                            PFILE_INTERNAL_INFORMATION InternalInfo,
275                            PULONG BufferLength)
276 {
277   assert (InternalInfo);
278   assert (Fcb);
279
280   if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION))
281     return STATUS_BUFFER_OVERFLOW;
282   // FIXME: get a real index, that can be used in a create operation
283   InternalInfo->IndexNumber.QuadPart = 0;
284   *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION);
285   return STATUS_SUCCESS;
286 }
287
288
289 static NTSTATUS
290 VfatGetNetworkOpenInformation(PVFATFCB Fcb,
291                               PFILE_NETWORK_OPEN_INFORMATION NetworkInfo,
292                               PULONG BufferLength)
293 /*
294  * FUNCTION: Retrieve the file network open information
295  */
296 {
297   assert (NetworkInfo);
298   assert (Fcb);
299
300   if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION))
301     return(STATUS_BUFFER_OVERFLOW);
302
303   FsdDosDateTimeToFileTime(Fcb->entry.CreationDate,
304                            Fcb->entry.CreationTime,
305                            &NetworkInfo->CreationTime);
306   FsdDosDateTimeToFileTime(Fcb->entry.AccessDate,
307                            0,
308                            &NetworkInfo->LastAccessTime);
309   FsdDosDateTimeToFileTime(Fcb->entry.UpdateDate,
310                            Fcb->entry.UpdateTime,
311                            &NetworkInfo->LastWriteTime);
312   NetworkInfo->ChangeTime = NetworkInfo->LastWriteTime;
313   NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize;
314   NetworkInfo->EndOfFile = Fcb->RFCB.FileSize;
315   NetworkInfo->FileAttributes = Fcb->entry.Attrib;
316
317   *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION);
318   return STATUS_SUCCESS;
319 }
320
321
322 static NTSTATUS
323 VfatGetAllInformation(PFILE_OBJECT FileObject,
324                       PVFATFCB Fcb,
325                       PFILE_ALL_INFORMATION Info,
326                       PULONG BufferLength)
327 /*
328  * FUNCTION: Retrieve the all file information
329  */
330 {
331   ULONG NameLength;
332
333   assert (Info);
334   assert (Fcb);
335
336   NameLength = wcslen(Fcb->PathName) * sizeof(WCHAR);
337   if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + NameLength + sizeof(WCHAR))
338     return(STATUS_BUFFER_OVERFLOW);
339
340   /* Basic Information */
341   FsdDosDateTimeToFileTime(Fcb->entry.CreationDate,
342                            Fcb->entry.CreationTime,
343                            &Info->BasicInformation.CreationTime);
344   FsdDosDateTimeToFileTime(Fcb->entry.AccessDate,
345                            0,
346                            &Info->BasicInformation.LastAccessTime);
347   FsdDosDateTimeToFileTime(Fcb->entry.UpdateDate,
348                            Fcb->entry.UpdateTime,
349                            &Info->BasicInformation.LastWriteTime);
350   Info->BasicInformation.ChangeTime = Info->BasicInformation.LastWriteTime;
351   Info->BasicInformation.FileAttributes = Fcb->entry.Attrib;
352
353   /* Standard Information */
354   Info->StandardInformation.AllocationSize = Fcb->RFCB.AllocationSize;
355   Info->StandardInformation.EndOfFile = Fcb->RFCB.FileSize;
356   Info->StandardInformation.NumberOfLinks = 0;
357   Info->StandardInformation.DeletePending = Fcb->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
358   Info->StandardInformation.Directory = Fcb->entry.Attrib & 0x10 ? TRUE : FALSE;
359
360   /* Internal Information */
361   /* FIXME: get a real index, that can be used in a create operation */
362   Info->InternalInformation.IndexNumber.QuadPart = 0;
363
364   /* EA Information */
365   Info->EaInformation.EaSize = 0;
366
367   /* Access Information */
368   /* The IO-Manager adds this information */
369
370   /* Position Information */
371   Info->PositionInformation.CurrentByteOffset.QuadPart = FileObject->CurrentByteOffset.QuadPart;
372
373   /* Mode Information */
374   /* The IO-Manager adds this information */
375
376   /* Alignment Information */
377   /* The IO-Manager adds this information */
378
379   /* Name Information */
380   Info->NameInformation.FileNameLength = NameLength;
381   RtlCopyMemory(Info->NameInformation.FileName, Fcb->PathName, NameLength + sizeof(WCHAR));
382
383   *BufferLength -= (sizeof(FILE_ALL_INFORMATION) + NameLength + sizeof(WCHAR));
384
385   return STATUS_SUCCESS;
386 }
387
388 VOID UpdateFileSize(PFILE_OBJECT FileObject, PVFATFCB Fcb, ULONG Size, ULONG ClusterSize)
389 {
390    if (Size > 0)
391    {
392       Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, ClusterSize);
393    }
394    else
395    {
396       Fcb->RFCB.AllocationSize.QuadPart = 0LL;
397    }
398    if (!vfatFCBIsDirectory(Fcb))
399    {
400       Fcb->entry.FileSize = Size;  
401    }
402    Fcb->RFCB.FileSize.QuadPart = Size;
403    Fcb->RFCB.ValidDataLength.QuadPart = Size;
404
405    if (FileObject->SectionObjectPointers->SharedCacheMap != NULL)
406    {
407       CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
408    }
409 }
410
411 NTSTATUS
412 VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject, 
413                                  PVFATFCB Fcb,
414                                  PDEVICE_EXTENSION DeviceExt,
415                                  PLARGE_INTEGER AllocationSize)
416 {
417   ULONG OldSize;
418   ULONG Cluster, FirstCluster;
419   ULONG Offset;
420   NTSTATUS Status;
421
422   ULONG ClusterSize = DeviceExt->FatInfo.BytesPerCluster;
423   ULONG NewSize = AllocationSize->u.LowPart;
424   ULONG NCluster;
425
426   DPRINT("VfatSetAllocationSizeInformation()\n");
427
428   OldSize = Fcb->entry.FileSize;
429   if (AllocationSize->u.HighPart > 0)
430   {
431     return STATUS_INVALID_PARAMETER;
432   }
433   if (OldSize == NewSize)
434     {
435       return(STATUS_SUCCESS);
436     }
437
438   FirstCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
439   
440   if (NewSize > Fcb->RFCB.AllocationSize.u.LowPart)
441   {
442     if (FirstCluster == 0)
443     {
444       Status = NextCluster (DeviceExt, Fcb, FirstCluster, &FirstCluster, TRUE);
445       if (!NT_SUCCESS(Status))
446       {
447         DPRINT1("NextCluster failed. Status = %x\n", Status);
448         return Status;
449       }
450       if (FirstCluster == 0xffffffff)
451       {
452          return STATUS_DISK_FULL;
453       }
454       Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster, 
455                  ROUND_DOWN(NewSize - 1, ClusterSize),
456                  &NCluster, TRUE);
457       if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
458       {
459          /* disk is full */
460          NCluster = Cluster = FirstCluster;
461          Status = STATUS_SUCCESS;
462          while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
463          {
464             Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
465             WriteCluster (DeviceExt, Cluster, 0);
466             Cluster = NCluster;
467          }
468          return STATUS_DISK_FULL;
469       }
470       Fcb->entry.FirstCluster = (FirstCluster & 0x0000FFFF);
471       Fcb->entry.FirstClusterHigh = (FirstCluster & 0xFFFF0000) >> 16;
472     }
473     else
474     {
475        Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster, 
476                   Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize,
477                   &Cluster, FALSE);
478        /* FIXME: Check status */
479        /* Cluster points now to the last cluster within the chain */
480        Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster, 
481                  ROUND_DOWN(NewSize - 1, ClusterSize),
482                  &NCluster, TRUE);
483        if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
484        {
485           /* disk is full */
486           NCluster = Cluster; 
487           Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
488           WriteCluster(DeviceExt, Cluster, 0xffffffff);
489           Cluster = NCluster;
490           while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
491           {
492             Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
493             WriteCluster (DeviceExt, Cluster, 0);
494             Cluster = NCluster;
495           }
496           return STATUS_DISK_FULL;
497        }
498     }
499     UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
500   }
501   else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
502   {
503     UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
504     if (NewSize > 0)
505     {
506       Status = OffsetToCluster(DeviceExt, Fcb, Cluster, 
507                   ROUND_DOWN(NewSize - 1, ClusterSize),
508                   &Cluster, FALSE);
509
510       NCluster = Cluster;
511       Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
512       WriteCluster(DeviceExt, Cluster, 0xffffffff);
513       Cluster = NCluster;
514     }
515     else
516     {
517       Fcb->entry.FirstCluster = 0;
518       Fcb->entry.FirstClusterHigh = 0;
519
520       NCluster = Cluster = FirstCluster;
521       Status = STATUS_SUCCESS;
522     }
523     while (NT_SUCCESS(Status) && 0xffffffff != Cluster && Cluster > 1)
524     {
525        Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
526        WriteCluster (DeviceExt, Cluster, 0);
527        Cluster = NCluster;
528     }
529   }
530   else
531   {
532      UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
533   }
534   /* Update the on-disk directory entry */
535   VfatUpdateEntry(DeviceExt, FileObject);
536   return STATUS_SUCCESS;
537 }
538
539 NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
540 /*
541  * FUNCTION: Retrieve the specified file information
542  */
543 {
544   FILE_INFORMATION_CLASS FileInformationClass;
545   PVFATFCB FCB = NULL;
546
547   NTSTATUS RC = STATUS_SUCCESS;
548   PVOID SystemBuffer;
549   ULONG BufferLength;
550
551   /* PRECONDITION */
552   assert (IrpContext);
553
554   /* INITIALIZATION */
555   FileInformationClass = IrpContext->Stack->Parameters.QueryFile.FileInformationClass;
556   FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
557
558   SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
559   BufferLength = IrpContext->Stack->Parameters.QueryFile.Length;
560
561   if (!(FCB->Flags & FCB_IS_PAGE_FILE))
562   {
563      if (!ExAcquireResourceSharedLite(&FCB->MainResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
564      {
565         return VfatQueueRequest (IrpContext);
566      }
567   }
568
569
570   switch (FileInformationClass)
571     {
572     case FileStandardInformation:
573       RC = VfatGetStandardInformation(FCB,
574                                       SystemBuffer,
575                                       &BufferLength);
576       break;
577     case FilePositionInformation:
578       RC = VfatGetPositionInformation(IrpContext->FileObject,
579                                       FCB,
580                                       IrpContext->DeviceObject,
581                                       SystemBuffer,
582                                       &BufferLength);
583       break;
584     case FileBasicInformation:
585       RC = VfatGetBasicInformation(IrpContext->FileObject,
586                                    FCB,
587                                    IrpContext->DeviceObject,
588                                    SystemBuffer,
589                                    &BufferLength);
590       break;
591     case FileNameInformation:
592       RC = VfatGetNameInformation(IrpContext->FileObject,
593                                   FCB,
594                                   IrpContext->DeviceObject,
595                                   SystemBuffer,
596                                   &BufferLength);
597       break;
598     case FileInternalInformation:
599       RC = VfatGetInternalInformation(FCB,
600                                       SystemBuffer,
601                                       &BufferLength);
602       break;
603     case FileNetworkOpenInformation:
604       RC = VfatGetNetworkOpenInformation(FCB,
605                                          SystemBuffer,
606                                          &BufferLength);
607       break;
608     case FileAllInformation:
609       RC = VfatGetAllInformation(IrpContext->FileObject,
610                                  FCB,
611                                  SystemBuffer,
612                                  &BufferLength);
613       break;
614
615     case FileAlternateNameInformation:
616       RC = STATUS_NOT_IMPLEMENTED;
617       break;
618     default:
619       RC = STATUS_NOT_SUPPORTED;
620     }
621
622   if (!(FCB->Flags & FCB_IS_PAGE_FILE))
623   {
624      ExReleaseResourceLite(&FCB->MainResource);
625   }
626   IrpContext->Irp->IoStatus.Status = RC;
627   if (NT_SUCCESS(RC))
628     IrpContext->Irp->IoStatus.Information =
629       IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
630   else
631     IrpContext->Irp->IoStatus.Information = 0;
632   IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
633   VfatFreeIrpContext(IrpContext);
634
635   return RC;
636 }
637
638 NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
639 /*
640  * FUNCTION: Retrieve the specified file information
641  */
642 {
643   FILE_INFORMATION_CLASS FileInformationClass;
644   PVFATFCB FCB = NULL;
645   NTSTATUS RC = STATUS_SUCCESS;
646   PVOID SystemBuffer;
647   BOOL CanWait = IrpContext->Flags & IRPCONTEXT_CANWAIT;
648   
649   /* PRECONDITION */
650   assert(IrpContext);
651   
652   DPRINT("VfatSetInformation(IrpContext %x)\n", IrpContext);
653   
654   /* INITIALIZATION */
655   FileInformationClass = 
656     IrpContext->Stack->Parameters.SetFile.FileInformationClass;
657   FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
658   SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
659   
660   DPRINT("FileInformationClass %d\n", FileInformationClass);
661   DPRINT("SystemBuffer %x\n", SystemBuffer);
662   
663   if (FCB->Flags & FCB_IS_PAGE_FILE)
664     {
665       if (!ExAcquireResourceExclusiveLite(&FCB->PagingIoResource, CanWait))
666         {
667           return(VfatQueueRequest (IrpContext));
668         }
669     }
670   else
671     {
672       if (!ExAcquireResourceExclusiveLite(&FCB->MainResource, CanWait))
673         {
674           return(VfatQueueRequest (IrpContext));
675         }
676     }
677
678   switch (FileInformationClass)
679     {
680     case FilePositionInformation:
681       RC = VfatSetPositionInformation(IrpContext->FileObject,
682                                       SystemBuffer);
683       break;
684     case FileDispositionInformation:
685       RC = VfatSetDispositionInformation(IrpContext->FileObject,
686                                          FCB,
687                                          IrpContext->DeviceObject,
688                                          SystemBuffer);
689       break;
690     case FileAllocationInformation:    
691     case FileEndOfFileInformation:
692       RC = VfatSetAllocationSizeInformation(IrpContext->FileObject,
693                                             FCB,
694                                             IrpContext->DeviceExt,
695                                             (PLARGE_INTEGER)SystemBuffer);
696       break;    
697     case FileBasicInformation:
698       RC = VfatSetBasicInformation(IrpContext->FileObject,
699                                    FCB,
700                                    IrpContext->DeviceExt,
701                                    SystemBuffer);
702       break;
703     case FileRenameInformation:
704       RC = STATUS_NOT_IMPLEMENTED;
705       break;
706     default:
707       RC = STATUS_NOT_SUPPORTED;
708     }
709
710   if (FCB->Flags & FCB_IS_PAGE_FILE)
711   {
712      ExReleaseResourceLite(&FCB->PagingIoResource);
713   }
714   else
715   {
716      ExReleaseResourceLite(&FCB->MainResource);
717   }
718
719   IrpContext->Irp->IoStatus.Status = RC;
720   IrpContext->Irp->IoStatus.Information = 0;
721   IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
722   VfatFreeIrpContext(IrpContext);
723
724   return RC;
725 }
726
727 /* EOF */