reactos/rosapps/ext2/dir.c

339 lines
8.1 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: services/fs/ext2/dir.c
* PURPOSE: ext2 filesystem
* PROGRAMMER: David Welch (welch@cwcom.net)
* UPDATE HISTORY:
*/
/* INCLUDES *****************************************************************/
#include <ntddk.h>
#include <wchar.h>
#include <string.h>
//#define NDEBUG
#include <debug.h>
#include "ext2fs.h"
/* FUNCTIONS *****************************************************************/
static VOID Ext2ConvertName(PWSTR Out, PCH In, ULONG Len)
{
ULONG i;
for (i=0; i<Len; i++)
{
*Out = *In;
Out++;
In++;
}
*Out = 0;
}
PVOID Ext2ProcessDirEntry(PDEVICE_EXTENSION DeviceExt,
struct ext2_dir_entry* dir_entry,
PIO_STACK_LOCATION IoStack,
PVOID Buffer,
ULONG FileIndex)
{
PFILE_DIRECTORY_INFORMATION FDI;
PFILE_NAMES_INFORMATION FNI;
PFILE_BOTH_DIRECTORY_INFORMATION FBI;
struct ext2_inode inode;
DPRINT("FileIndex %d\n",FileIndex);
DPRINT("Buffer %x\n",Buffer);
Ext2ReadInode(DeviceExt,
dir_entry->inode,
&inode);
switch (IoStack->Parameters.QueryDirectory.FileInformationClass)
{
case FileNamesInformation:
FNI = (PFILE_NAMES_INFORMATION)Buffer;
FNI->NextEntryOffset = sizeof(FileDirectoryInformation) +
dir_entry->name_len + 1;
FNI->FileNameLength = dir_entry->name_len;
Ext2ConvertName(FNI->FileName, dir_entry->name, dir_entry->name_len);
Buffer = Buffer + FNI->NextEntryOffset;
break;
case FileDirectoryInformation:
FDI = (PFILE_DIRECTORY_INFORMATION)Buffer;
FDI->NextEntryOffset = sizeof(FileDirectoryInformation) +
dir_entry->name_len + 1;
FDI->FileIndex = FileIndex;
// FDI->CreationTime = 0;
// FDI->LastAccessTime = 0;
// FDI->LastWriteTime = 0;
// FDI->ChangeTime = 0;
FDI->AllocationSize.QuadPart = FDI->EndOfFile.QuadPart = inode.i_size;
FDI->FileAttributes = 0;
FDI->FileNameLength = dir_entry->name_len;
Ext2ConvertName(FDI->FileName, dir_entry->name, dir_entry->name_len);
Buffer = Buffer + FDI->NextEntryOffset;
break;
case FileBothDirectoryInformation:
FBI = (PFILE_BOTH_DIRECTORY_INFORMATION)Buffer;
FBI->NextEntryOffset = sizeof(FileBothDirectoryInformation) +
dir_entry->name_len + 1;
FBI->FileIndex = FileIndex;
FBI->AllocationSize.QuadPart = FBI->EndOfFile.QuadPart = inode.i_size;
FBI->FileAttributes = 0;
FBI->FileNameLength = dir_entry->name_len;
Ext2ConvertName(FBI->FileName, dir_entry->name, dir_entry->name_len);
memset(FBI->ShortName, 0, sizeof(FBI->ShortName));
Buffer = Buffer + FBI->NextEntryOffset;
break;
default:
UNIMPLEMENTED;
}
return(Buffer);
}
NTSTATUS Ext2QueryDirectory(PDEVICE_EXTENSION DeviceExt,
PEXT2_FCB Fcb,
PIRP Irp,
PIO_STACK_LOCATION IoStack)
{
ULONG Max;
ULONG i;
ULONG StartIndex;
PVOID Buffer = NULL;
struct ext2_dir_entry dir_entry;
Buffer = Irp->UserBuffer;
DPRINT("Buffer %x\n",Buffer);
DPRINT("IoStack->Flags %x\n",IoStack->Flags);
if (IoStack->Flags & SL_RETURN_SINGLE_ENTRY)
{
Max = 1;
}
else
{
UNIMPLEMENTED;
}
DPRINT("Buffer->FileIndex %d\n",
((PFILE_DIRECTORY_INFORMATION)Buffer)->FileIndex);
if (IoStack->Flags & SL_INDEX_SPECIFIED)
{
StartIndex = ((PFILE_DIRECTORY_INFORMATION)Buffer)->FileIndex;
}
else
{
StartIndex = 0;
}
if (IoStack->Flags & SL_RESTART_SCAN)
{
StartIndex = 0;
}
DPRINT("StartIndex %d\n",StartIndex);
for (i=0; i<Max ;i++)
{
if (!Ext2ScanDir(DeviceExt,&Fcb->inode,"*",&dir_entry,&StartIndex))
{
((PFILE_DIRECTORY_INFORMATION)Buffer)->NextEntryOffset = 0;
return(STATUS_NO_MORE_FILES);
}
Buffer = Ext2ProcessDirEntry(DeviceExt,
&dir_entry,
IoStack,
Buffer,
StartIndex);
}
return(STATUS_SUCCESS);
}
NTSTATUS STDCALL
Ext2DirectoryControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT FileObject = Stack->FileObject;
PEXT2_FCB Fcb = (PVOID)FileObject->FsContext;
NTSTATUS Status;
PDEVICE_EXTENSION DeviceExt;
DPRINT("Ext2DirectoryControl(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
DeviceExt = DeviceObject->DeviceExtension;
switch (Stack->MinorFunction)
{
case IRP_MN_QUERY_DIRECTORY:
Status = Ext2QueryDirectory(DeviceExt, Fcb, Irp, Stack);
break;
default:
Status = STATUS_UNSUCCESSFUL;
}
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(Status);
}
BOOL Ext2ScanDir(PDEVICE_EXTENSION DeviceExt,
struct ext2_inode* dir,
PCH filename,
struct ext2_dir_entry* ret,
PULONG StartIndex)
{
ULONG i;
char* buffer;
ULONG offset;
char name[255];
struct ext2_dir_entry* current;
ULONG block;
BOOL b;
DPRINT("Ext2ScanDir(dir %x, filename %s, ret %x)\n",dir,filename,ret);
buffer = ExAllocatePool(NonPagedPool, BLOCKSIZE);
for (i=0; i<((*StartIndex)/BLOCKSIZE); i++);
for (; (block = Ext2BlockMap(DeviceExt, dir, i)) != 0; i++)
{
DPRINT("block %d\n",block);
b = Ext2ReadSectors(DeviceExt->StorageDevice,
block,
1,
buffer);
if (!b)
{
DbgPrint("ext2fs:%s:%d: Disk io failed\n", __FILE__, __LINE__);
return(FALSE);
}
offset = (*StartIndex)%BLOCKSIZE;
while (offset < BLOCKSIZE)
{
current = &buffer[offset];
strncpy(name,current->name,current->name_len);
name[current->name_len]=0;
DPRINT("Scanning offset %d inode %d name %s\n",
offset,current->inode,name);
DPRINT("Comparing %s %s\n",name,filename);
if (strcmp(name,filename)==0 || strcmp(filename,"*")==0)
{
DPRINT("Match found\n");
*StartIndex = (i*BLOCKSIZE) + offset + current->rec_len;
memcpy(ret,current,sizeof(struct ext2_dir_entry));
ExFreePool(buffer);
return(TRUE);
}
offset = offset + current->rec_len;
ASSERT(current->rec_len != 0);
DPRINT("offset %d\n",offset);
}
DPRINT("Onto next block\n");
}
DPRINT("No match\n");
ExFreePool(buffer);
return(FALSE);
}
void unicode_to_ansi(PCH StringA, PWSTR StringW)
{
while((*StringW)!=0)
{
*StringA = *StringW;
StringA++;
StringW++;
}
*StringA = 0;
}
NTSTATUS Ext2OpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
PWSTR FileName)
/*
* FUNCTION: Opens a file
*/
{
EXT2_INODE parent_inode;
struct ext2_dir_entry entry;
char name[255];
ULONG current_inode = 2;
char* current_segment;
PEXT2_FCB Fcb;
ULONG StartIndex = 0;
DPRINT("Ext2OpenFile(DeviceExt %x, FileObject %x, FileName %S)\n",
DeviceExt,FileObject,FileName);
Fcb = ExAllocatePool(NonPagedPool, sizeof(EXT2_FCB));
unicode_to_ansi(name,FileName);
DPRINT("name %s\n",name);
DPRINT("strtok %x\n",strtok);
current_segment = strtok(name,"\\");
DPRINT("current_segment %x\n", current_segment);
while (current_segment!=NULL)
{
Ext2LoadInode(DeviceExt,
current_inode,
&parent_inode);
if (!Ext2ScanDir(DeviceExt,
parent_inode.inode,
current_segment,
&entry,
&StartIndex))
{
Ext2ReleaseInode(DeviceExt,
&parent_inode);
ExFreePool(Fcb);
return(STATUS_UNSUCCESSFUL);
}
current_inode = entry.inode;
current_segment = strtok(NULL,"\\");
StartIndex = 0;
Ext2ReleaseInode(DeviceExt,
&parent_inode);
}
DPRINT("Found file\n");
Fcb->inode = current_inode;
CcRosInitializeFileCache(FileObject, &Fcb->Bcb, PAGE_SIZE*3);
FileObject->FsContext = Fcb;
return(STATUS_SUCCESS);
}
NTSTATUS STDCALL
Ext2Create(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT FileObject = Stack->FileObject;
NTSTATUS Status;
PDEVICE_EXTENSION DeviceExt;
DPRINT("Ext2Create(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
DeviceExt = DeviceObject->DeviceExtension;
Status = Ext2OpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(Status);
}