// Description   : RING1 kernel extension with File System of the NANO OS

// Copyright     : Proxima Centauri Romania SRL, ALL RIGHTS RESERVED. (http://www.ProximaCentauri.org)

// Author        : Alexander Ioan Mihail

 

#include "ring1.h"

#include <io.h>

#include <malloc.h>

#include <stdlib.h>

#include <errno.h>

#include <windows.h>

char*settings_folder_name="Settings";

unsigned long OurGetLogicalDrives();

bool IsDriveRemote(char*root_path);

bool GetVolumeName(char*root_path,char*volume_name,int sz);

#ifndef MAX_PATH

  #define MAX_PATH 256

#endif

START_NAMESPACE(NANO_RING1)

void*hmem;

 

CAT_RING1::CAT_RING1 (ELEMENT* container, ELEMENT* parent, char* name, ELEMENT* type, void* start, void* end)

  :CAT_CORE(container,parent,name,type,start,end,em_Max)

{

  char buf[sizeof(CAT_RING1)];

  memset(buf,0,sizeof(buf));

  ELEMENT*el=new(buf) ELEMENT();

  for (int i=0;i<em_Max;i++)

  {

    Types[i].TSLPIO[0].Insert(&CAT_CORE::Types[em_META].TSLPIO[0]);

    Types[i].TSLPIO[0].LVR[1]=*(char**)el;

  }

  INIT(this,nullptr,"FILE",&CAT_CORE::Types[CAT_CORE::em_ELEMENT],&CAT_CORE::Types[em_META],&Types[em_FILE],1);

  INIT(this,nullptr,"DIRECTORY",&Types[em_FILE],&CAT_CORE::Types[em_META],&Types[em_DIRECTORY],1);

  INIT(this,nullptr,"DRIVE",&Types[em_DIRECTORY],&CAT_CORE::Types[em_META],&Types[em_DRIVE],1);

  INIT(this,nullptr,"DEVICE",&Types[em_FILE],&CAT_CORE::Types[em_META],&Types[em_DEVICE],1);

  INIT(this,nullptr,"POS",&Types[em_DEVICE],&CAT_CORE::Types[em_META],&Types[em_POS],1);

  INIT(this,nullptr,"SENSOR",&Types[em_DEVICE],&CAT_CORE::Types[em_META],&Types[em_SENSOR],1);

  Types[em_DIRECTORY].TSLPIO[0].LVR[1]=*(char**)(new(buf) DIRECTORY());

  Types[em_DRIVE].TSLPIO[0].LVR[1]=*(char**)(new(buf) DRIVE());

  Types[em_DEVICE].TSLPIO[0].LVR[1]=*(char**)(new(buf) DEVICE());

  Types[em_POS].TSLPIO[0].LVR[1]=*(char**)(new(buf) DEVICE());

  Types[em_SENSOR].TSLPIO[0].LVR[1]=*(char**)(new(buf) SENSOR());

  INIT(this,this,"System",nullptr,&Types[em_DEVICE],&Types[rel_System],0);

  INIT(this,this,"Sensor",nullptr,&Types[em_SENSOR],&Types[rel_Sensor],0);

  ELEMENT*e,*s;

  if (!(e=Find(settings_folder_name,0)))

  {

    e=ELEMENT::INIT(nullptr,this,settings_folder_name,nullptr,&CAT_CORE::Types[em_ELEMENT],nullptr,0);

    ELEMENT::INIT(nullptr,e,"Copyright=Proxima Centauri Romania SRL",nullptr,&CAT_CORE::Types[em_ELEMENT],nullptr,0);

    char buf[100];

    sprintf(buf,"UserMode=%s",ELEMENT::IsAdmin()?"admin":"user");

    ELEMENT::INIT(nullptr,e,buf,nullptr,&CAT_CORE::Types[em_ELEMENT],nullptr,0);

    sprintf(buf,"%s%d",eqCDPL,1000);

    ELEMENT::INIT(nullptr,e,buf,nullptr,&CAT_CORE::Types[em_ELEMENT],nullptr,0);

  }

  e=&CAT_CORE::Types[CAT_CORE::em_Actors];

    ELEMENT::INIT(nullptr,e,"Common",nullptr,&CAT_CORE::Types[em_ELEMENT],nullptr,0);

}

void* CAT_RING1::operator new (size_t sz, void* ptr)

{

  return ptr;

}

CAT_RING1* CAT_RING1::KernelInit ()

{

  // Helps trap the service DebugBreak();

  size_t size=0x100000;

  char*address;

  hmem=init_shared_memory(

    #ifdef _M_X64

      "Global\\SharedMemory64.SMF",address=(char*)0x200000000,size

    #else

      "Global\\SharedMemory32.SMF",address=(char*)0x020000000,size

    #endif

  );

  CAT_RING1*core=(CAT_RING1*)address;

  if (!core->IsUsed())

    new(address) CAT_RING1(nullptr,nullptr,"core",(ELEMENT*)address,(char*)address+sizeof(CAT_RING1),(char*)address+size);

  core->Walk();

  return core;

}

