O KiddieOS é um sistema operacional open-source básico em desenvolvimento pelo curso gratuito D.S.O.S [Desenvolvendo Sistemas Operacionais Simples]. A intenção deste sistema será: Criar, editar ou excluir arquivos, codificar em uma linguagem própria do sistema, criar objetos visuais e automatizados (desenhos) através desta linguagem, utilizar uma interface simples e intuitiva, criar novas interfaces gráficas, como: Janelas, botões, campos, etc... e estimular crianças, jovens e adultos a programar numa linguagem simples dentro do sistema operacional KiddieOS. A intenção do curso D.S.O.S é dá início ao desenvolvimento de sistemas operacionais utilizando a linguagem Assembly e entender a fundo sobre diversos conceitos internos deste tipo de sistema. Aqui neste repositório serão armazenados arquivos de APIs do KiddieOS, a imagem de disco para teste e futuramente - todo o sistema operacional completo. Visite o link abaixo para nos acompanhar no curso do Youtube, se inscreva neste canal para se manter atualizado e siga-me no GitHub. Vejo vocês lá:
MIT License
46
stars
5
forks
source link
KiddieOS v1.3.8: Escrita, Renomeio e Atributo de Arquivos #8
Nesta versão, foi trabalhado algumas adaptações no comando Write de escrita/acréscimo de arquivos após adicionar novas funcionalidades no driver do FAT16, entre as funcionalidades temos a escrita de apenas entradas com atributos alterados, escrita de clusters e de dados de arquivos. Também foi implementado novos comandos: Como Attrib & Ren. Veja abaixo a descrição de cada comando e procedimentos:
Write: Foram implementadas algumas adaptações no comando de escrita em relação a versão anterior. O buffer de memória de dados foi alterado para o endereço de carregamento de arquivos e antes de qualquer cópia, os valores são zerados para não causar conflitos com dados antigos. Uma condicional também é feita para verificar se o parâmetro é de Append (-fa -> al = 1), para carregar o arquivo existente na memória antes do incremento de dados. Caso o arquivo seja existente, é feito uma cópia entre buffers em ordens diferentes, a depender de como o parâmetro foi colocado na CLI.
Ren: O comando Ren foi implementado para escrever a entrada do arquivo com nomes alterados. Primeiro é feito a formatação do diretório da CLI ou nome do arquivo no início, após isto, carregado os segmentos de cada cadeia de diretórios se houver, então é feito uma segunda formatação do arquivo da CLI do próximo argumento, pois há dois argumentos distintos, no entanto, o segundo argumento não é necessário incluir um caminho completo de diretório, apenas o novo nome de arquivo. Por fim, a nova rotina WriteThisEntry do driver FAT16 é invocada para escrever a entrada alterada, veremos sobre ela mais tarde.
Attrib: O comando Attrib primeiro verifica qual é o parâmetro inserido na CLI para definir um valor diferente para BX, um exemplo é se for o parâmetro -hi para tornar um arquivo oculto, é carregado 0x02 em bx, pois este valor que será escrito no campo ATTRIB da entrada. Depois é formatado o nome de arquivo na CLI, carregado o diretório e executado a rotina WriteThisEntry assim como no comando ren. Abaixo veremos quais são as novas rotinas do driver FAT16 e o que elas fazem.
Rotinas do Driver FAT16
Assim como na rotina de carregamento de arquivos LoadThisFile, uma busca inicial do arquivo deve ser feita antes de qualquer escrita ou leitura. Isto significa que é feita uma "cópia" da funcionalidade do LoadThisFile para procurar o arquivo para as rotinas WriteThisFile & WriteThisEntry, no entanto, quando elas encontram (ou não encontram) o arquivo, são executados novas rotinas diferentes.
Um exemplo é a rotina WriteThisFile que pode executar uma rotina mesmo se não encontrar o arquivo, que é o de criação de novos arquivos, deste modo, quando o arquivo é encontrado, uma rotina diferente é executada para realizar algumas configurações essenciais antes do "Acréscimo de dados" ou "Sobreescrita de Dados". Enquanto que na rotina WriteThisEntry, ela só executa uma nova rotina caso o arquivo é encontrado, caso não, ela finaliza a sua busca sem executar mais nada. O mesmo é feito na leitura de arquivos pelo LoadThisFile, porém com a diferença de que LoadThisFile contém tratamento de erros e retorno de código de erro.
Uma maneira comum de pensarmos o motivo desta busca ser quase a mesma do carregamento/leitura de arquivos, é pelo fato deste recurso se tratar do "Open" em operações de arquivos, ou seja, um arquivo primeiramente é aberto para depois efetuar alguma operação. A abertura de arquivo consiste exatamente nisso - buscar um arquivo no disco e caso encontrado, uma estrutura é criada para acessar o arquivo - isto significa que, a abertura de arquivos pode ser feita para o modo de escrita, leitura ou ambos. No entanto, atualmente a rotina de abertura de arquivos já é embutida em uma só chamada de operações de arquivos e ainda não pode criar a estrutura pois só retorna ao usuário após efetuar todas as operações. A rotina "OpenThisFile" será tratada futuramente de forma separada para gerenciamento por meio do usuário. Abaixo veremos a descrição das novas rotinas no qual esta busca executa:
ChangeEntry: Primeiramente veremos a rotina de "alteração de entrada" do arquivo pois devemos entender como ela funciona para compreender outras operações. Esta rotina é invocada pela busca de WriteThisEntry, caso encontre o arquivo, onde esta última é chamada pelos comandos attrib e ren. Considerando que estes comandos devem efetuar alterações nas propriedades do arquivo, onde estas propriedades se encontram na entrada do arquivo, logo deve ser definida qual variável da entrada será alterada. Esta variável é definida por dois registradores: DX e BX. O registrador DX contém o deslocamento do campo da estrutura da entrada, enquanto que BX contém o valor que será inserido neste campo.
A depender do que tiver em DX, um fluxo diferente é executado, como exemplo: Se DX for 0, significa que se trata do 1ª campo, que é o nome do arquivo, logo é feito uma cópia do nome apontado por BX para o campo em DI, mas se DX for 11, significa que é o campo do atributo, então é realizado uma cópia do atributo em bl para o campo em DI. Ambos como finalização, executará uma operação - SaveEntry. Esta label primeiro verifica se o segmento atual é o endereço inicial, caso for, concluímos que é o diretório raiz e como já conhecemos o setor lógico deste diretório, escrevemos setores lógicos do par apontado por ES:BX, a memória de diretório raiz. Porém, caso não for o endereço inicial, então é pesquisada a 1ª entrada do diretório "." que conterá o cluster inicial da pasta/diretório, onde este cluster será carregado em DX. Este fluxo de execução é determinado pelo endereço, porque sabemos que cada estrutura de diretório é carregado em um novo endereço.
A próxima operação é escrever a entrada apontada em memória para o disco, e para isto é necessário converter o cluster em DX para um LBA (Logic Block Address) que é o número de setor lógico e assim carregar no disco pelo par ES:BX. O endereço em BX é incrementado, e é calculado o próximo Cluster na cadeia, redefinindo o valor de DX para a próxima interação do loop converter para setor lógico, antes disso é verificado se o cluster é 0xFFFF, caso for, então o loop é finalizado e a entrada foi escrita, caso não for, o loop retorna ao início para escrita de setor lógico. Perceba que esta funcionalidade deve ser feita também para criação de arquivos, pois entradas de arquivos devem ser salvas antes de qualquer dado (As propriedades do arquivo). Então a próxima rotina veremos sobre criações de arquivos.
WriteFile: Esta rotina só é executado quando pela busca o arquivo foi encontrado. Primeiramente é feito é salvo na pilha o endereço do buffer de dados na pilha em BX, o endereço da entrada em DI, o segmento de diretórios em AX e a quantidade de caracteres do arquivo em CX. Após isto é lido o Cluster inicial do arquivo e definido o segmento da tabela FAT. Segundamente, é encontrado procurado o cluster inicial na tabela FAT e caso encontrado, o primeiro cluster é zerado, depois o segundo, o terceiro e assim por diante, até o último cluster 0xFFFF do arquivo. Após isto, todos os registradores salvos na pilha são recuperados, para serem empilhados novamente no CreateFile que de fato vai escrever o arquivo no disco. Este procedimento de "Zerar" Clusters é fundamental para uma configuração inicial pois o arquivo a ser escrito pode ser maior ou menor do que o original e a rotina CreateFile vai buscar o 1ª cluster livre (zerado) para efetuar a escrita, logo, para evitar fragmentações de disco, e não haver conflitos de arquivos maiores, todos os cluster inicialmente são zerados, Obs.:Isto é uma alternativa de versão própria adaptada do FAT16 para o KiddieOS afim de facilitar o desenvolvimento.
O que de fato acontece no Windows, por exemplo, ao editar arquivos existentes pelo FAT16 é zerar os clusters atuais porém escrever os mesmos (e novos) clusters em novas posições de memória, deixando o disco fragmentado, e como o FAT16 original não contém um sistema de desfragmentação de disco padrão, então cabe ao KiddieOS criar suas próprias alternativas. Outro fator é o tamanho de arquivos: O KiddieOS reaproveita os primeiros clusters zerados evitando fragmentação, porém quando é encontrado um cluster ocupado, mesmo que no meio do processo de leitura, o próximo cluster livre é utilizado, pois sabemos que a leitura/acesso do FAT é por meio do acesso encadeado, logo isto não interfere em questões de compatibilidade de leitura por sistemas modernos. Então para caso de arquivos maiores, o gerenciamento de espaço livre é feito, criando um encadeamento em posições distintas dos clusters, independente se o arquivo a ser editado for o primeiro e tiver dados maiores que o original, em casos de arquivos menores, os clusters que foram zerados pela rotina WriteFile são utilizados pelo CreateFile para novos arquivos, evitando desperdício.
CreateFile: Após as configurações de limpeza de cluster pelo WriteFile, a rotina de criação de arquivos é executado, no entanto, pode acontecer da rotina de criação ser executada diretamente pela rotina de busca WriteThisFile caso o arquivo mencionado não seja encontrado, então não seria preciso efetuar a limpeza de Clusters. Inicialmente, o que o CreateFile faz é empilhar os registradores igual no WriteFile, escrever o nome de arquivo movendo SI para DI, definir o arquivo como atributo 0x20 (Archive) e efetuar uma leitura de data/hora do sistema para realizar uma conversão para formato de data/hora das entradas FAT, isto é feito pelas rotinas GetSystemDateEntry e GetSystemTimeEntry. O tempo e data de modificação é definido pelos mesmos parâmetros e um primeiro gerenciamento de espaço livre é feito pela rotina FreeSpaceCluster que busca o primeiro cluster vazio na tabela FAT salvando o endereço deste cluster pelo par GS:BX e salvando também o contador, que será utilizado mais tarde. Este contador é retornado pela função de gerenciamento e escrito no campo de Cluster inicial da entrada do arquivo. O tamanho do arquivo também é restaurado da pilha e escrito no último campo da entrada. Todos estes procedimentos de definição de campos da entrada, é feito pela memória RAM, apontada por ES:DI, a fim de por meio de outras operações, escrever esta memória para o disco.
Após a memória com dados definidos, a entrada é escrita no disco. Este processo de escrita da entrada no disco é o mesmo mencionado pelo 2ª parágrafo do item ChangeEntry - Se o segmento for o inicial, então é feito uma escrita estática do setor já conhecido (Diretório raiz), se não for inicial, então é buscado o cluster do diretório atual, convertido para setor lógico, escrito no disco e lido os próximos clusters na cadeia até que o último é encontrado. Após este procedimento, temos a escrita da entrada do arquivo (propriedades) no disco, o que poderia ser a área de dados, diferentemente de arquivos do diretório raiz, as entradas de arquivos dentro de pastas são armazenados na área de dados, pois pastas tecnicamente também são arquivos. Então a próxima fase é efetuar a escrita da tabela FAT da memória para o disco.
Através da rotina WriteFAT nós temos alguns cálculos fundamentais para determinar o setor inicial da tabela FAT onde a escrita irá começar, como também determinar a quantidade de setores do FAT que serão escritos. Também é calculado a partir da quantidade de dados do arquivo, a quantidade de setores de dados que serão escritos. Após isto, todos os clusters encadeados, baseados na quantidade de dados do arquivo e o gerenciamento de espaços livres (clusters vazios/zerados), são determinados e escritos na memória, antes mesmo de ir pro disco. Após isto terminamos a escrita do FAT para o disco, então o endereço correto de dados é calculado, para a próxima fase - a rotina WriteDataFile. A rotina de escrita de dados no disco, WriteDataFile, contém o mesmo procedimento da escrita de diretórios, realizando conversão de cluster físico para setor lógico, escrita do setor lógico a partir do endereço calculado ES:BX e leitura do próximo cluster na cadeia até encontrar o último, no entanto, os setores são da Área de Dados.
Todos estes procedimentos são realizados pelo Driver do FAT16. Nossos próximos passos é escrever campos de entradas relacionado com permissões, criando uma outra alternativa do FAT16 para gerenciamento de permissões de arquivos. Também utilizaremos as mesmas lógicas para criação do comando de Cópia de arquivos Copy, o comando de criação de pastas Mkdir, o comando de deleção de arquivos Del e o comando de atribuição de permissões Chmod.
TODO: Novos sistemas a ser implementados
Rotina Open, Escrita e Leituras personalizadas: A função open() no KiddieOS irá procurar um arquivo, e se encontrado, irá criar uma estrutura de tamanho variável na memória, onde o primeiro valor da estrutura será o tamanho da estrutura e conterá também o número de setores/clusters do arquivo, o último campo da estrutura pode ter todos os números dos clusters indexados do arquivo, para facilitar a leitura pela função read(). A função open() retornará para a aplicação o endereço de memória que aponta para esta estrutura. Porque uma função read() alternativa (não a genérica atual) lerá o endereço fornecido pelo aplicativo (o endereço da estrutura) para ler os dados. A estrutura também terá um campo de flags, que identificará como o arquivo é aberto: Se é um arquivo binário para leitura, ou para escrita, ou se é um arquivo de texto para ambos os casos.
Permissão de Escrita/Leitura de arquivos: Outro sistema que também pretendo fazer é criar uma flag especial no campo de entrada de um arquivo, na verdade várias flags especiais: A primeira flag é o lock do arquivo, ele é definido quando o arquivo é aberto, pois toda vez que uma função open() tentar abrir o arquivo, ele vai verificar se esta flag está definida, se não estiver, ele define a flag mas se estiver, então ele se recusa a abrir, porque o arquivo já está sendo usado por outro processo, isso evita em partes que ocorra a chamada "corrida de condição" no compartilhamento de recursos do sistema operacional. As outras flags especiais no mesmo campo são sobre permissão de arquivo, havendo apenas dois tipos de usuário: administrador/root ou usuário; Para cada tipo de usuário haverá 3 bits: um para leitura, outro para escrita e outro para execução, totalizando 6 bits. O 8º bit será o lock do arquivo e o 7º bit será para determinar que todas as permissões principais dos dois tipos de usuários são permitidas, o que evita processamento desnecessário para verificar cada permissão, então os outros 6 bits podem assumir comportamentos diferentes se o 7º bit foi definido, pois podemos permitir/proibir que o usuário exclua, copie ou renomeie o arquivo, por exemplo. Então temos 8 bits da entrada do arquivo FAT, esses 8 bits é um campo reservado que não é utilizado, essa será uma das adaptações do "KFAT" (A versão alternativa do FAT16 do KiddieOS). Então posso criar um sistema que converta o argumento octal "777" do comando "chmod" em apenas "77", ou seja, "00 111 111".
Autenticação do usuário e permissões: Considerando que temos novos dados de campos de permissão nos arquivos, poderá existir um sistema que efetua autenticação de usuários. É um sistema bem simples que permite que o KiddieOS se torne multi-usuário: Primeiramente, deve existir um comando que realiza tanto o login do usuário no sistema, quanto o cadastro, caso o usuário não existir. O cadastro solicita o nome de usuário e senha, com o limite máximo de caracteres do usuário sendo oito caracteres, pois este nome será utilizado para criar uma pasta. Os dados serão criptografados e escritos na tag "Authentication" do arquivo de configuração AUTORUN.INI. O sistema operacional, na inicialização irá verificar se deve pedir solicitação de usuário e senha através de configurações prévias no autorun.ini, antes de abrir o Shell. Caso não tiver configuração para esta solicitação, o usuário poderá efetuar o login pelo comando Auth por exemplo (ou outro) para inserir usuário e senha. Então, automaticamente, quando o usuário é o primeiro a se cadastrar no sistema, ele é definido como "administrador" ou "root", porém a partir deste momento, apenas ele tem permissão para criar novos usuários e tornar outros usuários como administrador, caso um usuário não é administrador e pretende torná-lo, ele deve criar uma solicitação para o usuário administrador. Durante o registro de novos usuários, o sistema operacional irá utilizar os comandos de criação de diretórios, pois vários diretórios padrões de usuário serão escritos no disco dentro da pasta "Users", começando pelo diretório principal do nome de usuário. Esta criação de estruturas de diretórios do usuário pode ser feita por um arquivo de execução de Scripts que será lido e processado inicialmente pelo comando Auth durante um registro. Porém, todos os dados e configurações de execução ou autenticação, é pré-definida pelo autorun.ini, que contém permissão apenas de sistema para escrita direta dos dados deste arquivo, nem o usuário, nem o administrador terá permissão para manipular o arquivo autorun.ini diretamente, apenas via comandos (Permissão do sistema).
Execução automatizada de Scripts Shell: Após a criação destes novos comandos, um executor de Scripts será implementado no próprio Shell, uma rotina capaz de ler dados de um arquivo de console (.csl) para executar seus Scripts de comandos e variáveis. O funcionamento base de execução de Scripts já foi implementada, no entanto apenas para Strings estáticas de comandos fora do Shell, estes procedimentos serão atribuídos para leitura de arquivos de console. Em um diretório específico do sistema operacional, será depositado todos os arquivos de console com comandos para gerenciamento inicial do sistema operacional, durante inicialização ou até mesmo - autenticação. Este diretório será configurado no autorun.ini para ser compreendido como "Diretório de Configuração e Inicialização Automática", isto é, tudo que tiver neste diretório, será executado, como por exemplo: Se o usuário definiu no arquivo de configuração que ele quer já iniciar o KiddieOS com um usuário logado, bastaria ele inserir um arquivo .csl no diretório de inicialização com o comando Auth junto com seus dados e configurar determinado diretório no arquivo de configuração autorun.ini para ser inicializado automaticamente (Caso já não for o diretório pré-configurado de forma padronizada pelo KiddieOS). Outros Scripts podem ser inseridos para automatizar processos do sistema operacional KiddieOS. Obs.: É imprescindível que proteja seus dados de login em tais arquivos de console se for o caso alterando as permissões de leitura/escrita por usuários e administradores, permitindo apenas sistemas.
Funcionalidade/Alterações
Nesta versão, foi trabalhado algumas adaptações no comando Write de escrita/acréscimo de arquivos após adicionar novas funcionalidades no driver do FAT16, entre as funcionalidades temos a escrita de apenas entradas com atributos alterados, escrita de clusters e de dados de arquivos. Também foi implementado novos comandos: Como Attrib & Ren. Veja abaixo a descrição de cada comando e procedimentos:
Write: Foram implementadas algumas adaptações no comando de escrita em relação a versão anterior. O buffer de memória de dados foi alterado para o endereço de carregamento de arquivos e antes de qualquer cópia, os valores são zerados para não causar conflitos com dados antigos. Uma condicional também é feita para verificar se o parâmetro é de Append (-fa -> al = 1), para carregar o arquivo existente na memória antes do incremento de dados. Caso o arquivo seja existente, é feito uma cópia entre buffers em ordens diferentes, a depender de como o parâmetro foi colocado na CLI.
Ren: O comando Ren foi implementado para escrever a entrada do arquivo com nomes alterados. Primeiro é feito a formatação do diretório da CLI ou nome do arquivo no início, após isto, carregado os segmentos de cada cadeia de diretórios se houver, então é feito uma segunda formatação do arquivo da CLI do próximo argumento, pois há dois argumentos distintos, no entanto, o segundo argumento não é necessário incluir um caminho completo de diretório, apenas o novo nome de arquivo. Por fim, a nova rotina WriteThisEntry do driver FAT16 é invocada para escrever a entrada alterada, veremos sobre ela mais tarde.
Attrib: O comando Attrib primeiro verifica qual é o parâmetro inserido na CLI para definir um valor diferente para BX, um exemplo é se for o parâmetro -hi para tornar um arquivo oculto, é carregado 0x02 em bx, pois este valor que será escrito no campo ATTRIB da entrada. Depois é formatado o nome de arquivo na CLI, carregado o diretório e executado a rotina WriteThisEntry assim como no comando ren. Abaixo veremos quais são as novas rotinas do driver FAT16 e o que elas fazem.
Rotinas do Driver FAT16
Assim como na rotina de carregamento de arquivos LoadThisFile, uma busca inicial do arquivo deve ser feita antes de qualquer escrita ou leitura. Isto significa que é feita uma "cópia" da funcionalidade do LoadThisFile para procurar o arquivo para as rotinas WriteThisFile & WriteThisEntry, no entanto, quando elas encontram (ou não encontram) o arquivo, são executados novas rotinas diferentes.
Um exemplo é a rotina WriteThisFile que pode executar uma rotina mesmo se não encontrar o arquivo, que é o de criação de novos arquivos, deste modo, quando o arquivo é encontrado, uma rotina diferente é executada para realizar algumas configurações essenciais antes do "Acréscimo de dados" ou "Sobreescrita de Dados". Enquanto que na rotina WriteThisEntry, ela só executa uma nova rotina caso o arquivo é encontrado, caso não, ela finaliza a sua busca sem executar mais nada. O mesmo é feito na leitura de arquivos pelo LoadThisFile, porém com a diferença de que LoadThisFile contém tratamento de erros e retorno de código de erro.
Uma maneira comum de pensarmos o motivo desta busca ser quase a mesma do carregamento/leitura de arquivos, é pelo fato deste recurso se tratar do "Open" em operações de arquivos, ou seja, um arquivo primeiramente é aberto para depois efetuar alguma operação. A abertura de arquivo consiste exatamente nisso - buscar um arquivo no disco e caso encontrado, uma estrutura é criada para acessar o arquivo - isto significa que, a abertura de arquivos pode ser feita para o modo de escrita, leitura ou ambos. No entanto, atualmente a rotina de abertura de arquivos já é embutida em uma só chamada de operações de arquivos e ainda não pode criar a estrutura pois só retorna ao usuário após efetuar todas as operações. A rotina "OpenThisFile" será tratada futuramente de forma separada para gerenciamento por meio do usuário. Abaixo veremos a descrição das novas rotinas no qual esta busca executa:
A depender do que tiver em DX, um fluxo diferente é executado, como exemplo: Se DX for 0, significa que se trata do 1ª campo, que é o nome do arquivo, logo é feito uma cópia do nome apontado por BX para o campo em DI, mas se DX for 11, significa que é o campo do atributo, então é realizado uma cópia do atributo em bl para o campo em DI. Ambos como finalização, executará uma operação - SaveEntry. Esta label primeiro verifica se o segmento atual é o endereço inicial, caso for, concluímos que é o diretório raiz e como já conhecemos o setor lógico deste diretório, escrevemos setores lógicos do par apontado por ES:BX, a memória de diretório raiz. Porém, caso não for o endereço inicial, então é pesquisada a 1ª entrada do diretório "." que conterá o cluster inicial da pasta/diretório, onde este cluster será carregado em DX. Este fluxo de execução é determinado pelo endereço, porque sabemos que cada estrutura de diretório é carregado em um novo endereço.
A próxima operação é escrever a entrada apontada em memória para o disco, e para isto é necessário converter o cluster em DX para um LBA (Logic Block Address) que é o número de setor lógico e assim carregar no disco pelo par ES:BX. O endereço em BX é incrementado, e é calculado o próximo Cluster na cadeia, redefinindo o valor de DX para a próxima interação do loop converter para setor lógico, antes disso é verificado se o cluster é 0xFFFF, caso for, então o loop é finalizado e a entrada foi escrita, caso não for, o loop retorna ao início para escrita de setor lógico. Perceba que esta funcionalidade deve ser feita também para criação de arquivos, pois entradas de arquivos devem ser salvas antes de qualquer dado (As propriedades do arquivo). Então a próxima rotina veremos sobre criações de arquivos.
O que de fato acontece no Windows, por exemplo, ao editar arquivos existentes pelo FAT16 é zerar os clusters atuais porém escrever os mesmos (e novos) clusters em novas posições de memória, deixando o disco fragmentado, e como o FAT16 original não contém um sistema de desfragmentação de disco padrão, então cabe ao KiddieOS criar suas próprias alternativas. Outro fator é o tamanho de arquivos: O KiddieOS reaproveita os primeiros clusters zerados evitando fragmentação, porém quando é encontrado um cluster ocupado, mesmo que no meio do processo de leitura, o próximo cluster livre é utilizado, pois sabemos que a leitura/acesso do FAT é por meio do acesso encadeado, logo isto não interfere em questões de compatibilidade de leitura por sistemas modernos. Então para caso de arquivos maiores, o gerenciamento de espaço livre é feito, criando um encadeamento em posições distintas dos clusters, independente se o arquivo a ser editado for o primeiro e tiver dados maiores que o original, em casos de arquivos menores, os clusters que foram zerados pela rotina WriteFile são utilizados pelo CreateFile para novos arquivos, evitando desperdício.
Após a memória com dados definidos, a entrada é escrita no disco. Este processo de escrita da entrada no disco é o mesmo mencionado pelo 2ª parágrafo do item ChangeEntry - Se o segmento for o inicial, então é feito uma escrita estática do setor já conhecido (Diretório raiz), se não for inicial, então é buscado o cluster do diretório atual, convertido para setor lógico, escrito no disco e lido os próximos clusters na cadeia até que o último é encontrado. Após este procedimento, temos a escrita da entrada do arquivo (propriedades) no disco, o que poderia ser a área de dados, diferentemente de arquivos do diretório raiz, as entradas de arquivos dentro de pastas são armazenados na área de dados, pois pastas tecnicamente também são arquivos. Então a próxima fase é efetuar a escrita da tabela FAT da memória para o disco.
Através da rotina WriteFAT nós temos alguns cálculos fundamentais para determinar o setor inicial da tabela FAT onde a escrita irá começar, como também determinar a quantidade de setores do FAT que serão escritos. Também é calculado a partir da quantidade de dados do arquivo, a quantidade de setores de dados que serão escritos. Após isto, todos os clusters encadeados, baseados na quantidade de dados do arquivo e o gerenciamento de espaços livres (clusters vazios/zerados), são determinados e escritos na memória, antes mesmo de ir pro disco. Após isto terminamos a escrita do FAT para o disco, então o endereço correto de dados é calculado, para a próxima fase - a rotina WriteDataFile. A rotina de escrita de dados no disco, WriteDataFile, contém o mesmo procedimento da escrita de diretórios, realizando conversão de cluster físico para setor lógico, escrita do setor lógico a partir do endereço calculado ES:BX e leitura do próximo cluster na cadeia até encontrar o último, no entanto, os setores são da Área de Dados.
Todos estes procedimentos são realizados pelo Driver do FAT16. Nossos próximos passos é escrever campos de entradas relacionado com permissões, criando uma outra alternativa do FAT16 para gerenciamento de permissões de arquivos. Também utilizaremos as mesmas lógicas para criação do comando de Cópia de arquivos Copy, o comando de criação de pastas Mkdir, o comando de deleção de arquivos Del e o comando de atribuição de permissões Chmod.
TODO: Novos sistemas a ser implementados
Rotina Open, Escrita e Leituras personalizadas: A função open() no KiddieOS irá procurar um arquivo, e se encontrado, irá criar uma estrutura de tamanho variável na memória, onde o primeiro valor da estrutura será o tamanho da estrutura e conterá também o número de setores/clusters do arquivo, o último campo da estrutura pode ter todos os números dos clusters indexados do arquivo, para facilitar a leitura pela função read(). A função open() retornará para a aplicação o endereço de memória que aponta para esta estrutura. Porque uma função read() alternativa (não a genérica atual) lerá o endereço fornecido pelo aplicativo (o endereço da estrutura) para ler os dados. A estrutura também terá um campo de flags, que identificará como o arquivo é aberto: Se é um arquivo binário para leitura, ou para escrita, ou se é um arquivo de texto para ambos os casos.
Permissão de Escrita/Leitura de arquivos: Outro sistema que também pretendo fazer é criar uma flag especial no campo de entrada de um arquivo, na verdade várias flags especiais: A primeira flag é o lock do arquivo, ele é definido quando o arquivo é aberto, pois toda vez que uma função open() tentar abrir o arquivo, ele vai verificar se esta flag está definida, se não estiver, ele define a flag mas se estiver, então ele se recusa a abrir, porque o arquivo já está sendo usado por outro processo, isso evita em partes que ocorra a chamada "corrida de condição" no compartilhamento de recursos do sistema operacional. As outras flags especiais no mesmo campo são sobre permissão de arquivo, havendo apenas dois tipos de usuário: administrador/root ou usuário; Para cada tipo de usuário haverá 3 bits: um para leitura, outro para escrita e outro para execução, totalizando 6 bits. O 8º bit será o lock do arquivo e o 7º bit será para determinar que todas as permissões principais dos dois tipos de usuários são permitidas, o que evita processamento desnecessário para verificar cada permissão, então os outros 6 bits podem assumir comportamentos diferentes se o 7º bit foi definido, pois podemos permitir/proibir que o usuário exclua, copie ou renomeie o arquivo, por exemplo. Então temos 8 bits da entrada do arquivo FAT, esses 8 bits é um campo reservado que não é utilizado, essa será uma das adaptações do "KFAT" (A versão alternativa do FAT16 do KiddieOS). Então posso criar um sistema que converta o argumento octal "777" do comando "chmod" em apenas "77", ou seja, "00 111 111".
Autenticação do usuário e permissões: Considerando que temos novos dados de campos de permissão nos arquivos, poderá existir um sistema que efetua autenticação de usuários. É um sistema bem simples que permite que o KiddieOS se torne multi-usuário: Primeiramente, deve existir um comando que realiza tanto o login do usuário no sistema, quanto o cadastro, caso o usuário não existir. O cadastro solicita o nome de usuário e senha, com o limite máximo de caracteres do usuário sendo oito caracteres, pois este nome será utilizado para criar uma pasta. Os dados serão criptografados e escritos na tag "Authentication" do arquivo de configuração AUTORUN.INI. O sistema operacional, na inicialização irá verificar se deve pedir solicitação de usuário e senha através de configurações prévias no autorun.ini, antes de abrir o Shell. Caso não tiver configuração para esta solicitação, o usuário poderá efetuar o login pelo comando Auth por exemplo (ou outro) para inserir usuário e senha. Então, automaticamente, quando o usuário é o primeiro a se cadastrar no sistema, ele é definido como "administrador" ou "root", porém a partir deste momento, apenas ele tem permissão para criar novos usuários e tornar outros usuários como administrador, caso um usuário não é administrador e pretende torná-lo, ele deve criar uma solicitação para o usuário administrador. Durante o registro de novos usuários, o sistema operacional irá utilizar os comandos de criação de diretórios, pois vários diretórios padrões de usuário serão escritos no disco dentro da pasta "Users", começando pelo diretório principal do nome de usuário. Esta criação de estruturas de diretórios do usuário pode ser feita por um arquivo de execução de Scripts que será lido e processado inicialmente pelo comando Auth durante um registro. Porém, todos os dados e configurações de execução ou autenticação, é pré-definida pelo autorun.ini, que contém permissão apenas de sistema para escrita direta dos dados deste arquivo, nem o usuário, nem o administrador terá permissão para manipular o arquivo autorun.ini diretamente, apenas via comandos (Permissão do sistema).
Execução automatizada de Scripts Shell: Após a criação destes novos comandos, um executor de Scripts será implementado no próprio Shell, uma rotina capaz de ler dados de um arquivo de console (.csl) para executar seus Scripts de comandos e variáveis. O funcionamento base de execução de Scripts já foi implementada, no entanto apenas para Strings estáticas de comandos fora do Shell, estes procedimentos serão atribuídos para leitura de arquivos de console. Em um diretório específico do sistema operacional, será depositado todos os arquivos de console com comandos para gerenciamento inicial do sistema operacional, durante inicialização ou até mesmo - autenticação. Este diretório será configurado no autorun.ini para ser compreendido como "Diretório de Configuração e Inicialização Automática", isto é, tudo que tiver neste diretório, será executado, como por exemplo: Se o usuário definiu no arquivo de configuração que ele quer já iniciar o KiddieOS com um usuário logado, bastaria ele inserir um arquivo .csl no diretório de inicialização com o comando Auth junto com seus dados e configurar determinado diretório no arquivo de configuração autorun.ini para ser inicializado automaticamente (Caso já não for o diretório pré-configurado de forma padronizada pelo KiddieOS). Outros Scripts podem ser inseridos para automatizar processos do sistema operacional KiddieOS. Obs.: É imprescindível que proteja seus dados de login em tais arquivos de console se for o caso alterando as permissões de leitura/escrita por usuários e administradores, permitindo apenas sistemas.