Boudewjin's massive work on kernel32 and crtdll and a console driver.
[reactos.git] / reactos / ntoskrnl / io / fs.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/fs.c
5 * PURPOSE: Filesystem functions
6 * PROGRAMMER: David Welch (welch@mcmail.com)
7 * UPDATE HISTORY:
8 * Created 22/05/98
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <internal/io.h>
15
16 //#define NDEBUG
17 #include <internal/debug.h>
18
19 /* TYPES *******************************************************************/
20
21 typedef struct
22 {
23 PDEVICE_OBJECT DeviceObject;
24 LIST_ENTRY Entry;
25 } FILE_SYSTEM_OBJECT;
26
27 /* GLOBALS ******************************************************************/
28
29 static KSPIN_LOCK FileSystemListLock = {0,};
30 static LIST_ENTRY FileSystemListHead = {NULL,NULL};
31
32 /* FUNCTIONS *****************************************************************/
33
34 NTSTATUS
35 STDCALL
36 NtFsControlFile(
37 IN HANDLE DeviceHandle,
38 IN HANDLE EventHandle OPTIONAL,
39 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
40 IN PVOID ApcContext OPTIONAL,
41 OUT PIO_STATUS_BLOCK IoStatusBlock,
42 IN ULONG IoControlCode,
43 IN PVOID InputBuffer,
44 IN ULONG InputBufferSize,
45 OUT PVOID OutputBuffer,
46 IN ULONG OutputBufferSize
47 )
48 {
49 return(ZwFsControlFile(DeviceHandle,
50 EventHandle,
51 ApcRoutine,
52 ApcContext,
53 IoStatusBlock,
54 IoControlCode,
55 InputBuffer,
56 InputBufferSize,
57 OutputBuffer,
58 OutputBufferSize));
59 }
60
61 NTSTATUS
62 STDCALL
63 ZwFsControlFile(
64 IN HANDLE DeviceHandle,
65 IN HANDLE EventHandle OPTIONAL,
66 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
67 IN PVOID ApcContext OPTIONAL,
68 OUT PIO_STATUS_BLOCK IoStatusBlock,
69 IN ULONG IoControlCode,
70 IN PVOID InputBuffer,
71 IN ULONG InputBufferSize,
72 OUT PVOID OutputBuffer,
73 IN ULONG OutputBufferSize
74 )
75 {
76 NTSTATUS Status = -1;
77 PFILE_OBJECT FileObject;
78 PIRP Irp;
79 PIO_STACK_LOCATION StackPtr;
80 KEVENT Event;
81
82
83 if ( InputBufferSize > 0 ) {
84
85 Status = ObReferenceObjectByHandle(DeviceHandle,
86 FILE_WRITE_DATA|FILE_READ_DATA,
87 NULL,
88 UserMode,
89 (PVOID *) &FileObject,
90 NULL);
91 if (Status != STATUS_SUCCESS)
92 {
93 return(Status);
94 }
95
96 KeInitializeEvent(&Event,NotificationEvent,FALSE);
97 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_DEVICE_CONTROL,
98 FileObject->DeviceObject,
99 InputBuffer,
100 InputBufferSize,
101 0,
102 &Event,
103 IoStatusBlock);
104 StackPtr = IoGetNextIrpStackLocation(Irp);
105 if ( StackPtr == NULL )
106 return -1;
107 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
108 StackPtr->FileObject = FileObject;
109 StackPtr->Parameters.Write.Length = InputBufferSize;
110 DPRINT("FileObject->DeviceObject %x\n",FileObject->DeviceObject);
111 Status = IoCallDriver(FileObject->DeviceObject,Irp);
112 if (Status==STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO))
113 {
114 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
115 return Irp->IoStatus.Status;
116 }
117 }
118
119 if ( OutputBufferSize > 0 ) {
120 CHECKPOINT;
121 Status = ObReferenceObjectByHandle(DeviceHandle,
122 FILE_WRITE_DATA|FILE_READ_DATA,
123 NULL,
124 UserMode,
125 (PVOID *) &FileObject,
126 NULL);
127 if (Status != STATUS_SUCCESS)
128 {
129 return(Status);
130 }
131 CHECKPOINT;
132 KeInitializeEvent(&Event,NotificationEvent,FALSE);
133 CHECKPOINT;
134 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_DEVICE_CONTROL,
135 FileObject->DeviceObject,
136 OutputBuffer,
137 OutputBufferSize,
138 0,
139 &Event,
140 IoStatusBlock);
141 CHECKPOINT;
142 StackPtr = IoGetNextIrpStackLocation(Irp);
143 if ( StackPtr == NULL )
144 return -1;
145 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
146 StackPtr->FileObject = FileObject;
147 StackPtr->Parameters.Read.Length = OutputBufferSize;
148 DPRINT("FileObject->DeviceObject %x\n",FileObject->DeviceObject);
149 Status = IoCallDriver(FileObject->DeviceObject,Irp);
150 if (Status==STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO))
151 {
152 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
153 return Irp->IoStatus.Status;
154 }
155 }
156 CHECKPOINT;
157 return(Status);
158 }
159
160 VOID IoInitFileSystemImplementation(VOID)
161 {
162 InitializeListHead(&FileSystemListHead);
163 KeInitializeSpinLock(&FileSystemListLock);
164 }
165
166 NTSTATUS IoAskFileSystemToMountDevice(PDEVICE_OBJECT DeviceObject,
167 PDEVICE_OBJECT DeviceToMount)
168 {
169 PIRP Irp;
170 KEVENT Event;
171 IO_STATUS_BLOCK IoStatusBlock;
172 NTSTATUS Status;
173
174 DPRINT("IoAskFileSystemToMountDevice(DeviceObject %x, DeviceToMount %x)\n",
175 DeviceObject,DeviceToMount);
176
177 KeInitializeEvent(&Event,NotificationEvent,FALSE);
178 Irp = IoBuildFilesystemControlRequest(IRP_MN_MOUNT_VOLUME,
179 DeviceObject,
180 &Event,
181 &IoStatusBlock,
182 DeviceToMount);
183 Status = IoCallDriver(DeviceObject,Irp);
184 if (Status==STATUS_PENDING)
185 {
186 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
187 Status = IoStatusBlock.Status;
188 }
189 return(Status);
190 }
191
192 NTSTATUS IoAskFileSystemToLoad(PDEVICE_OBJECT DeviceObject)
193 {
194 UNIMPLEMENTED;
195 }
196
197 NTSTATUS IoTryToMountStorageDevice(PDEVICE_OBJECT DeviceObject)
198 /*
199 * FUNCTION: Trys to mount a storage device
200 * ARGUMENTS:
201 * DeviceObject = Device to try and mount
202 * RETURNS: Status
203 */
204 {
205 KIRQL oldlvl;
206 PLIST_ENTRY current_entry;
207 FILE_SYSTEM_OBJECT* current;
208 NTSTATUS Status;
209
210 DPRINT("IoTryToMountStorageDevice(DeviceObject %x)\n",DeviceObject);
211
212 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
213 current_entry = FileSystemListHead.Flink;
214 while (current_entry!=(&FileSystemListHead))
215 {
216 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
217 Status = IoAskFileSystemToMountDevice(current->DeviceObject,
218 DeviceObject);
219 switch (Status)
220 {
221 case STATUS_FS_DRIVER_REQUIRED:
222 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
223 (void)IoAskFileSystemToLoad(DeviceObject);
224 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
225 current_entry = FileSystemListHead.Flink;
226 break;
227
228 case STATUS_SUCCESS:
229 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
230 VPB_MOUNTED;
231 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
232 return(STATUS_SUCCESS);
233
234 case STATUS_UNRECOGNIZED_VOLUME:
235 default:
236 current_entry = current_entry->Flink;
237 }
238 }
239 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
240 return(STATUS_UNRECOGNIZED_VOLUME);
241 }
242
243 VOID IoRegisterFileSystem(PDEVICE_OBJECT DeviceObject)
244 {
245 FILE_SYSTEM_OBJECT* fs;
246
247 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
248
249 fs=ExAllocatePool(NonPagedPool,sizeof(FILE_SYSTEM_OBJECT));
250 assert(fs!=NULL);
251
252 fs->DeviceObject = DeviceObject;
253 ExInterlockedInsertTailList(&FileSystemListHead,&fs->Entry,
254 &FileSystemListLock);
255 }
256
257 VOID IoUnregisterFileSystem(PDEVICE_OBJECT DeviceObject)
258 {
259 KIRQL oldlvl;
260 PLIST_ENTRY current_entry;
261 FILE_SYSTEM_OBJECT* current;
262
263 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
264
265 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
266 current_entry = FileSystemListHead.Flink;
267 while (current_entry!=(&FileSystemListHead))
268 {
269 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
270 if (current->DeviceObject == DeviceObject)
271 {
272 RemoveEntryList(current_entry);
273 ExFreePool(current);
274 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
275 return;
276 }
277 current_entry = current_entry->Flink;
278 }
279 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
280 }
281
282