1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * FILE:             drivers/fs/vfat/cleanup.c
5  * PURPOSE:          VFAT Filesystem
6  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include "vfat.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* FUNCTIONS ****************************************************************/
17 
18 /*
19  * FUNCTION: Cleans up after a file has been closed.
20  */
21 static
22 NTSTATUS
23 VfatCleanupFile(
24     PVFAT_IRP_CONTEXT IrpContext)
25 {
26     PVFATFCB pFcb;
27     PVFATCCB pCcb;
28     BOOLEAN IsVolume;
29     PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt;
30     PFILE_OBJECT FileObject = IrpContext->FileObject;
31 
32     DPRINT("VfatCleanupFile(DeviceExt %p, FileObject %p)\n",
33            IrpContext->DeviceExt, FileObject);
34 
35     /* FIXME: handle file/directory deletion here */
36     pFcb = (PVFATFCB)FileObject->FsContext;
37     if (!pFcb)
38         return STATUS_SUCCESS;
39 
40     IsVolume = BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME);
41     if (IsVolume)
42     {
43         pFcb->OpenHandleCount--;
44 
45         if (pFcb->OpenHandleCount != 0)
46         {
47             IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
48         }
49     }
50     else
51     {
52         if(!ExAcquireResourceExclusiveLite(&pFcb->MainResource,
53                                            BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
54         {
55             return STATUS_PENDING;
56         }
57         if(!ExAcquireResourceExclusiveLite(&pFcb->PagingIoResource,
58                                            BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
59         {
60             ExReleaseResourceLite(&pFcb->MainResource);
61             return STATUS_PENDING;
62         }
63 
64         pCcb = FileObject->FsContext2;
65         if (BooleanFlagOn(pCcb->Flags, CCB_DELETE_ON_CLOSE))
66         {
67             pFcb->Flags |= FCB_DELETE_PENDING;
68         }
69 
70         /* Notify about the cleanup */
71         FsRtlNotifyCleanup(IrpContext->DeviceExt->NotifySync,
72                            &(IrpContext->DeviceExt->NotifyList),
73                            FileObject->FsContext2);
74 
75         pFcb->OpenHandleCount--;
76         DeviceExt->OpenHandleCount--;
77 
78         if (!vfatFCBIsDirectory(pFcb) &&
79             FsRtlAreThereCurrentFileLocks(&pFcb->FileLock))
80         {
81             /* remove all locks this process have on this file */
82             FsRtlFastUnlockAll(&pFcb->FileLock,
83                                FileObject,
84                                IoGetRequestorProcess(IrpContext->Irp),
85                                NULL);
86         }
87 
88         if (BooleanFlagOn(pFcb->Flags, FCB_IS_DIRTY))
89         {
90             VfatUpdateEntry (pFcb, vfatVolumeIsFatX(DeviceExt));
91         }
92 
93         if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
94             pFcb->OpenHandleCount == 0)
95         {
96             if (vfatFCBIsDirectory(pFcb) &&
97                 !VfatIsDirectoryEmpty(DeviceExt, pFcb))
98             {
99                 pFcb->Flags &= ~FCB_DELETE_PENDING;
100             }
101             else
102             {
103                 PFILE_OBJECT tmpFileObject;
104                 tmpFileObject = pFcb->FileObject;
105                 if (tmpFileObject != NULL)
106                 {
107                     pFcb->FileObject = NULL;
108                     CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
109                     ObDereferenceObject(tmpFileObject);
110                 }
111 
112                 pFcb->RFCB.ValidDataLength.QuadPart = 0;
113                 pFcb->RFCB.FileSize.QuadPart = 0;
114                 pFcb->RFCB.AllocationSize.QuadPart = 0;
115             }
116         }
117 
118         /* Uninitialize the cache (should be done even if caching was never initialized) */
119         CcUninitializeCacheMap(FileObject, &pFcb->RFCB.FileSize, NULL);
120 
121         if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
122             pFcb->OpenHandleCount == 0)
123         {
124             VfatDelEntry(DeviceExt, pFcb, NULL);
125 
126             FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
127                                         &(DeviceExt->NotifyList),
128                                         (PSTRING)&pFcb->PathNameU,
129                                         pFcb->PathNameU.Length - pFcb->LongNameU.Length,
130                                         NULL,
131                                         NULL,
132                                         vfatFCBIsDirectory(pFcb) ?
133                                         FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
134                                         FILE_ACTION_REMOVED,
135                                         NULL);
136         }
137 
138         if (pFcb->OpenHandleCount != 0)
139         {
140             IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
141         }
142 
143         FileObject->Flags |= FO_CLEANUP_COMPLETE;
144 
145         ExReleaseResourceLite(&pFcb->PagingIoResource);
146         ExReleaseResourceLite(&pFcb->MainResource);
147     }
148 
149 #ifdef ENABLE_SWAPOUT
150     if (IsVolume && BooleanFlagOn(DeviceExt->Flags, VCB_DISMOUNT_PENDING))
151     {
152         VfatCheckForDismount(DeviceExt, FALSE);
153     }
154 #endif
155 
156     return STATUS_SUCCESS;
157 }
158 
159 /*
160  * FUNCTION: Cleans up after a file has been closed.
161  */
162 NTSTATUS
163 VfatCleanup(
164     PVFAT_IRP_CONTEXT IrpContext)
165 {
166     NTSTATUS Status;
167 
168     DPRINT("VfatCleanup(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp);
169 
170     if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
171     {
172         IrpContext->Irp->IoStatus.Information = 0;
173         return STATUS_SUCCESS;
174     }
175 
176     if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
177                                         BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
178     {
179         return VfatMarkIrpContextForQueue(IrpContext);
180     }
181 
182     Status = VfatCleanupFile(IrpContext);
183 
184     ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
185 
186     if (Status == STATUS_PENDING)
187     {
188         return VfatMarkIrpContextForQueue(IrpContext);
189     }
190 
191     IrpContext->Irp->IoStatus.Information = 0;
192     return Status;
193 }
194 
195 /* EOF */
196