bool CAT_RING1::KernelDone (CAT_RING1* kernel)

{

  bool retval=false;

  if (retval=!kernel->IsUsed())

    kernel->~CAT_RING1();

  else

    kernel->Walk();

  done_shared_memory(hmem);

  return retval;

}

 

int DIRECTORY::Evaluate (int phase, int param1)

{

  int retval=Inherits::Evaluate(phase,param1);

  if (!(TSLPIO[1].Flags&(1<<BOND::flOpened)))

    return retval;

  ELEMENT*dev_type=TypeOf();

  CAT_RING1*core=(CAT_RING1*)GetKernel();

  char path[1000];

  GetPath(path);

  char *star=path+strlen(path);

  star[0]='*';

  star[1]=0;

  _finddata_t fd;

  long ff=_findfirst(path,&fd);

  if (ff==-1)

    return retval;

  ELEMENT*var=nullptr;

  while (!_findnext(ff,&fd))

  {

    FOR_CHILDREN_OF(this)

      if (!var->IsSelector())

        if (!strcmp(fd.name,var->Name))

           break;

    FOREND

    if (!var)

      ELEMENT::INIT(nullptr,this,fd.name,nullptr,(fd.attrib&_A_SUBDIR)?&core->Types[CAT_RING1::em_DIRECTORY]:&core->Types[CAT_RING1::em_FILE],nullptr,0);

  }

  _findclose(ff);

  FOR_CHILDREN_OF(this)

    var->GetPath(path);

  __R:

    ff=_findfirst(path,&fd);

    if (ff==-1)

      if (errno==22)

      {

        // Directory is a symbolic link, which is actually a file. Try again without wildcard.

        int plen=strlen(path);

        if (path[plen-1]=='*')

        {

          path[plen-2]=0;

          goto __R;

        }

      }

      else

        if (!var->IsSelector())

          delete var;

    _findclose(ff);

  FOREND

  return retval;

}

void DIRECTORY::Expand (BOND* aspect, bool on)

{

  Inherits::Expand(aspect,on);

  if (on)

    TSLPIO[1].Flags|=(1<<BOND::flOpened);

  else

    TSLPIO[1].Flags&=~(1<<BOND::flOpened);

  if (on)

    return;

  ELEMENT*var=nullptr;

  FOR_CHILDREN_OF(this)

    if (!var->IsSelector())

      delete var;

  FOREND

}

void DIRECTORY::GetPath (char* path)

{

  ((ELEMENT*)GetParent())->GetPath(path);

  path+=strlen(path);

  if (*(path-1)=='*')

    path--;

  strcpy(path,Name);

  path+=strlen(path);

  path[0]='\\';

  path[1]='*';

  path[2]=0;

}

 

void DRIVE::GetPath (char* path)

{

  strcpy(path,Name);

}

 

int DEVICE::Evaluate (int phase, int param1)

{

  int retval=Inherits::Evaluate(phase,param1);

  CAT_RING1*core=(CAT_RING1*)TSLPIO[0].POYC[0]->Object;

  ELEMENT*drive=&core->Types[CAT_RING1::em_DRIVE];

  ELEMENT*var=nullptr;

  FOR_INSTANCES_OF(drive)

    if (!((DRIVE*)var)->TSLPIO[5].POYC[0])

      break;           

  FOREND

  if (var)

  {

    var->TSLPIO[5].Insert(&TSLPIO[1]);

    ELEMENT::INIT(nullptr,this,0,var,&core->CAT_CORE::Types[CAT_CORE::em_HAS],nullptr,0);

    TRACE((NORMAL,0,"Drive %s bound to device %s.\n",var->Name,Name));

  }

  return retval;

}

 

int SENSOR::Evaluate (int phase, int param1)

{

  int retval=Inherits::Evaluate(phase,param1);

  CheckDrives("PRF");

  CheckDevices();

  return retval;

}

int SENSOR::CheckDrives (char* key)

