Resultado da tentativa de aprender Rust

Antes de começar esse texto propriamente dito, preciso comentar que conversando na comunidade de Rust no Telegram, recebi o link de um material de Rust muito bom do Elias (@eamaral), que é o novo livro, gostei muito mais desse que do anterior, e me pareceu muito melhor para quem não está migrando de C++ ou não tem um conhecimento prévio de muitos conceitos. Também gostaria de agradecer a “aula” que foi dada pelo mesmo sobre alguns conceitos, mesmo quando eu até estava tentando evitar a conversa, embora que isso já aconteceu comigo em outras comunidades de novas linguagens, tendo pessoas que realmente gostam de compartilhar o seu conhecimento sobre uma coisa nova.

Infelizmente essa primeira tentativa não terminou como eu gostaria, muito por querer desenvolver alguns projetos, onde ainda não conseguiria ter uma boa produtividade em Rust. Nos meus testes feitos, consegui fazer exemplos simples e entender a teoria de muitos conceitos, porém suas aplicações não se mostraram muito simples na prática. Porém acredito que o maior problema é a falta de experiência com a forma de programar e pensar de Rust.

Porém nem tudo foi em vão, o uso do enum e pattern matching, principalmente no tratamento de erros foi uma coisa que já usei fora do Rust, em outra linguagem de programação que desejo falar num texto futuro.

Então embora não tenha conseguido aprender um bom nível de Rust desta vez, aprendê-lo ainda não foi descartado, principalmente pelos que ele traz de interessante, como identificar muitos problemas em tempo de compilação, que embora já exista nas linguagens de programação funcional, é a primeira vez que vejo ser aplicado tão fortemente numa linguagem de outro paradigma.

Em busca de um material sobre Rust

No texto anterior contei o motivo da escolha de aprender Rust, neste texto vou falar sobre os materiais que encontrei.

A primeira vez que ouvi falar da linguagem foi em 2014 durante o FISL 15, na palestra “Servo: O web engine paralelo” do Bruno de Oliveira Abinader (infelizmente parece que a gravação não está mais no servidor). Inicialmente gostei do servo, porém não chegou a me interessar a ponto de correr atrás, tanto do servo, quanto do Rust. Mas de alguma forma, que não me lembro agora, acabei tento contato novamente com a linguagem.

Quando decidi começar a aprender, veio a primeira dificuldade de todas, encontrar um bom material. Achei alguns que poderiam ser bons, porém voltado principalmente para quem programa em C++, comentando principalmente as diferenças, porém não é o meu caso. Também não queria algo para quem esta começando a programar agora, ou só uma breve apresentação da linguagem, o ideal seria algo para quem só está migrando de linguagem, como talvez o tutorial do Python, explicando de forma direta e incremental as instruções e particularidades do Rust para qualquer um que tenha conhecimento de lógica de programação, independente da linguagem, que infelizmente não achei muito facilmente.

Antes de começar a estudar de fato, encontrei o Rust on the Rocks! do Dalmo Veras Neto, e a melhor parte é por ser em português, porém ele parou de postar os textos por falta de tempo, inclusive nem chegou a estrear o canal no YouTube.

Já que teria que ser em inglês mesmo, parti para o The Rust Programming Language, que encontrei na documentação oficial. Inicialmente não gostei muito da ordem dos tópicos, como comentar vários conceitos antes de me apresentar os tipos primitivos da linguagem, então fiquei um pouco perdido em algumas partes dos exemplos que eu só veria mais adiante.

Desta forma estou adotando a estratégia de simplesmente não me importar se não entender muito bem algo, tentar avançar o máximo que puder, para depois rever os conceitos com mais calma e uma base mair da linguagem. Aprendendo mesmo o que cada coisa significa, conceitos e elementos da sintaxe, num segundo estudo.

Ainda não terminei de lê-lo, porém me parece que será um bom guia de referência no futuro. Mas como material de estudo único, talvez falte um pouco a forma Rust de resolver os problemas, para evitar de só trocar a linguagem, mas não a mentalidade de resolver o problema. Então ainda estou em busca de um material, atualizado de preferência, com exemplo de um projeto para eu entender como me adaptar a linguagem.

