708320f74517f7af07b4a72c1eb5e5641247fb64
[reactos.git] / reactos / drivers / filesystems / npfs / dirctl.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/filesystems/npfs/dirctl.c
5 * PURPOSE: Named pipe filesystem
6 * PROGRAMMER: Eric Kohl
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "npfs.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* FUNCTIONS *****************************************************************/
17
18 static NTSTATUS
19 NpfsQueryDirectory(PNPFS_CCB Ccb,
20 PIRP Irp,
21 PULONG Size)
22 {
23 PIO_STACK_LOCATION Stack;
24 ULONG BufferLength = 0;
25 PUNICODE_STRING SearchPattern = NULL;
26 FILE_INFORMATION_CLASS FileInformationClass;
27 ULONG FileIndex = 0;
28 PUCHAR Buffer = NULL;
29 BOOLEAN First = FALSE;
30 PLIST_ENTRY CurrentEntry;
31 PNPFS_VCB Vcb;
32 PNPFS_FCB PipeFcb;
33 ULONG PipeIndex;
34 NTSTATUS Status = STATUS_SUCCESS;
35 PFILE_NAMES_INFORMATION NamesBuffer;
36 PFILE_DIRECTORY_INFORMATION DirectoryBuffer;
37 PFILE_FULL_DIR_INFORMATION FullDirBuffer;
38 PFILE_BOTH_DIR_INFORMATION BothDirBuffer;
39 ULONG InfoSize = 0;
40 ULONG NameLength;
41 ULONG CurrentOffset = 0;
42 ULONG LastOffset = 0;
43 PULONG NextEntryOffset;
44
45 Stack = IoGetCurrentIrpStackLocation(Irp);
46
47 /* Obtain the callers parameters */
48 BufferLength = Stack->Parameters.QueryDirectory.Length;
49 SearchPattern = Stack->Parameters.QueryDirectory.FileName;
50 FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
51 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
52
53 DPRINT("SearchPattern: %p '%wZ'\n", SearchPattern, SearchPattern);
54
55 /* Determine Buffer for result */
56 if (Irp->MdlAddress)
57 {
58 Buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,
59 NormalPagePriority);
60 }
61 else
62 {
63 Buffer = Irp->UserBuffer;
64 }
65
66 /* Build the search pattern string */
67 DPRINT("Ccb->u.Directory.SearchPattern.Buffer: %p\n", Ccb->u.Directory.SearchPattern.Buffer);
68 if (Ccb->u.Directory.SearchPattern.Buffer == NULL)
69 {
70 First = TRUE;
71
72 if (SearchPattern != NULL)
73 {
74 Ccb->u.Directory.SearchPattern.Buffer =
75 ExAllocatePoolWithTag(NonPagedPool,
76 SearchPattern->Length + sizeof(WCHAR),
77 TAG_NPFS_NAMEBLOCK);
78 if (Ccb->u.Directory.SearchPattern.Buffer == NULL)
79 {
80 return STATUS_INSUFFICIENT_RESOURCES;
81 }
82
83 Ccb->u.Directory.SearchPattern.Length = SearchPattern->Length;
84 Ccb->u.Directory.SearchPattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
85 RtlCopyMemory(Ccb->u.Directory.SearchPattern.Buffer,
86 SearchPattern->Buffer,
87 SearchPattern->Length);
88 Ccb->u.Directory.SearchPattern.Buffer[SearchPattern->Length / sizeof(WCHAR)] = 0;
89 }
90 else
91 {
92 Ccb->u.Directory.SearchPattern.Buffer =
93 ExAllocatePoolWithTag(NonPagedPool,
94 2 * sizeof(WCHAR),
95 TAG_NPFS_NAMEBLOCK);
96 if (Ccb->u.Directory.SearchPattern.Buffer == NULL)
97 {
98 return STATUS_INSUFFICIENT_RESOURCES;
99 }
100
101 Ccb->u.Directory.SearchPattern.Length = sizeof(WCHAR);
102 Ccb->u.Directory.SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
103 Ccb->u.Directory.SearchPattern.Buffer[0] = L'*';
104 Ccb->u.Directory.SearchPattern.Buffer[1] = 0;
105 }
106 }
107 DPRINT("Search pattern: '%wZ'\n", &Ccb->u.Directory.SearchPattern);
108
109 /* Determine the file index */
110 if (First || (Stack->Flags & SL_RESTART_SCAN))
111 {
112 FileIndex = 0;
113 }
114 else if ((Stack->Flags & SL_INDEX_SPECIFIED) == 0)
115 {
116 FileIndex = Ccb->u.Directory.FileIndex + 1;
117 }
118 DPRINT("FileIndex: %lu\n", FileIndex);
119
120 DPRINT("Buffer = %p tofind = %wZ\n", Buffer, &Ccb->u.Directory.SearchPattern);
121
122 switch (FileInformationClass)
123 {
124 case FileDirectoryInformation:
125 InfoSize = sizeof(FILE_DIRECTORY_INFORMATION) - sizeof(WCHAR);
126 break;
127
128 case FileFullDirectoryInformation:
129 InfoSize = sizeof(FILE_FULL_DIR_INFORMATION) - sizeof(WCHAR);
130 break;
131
132 case FileBothDirectoryInformation:
133 InfoSize = sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR);
134 break;
135
136 case FileNamesInformation:
137 InfoSize = sizeof(FILE_NAMES_INFORMATION) - sizeof(WCHAR);
138 break;
139
140 default:
141 DPRINT1("Invalid information class: %lu\n", FileInformationClass);
142 return STATUS_INVALID_INFO_CLASS;
143 }
144
145 PipeIndex = 0;
146
147 Vcb = Ccb->Fcb->Vcb;
148 KeLockMutex(&Vcb->PipeListLock);
149 CurrentEntry = Vcb->PipeListHead.Flink;
150 while (CurrentEntry != &Vcb->PipeListHead &&
151 Status == STATUS_SUCCESS)
152 {
153 /* Get the FCB of the next pipe */
154 PipeFcb = CONTAINING_RECORD(CurrentEntry,
155 NPFS_FCB,
156 PipeListEntry);
157
158 /* Make sure it is a pipe FCB */
159 ASSERT(PipeFcb->Type == FCB_PIPE);
160
161 DPRINT("PipeName: %wZ\n", &PipeFcb->PipeName);
162
163 if (FsRtlIsNameInExpression(&Ccb->u.Directory.SearchPattern,
164 &PipeFcb->PipeName,
165 TRUE,
166 NULL))
167 {
168 DPRINT("Found pipe: %wZ\n", &PipeFcb->PipeName);
169
170 if (PipeIndex >= FileIndex)
171 {
172 /* Determine whether or not the full pipe name fits into the buffer */
173 if (InfoSize + PipeFcb->PipeName.Length > BufferLength)
174 {
175 NameLength = BufferLength - InfoSize;
176 Status = STATUS_BUFFER_OVERFLOW;
177 }
178 else
179 {
180 NameLength = PipeFcb->PipeName.Length;
181 Status = STATUS_SUCCESS;
182 }
183
184 /* Initialize the information struct */
185 RtlZeroMemory(&Buffer[CurrentOffset], InfoSize);
186
187 switch (FileInformationClass)
188 {
189 case FileDirectoryInformation:
190 DirectoryBuffer = (PFILE_DIRECTORY_INFORMATION)&Buffer[CurrentOffset];
191 DirectoryBuffer->FileIndex = PipeIndex;
192 DirectoryBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
193 DirectoryBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
194 DirectoryBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
195 DirectoryBuffer->FileNameLength = NameLength;
196 RtlCopyMemory(DirectoryBuffer->FileName,
197 PipeFcb->PipeName.Buffer,
198 NameLength);
199 break;
200
201 case FileFullDirectoryInformation:
202 FullDirBuffer = (PFILE_FULL_DIR_INFORMATION)&Buffer[CurrentOffset];
203 FullDirBuffer->FileIndex = PipeIndex;
204 FullDirBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
205 FullDirBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
206 FullDirBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
207 FullDirBuffer->FileNameLength = NameLength;
208 RtlCopyMemory(FullDirBuffer->FileName,
209 PipeFcb->PipeName.Buffer,
210 NameLength);
211 break;
212
213 case FileBothDirectoryInformation:
214 BothDirBuffer = (PFILE_BOTH_DIR_INFORMATION)&Buffer[CurrentOffset];
215 BothDirBuffer->NextEntryOffset = 0;
216 BothDirBuffer->FileIndex = PipeIndex;
217 BothDirBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
218 BothDirBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
219 BothDirBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
220 BothDirBuffer->FileNameLength = NameLength;
221 RtlCopyMemory(BothDirBuffer->FileName,
222 PipeFcb->PipeName.Buffer,
223 NameLength);
224 break;
225
226 case FileNamesInformation:
227 NamesBuffer = (PFILE_NAMES_INFORMATION)&Buffer[CurrentOffset];
228 NamesBuffer->FileIndex = PipeIndex;
229 NamesBuffer->FileNameLength = NameLength;
230 RtlCopyMemory(NamesBuffer->FileName,
231 PipeFcb->PipeName.Buffer,
232 NameLength);
233 break;
234
235 default:
236 /* Should never happen! */
237 ASSERT(FALSE);
238 break;
239 }
240
241 DPRINT("CurrentOffset: %lu\n", CurrentOffset);
242
243 /* Store the current pipe index in the CCB */
244 Ccb->u.Directory.FileIndex = PipeIndex;
245
246 /* Get the pointer to the previous entries NextEntryOffset */
247 NextEntryOffset = (PULONG)&Buffer[LastOffset];
248
249 /* Set the previous entries NextEntryOffset */
250 *NextEntryOffset = CurrentOffset - LastOffset;
251
252 /* Return the used buffer size */
253 *Size = CurrentOffset + InfoSize + NameLength;
254
255 /* Leave, if there is no space left in the buffer */
256 if (Status == STATUS_BUFFER_OVERFLOW)
257 {
258 KeUnlockMutex(&Vcb->PipeListLock);
259 return Status;
260 }
261
262 /* Leave, if we should return only one entry */
263 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
264 {
265 KeUnlockMutex(&Vcb->PipeListLock);
266 return STATUS_SUCCESS;
267 }
268
269 /* Store the current offset for the next round */
270 LastOffset = CurrentOffset;
271
272 /* Set the offset for the next entry */
273 CurrentOffset += ROUND_UP(InfoSize + NameLength, sizeof(ULONG));
274 }
275
276 PipeIndex++;
277 }
278
279 CurrentEntry = CurrentEntry->Flink;
280 }
281 KeUnlockMutex(&Vcb->PipeListLock);
282
283 /* Return STATUS_NO_MORE_FILES if no matching pipe name was found */
284 if (CurrentOffset == 0)
285 Status = STATUS_NO_MORE_FILES;
286
287 return Status;
288 }
289
290
291 NTSTATUS NTAPI
292 NpfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
293 PIRP Irp)
294 {
295 PIO_STACK_LOCATION IoStack;
296 PFILE_OBJECT FileObject;
297 PNPFS_CCB Ccb;
298 //PNPFS_FCB Fcb;
299 NTSTATUS Status;
300 ULONG Size = 0;
301
302 UNREFERENCED_PARAMETER(DeviceObject);
303
304 DPRINT("NpfsDirectoryControl() called\n");
305
306 IoStack = IoGetCurrentIrpStackLocation(Irp);
307
308 FileObject = IoStack->FileObject;
309
310 if (NpfsGetCcb(FileObject, &Ccb) != CCB_DIRECTORY)
311 {
312 Status = STATUS_INVALID_PARAMETER;
313
314 Irp->IoStatus.Status = Status;
315 Irp->IoStatus.Information = 0;
316
317 IoCompleteRequest(Irp, IO_NO_INCREMENT);
318
319 return Status;
320 }
321
322 //Fcb = Ccb->Fcb;
323
324 switch (IoStack->MinorFunction)
325 {
326 case IRP_MN_QUERY_DIRECTORY:
327 Status = NpfsQueryDirectory(Ccb,
328 Irp,
329 &Size);
330 break;
331
332 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
333 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
334 Status = STATUS_NOT_IMPLEMENTED;
335 break;
336
337 default:
338 DPRINT1("NPFS: MinorFunction %d\n", IoStack->MinorFunction);
339 Status = STATUS_INVALID_DEVICE_REQUEST;
340 break;
341 }
342
343 Irp->IoStatus.Status = Status;
344 Irp->IoStatus.Information = Size;
345
346 IoCompleteRequest(Irp, IO_NO_INCREMENT);
347
348 return Status;
349 }
350
351 /* EOF */