:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / fs / ext2 / dir.c
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * FILE:             services/fs/ext2/dir.c
5  * PURPOSE:          ext2 filesystem
6  * PROGRAMMER:       David Welch (welch@cwcom.net)
7  * UPDATE HISTORY: 
8  */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ddk/ntddk.h>
13 #include <wchar.h>
14 #include <string.h>
15
16 //#define NDEBUG
17 #include <debug.h>
18
19 #include "ext2fs.h"
20
21 /* FUNCTIONS *****************************************************************/
22
23
24 static VOID Ext2ConvertName(PWSTR Out, PCH In, ULONG Len)
25 {
26    ULONG i;
27    
28    for (i=0; i<Len; i++)
29      {
30         *Out = *In;
31         Out++;
32         In++;
33      }
34    *Out = 0;
35 }
36
37 PVOID Ext2ProcessDirEntry(PDEVICE_EXTENSION DeviceExt,
38                           struct ext2_dir_entry* dir_entry,
39                           PIO_STACK_LOCATION IoStack,
40                           PVOID Buffer,
41                           ULONG FileIndex)
42 {
43    PFILE_DIRECTORY_INFORMATION FDI;
44    PFILE_NAMES_INFORMATION FNI;
45    PFILE_BOTH_DIRECTORY_INFORMATION FBI;
46    struct ext2_inode inode;
47    
48    DPRINT("FileIndex %d\n",FileIndex);
49    DPRINT("Buffer %x\n",Buffer);
50    
51    Ext2ReadInode(DeviceExt,
52                  dir_entry->inode,
53                  &inode);
54      
55    switch (IoStack->Parameters.QueryDirectory.FileInformationClass)
56      {
57       case FileNamesInformation:
58         FNI = (PFILE_NAMES_INFORMATION)Buffer;
59         FNI->NextEntryOffset = sizeof(FileDirectoryInformation) +
60           dir_entry->name_len + 1;
61         FNI->FileNameLength = dir_entry->name_len;      
62         Ext2ConvertName(FNI->FileName, dir_entry->name, dir_entry->name_len);
63         Buffer = Buffer + FNI->NextEntryOffset;
64         break;
65         
66       case FileDirectoryInformation:
67         FDI = (PFILE_DIRECTORY_INFORMATION)Buffer;
68         FDI->NextEntryOffset = sizeof(FileDirectoryInformation) + 
69                                dir_entry->name_len + 1;
70         FDI->FileIndex = FileIndex;
71 //      FDI->CreationTime = 0;
72 //      FDI->LastAccessTime = 0;
73 //      FDI->LastWriteTime = 0;
74 //      FDI->ChangeTime = 0;
75         FDI->AllocationSize.QuadPart = FDI->EndOfFile.QuadPart = inode.i_size;
76         FDI->FileAttributes = 0;
77         FDI->FileNameLength = dir_entry->name_len;
78         Ext2ConvertName(FDI->FileName, dir_entry->name, dir_entry->name_len);
79         Buffer = Buffer + FDI->NextEntryOffset;
80         break;
81         
82       case FileBothDirectoryInformation:
83         FBI = (PFILE_BOTH_DIRECTORY_INFORMATION)Buffer;
84         FBI->NextEntryOffset = sizeof(FileBothDirectoryInformation) +
85           dir_entry->name_len + 1;
86         FBI->FileIndex = FileIndex;
87         FBI->AllocationSize.QuadPart = FBI->EndOfFile.QuadPart = inode.i_size;
88         FBI->FileAttributes = 0;
89         FBI->FileNameLength = dir_entry->name_len;
90         Ext2ConvertName(FBI->FileName, dir_entry->name, dir_entry->name_len);
91         memset(FBI->ShortName, 0, sizeof(FBI->ShortName));
92         Buffer = Buffer + FBI->NextEntryOffset;
93         break;
94         
95       default:
96         UNIMPLEMENTED;
97      }
98    return(Buffer);
99 }
100
101
102 NTSTATUS Ext2QueryDirectory(PDEVICE_EXTENSION DeviceExt,
103                             PEXT2_FCB Fcb,
104                             PIRP Irp,
105                             PIO_STACK_LOCATION IoStack)
106 {
107    ULONG Max;
108    ULONG i;
109    ULONG StartIndex;
110    PVOID Buffer = NULL;
111    struct ext2_dir_entry dir_entry;
112    
113    Buffer = Irp->UserBuffer;
114    DPRINT("Buffer %x\n",Buffer);
115    DPRINT("IoStack->Flags %x\n",IoStack->Flags);
116    
117    if (IoStack->Flags & SL_RETURN_SINGLE_ENTRY)
118      {
119         Max = 1;
120      }
121    else
122      {
123         UNIMPLEMENTED;
124      }
125    
126    DPRINT("Buffer->FileIndex %d\n",
127           ((PFILE_DIRECTORY_INFORMATION)Buffer)->FileIndex);
128    if (IoStack->Flags & SL_INDEX_SPECIFIED)
129      {
130         StartIndex = ((PFILE_DIRECTORY_INFORMATION)Buffer)->FileIndex;
131      }
132    else
133      {
134         StartIndex = 0;
135      }
136    
137    if (IoStack->Flags & SL_RESTART_SCAN)
138      {
139         StartIndex = 0;
140      }
141    
142    DPRINT("StartIndex %d\n",StartIndex);
143    
144    for (i=0; i<Max ;i++)
145      {
146         if (!Ext2ScanDir(DeviceExt,&Fcb->inode,"*",&dir_entry,&StartIndex))
147           {
148              ((PFILE_DIRECTORY_INFORMATION)Buffer)->NextEntryOffset = 0;
149              return(STATUS_NO_MORE_FILES);
150           }
151         Buffer = Ext2ProcessDirEntry(DeviceExt,
152                                      &dir_entry, 
153                                      IoStack, 
154                                      Buffer, 
155                                      StartIndex);
156      }
157    return(STATUS_SUCCESS);
158 }
159
160 NTSTATUS STDCALL
161 Ext2DirectoryControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
162 {
163    PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
164    PFILE_OBJECT FileObject = Stack->FileObject;
165    PEXT2_FCB Fcb = (PVOID)FileObject->FsContext;
166    NTSTATUS Status;
167    PDEVICE_EXTENSION DeviceExt;
168    
169    DPRINT("Ext2DirectoryControl(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
170    
171    DeviceExt = DeviceObject->DeviceExtension;
172    
173    switch (Stack->MinorFunction)
174      {
175       case IRP_MN_QUERY_DIRECTORY:
176         Status = Ext2QueryDirectory(DeviceExt, Fcb, Irp, Stack);
177         break;
178         
179       default:
180         Status = STATUS_UNSUCCESSFUL;
181      }
182    
183    Irp->IoStatus.Status = Status;
184    Irp->IoStatus.Information = 0;
185    
186    IoCompleteRequest(Irp, IO_NO_INCREMENT);
187    return(Status);   
188 }
189
190 BOOL Ext2ScanDir(PDEVICE_EXTENSION DeviceExt,
191                  struct ext2_inode* dir, 
192                  PCH filename,
193                  struct ext2_dir_entry* ret,
194                  PULONG StartIndex)
195 {
196    ULONG i;
197    char* buffer;
198    ULONG offset;
199    char name[255];
200    struct ext2_dir_entry* current;
201    ULONG block;
202    BOOL b;
203    
204    DPRINT("Ext2ScanDir(dir %x, filename %s, ret %x)\n",dir,filename,ret);
205    
206    buffer = ExAllocatePool(NonPagedPool, BLOCKSIZE);
207    
208    for (i=0; i<((*StartIndex)/BLOCKSIZE); i++);
209    for (; (block = Ext2BlockMap(DeviceExt, dir, i)) != 0; i++)
210      {
211         DPRINT("block %d\n",block);
212         b = Ext2ReadSectors(DeviceExt->StorageDevice,
213                             block,
214                             1,
215                             buffer);
216         if (!b)
217           {
218              DbgPrint("ext2fs:%s:%d: Disk io failed\n", __FILE__, __LINE__);
219              return(FALSE);
220           }
221         
222         offset = (*StartIndex)%BLOCKSIZE;
223         while (offset < BLOCKSIZE)
224           {
225              current = &buffer[offset];
226              
227              strncpy(name,current->name,current->name_len);
228              name[current->name_len]=0;
229              
230              DPRINT("Scanning offset %d inode %d name %s\n",
231                     offset,current->inode,name);
232
233              DPRINT("Comparing %s %s\n",name,filename);
234              if (strcmp(name,filename)==0 || strcmp(filename,"*")==0)
235                {
236                   DPRINT("Match found\n");
237                   *StartIndex = (i*BLOCKSIZE) + offset + current->rec_len;
238                   memcpy(ret,current,sizeof(struct ext2_dir_entry));
239                   ExFreePool(buffer);
240                   return(TRUE);
241                }
242              
243              offset = offset + current->rec_len;
244              assert(current->rec_len != 0);
245              DPRINT("offset %d\n",offset);
246           }
247         DPRINT("Onto next block\n");
248      }
249    DPRINT("No match\n");
250    ExFreePool(buffer);
251    return(FALSE);
252 }
253
254 void unicode_to_ansi(PCH StringA, PWSTR StringW)
255 {
256    while((*StringW)!=0)
257      {
258         *StringA = *StringW;
259         StringA++;
260         StringW++;
261      }
262    *StringA = 0;
263 }
264
265 NTSTATUS Ext2OpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, 
266                      PWSTR FileName)
267 /*
268  * FUNCTION: Opens a file
269  */
270 {
271    EXT2_INODE parent_inode;
272    struct ext2_dir_entry entry;
273    char name[255];
274    ULONG current_inode = 2;
275    char* current_segment;
276    PEXT2_FCB Fcb;
277    ULONG StartIndex = 0;
278    
279    DPRINT("Ext2OpenFile(DeviceExt %x, FileObject %x, FileName %S)\n",
280           DeviceExt,FileObject,FileName);
281    
282    Fcb = ExAllocatePool(NonPagedPool, sizeof(EXT2_FCB));
283    
284    unicode_to_ansi(name,FileName);
285    DPRINT("name %s\n",name);
286    DPRINT("strtok %x\n",strtok);
287    current_segment = strtok(name,"\\");
288    DPRINT("current_segment %x\n", current_segment);
289    while (current_segment!=NULL)
290      {
291         Ext2LoadInode(DeviceExt,
292                       current_inode,
293                       &parent_inode);
294         if (!Ext2ScanDir(DeviceExt,
295                          parent_inode.inode,
296                          current_segment,
297                          &entry,
298                          &StartIndex))
299           {
300              Ext2ReleaseInode(DeviceExt,
301                               &parent_inode);
302              ExFreePool(Fcb);
303              return(STATUS_UNSUCCESSFUL);
304           }
305         current_inode = entry.inode;
306         current_segment = strtok(NULL,"\\");
307         StartIndex = 0;
308         Ext2ReleaseInode(DeviceExt,
309                          &parent_inode);
310      }
311    DPRINT("Found file\n");
312    
313    Fcb->inode = current_inode;
314    CcRosInitializeFileCache(FileObject, &Fcb->Bcb, PAGE_SIZE*3);
315    FileObject->FsContext = Fcb;
316    
317    return(STATUS_SUCCESS);
318 }
319
320 NTSTATUS STDCALL
321 Ext2Create(PDEVICE_OBJECT DeviceObject, PIRP Irp)
322 {
323    PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
324    PFILE_OBJECT FileObject = Stack->FileObject;
325    NTSTATUS Status;
326    PDEVICE_EXTENSION DeviceExt;
327    
328    DPRINT("Ext2Create(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
329    
330    DeviceExt = DeviceObject->DeviceExtension;
331    Status = Ext2OpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
332    
333    Irp->IoStatus.Status = Status;
334    Irp->IoStatus.Information = 0;
335    
336    IoCompleteRequest(Irp, IO_NO_INCREMENT);
337    return(Status);
338 }