{

  int retval=0;

  CAT_RING1*core=(CAT_RING1*)TSLPIO[0].POYC[0]->Object;

  ELEMENT*folder=(ELEMENT*)core;

  unsigned long lds=OurGetLogicalDrives();

  char root_path1[]="C:\\";

  _finddata_t fi;

  char volume_name[MAX_PATH];

  ELEMENT*var=nullptr;

  for (int i=0;i<sizeof(lds)*8;i++)

  {

    root_path1[0]='A'+i;

    if (!(lds&(1<<i)))

      continue;

    FOR_INSTANCES_OF(&core->Types[CAT_RING1::em_DRIVE])

      char temp[MAX_PATH];

      ((DRIVE*)var)->GetPath(temp);

      if (!strcmp(temp,root_path1))

        break;           

    FOREND

    if (var)

      continue;

    if (IsDriveRemote(root_path1))

       continue;

    //TRACE((NORMAL,0,"Drive %s... ",root_path1));

    if (GetVolumeName(root_path1,volume_name,sizeof(volume_name)))

    {

      TRACE((NORMAL,0,"%s\r\n",volume_name));

      char buf[MAX_PATH];

      strcpy(buf,root_path1);

      if (volume_name[0])

       sprintf(buf+strlen(buf),"[%s]",volume_name);

      DEVICE*device=0;

      if (!strstr(volume_name,key))

        BreakPoint(); //device=&core->System;

      ELEMENT*drv=DRIVE::INIT(nullptr,folder,buf,device,&core->Types[CAT_RING1::em_DRIVE],nullptr,0);

      retval|=(1<<0);

      drv->Translate(+1,0,root_path1,strlen(root_path1)+1,0);

    }

  }

__L:

  FOR_INSTANCES_OF(&core->Types[CAT_RING1::em_DRIVE])

    for (int i=0;i<sizeof(lds)*8;i++)

    {

      root_path1[0]='A'+i;

      if (!(lds&(1<<i)))

      {

        char temp[MAX_PATH];

        ((DRIVE*)var)->GetPath(temp);

        if (!strcmp(temp,root_path1))

        {

          delete var;

          retval|=(1<<1);

          goto __L;

        }

      }

    }

  FOREND

  return retval;

}

void SENSOR::CheckDevices ()

{

 #ifdef _WINDOWS_

  HKEY hkUSBSTOR = NULL;

  if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Services\\USBSTOR\\Enum",0,KEY_QUERY_VALUE,&hkUSBSTOR))

     return;

  DWORD ddata;

  DWORD size=sizeof(ddata);

  DWORD type;

  if (!RegQueryValueExA(hkUSBSTOR,"Count",NULL,&type,(LPBYTE)&ddata,&size))

  {

    CAT_RING1*cat=(CAT_RING1*)TSLPIO[0].POYC[0]->Object;

    char buf[20];

    char str[0x100];

    for (int i=0;i<ddata;i++)

    {

      sprintf(buf,"%d",i);

      size=sizeof(str);

      if (RegQueryValueExA(hkUSBSTOR,buf,NULL,NULL,(LPBYTE)str,&size)||!str)

        continue;

      DEVICE*dev=(DEVICE*)Find(strupr(str),INSENSITIVE);

      if (!dev)

        if (strstr(strupr(str),"VID_0642&PID_1112"))

          dev=(DEVICE*)DEVICE::INIT(nullptr,this,str,nullptr,&cat->Types[CAT_RING1::em_POS],nullptr,0);

      if (dev)

        CheckDrive("PRF",dev);

    }

    ELEMENT*var=nullptr;

    FOR_CHILDREN_OF(this)

      if (!var->IsSelector())

      {

        int i;

        for (i=0;i<ddata;i++)

        {

          sprintf(buf,"%d",i);

          size=sizeof(str);

          if (!RegQueryValueExA(hkUSBSTOR,buf,NULL,NULL,(LPBYTE)str,&size)&&str)

            if (!strcmp(strupr(str),var->Name))

              break;

        }

        if (i==ddata)

          delete var;

     }

    FOREND

  }

  RegCloseKey(hkUSBSTOR);

 #else

  #error Port to the new platform

 #endif

  return;

}

void SENSOR::CheckDrive (char* key, DEVICE* dev)

{

  static int checking=false;

  if (checking)

    return;

  checking=true;

  //"\??\STORAGE#RemovableMedia#8&2fa165b2&2&RM#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}"

  CAT_RING1*cat=(CAT_RING1*)TSLPIO[0].POYC[0]->Object;

  ELEMENT*dev_type=dev->TypeOf();

  unsigned long lds=OurGetLogicalDrives();

  char root_path1[]="C:\\";

  _finddata_t fi;

  char volume_name[MAX_PATH];

  unsigned long MaximumComponentLength=0;

  unsigned long FileSystemFlags;

  char  fs_name[20];

  for (int i=0;i<sizeof(lds)*8;i++)

  {

      root_path1[0]='A'+i;

      if (!(lds&(1<<i)))

       continue;

      ELEMENT*var=nullptr;

      //TRACE((NORMAL,0,"%s ",root_path1));

      /*

      if  (GetVolumeInformationA

           (

               root_path1,

               volume_name,

               sizeof(volume_name),

               NULL,

               &MaximumComponentLength,

               &FileSystemFlags,

               fs_name,

               sizeof(fs_name)

           )

          )

      {

          TRACE((NORMAL,0,"%s\r\n",volume_name));

          if (!strcmp(volume_name,key))

          {

          }

      }

      */

  }

  checking=false;

}

 

END_NAMESPACE(NANO_RING1)