mirror of
https://github.com/reactos/reactos.git
synced 2024-09-12 05:43:24 +00:00
339 lines
8.1 KiB
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);
|
|
}
|