En Linux, ¿existe una capa/script que maneje las solicitudes de programa para abrir archivos?
Como cuando abres un descriptor de archivo en bash: exec 3 <>/documents/foo.txt
o se abre tu editor de texto/documents/foo.txt
No puedo creer que un editor pueda "simplemente abrir un archivo" para acceso de lectura/escritura por sí solo.
Prefiero imaginar que esto es una solicitud a una "capa" (¿Secuencia de comandos init.d?) que, para empezar, solo puede abrir una cierta cantidad de archivos y que controla los archivos abiertos con sus tipos de acceso, mediante qué procesos se abren, etc.
Respuesta1
Esta capa está dentro del kernel en Linux y otros sistemas que no se alejan demasiado del diseño histórico de Unix (y también en la mayoría de los sistemas operativos que no son Unix).
Esta parte del núcleo se llamaCapa VFS (sistema de archivos virtual). La función del VFS es gestionar información sobre archivos abiertos (la correspondencia entredescriptores de archivos,abrir descripciones de archivosy entradas de directorio), para analizar rutas de archivos (interpretando y /
) y para enviar operaciones en entradas de directorio al controlador correcto del sistema de archivos..
..
La mayoría de los controladores del sistema de archivos también están en el kernel, pero elFUSIBLEEl controlador del sistema de archivos permite delegar esta funcionalidad fuera del kernel. Las operaciones del sistema de archivos también pueden involucrar el código de tierra del usuario si un almacenamiento de nivel inferior lo hace, por ejemplo, si un sistema de archivos de disco está en undispositivo de bucle.
Respuesta2
La apertura de archivos en Linux la maneja directamente el kernelpero hay varias cosas que puedes hacer para influir y estudiar el proceso.
llamadas al sistema
Comenzando desde arriba, puede ver que la interfaz que utilizan las aplicaciones para interactuar con los archivos esllamadas al sistema.
Abierto,leeryescribirhaz lo que esperas, mientrasestadísticadevuelve información sobre un archivo sin abrirlo.
Puedes estudiar el uso que hace un programa de llamadas al sistema relacionadas con archivos usando strace:
$ strace -e trace=%file /bin/ls /etc
[...]
stat("/etc", {st_mode=S_IFDIR|0755, ...}) = 0
openat(AT_FDCWD, "/etc", O_RDONLY...) = 3
Esto analiza las llamadas al sistema causadas por ls /etc
, mostrando que stat
y openat
son llamados en el /etc
directorio.
Quizás se pregunte por qué llamamos a operaciones de archivos en un directorio. En UNIX, los directorios también son archivos. De hechotodo es un archivo!
Descriptores de archivos
Quizás se pregunte acerca del openat() = 3
resultado anterior.
En UNIX los archivos abiertos están representados por undescriptor de archivo, que es una representación única del archivo abierto mediante un determinado proceso. Los descriptores de archivo 0, 1 y 2 generalmente están reservados para elflujos estándar(entrada/salida del usuario), por lo que el primer archivo abierto será 3.
Puede obtener una lista de descriptores de archivos abiertos para un proceso determinado utilizandolsof
(yoistohbolígrafoFarchivos):
$ 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
La FD
columna le muestra el número del descriptor del archivo, junto con el acceso.
También puedes usarfuser
para buscar procesos que contienen archivos particulares:
$ fuser /dev/urandom
/dev/urandom: ... 3242 ...
Pseudosistema de archivos de información de proceso - /proc
A estas alturas quizás te estés preguntando:pero, ¿cómo puedo lsof
saber qué archivos están abiertos en primer lugar??
Bueno, ¡echemos un vistazo!
$ 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
...
Entonces lsof
sabe qué archivos están abiertos... ¡leyendo más archivos! En concreto, el directorio /proc/3242/fd
. Todo lo que aparece a continuación /proc
es un sistema de archivos "falso" mantenido por el kernel. Puedes ls -l
verlo para ver su estructura.
Influir en la apertura de archivos
Hay varios métodos que puede utilizar para influir en la apertura de archivos, aunque no son tan fáciles como simplemente reemplazar algún script.
Si está buscando cambiar la forma en que se almacenan o se accede a los archivos, como proporcionar cifrado, almacenarlos en caché, distribuirlos en varios discos o algo similar, es muy probable que ya exista unamapeador de dispositivosque se adapta a tus necesidades.
Si desea un control detallado sobre la apertura de archivos en un directorio/montaje en particular, puede escribir un simpleFUSIBLEsistema de archivos y montarlo.
A nivel de programa/proceso, puede utilizarLD_PRELOADpara cambiar las llamadas a la biblioteca C y evitar que realicen las llamadas al sistema normales.
La forma más difícil pero más flexible sería escribir su propio controlador de sistema de archivos.
Respuesta3
Administrar el acceso a los archivos es la primera y más importante función de un sistema operativo. DOS, que es uno de los sistemas operativos más antiguos en computadoras personales, significa Sistema Operativo de Disco. Permitió que los programas accedieran directamente al hardware en su mayor parte, pero no así para acceder a los archivos. Los programas tenían que usar llamadas de DOS y DOS se encargaba de ingresar y sacar datos de los archivos para el programa. Sólo las utilidades de disco accederían al disco duro y a los archivos directamente en DOS.
Los sistemas operativos modernos en modo protegido, como Linux, manejan el acceso a archivos como lo hace DOS, pero también requieren que cada acceso a cualquier cosa fuera del programa en sí (o cualquier otro programa con el que se haya configurado para compartir memoria) pase por el kernel (Linux es un núcleo).
Su programa en Linux puede llamar a una función en la biblioteca C para leer o escribir datos en un archivo. Luego, la biblioteca C hace su parte de organizar el acceso a los datos del archivo mientras se ejecuta en el mismo contexto que su programa. Luego, la biblioteca C llamará al kernel (Linux) con la función correcta para acceder a un archivo, lo que cambia la CPU al modo ring 0 o privilegiado. La CPU ahora ejecuta el controlador del sistema de archivos de Linux y el software del controlador del disco duro en modo privilegiado, que accede directamente al hardware para acceder al archivo. Los datos se copian al área de memoria donde la biblioteca C le indicó a Linux que colocara los datos, y la CPU vuelve al modo de usuario con el contexto de seguridad de su programa y la biblioteca C se reanuda y realiza cualquier procesamiento necesario. esos datos y luego vuelve a ejecutar su programa.
Respuesta4
En resumen, esto es lo que sucede cuando un programa escribe en un archivo.
- El programa le pide al kernel que
open
escriba un archivo, proporcionado por una ruta. - El kernel configura algunas estructuras internas y delega parte de la tarea de abrir el archivo a un controlador específico para el tipo de sistema de archivos. Luego, el núcleo devuelve un descriptor de archivo, que es simplemente un número entero (por ejemplo, 3), al programa.
- El programa solicita al núcleo
write
una secuencia de bytes (por ejemplo, una cadena) al archivo al que hace referencia el descriptor de archivo. - El núcleo nuevamente delega trabajo al controlador.
- Los pasos 3 y 4 probablemente se repitan varias veces.
- El programa solicita al kernel
close
el archivo al que hace referencia el descriptor de archivo. - El núcleo nuevamente delega trabajo al controlador y luego destruye las estructuras internas.
Aquí hay un programa ensamblador bastante minimalista que escribe "¡Hola mundo!" al archivo saludo.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
Guarde el código en write.s y compílelo usando
as -o write.o write.s
ld -o write write.o
y luego correr con
./write
Ojalá todo funcione.
(Nota: no manejo ningún error. Esto es solo código de juguete).