no Linux, existe uma camada/script que lida com solicitações de programas para abrir arquivos?
Como quando você abre um descritor de arquivo no bash: exec 3 <>/documents/foo.txt
ou seu editor de texto abre/documents/foo.txt
Não acredito que um editor possa "simplesmente abrir um arquivo" para acesso de leitura/gravação por conta própria.
Prefiro imaginar que isso seja um pedido a uma "camada" (script init.d?) que pode inicialmente abrir apenas uma certa quantidade de arquivos e que mantém o controle sobre os arquivos abertos com seus tipos de acesso, por quais processos eles são abertos, etc.
Responder1
Essa camada está dentro do kernel no Linux e em outros sistemas que não se afastam muito do design histórico do Unix (e também na maioria dos sistemas operacionais não-Unix).
Esta parte do kernel é chamada deCamada VFS (sistema de arquivos virtual). A função do VFS é gerenciar informações sobre arquivos abertos (a correspondência entredescritores de arquivo,abrir descrições de arquivose entradas de diretório), para analisar caminhos de arquivos (interpretando /
, .
e ..
) e para despachar operações em entradas de diretório para o driver de sistema de arquivos correto.
A maioria dos drivers de sistema de arquivos também está no kernel, mas oFUSÍVELO driver do sistema de arquivos permite que essa funcionalidade seja delegada fora do kernel. As operações do sistema de arquivos também podem envolver código de usuário se um armazenamento de nível inferior o fizer, por exemplo, se um sistema de arquivos em disco estiver em umdispositivo de loop.
Responder2
A abertura de arquivos no Linux é feita diretamente pelo kernelmas há várias coisas que você pode fazer para influenciar e estudar o processo.
Chamadas do sistema
Começando do topo, você pode ver que a interface que os aplicativos usam para interagir com os arquivos échamadas do sistema.
Abrir,lereescreverfaça o que você espera, enquantoEstadoretorna informações sobre um arquivo sem abri-lo.
Você pode estudar o uso de syscalls relacionados a arquivos por um programa usando strace:
$ strace -e trace=%file /bin/ls /etc
[...]
stat("/etc", {st_mode=S_IFDIR|0755, ...}) = 0
openat(AT_FDCWD, "/etc", O_RDONLY...) = 3
Isso analisa as syscalls causadas por ls /etc
, mostrando que stat
e openat
são chamadas no /etc
diretório.
Você deve estar se perguntando por que estamos chamando operações de arquivo em um diretório. No UNIX, os diretórios também são arquivos. Na verdadetudo é um arquivo!
Descritores de arquivo
Você pode estar se perguntando sobre openat() = 3
o resultado acima.
No UNIX, os arquivos abertos são representados por umdescritor de arquivo, que é uma representação exclusiva do arquivo aberto por um determinado processo. Os descritores de arquivo 0, 1 e 2 são geralmente reservados para ofluxos padrão(entrada/saída do usuário), então o primeiro arquivo aberto será 3.
Você pode obter uma lista de descritores de arquivos abertos para um determinado processo usandolsof
(eueuétócanetafarquivos):
$ cat /dev/urandom > /dev/null &
[1] 3242
$ lsof -p 3242
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
...
cat 3242 user 0u CHR 136,0 0t0 3 /dev/pts/0
cat 3242 user 1w CHR 1,3 0t0 1028 /dev/null
cat 3242 user 2u CHR 136,0 0t0 3 /dev/pts/0
cat 3242 user 3r CHR 1,9 0t0 1033 /dev/urandom
A FD
coluna mostra o número do descritor do arquivo, junto com o acesso.
Você também pode usarfuser
para procurar processos que contenham arquivos específicos:
$ fuser /dev/urandom
/dev/urandom: ... 3242 ...
Pseudo-sistema de arquivos de informações de processo - /proc
Agora você deve estar se perguntando:mas como lsof
saber quais arquivos estão abertos em primeiro lugar?
Bem, vamos dar uma olhada!
$ strace -e trace=%file lsof -p 3242
...
stat("/proc/3242/", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
openat(AT_FDCWD, "/proc/3242/stat", O_RDONLY) = 4
...
openat(AT_FDCWD, "/proc/3242/fd", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
readlink("/proc/3242/fd/0", "/dev/pts/0", 4096) = 10
lstat("/proc/3242/fd/0", {st_mode=S_IFLNK|0700, st_size=64, ...}) = 0
stat("/proc/3242/fd/0", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
openat(AT_FDCWD, "/proc/3242/fdinfo/0", O_RDONLY) = 7
...
Então lsof
sabe quais arquivos estão abertos... lendo mais arquivos! Especificamente, o diretório /proc/3242/fd
. Tudo abaixo /proc
é um sistema de arquivos "falso" mantido pelo kernel. Você pode ls -l
ver sua estrutura.
Influenciando a abertura de arquivos
Existem vários métodos que você pode usar para influenciar a abertura de arquivos, embora não sejam tão fáceis quanto apenas substituir algum script.
Se você deseja alterar a forma como os arquivos são armazenados ou acessados, como fornecer criptografia, armazená-los em cache, distribuí-los por vários discos ou algo semelhante, há uma boa chance de que já exista ummapeador de dispositivosque atenda às suas necessidades.
Se você deseja um controle refinado sobre a abertura de arquivos em um diretório/montagem específico, você pode escrever um simplesFUSÍVELsistema de arquivos e monte-o.
No nível do programa/processo, você pode usarLD_PRELOADpara alterar as chamadas da biblioteca C e impedi-las de fazer syscalls normais.
A maneira mais difícil, porém mais flexível, seria escrever seu próprio driver de sistema de arquivos.
Responder3
Gerenciar o acesso aos arquivos é a primeira e mais importante função de um sistema operacional. DOS, que é um dos sistemas operacionais mais antigos em computadores pessoais, significa Sistema Operacional de Disco. Ele permitiu que os programas acessassem diretamente o hardware em sua maior parte, mas não para acessar arquivos. Os programas tinham que usar chamadas do DOS e o DOS gerenciaria a entrada e saída de dados dos arquivos do programa. Somente utilitários de disco acessariam o disco rígido e os arquivos diretamente no DOS.
Os sistemas operacionais modernos em modo protegido, como o Linux, lidam com o acesso a arquivos como o DOS, mas também exigem que todo acesso a qualquer coisa fora do próprio programa (ou qualquer outro programa com o qual tenha sido configurado para compartilhar memória) passe pelo kernel (o Linux é um núcleo).
Seu programa no Linux pode chamar uma função na biblioteca C para ler ou gravar dados em um arquivo. A biblioteca C então faz sua parte de organizar o acesso aos dados no arquivo enquanto ainda é executada no mesmo contexto do seu programa. Então a biblioteca C chamará o kernel (Linux) com a função correta para acessar um arquivo, que muda a CPU para o anel 0 ou modo privilegiado. A CPU agora está executando o driver do sistema de arquivos Linux e o software do driver do disco rígido em modo privilegiado que acessa diretamente o hardware para acessar o arquivo. Os dados são copiados para a área de memória onde a biblioteca C instruiu o Linux a colocar os dados, e a CPU volta ao modo de usuário com o contexto de segurança do seu programa e a biblioteca C retoma e faz qualquer processamento necessário. esses dados e depois retorna à execução do seu programa.
Responder4
Resumindo, é isso que acontece quando um programa grava em um arquivo
- O programa solicita ao kernel
open
um arquivo, fornecido por um caminho, para gravação. - O kernel configura algumas estruturas internas e delega parte da tarefa de abrir o arquivo a um driver específico para o tipo de sistema de arquivos. O kernel então retorna um descritor de arquivo, que é apenas um número inteiro (por exemplo, 3), para o programa.
- O programa solicita ao kernel
write
uma sequência de bytes (por exemplo, uma string) para o arquivo referenciado pelo descritor de arquivo. - O kernel novamente delega trabalho ao driver.
- As etapas 3 e 4 provavelmente são repetidas várias vezes.
- O programa solicita ao kernel
close
o arquivo referenciado pelo descritor de arquivo. - O kernel delega novamente o trabalho ao driver e então destrói as estruturas internas.
Aqui está um programa assembly bastante minimalista que escreve "Hello World!" para o arquivo saudação.txt:
.text
.globl _start
_start:
# Open and possible create file
mov $2, %rax # syscall 'open'
mov $path_start, %rdi # path
mov $0101, %rsi # create + write
mov $400, %edx # only user gets read permissions
syscall
mov %rax, %r10 # file descriptor
# Write string to file
mov $1, %rax # syscall 'write'
mov %r10, %rdi # file descriptor
mov $msg_start, %rsi # start of data
mov $msg_length, %edx # length of data
syscall # perform syscall
# Close file
mov $3, %rax # syscall 'close'
mov %r10, %rdi # file descriptor
syscall
# Exit program
mov $60, %rax # syscall 'exit'
syscall # perform syscall
.section .rodata
path_start:
.string "greeting.txt\0"
path_end:
path_length = path_end - path_start
msg_start:
.string "Hello World!\n"
msg_end:
msg_length = msg_end - msg_start
Salve o código em write.s e construa usando
as -o write.o write.s
ld -o write write.o
e então corra com
./write
Espero que tudo funcione.
(Observação: não faço nenhum tratamento de erros. Este é apenas um código de brinquedo.)