#include "precomp.h"

#include "RFSHELL.h"

#include "IFilesystem.h"

#include "reiserfs.h"


class ReiserFS_FSWrapper : public IFilesystem
    {
    public:
        ReiserFS_FSWrapper();
        virtual ~ReiserFS_FSWrapper();

        virtual void AddRef();
        virtual void Release();

	    virtual HANDLE WINAPI OpenFile(LPCTSTR szFilename) const;
	    virtual void WINAPI ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD NumberOfBytesToRead, DWORD& NumberOfBytesRead) const;
	    virtual void WINAPI CloseFile(HANDLE hFile) const;
	    
	    virtual HANDLE WINAPI FindFirstFile(LPCTSTR szPath) const;
	    virtual BOOL WINAPI FindNextFile(HANDLE hFind, UNIX_FILEINFO& FileInfo) const;
	    virtual void WINAPI CloseFind(HANDLE hFind) const;

        virtual DWORD WINAPI GetVersion() const;
	    virtual BOOL WINAPI CopyFile(LPCTSTR szPath, ICreateFileInfo* lpContext ) const;

        ReiserFsPartition m_Partition;
        ULONG m_ulRefCount;
    };

ReiserFS_FSWrapper::ReiserFS_FSWrapper()
{
    m_ulRefCount = 1;
}

void ReiserFS_FSWrapper::AddRef()
{
    m_ulRefCount++;
}

void ReiserFS_FSWrapper::Release()
{
    if(m_ulRefCount)
    {
        m_ulRefCount--;
    }
    if(!m_ulRefCount)
    {
        delete this;
    }
}

ReiserFS_FSWrapper::~ReiserFS_FSWrapper()
{
}


class RFSFileInfo : public ICreateFileInfo
    {
    public:
        RFSFileInfo();
        virtual ~RFSFileInfo();

        virtual BOOL SetFileSize( INT64 Size );
        virtual void Write( LPBYTE lpbData, DWORD dwSize );

        DWORD m_dwSize;
        DWORD m_dwUsed;
        DWORD m_dwReadPos;
        LPBYTE m_lpbMemory;
    };

RFSFileInfo::RFSFileInfo()
{
    m_dwSize = 0;
    m_dwReadPos = 0;
    m_dwUsed = 0;
    m_lpbMemory = 0;
}

RFSFileInfo::~RFSFileInfo()
{
    delete m_lpbMemory;
}

BOOL RFSFileInfo::SetFileSize( INT64 Size )
{
    m_lpbMemory = 0;
    if( (Size < 0) || (Size >= 0x7FFFFFFF) )
        return FALSE;
    m_dwSize = (DWORD) Size;
    m_lpbMemory = new BYTE[m_dwSize];
    return (m_lpbMemory != 0);
}


    
void RFSFileInfo::Write( LPBYTE lpbData, DWORD dwSize )
{
    if( m_lpbMemory )
    {
        DWORD dwBytesToWrite = dwSize;
        if( dwBytesToWrite + m_dwUsed > m_dwSize )
            dwBytesToWrite = m_dwSize - m_dwUsed;
        CopyMemory( m_lpbMemory + m_dwUsed, lpbData, dwBytesToWrite );
        m_dwUsed += dwBytesToWrite;
    }
}


HANDLE ReiserFS_FSWrapper::OpenFile(LPCTSTR szFilename)  const
{
    RFSFileInfo* fi = new RFSFileInfo;
    ReiserFsPartition* p = (ReiserFsPartition*) &m_Partition;

    if( p->GetFileEx(szFilename, fi) )
    {
        return (HANDLE) fi;
    }
    return INVALID_HANDLE_VALUE;
}

DWORD WINAPI ReiserFS_FSWrapper::GetVersion() const
{
    return RFSHELL_API_VERSION;
}

BOOL WINAPI ReiserFS_FSWrapper::CopyFile(LPCTSTR szPath, ICreateFileInfo* cfi ) const
{
    ReiserFsPartition* p = (ReiserFsPartition*) &m_Partition;
    return p->GetFileEx(szPath, cfi);
}

void ReiserFS_FSWrapper::ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD NumberOfBytesToRead, DWORD& NumberOfBytesRead)  const
{
    RFSFileInfo* fi = (RFSFileInfo*) hFile;

    NumberOfBytesRead = NumberOfBytesToRead;
    if( fi->m_dwReadPos + NumberOfBytesRead > fi->m_dwSize )
        NumberOfBytesRead = fi->m_dwSize - fi->m_dwReadPos;
    if( NumberOfBytesRead )
    {
        CopyMemory( (LPBYTE) lpBuffer, fi->m_lpbMemory + fi->m_dwReadPos, NumberOfBytesRead );
        fi->m_dwReadPos += NumberOfBytesRead;
    }
        
    
}

void ReiserFS_FSWrapper::CloseFile(HANDLE hFile) const
{
    RFSFileInfo* fi = (RFSFileInfo*) hFile;
    delete fi;
}

HANDLE ReiserFS_FSWrapper::FindFirstFile(LPCTSTR szPath) const
{
    PList* files = new PList;
    if( !files )
        return INVALID_HANDLE_VALUE;

    // CONST SUCKS. 


    ReiserFsPartition* p = (ReiserFsPartition*) &m_Partition;

    if( p->ListDir(files,szPath) )
    {
        return (HANDLE) files;
    }
    else
    {
        delete files;
        return INVALID_HANDLE_VALUE;
    }
}

BOOL ReiserFS_FSWrapper::FindNextFile(HANDLE hFind, UNIX_FILEINFO& FileInfo) const
{
    PList* p = (PList*) hFind;
    ReiserFsFileInfo* pFI = (ReiserFsFileInfo*) p->m_pHead;
    if( pFI )
    {
        FileInfo.i_mode = pFI->m_stat.sd_mode;
        FileInfo.i_uid = (__u16) pFI->m_stat.sd_uid;
        FileInfo.i_gid = (__u16) pFI->m_stat.sd_gid;
        FileInfo.i_size = (__u64) pFI->m_stat.sd_size;
        FileInfo.i_atime = pFI->m_stat.sd_atime;
        FileInfo.i_ctime = pFI->m_stat.sd_ctime;
        FileInfo.i_mtime = pFI->m_stat.sd_mtime;
	    strncpy( FileInfo.szFileName, pFI->m_strName, UNIX_FILENAME_LENGTH );
        p->Delete(pFI);
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

void ReiserFS_FSWrapper::CloseFind(HANDLE hFind) const
{
    PList* p = (PList*) hFind;
    delete p;
}




extern "C" {

void WINAPI FS_Autodetect( LPFNFoundPartition lpCallback, LPVOID lpContext )
{
    ReiserFsPartition partition;
    partition.Autodetect(60, lpCallback, lpContext);
}

IFilesystem* WINAPI FS_CreateInstance( LPCSTR lpszName )
{
    // invalid name

    if( strncmp( lpszName, "/dev/hd", 7 ) )
        return 0;

    lpszName += 7;
    int iDrive = lpszName[0] - 'a';
    int iPartition = strtol(lpszName+1,0,10);

    ReiserFS_FSWrapper* instance = new ReiserFS_FSWrapper;
    if( !instance )
        return NULL;

    if( !instance->m_Partition.Open(iDrive, iPartition) )
        return NULL;

    return instance;
}

}

syntax highlighted by Code2HTML, v. 0.9.1