Há alguns antipadrões a serem considerados ao acessar o sistema de arquivos. Esse artigo presume conhecimento das APIs GFile
, GInputStream
e GOutputStream
padrões.
Use E/S assíncrona para acesso de arquivo. ()
Sempre use funções adequadas para construir nomes e caminhos de arquivos . ()
Valide caminhos de arquivos que estão em diretórios esperados antes de usá-los. ()
Use perfis obrigatórios de controle de acesso para reforçar restrições de acesso de arquivos. ()
Quase toda E/S deve ser feita assincronamente, ou seja, sem bloqueio do contexto principal do GLib. Isso pode ser alcançado por sempre usar as variantes *_async()
e *_finish()
de cada função de E/S.
Por exemplo, g_input_stream_read_async()
em vez de g_input_stream_read()
.
E/S síncrona bloqueia o loop principal, o que significa que outros eventos, tal como entrada de usuário, chegada de pacotes de rede, expiração de tempo limite e retorno de chamada ocioso, não são tratados até que a função bloqueadora retorne.
E/S síncrona é aceitável em certas circunstâncias nas quais a sobrecarga de agendar uma operação assíncrona excede o custo de E/S síncrona local no Linux. Por exemplo, fazer uma leitura pequena de um arquivo local, ou de um sistema de arquivos virtual tal como g_open()
, read()
e g_close()
devem ser usadas, em vez do GIO.
Arquivos no diretório pessoal do usuário não contam como locais, pois eles podem estar em um sistema de arquivos de rede.
Note que a alternativa – executar E/S síncrona em uma thread separada – é altamente desencorajada; veja as diretrizes de thread para mais informações.
Nomes e caminhos de arquivos não são strings normais: em alguns sistemas, eles podem usar uma codificação de caracteres diferente de UTF-8, enquanto strings normais no GLib têm a garantia de sempre usar UTF-8. Por este motivo, funções especiais devem ser usadas para compilar e tratar nomes e caminhos de arquivos. (Sistemas Linux modernos quase que universalmente usam UTF-8 para codificação de nome de arquivo, então isso não é um problema na prática, mas as funções de caminho de arquivo ainda devem ser usadas para compatibilidade com sistemas como o Windows, que usam nomes de arquivos UTF-16.)
Por exemplo, caminhos de arquivos devem ser construídos usando g_build_filename()
em vez de g_strconcat()
.
Fazer isso deixa mais claro qual é a intenção do código e também elimina separadores duplicados de diretórios, de forma que o caminho retornado é canonical (apesar de não necessariamente absoluto).
Como um outro exemplo, caminhos devem ser desmembrados usando g_path_get_basename()
e g_path_get_dirname()
em vez de g_strrstr()
e outras funções manuais de pesquisa.
Se um nome ou caminho de arquivo vem com uma entrada externa, tal como uma página web ou entrada de usuário, ele deve ser validado para garantir que colocá-lo em um caminho de arquivo não produzirá um caminho arbitrário. Por exemplo, se um nome de arquivo é construído a partir de uma string constante
Isso pode ser evitado por meio de uma validação dos caminhos construídos antes de usá-los usando g_file_resolve_relative_path()
para converter quaisquer caminhos relativos para absolutos e, então, validar se aqueles caminhos estão dentro de um diretório raiz de sandbox apropriado para a operação. Por exemplo, se um código baixa um arquivo, ele poderia validar se aqueles caminhos estejam dentro de g_file_has_parent()
.
Como uma segunda linha de defesa, todos os projetos que acessam o sistema de arquivos devem considerar fornecer um perfil obrigatório de controle de acesso, usando um sistema tal como AppArmor ou SELinux que limita os diretórios e arquivos nos quais eles podem ler de ou escrever em.