[NTOSKRNL]
[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 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 KeLockMutex(&Vcb->PipeListLock);
148 CurrentEntry = Vcb->PipeListHead.Flink;
149 while (CurrentEntry != &Vcb->PipeListHead &&
150 Status == STATUS_SUCCESS)
151 {
152 /* Get the FCB of the next pipe */
153 PipeFcb = CONTAINING_RECORD(CurrentEntry,
154 NPFS_FCB,
155 PipeListEntry);
156
157 /* Make sure it is a pipe FCB */
158 ASSERT(PipeFcb->Type == FCB_PIPE);
159
160 DPRINT("PipeName: %wZ\n", &PipeFcb->PipeName);
161
162 if (FsRtlIsNameInExpression(&Ccb->u.Directory.SearchPattern,
163 &PipeFcb->PipeName,
164 TRUE,
165 NULL))
166 {
167 DPRINT("Found pipe: %wZ\n", &PipeFcb->PipeName);
168
169 if (PipeIndex >= FileIndex)
170 {
171 /* Determine whether or not the full pipe name fits into the buffer */
172 if (InfoSize + PipeFcb->PipeName.Length > BufferLength)
173 {
174 NameLength = BufferLength - InfoSize;
175 Status = STATUS_BUFFER_OVERFLOW;
176 }
177 else
178 {
179 NameLength = PipeFcb->PipeName.Length;
180 Status = STATUS_SUCCESS;
181 }
182
183 /* Initialize the information struct */
184 RtlZeroMemory(&Buffer[CurrentOffset], InfoSize);
185
186 switch (FileInformationClass)
187 {
188 case FileDirectoryInformation:
189 DirectoryBuffer = (PFILE_DIRECTORY_INFORMATION)&Buffer[CurrentOffset];
190 DirectoryBuffer->FileIndex = PipeIndex;
191 DirectoryBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
192 DirectoryBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
193 DirectoryBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
194 DirectoryBuffer->FileNameLength = NameLength;
195 RtlCopyMemory(DirectoryBuffer->FileName,
196 PipeFcb->PipeName.Buffer,
197 NameLength);
198 break;
199
200 case FileFullDirectoryInformation:
201 FullDirBuffer = (PFILE_FULL_DIR_INFORMATION)&Buffer[CurrentOffset];
202 FullDirBuffer->FileIndex = PipeIndex;
203 FullDirBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
204 FullDirBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
205 FullDirBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
206 FullDirBuffer->FileNameLength = NameLength;
207 RtlCopyMemory(FullDirBuffer->FileName,
208 PipeFcb->PipeName.Buffer,
209 NameLength);
210 break;
211
212 case FileBothDirectoryInformation:
213 BothDirBuffer = (PFILE_BOTH_DIR_INFORMATION)&Buffer[CurrentOffset];
214 BothDirBuffer->NextEntryOffset = 0;
215 BothDirBuffer->FileIndex = PipeIndex;
216 BothDirBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
217 BothDirBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
218 BothDirBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
219 BothDirBuffer->FileNameLength = NameLength;
220 RtlCopyMemory(BothDirBuffer->FileName,
221 PipeFcb->PipeName.Buffer,
222 NameLength);
223 break;
224
225 case FileNamesInformation:
226 NamesBuffer = (PFILE_NAMES_INFORMATION)&Buffer[CurrentOffset];
227 NamesBuffer->FileIndex = PipeIndex;
228 NamesBuffer->FileNameLength = NameLength;
229 RtlCopyMemory(NamesBuffer->FileName,
230 PipeFcb->PipeName.Buffer,
231 NameLength);
232 break;
233
234 default:
235 /* Should never happen! */
236 ASSERT(FALSE);
237 break;
238 }
239
240 DPRINT("CurrentOffset: %lu\n", CurrentOffset);
241
242 /* Store the current pipe index in the CCB */
243 Ccb->u.Directory.FileIndex = PipeIndex;
244
245 /* Get the pointer to the previous entries NextEntryOffset */
246 NextEntryOffset = (PULONG)&Buffer[LastOffset];
247
248 /* Set the previous entries NextEntryOffset */
249 *NextEntryOffset = CurrentOffset - LastOffset;
250
251 /* Return the used buffer size */
252 *Size = CurrentOffset + InfoSize + NameLength;
253
254 /* Leave, if there is no space left in the buffer */
255 if (Status == STATUS_BUFFER_OVERFLOW)
256 {
257 KeUnlockMutex(&Vcb->PipeListLock);
258 return Status;
259 }
260
261 /* Leave, if we should return only one entry */
262 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
263 {
264 KeUnlockMutex(&Vcb->PipeListLock);
265 return STATUS_SUCCESS;
266 }
267
268 /* Store the current offset for the next round */
269 LastOffset = CurrentOffset;
270
271 /* Set the offset for the next entry */
272 CurrentOffset += ROUND_UP(InfoSize + NameLength, sizeof(ULONG));
273 }
274
275 PipeIndex++;
276 }
277
278 CurrentEntry = CurrentEntry->Flink;
279 }
280 KeUnlockMutex(&Vcb->PipeListLock);
281
282 /* Return STATUS_NO_MORE_FILES if no matching pipe name was found */
283 if (CurrentOffset == 0)
284 Status = STATUS_NO_MORE_FILES;
285
286 return Status;
287 }
288
289
290 NTSTATUS NTAPI
291 NpfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
292 PIRP Irp)
293 {
294 PIO_STACK_LOCATION IoStack;
295 PFILE_OBJECT FileObject;
296 PNPFS_CCB Ccb;
297 //PNPFS_FCB Fcb;
298 NTSTATUS Status;
299 ULONG Size = 0;
300
301 DPRINT("NpfsDirectoryControl() called\n");
302
303 IoStack = IoGetCurrentIrpStackLocation(Irp);
304
305 FileObject = IoStack->FileObject;
306
307 if (NpfsGetCcb(FileObject, &Ccb) != CCB_DIRECTORY)
308 {
309 Status = STATUS_INVALID_PARAMETER;
310
311 Irp->IoStatus.Status = Status;
312 Irp->IoStatus.Information = 0;
313
314 IoCompleteRequest(Irp, IO_NO_INCREMENT);
315
316 return Status;
317 }
318
319 //Fcb = Ccb->Fcb;
320
321 switch (IoStack->MinorFunction)
322 {
323 case IRP_MN_QUERY_DIRECTORY:
324 Status = NpfsQueryDirectory(Ccb,
325 Irp,
326 &Size);
327 break;
328
329 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
330 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
331 Status = STATUS_NOT_IMPLEMENTED;
332 break;
333
334 default:
335 DPRINT1("NPFS: MinorFunction %d\n", IoStack->MinorFunction);
336 Status = STATUS_INVALID_DEVICE_REQUEST;
337 break;
338 }
339
340 Irp->IoStatus.Status = Status;
341 Irp->IoStatus.Information = Size;
342
343 IoCompleteRequest(Irp, IO_NO_INCREMENT);
344
345 return Status;
346 }
347
348 /* EOF */