xref: /reactos/drivers/filesystems/ext2/src/ea.c (revision 9393fc32)
1 /*
2 * COPYRIGHT:        See COPYRIGHT.TXT
3 * PROJECT:          Ext2 File System Driver for Windows >= NT
4 * FILE:             ea.c
5 * PROGRAMMER:       Matt Wu <mattwu@163.com>  Kaho Ng <ngkaho1234@gmail.com>
6 * HOMEPAGE:         http://www.ext2fsd.com
7 * UPDATE HISTORY:
8 */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include "ext2fs.h"
13 #include <linux/ext4_xattr.h>
14 
15 #ifdef ALLOC_PRAGMA
16 #pragma alloc_text(PAGE, Ext2QueryEa)
17 #pragma alloc_text(PAGE, Ext2SetEa)
18 #pragma alloc_text(PAGE, Ext2IsEaNameValid)
19 #endif
20 
21 // Ea iterator
22 struct EaIterator {
23 	// Return only an entry
24 	BOOLEAN ReturnSingleEntry;
25 
26 	// Is the buffer overflowing?
27 	BOOL OverFlow;
28 
29 	// FILE_FULL_EA_INFORMATION output buffer
30 	PFILE_FULL_EA_INFORMATION FullEa;
31 	PFILE_FULL_EA_INFORMATION LastFullEa;
32 
33 	// UserBuffer's size
34 	ULONG UserBufferLength;
35 
36 	// Remaining UserBuffer's size
37 	ULONG RemainingUserBufferLength;
38 
39 	// Start scanning from this EA
40 	ULONG EaIndex;
41 
42 	// Next EA index returned by Ext2IterateAllEa
43 	ULONG EaIndexCounter;
44 };
45 
46 static int Ext2IterateAllEa(struct ext4_xattr_ref *xattr_ref, struct ext4_xattr_item *item, BOOL is_last)
47 {
48 	struct EaIterator *pEaIterator = xattr_ref->iter_arg;
49 	ULONG EaEntrySize = 4 + 1 + 1 + 2 + item->name_len + 1 + item->data_size;
50 	ASSERT(pEaIterator);
51 	if (!is_last && !pEaIterator->ReturnSingleEntry)
52 		EaEntrySize = ALIGN_UP(EaEntrySize, ULONG);
53 
54 	// Start iteration from index specified
55 	if (pEaIterator->EaIndexCounter < pEaIterator->EaIndex) {
56 		pEaIterator->EaIndexCounter++;
57 		return EXT4_XATTR_ITERATE_CONT;
58 	}
59 	pEaIterator->EaIndexCounter++;
60 
61 	if (EaEntrySize > pEaIterator->RemainingUserBufferLength) {
62 		pEaIterator->OverFlow = TRUE;
63 		return EXT4_XATTR_ITERATE_STOP;
64 	}
65 	pEaIterator->FullEa->NextEntryOffset = 0;
66 	pEaIterator->FullEa->Flags = 0;
67 	pEaIterator->FullEa->EaNameLength = (UCHAR)item->name_len;
68 	pEaIterator->FullEa->EaValueLength = (USHORT)item->data_size;
69 	RtlCopyMemory(&pEaIterator->FullEa->EaName[0],
70 		item->name,
71 		item->name_len);
72 	RtlCopyMemory(&pEaIterator->FullEa->EaName[0] + item->name_len + 1,
73 		item->data,
74 		item->data_size);
75 
76 	// Link FullEa and LastFullEa together
77 	if (pEaIterator->LastFullEa) {
78 		pEaIterator->LastFullEa->NextEntryOffset = (ULONG)
79 			((PCHAR)pEaIterator->FullEa - (PCHAR)pEaIterator->LastFullEa);
80 	}
81 
82 	pEaIterator->LastFullEa = pEaIterator->FullEa;
83 	pEaIterator->FullEa = (PFILE_FULL_EA_INFORMATION)
84 			((PCHAR)pEaIterator->FullEa + EaEntrySize);
85 	pEaIterator->RemainingUserBufferLength -= EaEntrySize;
86 
87 	if (pEaIterator->ReturnSingleEntry)
88 		return EXT4_XATTR_ITERATE_STOP;
89 
90 	return EXT4_XATTR_ITERATE_CONT;
91 }
92 
93 NTSTATUS
94 Ext2QueryEa (
95 	IN PEXT2_IRP_CONTEXT    IrpContext
96 )
97 {
98 	PIRP                Irp = NULL;
99 	PIO_STACK_LOCATION  IrpSp;
100 
101 	PDEVICE_OBJECT      DeviceObject;
102 
103 	PEXT2_VCB           Vcb = NULL;
104 	PEXT2_FCB           Fcb = NULL;
105 	PEXT2_CCB           Ccb = NULL;
106 	PEXT2_MCB           Mcb = NULL;
107 
108 	PUCHAR  UserEaList;
109 	ULONG   UserEaListLength;
110 	ULONG   UserEaIndex;
111 
112 	BOOLEAN RestartScan;
113 	BOOLEAN ReturnSingleEntry;
114 	BOOLEAN IndexSpecified;
115 
116 	BOOLEAN             MainResourceAcquired = FALSE;
117 	BOOLEAN             XattrRefAcquired = FALSE;
118 
119 	NTSTATUS            Status = STATUS_UNSUCCESSFUL;
120 
121 	struct ext4_xattr_ref xattr_ref;
122 	PCHAR UserBuffer;
123 
124 	ULONG UserBufferLength = 0;
125 	ULONG RemainingUserBufferLength = 0;
126 
127 	PFILE_FULL_EA_INFORMATION FullEa, LastFullEa = NULL;
128 
129 	_SEH2_TRY {
130 
131 		Ccb = IrpContext->Ccb;
132 		ASSERT(Ccb != NULL);
133 		ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
134 			(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
135 		DeviceObject = IrpContext->DeviceObject;
136 		Vcb = (PEXT2_VCB)DeviceObject->DeviceExtension;
137 		Fcb = IrpContext->Fcb;
138 		Mcb = Fcb->Mcb;
139 		Irp = IrpContext->Irp;
140 		IrpSp = IoGetCurrentIrpStackLocation(Irp);
141 
142 		Irp->IoStatus.Information = 0;
143 
144 		//
145 		// Receive input parameter from caller
146 		//
147 		UserBuffer = Ext2GetUserBuffer(Irp);
148 		if (!UserBuffer) {
149 			Status = STATUS_INSUFFICIENT_RESOURCES;
150 			_SEH2_LEAVE;
151 		}
152 		UserBufferLength = IrpSp->Parameters.QueryEa.Length;
153 		RemainingUserBufferLength = UserBufferLength;
154 		UserEaList = IrpSp->Parameters.QueryEa.EaList;
155 		UserEaListLength = IrpSp->Parameters.QueryEa.EaListLength;
156 		UserEaIndex = IrpSp->Parameters.QueryEa.EaIndex;
157 		RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
158 		ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
159 		IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);
160 
161 		if (!Mcb)
162 			_SEH2_LEAVE;
163 
164 		//
165 		// We do not allow multiple instance gaining EA access to the same file
166 		//
167 		if (!ExAcquireResourceExclusiveLite(
168 			&Fcb->MainResource,
169 			IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
170 			Status = STATUS_PENDING;
171 			_SEH2_LEAVE;
172 		}
173 		MainResourceAcquired = TRUE;
174 
175 		Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref));
176 		if (!NT_SUCCESS(Status)) {
177 			DbgPrint("ext4_fs_get_xattr_ref() failed!\n");
178 			_SEH2_LEAVE;
179 		}
180 
181 		FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
182 
183 		XattrRefAcquired = TRUE;
184 
185 		if (RemainingUserBufferLength)
186 			RtlZeroMemory(FullEa, RemainingUserBufferLength);
187 
188 		if (UserEaList != NULL) {
189 			int i = 0;
190 			PFILE_GET_EA_INFORMATION GetEa;
191 			for (GetEa = (PFILE_GET_EA_INFORMATION)&UserEaList[0];
192 					GetEa < (PFILE_GET_EA_INFORMATION)((PUCHAR)UserEaList
193 					+ UserEaListLength);
194 				GetEa = (GetEa->NextEntryOffset == 0
195 					? (PFILE_GET_EA_INFORMATION)MAXUINT_PTR
196 					: (PFILE_GET_EA_INFORMATION)((PUCHAR)GetEa
197 						+ GetEa->NextEntryOffset))) {
198 
199 				size_t ItemSize;
200 				OEM_STRING Str;
201 				ULONG EaEntrySize;
202 				BOOL is_last = !GetEa->NextEntryOffset;
203 
204 				Str.MaximumLength = Str.Length = GetEa->EaNameLength;
205 				Str.Buffer = &GetEa->EaName[0];
206 
207 				//
208 				// At the moment we only need to know whether the item exists
209 				// and its size.
210 				//
211 				Status = Ext2WinntError(ext4_fs_get_xattr(&xattr_ref,
212 					EXT4_XATTR_INDEX_USER,
213 					Str.Buffer,
214 					Str.Length,
215 					NULL,
216 					0,
217 					&ItemSize));
218 				if (!NT_SUCCESS(Status))
219 					continue;
220 
221 				//
222 				//  We were not able to locate the name therefore we must
223 				//  dummy up a entry for the query.  The needed Ea size is
224 				//  the size of the name + 4 (next entry offset) + 1 (flags)
225 				//  + 1 (name length) + 2 (value length) + the name length +
226 				//  1 (null byte) + Data Size.
227 				//
228 				EaEntrySize = 4 + 1 + 1 + 2 + GetEa->EaNameLength + 1 + ItemSize;
229 				if (!is_last)
230 					EaEntrySize = ALIGN_UP(EaEntrySize, ULONG);
231 
232 				if (EaEntrySize > RemainingUserBufferLength) {
233 
234 					Status = i ? STATUS_BUFFER_OVERFLOW : STATUS_BUFFER_TOO_SMALL;
235 					_SEH2_LEAVE;
236 				}
237 				FullEa->NextEntryOffset = 0;
238 				FullEa->Flags = 0;
239 				FullEa->EaNameLength = GetEa->EaNameLength;
240 				FullEa->EaValueLength = (USHORT)ItemSize;
241 				RtlCopyMemory(&FullEa->EaName[0],
242 					&GetEa->EaName[0],
243 					GetEa->EaNameLength);
244 
245 				//
246 				// This query must succeed, or is guarenteed to succeed
247 				// since we are only looking up
248 				// an EA entry in a in-memory tree structure.
249 				// Otherwise that means someone might be operating on
250 				// the xattr_ref without acquiring Inode lock.
251 				//
252 				ASSERT(NT_SUCCESS(Ext2WinntError(
253 					ext4_fs_get_xattr(&xattr_ref,
254 						EXT4_XATTR_INDEX_USER,
255 						Str.Buffer,
256 						Str.Length,
257 						&FullEa->EaName[0] + FullEa->EaNameLength + 1,
258 						ItemSize,
259 						&ItemSize
260 				))));
261 				FullEa->EaValueLength = (USHORT)ItemSize;
262 
263 				// Link FullEa and LastFullEa together
264 				if (LastFullEa)
265 					LastFullEa->NextEntryOffset = (ULONG)((PCHAR)FullEa -
266                                                           (PCHAR)LastFullEa);
267 
268 				LastFullEa = FullEa;
269 				FullEa = (PFILE_FULL_EA_INFORMATION)
270 					((PCHAR)FullEa + EaEntrySize);
271 				RemainingUserBufferLength -= EaEntrySize;
272 				i++;
273 			}
274 		} else if (IndexSpecified) {
275 			struct EaIterator EaIterator;
276 			//
277 			//  The user supplied an index into the Ea list.
278 			//
279 			if (RemainingUserBufferLength)
280 				RtlZeroMemory(FullEa, RemainingUserBufferLength);
281 
282 			EaIterator.OverFlow = FALSE;
283 			EaIterator.RemainingUserBufferLength = UserBufferLength;
284 			// In this case, return only an entry.
285 			EaIterator.ReturnSingleEntry = TRUE;
286 			EaIterator.FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
287 			EaIterator.LastFullEa = NULL;
288 			EaIterator.UserBufferLength = UserBufferLength;
289 			EaIterator.EaIndex = UserEaIndex;
290 			EaIterator.EaIndexCounter = 1;
291 
292 			xattr_ref.iter_arg = &EaIterator;
293 			ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa);
294 
295 			RemainingUserBufferLength = EaIterator.RemainingUserBufferLength;
296 
297 			Status = STATUS_SUCCESS;
298 
299 			// It seems that the item isn't found
300 			if (RemainingUserBufferLength == UserBufferLength)
301 				Status = STATUS_OBJECTID_NOT_FOUND;
302 
303 			if (EaIterator.OverFlow) {
304 				if (RemainingUserBufferLength == UserBufferLength)
305 					Status = STATUS_BUFFER_TOO_SMALL;
306 				else
307 					Status = STATUS_BUFFER_OVERFLOW;
308 			}
309 
310 		} else {
311 			struct EaIterator EaIterator;
312 			//
313 			//  Else perform a simple scan, taking into account the restart
314 			//  flag and the position of the next Ea stored in the Ccb.
315 			//
316 			if (RestartScan)
317 				Ccb->EaIndex = 1;
318 
319 			if (RemainingUserBufferLength)
320 				RtlZeroMemory(FullEa, RemainingUserBufferLength);
321 
322 			EaIterator.OverFlow = FALSE;
323 			EaIterator.RemainingUserBufferLength = UserBufferLength;
324 			EaIterator.ReturnSingleEntry = ReturnSingleEntry;
325 			EaIterator.FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
326 			EaIterator.LastFullEa = NULL;
327 			EaIterator.UserBufferLength = UserBufferLength;
328 			EaIterator.EaIndex = Ccb->EaIndex;
329 			EaIterator.EaIndexCounter = 1;
330 
331 			xattr_ref.iter_arg = &EaIterator;
332 			ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa);
333 
334 			RemainingUserBufferLength = EaIterator.RemainingUserBufferLength;
335 
336 			if (Ccb->EaIndex < EaIterator.EaIndexCounter)
337 				Ccb->EaIndex = EaIterator.EaIndexCounter;
338 
339 			Status = STATUS_SUCCESS;
340 
341 			if (EaIterator.OverFlow) {
342 				if (RemainingUserBufferLength == UserBufferLength)
343 					Status = STATUS_BUFFER_TOO_SMALL;
344 				else
345 					Status = STATUS_BUFFER_OVERFLOW;
346 			}
347 
348 		}
349 	}
350 	_SEH2_FINALLY {
351 
352 		if (XattrRefAcquired) {
353 			if (!NT_SUCCESS(Status)) {
354 				xattr_ref.dirty = FALSE;
355 				ext4_fs_put_xattr_ref(&xattr_ref);
356 			}
357 			else
358 				Status = Ext2WinntError(ext4_fs_put_xattr_ref(&xattr_ref));
359 		}
360 
361 		if (MainResourceAcquired) {
362 			ExReleaseResourceLite(&Fcb->MainResource);
363 		}
364 
365 		if (NT_SUCCESS(Status)) {
366 			Ext2NotifyReportChange(
367 				IrpContext,
368 				Vcb,
369 				Mcb,
370 				FILE_NOTIFY_CHANGE_EA,
371 				FILE_ACTION_MODIFIED);
372 			Irp->IoStatus.Information = UserBufferLength - RemainingUserBufferLength;
373 		}
374 
375 		if (!_SEH2_AbnormalTermination()) {
376 			if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
377 				Status = Ext2QueueRequest(IrpContext);
378 			}
379 			else {
380 				Ext2CompleteIrpContext(IrpContext, Status);
381 			}
382 		}
383 	} _SEH2_END;
384 
385 	return Status;
386 }
387 
388 BOOLEAN
389 Ext2IsEaNameValid(
390 	IN OEM_STRING Name
391 )
392 {
393 	ULONG Index;
394 	UCHAR Char;
395 
396 	//
397 	//  Empty names are not valid
398 	//
399 
400 	if (Name.Length == 0)
401 		return FALSE;
402 
403 	//
404 	// Do not allow EA name longer than 255 bytes
405 	//
406 	if (Name.Length > 255)
407 		return FALSE;
408 
409 	for (Index = 0; Index < (ULONG)Name.Length; Index += 1) {
410 
411 		Char = Name.Buffer[Index];
412 
413 		//
414 		//  Skip over and Dbcs chacters
415 		//
416 		if (FsRtlIsLeadDbcsCharacter(Char)) {
417 
418 			ASSERT(Index != (ULONG)(Name.Length - 1));
419 			Index += 1;
420 			continue;
421 		}
422 
423 		//
424 		//  Make sure this character is legal, and if a wild card, that
425 		//  wild cards are permissible.
426 		//
427 		if (!FsRtlIsAnsiCharacterLegalFat(Char, FALSE))
428 			return FALSE;
429 
430 	}
431 
432 	return TRUE;
433 }
434 
435 NTSTATUS
436 Ext2SetEa (
437 	IN PEXT2_IRP_CONTEXT    IrpContext
438 )
439 {
440 	PIRP                Irp = NULL;
441 	PIO_STACK_LOCATION  IrpSp;
442 
443 	PDEVICE_OBJECT      DeviceObject;
444 
445 	PEXT2_VCB           Vcb = NULL;
446 	PEXT2_FCB           Fcb = NULL;
447 	PEXT2_CCB           Ccb = NULL;
448 	PEXT2_MCB           Mcb = NULL;
449 
450 	BOOLEAN             MainResourceAcquired = FALSE;
451 	BOOLEAN             FcbLockAcquired = FALSE;
452 	BOOLEAN             XattrRefAcquired = FALSE;
453 
454 	NTSTATUS            Status = STATUS_UNSUCCESSFUL;
455 
456 	struct ext4_xattr_ref xattr_ref;
457 	PCHAR UserBuffer;
458 	ULONG UserBufferLength;
459 
460 	PFILE_FULL_EA_INFORMATION FullEa;
461 
462 	_SEH2_TRY {
463 
464 		Ccb = IrpContext->Ccb;
465 		ASSERT(Ccb != NULL);
466 		ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
467 			(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
468 		DeviceObject = IrpContext->DeviceObject;
469 		Vcb = (PEXT2_VCB)DeviceObject->DeviceExtension;
470 		Fcb = IrpContext->Fcb;
471 		Mcb = Fcb->Mcb;
472 		Irp = IrpContext->Irp;
473 		IrpSp = IoGetCurrentIrpStackLocation(Irp);
474 
475 		Irp->IoStatus.Information = 0;
476 
477 		//
478 		// Receive input parameter from caller
479 		//
480 		UserBufferLength = IrpSp->Parameters.SetEa.Length;
481 		UserBuffer = Irp->UserBuffer;
482 
483 		// Check if the EA buffer provided is valid
484 		Status = IoCheckEaBufferValidity((PFILE_FULL_EA_INFORMATION)UserBuffer,
485 			UserBufferLength,
486 			(PULONG)&Irp->IoStatus.Information);
487 		if (!NT_SUCCESS(Status))
488 			_SEH2_LEAVE;
489 
490 		ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
491 		FcbLockAcquired = TRUE;
492 
493 		if (!Mcb)
494 			_SEH2_LEAVE;
495 
496 		//
497 		// We do not allow multiple instance gaining EA access to the same file
498 		//
499 		if (!ExAcquireResourceExclusiveLite(
500 			&Fcb->MainResource,
501 			IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
502 			Status = STATUS_PENDING;
503 			_SEH2_LEAVE;
504 		}
505 		MainResourceAcquired = TRUE;
506 
507 		Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref));
508 		if (!NT_SUCCESS(Status)) {
509 			DbgPrint("ext4_fs_get_xattr_ref() failed!\n");
510 			_SEH2_LEAVE;
511 		}
512 
513 		XattrRefAcquired = TRUE;
514 
515 		//
516 		// Remove all existing EA entries.
517 		//
518 		ext4_xattr_purge_items(&xattr_ref);
519 		xattr_ref.dirty = TRUE;
520 		Status = STATUS_SUCCESS;
521 
522 		// Iterate the whole EA buffer to do inspection
523 		for (FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
524 			FullEa < (PFILE_FULL_EA_INFORMATION)&UserBuffer[UserBufferLength];
525 			FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ?
526 				&UserBuffer[UserBufferLength] :
527 				(PCHAR)FullEa + FullEa->NextEntryOffset)) {
528 
529 			OEM_STRING EaName;
530 
531 			EaName.MaximumLength = EaName.Length = FullEa->EaNameLength;
532 			EaName.Buffer = &FullEa->EaName[0];
533 
534 			// Check if EA's name is valid
535 			if (!Ext2IsEaNameValid(EaName)) {
536 				Irp->IoStatus.Information = (PCHAR)FullEa - UserBuffer;
537 				Status = STATUS_INVALID_EA_NAME;
538 				_SEH2_LEAVE;
539 			}
540 		}
541 
542 		// Now add EA entries to the inode
543 		for (FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
544 			FullEa < (PFILE_FULL_EA_INFORMATION)&UserBuffer[UserBufferLength];
545 			FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ?
546 				&UserBuffer[UserBufferLength] :
547 				(PCHAR)FullEa + FullEa->NextEntryOffset)) {
548 
549 				int ret;
550 				OEM_STRING EaName;
551 
552 				EaName.MaximumLength = EaName.Length = FullEa->EaNameLength;
553 				EaName.Buffer = &FullEa->EaName[0];
554 
555 				Status = Ext2WinntError(ret =
556 					ext4_fs_set_xattr_ordered(&xattr_ref,
557 						EXT4_XATTR_INDEX_USER,
558 						EaName.Buffer,
559 						EaName.Length,
560 						&FullEa->EaName[0] + FullEa->EaNameLength + 1,
561 						FullEa->EaValueLength));
562 				if (!NT_SUCCESS(Status))
563 					_SEH2_LEAVE;
564 
565 		}
566 	} _SEH2_FINALLY {
567 
568 		if (XattrRefAcquired) {
569 			if (!NT_SUCCESS(Status)) {
570 				xattr_ref.dirty = FALSE;
571 				ext4_fs_put_xattr_ref(&xattr_ref);
572 			} else
573 				Status = Ext2WinntError(ext4_fs_put_xattr_ref(&xattr_ref));
574 		}
575 
576 		if (FcbLockAcquired) {
577 			ExReleaseResourceLite(&Vcb->FcbLock);
578 			FcbLockAcquired = FALSE;
579 		}
580 
581 		if (MainResourceAcquired) {
582 			ExReleaseResourceLite(&Fcb->MainResource);
583 		}
584 
585 		if (NT_SUCCESS(Status)) {
586 			Ext2NotifyReportChange(
587 				IrpContext,
588 				Vcb,
589 				Mcb,
590 				FILE_NOTIFY_CHANGE_EA,
591 				FILE_ACTION_MODIFIED);
592 		}
593 
594 		if (!_SEH2_AbnormalTermination()) {
595 			if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
596 				Status = Ext2QueueRequest(IrpContext);
597 			}
598 			else {
599 				Ext2CompleteIrpContext(IrpContext, Status);
600 			}
601 		}
602 	} _SEH2_END;
603 	return Status;
604 }
605