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