[NtUser]
[reactos.git] / reactos / sdk / lib / drivers / copysup / copysup.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2017 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/copysup/copysup.c
23 * PURPOSE: CopySup library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "copysup.h"
30 #include <pseh/pseh2.h>
31
32 /* FUNCTIONS ****************************************************************/
33
34 /*
35 * @implemented
36 */
37 BOOLEAN
38 FsRtlCopyRead2(
39 IN PFILE_OBJECT FileObject,
40 IN PLARGE_INTEGER FileOffset,
41 IN ULONG Length,
42 IN BOOLEAN Wait,
43 IN ULONG LockKey,
44 OUT PVOID Buffer,
45 OUT PIO_STATUS_BLOCK IoStatus,
46 IN PDEVICE_OBJECT DeviceObject,
47 IN PVOID TopLevelContext)
48 {
49 BOOLEAN Ret;
50 ULONG PageCount;
51 LARGE_INTEGER FinalOffset;
52 PFSRTL_COMMON_FCB_HEADER Fcb;
53 PFAST_IO_DISPATCH FastIoDispatch;
54 PDEVICE_OBJECT RelatedDeviceObject;
55
56 PAGED_CODE();
57
58 Ret = TRUE;
59 PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(FileOffset, Length);
60
61 /* Null-length read is always OK */
62 if (Length == 0)
63 {
64 IoStatus->Information = 0;
65 IoStatus->Status = STATUS_SUCCESS;
66
67 return TRUE;
68 }
69
70 /* Check we don't overflow */
71 FinalOffset.QuadPart = FileOffset->QuadPart + Length;
72 if (FinalOffset.QuadPart <= 0)
73 {
74 return FALSE;
75 }
76
77 /* Get the FCB (at least, its header) */
78 Fcb = FileObject->FsContext;
79
80 FsRtlEnterFileSystem();
81
82 /* Acquire its resource (shared) */
83 if (Wait)
84 {
85 ExAcquireResourceSharedLite(Fcb->Resource, TRUE);
86 }
87 else
88 {
89 if (!ExAcquireResourceSharedLite(Fcb->Resource, FALSE))
90 {
91 Ret = FALSE;
92 goto CriticalSection;
93 }
94 }
95
96 /* If cache wasn't initialized, or FastIO isn't possible, fail */
97 if (FileObject->PrivateCacheMap == NULL || Fcb->IsFastIoPossible == FastIoIsNotPossible)
98 {
99 Ret = FALSE;
100 goto Resource;
101 }
102
103 /* If FastIO is questionable, then, question! */
104 if (Fcb->IsFastIoPossible == FastIoIsQuestionable)
105 {
106 RelatedDeviceObject = IoGetRelatedDeviceObject(FileObject);
107 FastIoDispatch = RelatedDeviceObject->DriverObject->FastIoDispatch;
108 ASSERT(FastIoDispatch != NULL);
109 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
110
111 /* If it's not possible, then fail */
112 if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, FileOffset, Length,
113 Wait, LockKey, TRUE, IoStatus, RelatedDeviceObject))
114 {
115 Ret = FALSE;
116 goto Resource;
117 }
118 }
119
120 /* If we get beyond file end... */
121 if (FinalOffset.QuadPart > Fcb->FileSize.QuadPart)
122 {
123 /* Fail if the offset was already beyond file end */
124 if (FileOffset->QuadPart >= Fcb->FileSize.QuadPart)
125 {
126 IoStatus->Information = 0;
127 IoStatus->Status = STATUS_END_OF_FILE;
128 goto Resource;
129 }
130
131 /* Otherwise, just fix read length */
132 Length = (ULONG)(Fcb->FileSize.QuadPart - FileOffset->QuadPart);
133 }
134
135 /* Set caller provided context as TLI */
136 IoSetTopLevelIrp(TopLevelContext);
137
138 _SEH2_TRY
139 {
140 /* If we cannot wait, or if file is bigger than 4GB */
141 if (!Wait || (FinalOffset.HighPart | Fcb->FileSize.HighPart) != 0)
142 {
143 /* Forward to Cc */
144 Ret = CcCopyRead(FileObject, FileOffset, Length, Wait, Buffer, IoStatus);
145 SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
146
147 /* Validate output */
148 ASSERT(!Ret || (IoStatus->Status == STATUS_END_OF_FILE) || (((ULONGLONG)FileOffset->QuadPart + IoStatus->Information) <= (ULONGLONG)Fcb->FileSize.QuadPart));
149 }
150 else
151 {
152 /* Forward to Cc */
153 CcFastCopyRead(FileObject, FileOffset->LowPart, Length, PageCount, Buffer, IoStatus);
154 SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
155
156 /* Validate output */
157 ASSERT((IoStatus->Status == STATUS_END_OF_FILE) || ((FileOffset->LowPart + IoStatus->Information) <= Fcb->FileSize.LowPart));
158 }
159
160 /* If read was successful, update the byte offset in the FO */
161 if (Ret)
162 {
163 FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information;
164 }
165 }
166 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
167 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
168 {
169 Ret = FALSE;
170 }
171 _SEH2_END;
172
173 /* Reset TLI */
174 IoSetTopLevelIrp(NULL);
175
176 Resource:
177 ExReleaseResourceLite(Fcb->Resource);
178 CriticalSection:
179 FsRtlExitFileSystem();
180
181 return Ret;
182 }