Acho importante essa parte de se adaptar a linguagem, uma vez que mesmo que não vá mais utilizá-la, aprenderei conceitos que podem ser uteis em outras linguagem. Também entender como a tecnologia funciona, para não tentar usá-la de forma incorreta e gerando vários problemas por causa disso. Infelizmente essa é a parte mais difícil.

Começo a aprender Rust

Começo a aprender Rust

Neste final de semana comecei a estudar a linguagem de programação Rust. E para registrar o meu estudo, pretendo escrever alguns textos aqui, começando pelo motivo de ter escolhido esta linguagem, mas depois comentar o que estou achando e dificuldades que estou encontrando.

O principal motivo para eu escolher esta linguagem está ligando as principais linguagens que utilizo, sendo que existia um caso onde elas não atendiam. Para entender a necessidade vou listá-las.

De forma geral utilizo shell script (bash para ser mais específico) quando tenho que fazer automações, ou se já existe algum programa pronto, simplificar o seu uso. Sendo seu maior exemplo o Commit Rules, que permite executar comandos para validar o commit, onde leio o arquivo de configuração, executo alguns comandos e manipulo a saída e exit status dos mesmos.

Quando preciso desenvolver algo mais elaborado, opto pelo Python, que por ser uma linguagem bem geral e de rápido desenvolvimento, facilita bastante o meu trabalho, sendo desde programas em linha de comando, até aplicações web. Vou deixar aqui de exemplo o Deduplicated, que foi desenvolvido como uma biblioteca, tendo tanto uma interface por linha de comando, quanto web.

Porém Python não é uma linguagem que tem foco em performance, especialmente na versão 3. Este foi um dos principais motivos de algumas pessoas da comunidade Python ficarem de olho no Go, o que talvez seria o meu caminho, se tivesse tido necessidade de performance. Também cheguei a pesquisar sobre o Genie, porém por ser recente e a pouca documentação, fizeram eu a deixá-la de lado, até por nem ela, nem Vala terem tido um grande sucesso.

Tenho algum conhecimento de C, porém é mais teórico que prático, não tendo tanta confiança para escrever um software seguro nesta linguagem. Também já tentei estudar mais sobre algumas ferramentas, como Make e Autoconf, porém não encontrei bons materiais para o meu estudo.

Neste ponto encontrei Rust, que pode ser visto como uma alternativa ao C, porém verifica o acesso seguro a memória em tempo de compilação, aumentando minha confiança em escrever um software seguro. Ele também um tem gerenciador de pacotes, que pelos meus testes funcionou muito bem e sem espalhar vários arquivos pelo sistema inteiro, podendo ser excluídos ao apagar um único diretório.

Rust tem outras qualidades, porém esses dois pontos suprem minhas “dificuldades” do C. Se encaixando como uma opção de linguagem quando preciso de desempenho (tenho controle semelhante ao C, e sem garbage collector como outras linguagens), porém ainda é uma linguagem nova com recursos bem interessantes em suas expressões (comandos).

No próximo texto comentarei mais sobre materiais e primeiras impressões.

Recuperando arquivos apagados

Uma hora ou outra, todos perderão alguns arquivos, corrompidos pelo sistema de arquivos, ou simplesmente deletado sem intenção. Na linha de comando é necessário ter cuidados maiores com espaços em branco. Meu problema não foi muito grave, na verdade até fiquei bem tranquilo, porém como sempre, ainda queria saber quais arquivos foram apagados para que pudesse recuperá-los. Contarei a história do que foi possível fazer neste caso.

A primeira coisa, para evitar mais perdas, aumentando as chances de recuperação, é desmontar a unidade, ou colocá-la em somente leitura, o que poderia ser feito com um umount ou mont -o remount,ro. No meu caso como era no próprio /, desliguei o computador e usei um sistema num pendrive. Isso é importante, como serão alterados alguns dados do sistema de arquivos, evita mais percas ou o corrompimento total do sistema de arquivos.

