Implemented CcCopyRead(), CcCopyWrite() and some other functions.
[reactos.git] / reactos / ntoskrnl / cc / copy.c
1 /* $Id: copy.c,v 1.1 2001/10/10 21:46:13 hbirr Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cc/copy.c
6 * PURPOSE: Implements cache managers copy interface
7 * PROGRAMMER: Hartmut Birr
8 * UPDATE HISTORY:
9 * Created 05.10.2001
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <ddk/ntifs.h>
16 #include <internal/mm.h>
17 #include <internal/cc.h>
18 #include <internal/pool.h>
19 #include <internal/io.h>
20 #include <ntos/minmax.h>
21
22 #define NDEBUG
23 #include <internal/debug.h>
24
25 /* GLOBALS *******************************************************************/
26
27 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
28
29 /* FUNCTIONS *****************************************************************/
30
31 NTSTATUS ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
32 {
33 ULONG Size;
34 PMDL Mdl;
35 NTSTATUS Status;
36 LARGE_INTEGER SegOffset;
37 IO_STATUS_BLOCK IoStatus;
38
39 SegOffset.QuadPart = CacheSeg->FileOffset;
40 Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
41 if (Size > CacheSeg->Bcb->CacheSegmentSize)
42 {
43 Size = CacheSeg->Bcb->CacheSegmentSize;
44 }
45 Mdl = MmCreateMdl(NULL, CacheSeg->BaseAddress, Size);
46 MmBuildMdlForNonPagedPool(Mdl);
47 Status = IoPageRead(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &IoStatus, TRUE);
48 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
49 {
50 CcRosReleaseCacheSegment(CacheSeg->Bcb, CacheSeg, FALSE);
51 DPRINT1("IoPageRead failed, Status %x\n", Status);
52 return Status;
53 }
54 if (CacheSeg->Bcb->CacheSegmentSize > Size)
55 {
56 memset (CacheSeg->BaseAddress + Size, 0, CacheSeg->Bcb->CacheSegmentSize - Size);
57 }
58 return STATUS_SUCCESS;
59 }
60
61 NTSTATUS WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
62 {
63 ULONG Size;
64 PMDL Mdl;
65 NTSTATUS Status;
66 IO_STATUS_BLOCK IoStatus;
67 LARGE_INTEGER SegOffset;
68
69 SegOffset.QuadPart = CacheSeg->FileOffset;
70 Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
71 if (Size > CacheSeg->Bcb->CacheSegmentSize)
72 {
73 Size = CacheSeg->Bcb->CacheSegmentSize;
74 }
75 Mdl = MmCreateMdl(NULL, CacheSeg->BaseAddress, Size);
76 MmBuildMdlForNonPagedPool(Mdl);
77 Status = IoPageWrite(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &IoStatus, TRUE);
78 if (!NT_SUCCESS(Status))
79 {
80 DPRINT1("IoPageWrite failed, Status %x\n", Status);
81 }
82 return Status;
83 }
84
85 BOOLEAN STDCALL
86 CcCopyRead (
87 IN PFILE_OBJECT FileObject,
88 IN PLARGE_INTEGER FileOffset,
89 IN ULONG Length,
90 IN BOOLEAN Wait,
91 OUT PVOID Buffer,
92 OUT PIO_STATUS_BLOCK IoStatus)
93 {
94 ULONG ReadOffset;
95 ULONG TempLength;
96 NTSTATUS Status = STATUS_SUCCESS;
97 PVOID BaseAddress;
98 PCACHE_SEGMENT CacheSeg;
99 BOOLEAN Valid;
100 ULONG ReadLength = 0;
101 PBCB Bcb;
102 KIRQL oldirql;
103 PLIST_ENTRY current_entry;
104 PCACHE_SEGMENT current;
105
106 DPRINT("CcCopyRead(FileObject %x, FileOffset %x, "
107 "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
108 FileObject, (ULONG)FileOffset->QuadPart, Length, Wait,
109 Buffer, IoStatus);
110
111 Bcb = ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->Bcb;
112 ReadOffset = FileOffset->QuadPart;
113
114 DPRINT("AllocationSize %d, FileSize %d\n",
115 (ULONG)Bcb->AllocationSize.QuadPart,
116 (ULONG)Bcb->FileSize.QuadPart);
117
118 if (!Wait)
119 {
120 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
121 current_entry = Bcb->CacheSegmentListHead.Flink;
122 while (current_entry != &Bcb->CacheSegmentListHead)
123 {
124 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbListEntry);
125 if (!current->Valid && current->FileOffset < ReadOffset + Length
126 && current->FileOffset + Bcb->CacheSegmentSize > ReadOffset)
127 {
128 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
129 IoStatus->Status = STATUS_UNSUCCESSFUL;
130 IoStatus->Information = 0;
131 return FALSE;
132 }
133 current_entry = current_entry->Flink;
134 }
135 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
136 }
137
138 TempLength = ReadOffset % Bcb->CacheSegmentSize;
139 if (TempLength != 0)
140 {
141 TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
142 Status = CcRosRequestCacheSegment(Bcb,
143 ROUND_DOWN(ReadOffset, Bcb->CacheSegmentSize),
144 &BaseAddress, &Valid, &CacheSeg);
145 if (!NT_SUCCESS(Status))
146 {
147 IoStatus->Information = 0;
148 IoStatus->Status = Status;
149 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
150 return FALSE;
151 }
152 if (!Valid)
153 {
154 Status = ReadCacheSegment(CacheSeg);
155 if (!NT_SUCCESS(Status))
156 {
157 IoStatus->Information = 0;
158 IoStatus->Status = Status;
159 return FALSE;
160 }
161 }
162 memcpy (Buffer, BaseAddress + ReadOffset % Bcb->CacheSegmentSize, TempLength);
163 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
164 ReadLength += TempLength;
165 Length -= TempLength;
166 ReadOffset += TempLength;
167 Buffer += TempLength;
168 }
169
170 while (Length > 0)
171 {
172 TempLength = min (Bcb->CacheSegmentSize, Length);
173 Status = CcRosRequestCacheSegment(Bcb, ReadOffset,
174 &BaseAddress, &Valid, &CacheSeg);
175 if (!NT_SUCCESS(Status))
176 {
177 IoStatus->Information = 0;
178 IoStatus->Status = Status;
179 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
180 return FALSE;
181 }
182 if (!Valid)
183 {
184 Status = ReadCacheSegment(CacheSeg);
185 if (!NT_SUCCESS(Status))
186 {
187 IoStatus->Information = 0;
188 IoStatus->Status = Status;
189 return FALSE;
190 }
191 }
192 memcpy (Buffer, BaseAddress, TempLength);
193 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
194 ReadLength += TempLength;
195 Length -= TempLength;
196 ReadOffset += TempLength;
197 Buffer += TempLength;
198 }
199 IoStatus->Status = STATUS_SUCCESS;
200 IoStatus->Information = ReadLength;
201 DPRINT("CcCopyRead O.K.\n");
202 return TRUE;
203 }
204
205 BOOLEAN STDCALL
206 CcCopyWrite (
207 IN PFILE_OBJECT FileObject,
208 IN PLARGE_INTEGER FileOffset,
209 IN ULONG Length,
210 IN BOOLEAN Wait,
211 IN PVOID Buffer)
212 {
213 NTSTATUS Status;
214 ULONG WriteOffset;
215 KIRQL oldirql;
216 PBCB Bcb;
217 PLIST_ENTRY current_entry;
218 PCACHE_SEGMENT CacheSeg;
219 ULONG TempLength;
220 PVOID BaseAddress;
221 BOOLEAN Valid;
222
223 DPRINT("CcCopyWrite(FileObject %x, FileOffset %x, "
224 "Length %d, Wait %d, Buffer %x)\n",
225 FileObject, (ULONG)FileOffset->QuadPart, Length, Wait, Buffer);
226
227 Bcb = ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->Bcb;
228 WriteOffset = (ULONG)FileOffset->QuadPart;
229
230 if (!Wait)
231 {
232 // testing, if the requested datas are available
233 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
234 current_entry = Bcb->CacheSegmentListHead.Flink;
235 while (current_entry != &Bcb->CacheSegmentListHead)
236 {
237 CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbListEntry);
238 if (!CacheSeg->Valid)
239 {
240 if ((WriteOffset >= CacheSeg->FileOffset && WriteOffset < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
241 || (WriteOffset + Length > CacheSeg->FileOffset && WriteOffset + Length <= CacheSeg->FileOffset + Bcb->CacheSegmentSize))
242 {
243 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
244 // datas not available
245 return FALSE;
246 }
247 }
248 current_entry = current_entry->Flink;
249 }
250 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
251 }
252
253 TempLength = WriteOffset % Bcb->CacheSegmentSize;
254 if (TempLength != 0)
255 {
256 TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
257 Status = CcRosRequestCacheSegment(Bcb,
258 ROUND_DOWN(WriteOffset, Bcb->CacheSegmentSize),
259 &BaseAddress, &Valid, &CacheSeg);
260 if (!NT_SUCCESS(Status))
261 {
262 return FALSE;
263 }
264 if (!Valid)
265 {
266 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
267 {
268 return FALSE;
269 }
270 }
271 memcpy (BaseAddress + WriteOffset % Bcb->CacheSegmentSize, Buffer, TempLength);
272 if (!NT_SUCCESS(WriteCacheSegment(CacheSeg)))
273 {
274 return FALSE;
275 }
276 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
277
278 Length -= TempLength;
279 WriteOffset += TempLength;
280 Buffer += TempLength;
281 }
282
283 while (Length > 0)
284 {
285 TempLength = min (Bcb->CacheSegmentSize, Length);
286 Status = CcRosRequestCacheSegment(Bcb, WriteOffset,
287 &BaseAddress, &Valid, &CacheSeg);
288 if (!NT_SUCCESS(Status))
289 {
290 return FALSE;
291 }
292 if (!Valid && TempLength < Bcb->CacheSegmentSize)
293 {
294 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
295 {
296 return FALSE;
297 }
298 }
299 memcpy (BaseAddress, Buffer, TempLength);
300 if (!NT_SUCCESS(WriteCacheSegment(CacheSeg)))
301 {
302 return FALSE;
303 }
304 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
305 Length -= TempLength;
306 WriteOffset += TempLength;
307 Buffer += TempLength;
308 }
309 return TRUE;
310 }
311
312