[NPFS]
[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/filesastems/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 LONG 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 = MmGetSystemAddressForMdl(Irp->MdlAddress);
59 }
60 else
61 {
62 Buffer = Irp->UserBuffer;
63 }
64
65 /* Build the search pattern string */
66 DPRINT("Ccb->u.Directory.SearchPattern.Buffer: %p\n", Ccb->u.Directory.SearchPattern.Buffer);
67 if (Ccb->u.Directory.SearchPattern.Buffer == NULL)
68 {
69 First = TRUE;
70
71 if (SearchPattern != NULL)
72 {
73 Ccb->u.Directory.SearchPattern.Buffer =
74 ExAllocatePool(NonPagedPool, SearchPattern->Length + sizeof(WCHAR));
75 if (Ccb->u.Directory.SearchPattern.Buffer == NULL)
76 {
77 return STATUS_INSUFFICIENT_RESOURCES;
78 }
79
80 Ccb->u.Directory.SearchPattern.Length = SearchPattern->Length;
81 Ccb->u.Directory.SearchPattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
82 RtlCopyMemory(Ccb->u.Directory.SearchPattern.Buffer,
83 SearchPattern->Buffer,
84 SearchPattern->Length);
85 Ccb->u.Directory.SearchPattern.Buffer[SearchPattern->Length / sizeof(WCHAR)] = 0;
86 }
87 else
88 {
89 Ccb->u.Directory.SearchPattern.Buffer =
90 ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR));
91 if (Ccb->u.Directory.SearchPattern.Buffer == NULL)
92 {
93 return STATUS_INSUFFICIENT_RESOURCES;
94 }
95
96 Ccb->u.Directory.SearchPattern.Length = sizeof(WCHAR);
97 Ccb->u.Directory.SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
98 Ccb->u.Directory.SearchPattern.Buffer[0] = L'*';
99 Ccb->u.Directory.SearchPattern.Buffer[1] = 0;
100 }
101 }
102 DPRINT("Search pattern: '%wZ'\n", &Ccb->u.Directory.SearchPattern);
103
104 /* Determine the file index */
105 if (First || (Stack->Flags & SL_RESTART_SCAN))
106 {
107 FileIndex = 0;
108 }
109 else if ((Stack->Flags & SL_INDEX_SPECIFIED) == 0)
110 {
111 FileIndex = Ccb->u.Directory.FileIndex + 1;
112 }
113 DPRINT("FileIndex: %lu\n", FileIndex);
114
115 DPRINT("Buffer = %p tofind = %wZ\n", Buffer, &Ccb->u.Directory.SearchPattern);
116
117 switch (FileInformationClass)
118 {
119 case FileDirectoryInformation:
120 InfoSize = sizeof(FILE_DIRECTORY_INFORMATION) - sizeof(WCHAR);
121 break;
122
123 case FileFullDirectoryInformation:
124 InfoSize = sizeof(FILE_FULL_DIR_INFORMATION) - sizeof(WCHAR);
125 break;
126
127 case FileBothDirectoryInformation:
128 InfoSize = sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR);
129 break;
130
131 case FileNamesInformation:
132 InfoSize = sizeof(FILE_NAMES_INFORMATION) - sizeof(WCHAR);
133 break;
134
135 default:
136 DPRINT1("Invalid information class: %lu\n", FileInformationClass);
137 return STATUS_INVALID_INFO_CLASS;
138 }
139
140 PipeIndex = 0;
141
142 Vcb = Ccb->Fcb->Vcb;
143 CurrentEntry = Vcb->PipeListHead.Flink;
144 while (CurrentEntry != &Vcb->PipeListHead &&
145 Status == STATUS_SUCCESS)
146 {
147 /* Get the FCB of the next pipe */
148 PipeFcb = CONTAINING_RECORD(CurrentEntry,
149 NPFS_FCB,
150 PipeListEntry);
151
152 /* Make sure it is a pipe FCB */
153 ASSERT(PipeFcb->Type == FCB_PIPE);
154
155 DPRINT("PipeName: %wZ\n", &PipeFcb->PipeName);
156
157 if (FsRtlIsNameInExpression(&Ccb->u.Directory.SearchPattern,
158 &PipeFcb->PipeName,
159 TRUE,
160 NULL))
161 {
162 DPRINT("Found pipe: %wZ\n", &PipeFcb->PipeName);
163
164 if (PipeIndex >= FileIndex)
165 {
166 /* Determine whether or not the full pipe name fits into the buffer */
167 if (InfoSize + PipeFcb->PipeName.Length > BufferLength)
168 {
169 NameLength = BufferLength - InfoSize;
170 Status = STATUS_BUFFER_OVERFLOW;
171 }
172 else
173 {
174 NameLength = PipeFcb->PipeName.Length;
175 Status = STATUS_SUCCESS;
176 }
177
178 /* Initialize the information struct */
179 RtlZeroMemory(&Buffer[CurrentOffset], InfoSize);
180
181 switch (FileInformationClass)
182 {
183 case FileDirectoryInformation:
184 DirectoryBuffer = (PFILE_DIRECTORY_INFORMATION)&Buffer[CurrentOffset];
185 DirectoryBuffer->FileIndex = PipeIndex;
186 DirectoryBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
187 DirectoryBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
188 DirectoryBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
189 DirectoryBuffer->FileNameLength = NameLength;
190 RtlCopyMemory(DirectoryBuffer->FileName,
191 PipeFcb->PipeName.Buffer,
192 NameLength);
193 break;
194
195 case FileFullDirectoryInformation:
196 FullDirBuffer = (PFILE_FULL_DIR_INFORMATION)&Buffer[CurrentOffset];
197 FullDirBuffer->FileIndex = PipeIndex;
198 FullDirBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
199 FullDirBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
200 FullDirBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
201 FullDirBuffer->FileNameLength = NameLength;
202 RtlCopyMemory(FullDirBuffer->FileName,
203 PipeFcb->PipeName.Buffer,
204 NameLength);
205 break;
206
207 case FileBothDirectoryInformation:
208 BothDirBuffer = (PFILE_BOTH_DIR_INFORMATION)&Buffer[CurrentOffset];
209 BothDirBuffer->NextEntryOffset = 0;
210 BothDirBuffer->FileIndex = PipeIndex;
211 BothDirBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
212 BothDirBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
213 BothDirBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
214 BothDirBuffer->FileNameLength = NameLength;
215 RtlCopyMemory(BothDirBuffer->FileName,
216 PipeFcb->PipeName.Buffer,
217 NameLength);
218 break;
219
220 case FileNamesInformation:
221 NamesBuffer = (PFILE_NAMES_INFORMATION)&Buffer[CurrentOffset];
222 NamesBuffer->FileIndex = PipeIndex;
223 NamesBuffer->FileNameLength = NameLength;
224 RtlCopyMemory(NamesBuffer->FileName,
225 PipeFcb->PipeName.Buffer,
226 NameLength);
227 break;
228
229 default:
230 /* Should never happen! */
231 ASSERT(FALSE);
232 break;
233 }
234
235 DPRINT("CurrentOffset: %lu\n", CurrentOffset);
236
237 /* Store the current pipe index in the CCB */
238 Ccb->u.Directory.FileIndex = PipeIndex;
239
240 /* Get the pointer to the previous entries NextEntryOffset */
241 NextEntryOffset = (PULONG)&Buffer[LastOffset];
242
243 /* Set the previous entries NextEntryOffset */
244 *NextEntryOffset = CurrentOffset - LastOffset;
245
246 /* Return the used buffer size */
247 *Size = CurrentOffset + InfoSize + NameLength;
248
249 /* Leave, if there is no space left in the buffer */
250 if (Status == STATUS_BUFFER_OVERFLOW)
251 return Status;
252
253 /* Leave, if we should return only one entry */
254 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
255 return STATUS_SUCCESS;
256
257 /* Store the current offset for the next round */
258 LastOffset = CurrentOffset;
259
260 /* Set the offset for the next entry */
261 CurrentOffset += ROUND_UP(InfoSize + NameLength, sizeof(ULONG));
262 }
263
264 PipeIndex++;
265 }
266
267 CurrentEntry = CurrentEntry->Flink;
268 }
269
270 /* Return STATUS_NO_MORE_FILES if no matching pipe name was found */
271 if (CurrentOffset == 0)
272 Status = STATUS_NO_MORE_FILES;
273
274 return Status;
275 }
276
277
278 NTSTATUS NTAPI
279 NpfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
280 PIRP Irp)
281 {
282 PIO_STACK_LOCATION IoStack;
283 PFILE_OBJECT FileObject;
284 PNPFS_CCB Ccb;
285 PNPFS_FCB Fcb;
286 NTSTATUS Status;
287 ULONG Size = 0;
288
289 DPRINT("NpfsDirectoryControl() called\n");
290
291 IoStack = IoGetCurrentIrpStackLocation(Irp);
292
293 FileObject = IoStack->FileObject;
294
295 if (NpfsGetCcb(FileObject, &Ccb) != CCB_DIRECTORY)
296 {
297 Status = STATUS_INVALID_PARAMETER;
298
299 Irp->IoStatus.Status = Status;
300 Irp->IoStatus.Information = 0;
301
302 IoCompleteRequest(Irp, IO_NO_INCREMENT);
303
304 return Status;
305 }
306
307 Fcb = Ccb->Fcb;
308
309 switch (IoStack->MinorFunction)
310 {
311 case IRP_MN_QUERY_DIRECTORY:
312 Status = NpfsQueryDirectory(Ccb,
313 Irp,
314 &Size);
315 break;
316
317 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
318 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
319 Status = STATUS_NOT_IMPLEMENTED;
320 break;
321
322 default:
323 DPRINT1("NPFS: MinorFunction %d\n", IoStack->MinorFunction);
324 Status = STATUS_INVALID_DEVICE_REQUEST;
325 break;
326 }
327
328 Irp->IoStatus.Status = Status;
329 Irp->IoStatus.Information = Size;
330
331 IoCompleteRequest(Irp, IO_NO_INCREMENT);
332
333 return Status;
334 }
335
336 /* EOF */