Uma ferramenta fácil e simples para recuperar os arquivos é o extundelete (pacote extundelete no Debian). Para usá-la basta executar extundelete, caminho do sistema de arquivos e uma opção de recuperação, como --restore-file caminho_do_araquivo, --restore-directory caminho_do_diretorio, ou até mesmo um --restore-all para recupera todos os arquivos. Lembrando que todos esses caminhos são relativos a raiz do sistema de arquivos, se o arquivo for o “/home/user/arquivo.txt”, sendo “/home” o ponto de montagem da partição “/dev/sdb1” seria extundelete /dev/sdb1 user/arquivo.txt.

Na maioria dos casos essa ferramenta atende, porém se quiser ir mais a fundo para buscar algum pedaço de informação que não pode ser recuperado ainda existe o debugfs. No caso executei um debugfs /dev/sdb1, executei o cd até chegar no diretório desejado e usei os comandos lsdel e ls -d para listar os arquivos. Com o ls -d consegui o número do inode aonde está o arquivo, na posse desta informação é possível utilizar várias outras técnicas, ou simplesmente a lista de arquivos que estava ali e foram apagados, mesmo que não tenha sido possível recuperá-lo anteriormente com o extundelete.

Dividir arquivos em partes

Recentemente tive que copiar um arquivo de quase 6 GB entre dois computadores que utilizo. Esses computadores não estavam perto um do outro, muito menos na mesma rede. Solução simples: utilizar um pendrive.

Meu celular tem espaço na memória interna suficiente para copiar o arquivo, porém para minha surpresa não consegui copiar o arquivo inteiro. Quando vi a mensagem de erro lembrei que o sistema de arquivos do celular é FAT, com o limite do tamanho em quase 4GB. Ou seja, o tamanho do arquivo é maior que o suportado pelo sistema de arquivos.

Como trocar o sistema de arquivos não era a opção, procurei como dividir o arquivo em partes. A solução é extremamente simples, basta utilizar o comando split. Este comando permite dividir o arquivo baseado em alguns critérios como bytes e número de linhas. Meu caso como é um arquivo binário e o que me interessava era o tamanho, fiz a divisão por bytes.

O comando utilizado foi:
split -b 1G arquivo-original prefixo-das-partes

Explicando, -b diz para o split dividir por bytes e que cada parte terá 1GB. arquivo-original é o arquivo que desejo dividir. prefixo-das-partes é o nome dado a cada parte, seguido de sua numeração, caso seja arquivo. serão criados vários arquivos como arquivo.aa, arquivo.ab e assim por diante. Se quiser números em vez de letras basta adicionar o parâmetro -d no comando.

Não foi o meu caso, porém se tiver um arquivo de texto grande, como um log, e quiser dividi-lo, basta utilizar o parâmetro -l 1000 que gerará arquivos de 1000 linhas cada, sem o risco de dividir alguma linha em dois arquivos.

Com cinco arquivos de 1GB e outro de aproximadamente 700MB, finalmente foi copiado para o celular.

Porém ainda precisava juntar as partes no destino, que bastou um:
cat prefixo-das-partes* > arquivo-original

Explicando, o cat recebeu o nome de todas as partes por causa do “*”, que também foram passadas como argumento na ordem correta, mesma coisa que executar um cat arquivo.aa arquivo.ab ... > arquivo. E assim recuperando o arquivo original.

O cat também funciona com arquivos de texto dividido pelo número de linhas. Se quiser dividir vários arquivos basta gerar um “.tar.gz” ou “.tar.bz2” antes.

FLISOL 2015

Neste final de semana aconteceu o FLISOL em várias cidades da América Latina, e eu estive presente no evento organizado pelo grupo Colméia na cidade de Joinville.

Gostei bastante do evento deste ano, as palestras foram bem interessantes, começando com uma sobre Openstack, Fedora Next, programação funcional com Haskell, licenças de software livre e Fedora QA (processo de qualidade). Também foi oferecido dois minicursos, shell script e arduino, porém não participei de nenhum.

Eu destaco a palestra sobre licenças, que falou sobre as liberdades, porém de uma forma muito mais prática. Além de incentivar o uso das licenças da família GPL, mostrou particularidades de cada uma. Então mesmo que você já soubesse a diferença entre software livre, open source e software proprietário, valeria a pena para entender como licenciar seu código e qual a melhor variação a ser utilizada.

Outra que gostei bastante foi a de programação funcional. Apesar de eu já ter ouvido falar sobre, nunca cheguei a estudar muito a fundo ou utilizar realmente em algum projeto, a meu ver caberia mais uma palestra mostrando o uso prático, com código, ou até um minicurso que com certeza eu faria-o.

Para quem pode ir até o local foi oferecido o steam das palestras, porém não achei essa informação no site e também não sei se ficou gravado em algum lugar. Então marco um ponto negativo a esta divulgação.

Agora é esperar até ano que vem. Quem quiser mais informações sobre o evento pode entrar no site oficial (http://flisol.info/), que apesar de estar em espanhol, tudo o que é referente ao Brasil está em português. Também recomendo o episódio da volta do Opencast que foi uma entrevista com o coordenador nacional do evento neste ano.

Atualização do Deduplicated e aviso

Não consegui escrever um post semana passada, infelizmente estou com menos tempo livre do que imaginei que teria este ano.

Porém semana passada não foi improdutiva, consegui fazer alguns testes do Deduplicated, que com alguns ajustes agora está funcionando com todos seus recursos no Windows também. Quem quiser fazer a instalação pode dar uma olhada no histórico da Issue no GitHub. Aproveito para agradecer a todos que deram uma olhada no projeto e até as pessoas que entraram em contato para verificar alguma questão.

Também comecei a publicar o código do meu gerenciador pessoa, são todos os repositórios que começam com “ergo” no meu GitHub, ainda estou mexendo bastante e pode mudar muita coisa até ficar relativamente estável. Quando conseguir finalizar mais alguns módulos e ajustes, trago um texto explicando sobre o mesmo.

Estou querendo iniciar mais um projeto, uma série na verdade, já tenho os assuntos separados, porém ainda preciso estudar alguns softwares antes de iniciá-la, mas aguarde por novidades no futuro. O que posso adiantar é que será sobre Python, porém não exatamente sobre desenvolvimento em si.

Aproveito para avisar que o FLISOL está chegando, então entre no site e descubra qual o local que terá o evento mais próximo de você. Nos dois anos que participei foi bastante interessante com várias palestras e até minicursos. Se você não tem muito conhecimento sobre software livre é uma ótima oportunidade, conhecer a comunidade da sua região, ou até aprender uma tecnologia/ferramenta nova nas palestras. Lembrando que você pode utilizar software livre, mesmo se seu sistema operacional não for.

Por hoje são estes avisos curtos.

Criptografando HD/HD externo/Pendrive

Já comentei em vários textos anteriores ferramentas que utilizo para o meu backup e chegou a vez da criptografia, processo que precisei refazer quando chegou meu novo HD externo. Na criptografia temos duas opções, a primeira é criptografar o arquivo, que depende do suporte do programa, ou que o mesmo seja descriptografado toda vez que for utilizado e criptografado novamente no final do processo. A segunda opção é criptografar o sistema de arquivos, que depende do suporte do sistema operacional, porém é transparente para os programas e os processos de criptografar e descriptografar é automático.

Minha opção foi criptografar o sistema de arquivos, e utilizar o recurso chamado dm-crypt, que no Debian existe um programa de configuração chamado cryptsetup, podendo ser instalado com um apt-get install cryptsetup.

Como este método de criptografia é baseado no sistema de arquivos, o particionamento ocorre da mesma forma, porém em vez de criar um sistema de arquivos Ext4, criei uma partição com o LUKS (Linux Unified Key Setup). Para explicar os comandos e quem tiver vontade poder executá-los também, em vez de criptografar uma partição, farei isso com um arquivo, já que em sistemas Unix tudo é arquivo, porém vale lembrar que todos os dados do arquivo ou partição serão perdidos.

Primeiro, para este exemplo, precisamos de um arquivo grande e existe uma forma de gerá-lo com o comando dd, exemplo: dd if=/dev/zero of=/tmp/arquivo bs=1M count=1024, se for fazer o procedimento numa partição, este comando não é necessário e troque sempre que vir o /tmp/arquivo pelo caminho da partição, exemeplo: /dev/sdb2. O parâmetro if=/dev/zero é um arquivo especial que possui zeros infinitos, então toda vez que for lido retornará “0”. O of=/tmp/arquivo é o caminho do arquivo que criarei, se for utilizado o caminho de um HD como /dev/sdb ou partição como /dev/sdb2 toda esta área será preenchida com zeros. Os parâmetros bs=1M e count=1024 representam o tamanho do bloco que será copiado e quantas vezes esse processo será repetido respectivamente, ou seja, serão copiados 1 MB 1024 vezes, gerando um arquivo de 1 GB em branco no HD.

Para formatarmos com o LUKS, podemos utilizar o comando cryptsetup luksFormat /tmp/arquivo e digitando a senha, lembrando que todos os dados do arquivo ou partição serão perdidos. Para conseguirmos utilizar a partição criptografada é preciso abri-la primeiro com o comando cryptsetup open /tmp/arquivo arquivo1, o primeiro é o caminho do arquivo o segundo é um nome para o mapeamento que será criado em /dev/mapper.

Próximo passo é a formatação do sistema de arquivos, porém em vez de formatar a partição diretamente, é preciso usar o mapeamento, no caso /dev/mapper/arquivo1. Um exemplo de formatação com Ext4 é mkfs.ext4 /dev/mapper/arquivo1. Agora podemos montar este mapeamento e gravar os arquivos normalmente que tudo salvo nesta partição será criptografada.

Na hora de remover a partição, basta fazer o procedimento na ordem inversa, primeiro desmonte o sistema de arquivo do /dev/mapper/arquivo1. Depois feche o mapeamento com o comando cryptsetup close /dev/mapper/arquivo1. Para abrir a partição novamente basta abrir o mapeamento e depois montar a partição.

Uma coisa legal do LUKS é que ele permite o uso de até 8 chaves diferentes, para adicionar uma chave nova basta executar o comando cryptsetup luksAddKey /tmp/arquivo, e agora qualquer uma das duas senhas poderão ser utilizadas para acessar a partição. Além de senhas também é possível utilizar um arquivo como chave o que pode ser um recurso interessante também. Caso deseje ver mais informações a respeito do LUKS ou chaves desta partição também é possível executar o comando cryptsetup luksDump /tmp/arquivo, um exemplo de saída é:

LUKS header information for /tmp/arquivo

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha1
Payload offset: 4096
MK bits:        256
MK digest:      81 e6 1f 37 b2 5c 8d 97 a4 a9 57 c1 2b 1b 89 49 35 0e 59 8f 
MK salt:        3b e4 4b bc 0d 09 b1 2a 5c 38 ea e2 a1 67 e6 5e 
                39 97 05 1d d5 73 cf 33 da 08 e1 bc 73 9f d5 95 
MK iterations:  146750
UUID:           2013f2e3-1d73-429a-818d-b4a182d8658e

Key Slot 0: ENABLED
        Iterations:             587155
        Salt:                   23 e7 e8 73 a0 a5 a9 58 a6 58 ba ec 81 41 49 d1 
                                75 a8 51 89 99 fb 8d a9 87 cc e7 23 eb bf 44 cb 
        Key material offset:    8
        AF stripes:             4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

Para quem formatou uma partição em vez do arquivo, o navegador de arquivos pode simplificar o processo de acesso a partição, no meu caso no Thunar consigo acessar meu HD externo da mesma forma como se o mesmo não estivesse criptografado clicando no ícone do mesmo, porém aparece uma janela solicitando a chave de acesso.

Para quem quiser mais informações, ou desejar criptografar partições do sistema, recomendo dar uma olhada no texto da wiki do Arch Linux, que apesar de estar na wiki de uma distribuição específica, os programas são os mesmos para todas e a lógica é a mesma, só confirmar se os parâmetros da wiki existem na versão instalada no seu sistema, que as vezes um dos dois podem estar uma versão mais antiga.

Remover arquivos duplicados

Há algum tempo, escrevi sobre o método que utilizo para fazer backup do meu hd externo. Porém quando comecei a utilizá-lo, tinha pouco mais de 500 GB de arquivos e muitos backups antigos, diretórios que quando iria formatava o computador, simplesmente olhava que faltava fazer backup de um diretório apenas, copiava-o inteiro, recuperar os arquivos mais importantes ou utilizados, enquanto os demais ficavam perdidos e ocupando espaço, mesmo já vindo de outro backup.

A questão é que eu tinha, pelo menos, uns seis backups, envolvendo formatação e cópias de pendrivers. Muitos desses arquivos estavam repetidos, significando que eu poderia deixar apenas uma cópia, apagando as demais e mesmo assim ter todos os meus arquivos.

O primeiro método que pensei foi gerar hash de todos os arquivos, e depois compará-los para encontrar duplicados, porém gerar hash de 500 GB é extremamente demorado e muitos desses arquivos não sobrem alterações, então não seria necessário recalcular toda execução. Olhando no sistema de arquivos, temos a informação de última alteração no arquivo, então bastava gerar um cache com informações de arquivo, hash e data da última alteração, toda vez que o for executado, poderia comparar primeiro a data de alteração e calcular o hash apenas se necessário.

Com o script pronto, a primeira execução foi demorada, uma vez que teria que calcular o hash dos 500 GB, levando algumas horas, encontrando 5 GB de arquivos que poderiam ser apagados sem que eu perdesse qualquer informação. Uma próxima execução foi muito mais rápida, não levando mais de dois minutos, desde que com modificações em arquivos pequenos.

Consegui logo apagar uns 2 ou 3 GB, porém a lista de arquivos duplicados, apesar de auxiliar no processo, não era algo muito prática, uma vez que teria que buscar o arquivo manualmente para apagá-lo. Com arquivos grandes o processo ia rápido, e liberava mais espaço, porém em arquivos de texto puro não dava um rendimento satisfatório. Como sou programador web, logo montei uma página para listar esses arquivos, com um checkbox para selecionar os arquivos que desejava apagar, deixando o processo todo muito mais prático. Hoje tenho menos de 5 MB de pequenos arquivos duplicados, que comparados aos 5 GB representa menos de 0,1%.

Reorganizei todo o código, aproveitando para montar uma interface web mais completa, e publiquei o código no github sobre licença MIT (https://github.com/eduardoklosowski/deduplicated), então quem quiser dar uma olhada, utilizar, ou até contribuir com o desenvolvimento do mesmo fique à vontade.

Uma explicação rápida para quem deseja utilizá-lo. Por ser escrito em Python, recomendo a instalação via pip com o comando pip install git+https://github.com/eduardoklosowski/deduplicated.git ou pip install git+https://github.com/eduardoklosowski/deduplicated.git#egg=deduplicated[web] caso deseje instalar as dependências da interface web. Com isto você terá o comando deduplicated, bastando utilizar os parâmetros update para atualizar o cache dos arquivos, duplicated para listar os arquivos duplicados ou check para atualizar o cache e exibir os arquivos duplicados, seguido de um ou mais diretórios que deseja verificar, exemplo deduplicated check /home/eduardo. Caso tenha instalado a interface web, basta executar o comando deduplicated-web e abrir o endereço http://127.0.0.1:5050/.

Também existe uma opção para verificar se um arquivo está no cache com o comando indir, exemplo deduplicated indir meuarquivo.txt /home/eduardo. A vantagem é que você não precisa ter os arquivos para fazer essa verificação, eu verificava se os arquivos do meu notebook estavam no hd externo desta forma, sem precisar estar com ele ligado.

Recentemente tive um problema com o meu hd externo, essa história está no hack ‘n’ cast (quando for publicado disponibilizo o link aqui). Como eu tinha o cache do meu hd externo, pude compará-lo com o meu backup, descobrindo o que não estava atualizado e se eu tinha perdido algo. Esse procedimento se resumiu a executar as funções de atualização do cache na manualmente para adaptar certas partes e listar determinados valores. Caso alguém deseje posso até montar o script como uma função extra.

Eu fiquei extremamente feliz ao conseguir economizar o espaço do meu hd externo, o que já valeu o programa. Quando tive problemas no hd externo, percebi que ter as coisas organizadas e automatizadas, podendo consultar alguns logs, torna tudo mais fácil e tranquilo, bastando efetuar o RMA e depois executar um rsync para resolver todo o problema, obviamente teve a parte de formatação e criptografia também.