Archivos y directorios: Organización de archivos
Índice
1 Introducción
De los roles que cumple el sistema operativo, probablemente el que más consciente tengan en general sus usuarios es el de la gestión del espacio de almacenamiento, esto es, la organización de la información en un sistema de archivos. Al día de hoy, todos los usuarios de equipo de cómputo dan por sentado y comprenden a grandes rasgos la organización del espacio de almacenamiento en un directorio jerárquico, con unidades de almacenamiento llamadas archivos, de diferentes tipos según su función. En el presente capítulo se revisará la semántica que compone a este modelo, para en el capítulo FS continuar con los detalles de la gestión del espacio físico donde éstos están alojados.
La abstracción que hoy se conoce como sistemas de archivos es una de las que más tiempo ha vivido y se ha mantenido a lo largo de la historia de la computación, sobreviviendo a lo largo de prácticamente todas las generaciones de sistemas operativos. Sin embargo, para poder analizar cómo es que el sistema operativo representa la información en el dispositivo físico, el presente capítulo inicia discutiendo cómo es que esta información es comprendida por los niveles más altos — Por los programas en espacio de usuario.
Capas de abstracción para implementar los sistemas de archivos
La información cruda tiene que pasar una serie de transformaciones. Yendo de niveles superiores a niveles más bajos, un programa estructura sus datos en archivos, siguiendo el formato que resulte mas pertinente al tipo de información a representar. Un conjunto de archivos hoy en día es típicamente representado en una estructura de directorios,1.
Cada dispositivo empleado para almacenar archivos tiene un directorio. Cuando un sistema opera con más de un dispositivo físico, existen principalmente dos mecanismos para integrar a dichos dispositivos en un sistema de archivos virtual,2 brindnado al usuario una interfaz uniforme. Por último, los archivos son una estructura meramente lógica; deben ser convertidos para ser representados en un dispositivo de bloques como los diversos tipos de unidades –aunque esta nomenclatura es a veces incorrecta– como discos. Este último paso será abordado en el capítulo FS.
Del diagrama presentado en la figura DIRcapasaccesoadiscos, toca al objeto de nuestro estudio –el sistema operativo– recibir del espacio de usuario las llamadas al sistema que presentan la interfaz de archivos y directorios, integrar el sistema de archivos virtual, y traducir la información resultante a un sistema de archivos.
Cabe mencionar que varias de las capas aquí presentadas podrían perfectamente ser subdivididas, analizadas por separado, e incluso tratarse de forma completamente modular — De hecho, este es precisamente el modo en que se implementan de forma transparente características hoy en día tan comunes como sistemas de archivos en red, o compresión y cifrado de la información. Una referencia más detallada acerca de ventajas, desventajas, técnicas y mecanismos de la división y comunicación entre capas puede ubicarse en el artículo de Heidemann y Popek (1994).
2 Concepto de archivo
En primer término, un archivo es un tipo de datos abstracto — Esto es, podría verse como una estructura que exclusivamente permite la manipulación por medio de una interfaz orientada a objetos: Los procesos en el sistema sólo pueden tener acceso a los archivos por medio de la interfaz ofrecida por el sistema operativo.3 La siguiente sección describe las principales operaciones provistas por esta interfaz.
Para el usuario, los archivos son la unidad lógica mínima al hablar de almacenamiento: Todo el almacenamiento persistente (que sobrevive en el tiempo, sea a reinicios del sistema, a pérdida de corriente o a otras circunstancias en el transcurso normal de ejecución) en el sistema al que tiene acceso, se efectúa dentro de archivos; el espacio libre en los diferentes dispositivos no tiene mayor existencia fuera de saber que está potencialmente disponible.
Dentro de cada volúmen (cada medio de almacenamiento), los archivos disponibles conforman a un directorio, y son típicamente identificados por un nombre o una ruta. Más adelante se presentarán de las diferentes construcciones semánticas que pueden conformar a los directorios.
2.1 Operaciones con archivos
Cada sistema operativo definirá la interfaz de archivos acorde con su semántica, pero en líneas generales, las operaciones que siempre estarán disponibles con un archivo son:
- Borrar
- Elimina al archivo del directorio y, de ser procedente, libera el espacio del dispositivo
- Abrir
- Solicita al sistema operativo verificar si el archivo existe o
puede ser creado (dependiendo del modo requerido) y se cuenta con el
acceso para el modo de acceso al archivo indicado y
si el medio lo soporta (por ejemplo, a pesar de contar con
todos los permisos necesarios, el sistema operativo no debe
permitir abrir para escritura un archivo en un CD-ROM u
otro medio de sólo lectura). En C, esto se hace con la
función
fopen()
.Al abrir un archivo, el sistema operativo asigna un descriptor de archivo que identifica la relación entre el proceso y el archivo en cuestión; estos serán definidos propiamente en la sección DIRtablasdearchivos.
Todas las operaciones descritas a continuación operan sobre el descriptor de archivo, no con su nombre o ruta.
- Cerrar
- Indica al sistema que el proceso en cuestión terminó de
trabajar con el archivo; el sistema entonces debe escribir
los buffers a disco y eliminar la entrada que representa a
esta combinación archivo-proceso de las tablas activas,
invalidando al descriptor de archivo. En C, para cerrar
un descriptor de archivo se usa
fclose()
.Dado que todas las operaciones se realizan a través del descriptor de archivo, si un proceso cierra un archivo y requiere seguir utilizándolo, tendrá que abrirlo de nuevo para obtener un nuevo descriptor.
- Leer
- Si se solicita al sistema la lectura leer de un archivo
hacia determinado buffer, éste copia el siguiente pedazo
de información a éste. Este pedazo podría ser una línea o
un bloque de longitud definida, dependiendo del modo en que
se solicite la lectura. El sistema mantiene un apuntador a
la última posición leída, para poder continuar con la
lectura de forma secuencial.
La función que implementa la lectura en C es
fread()
. Cabe mencionar quefread()
entrega el número de caracteres especificado; para trabajar con líneas de texto hace falta trabajar con bibliotecas que implementen esta funcionalidad, comoreadline
. - Escribir
- Teniendo un archivo abierto, guarda información en
él. Puede ser que escriba desde su primer posición
(truncando al archivo, esto es, borrando toda la
información que pudiera ya tener), o agregando al
archivo, esto es, iniciando con el apuntador de
escritura al final del mismo. La función C para escribir a
un descriptor de archivo es
fwrite()
. - Reposicionar
- Tanto la lectura como la escritura se hacen
siguiendo a un apuntador, que indica cuál fue la
última posición del archivo a la que accesó el
proceso actual. Al reposicionar el apuntador,
se puede saltar a otro punto del archivo. La
función que reposiciona el apuntador dentro de un
descriptor de archivos es
fseek()
.
Hay varias otras operaciones comunes que pueden implementarse con llamadas compuestas a estas operaciones (por ejemplo, copiar un archivo puede implementarse como crear un archivo nuevo en modo de escritura, abrir en modo de lectura al archivo fuente, e ir leyendo de éste y escribiendo al nuevo hasta llegar al fin de archivo fuente).
Las operaciones aquí presentadas no son todas las operaciones existentes; dependiendo del sistema operativo, habrá algunas adicionales; estas se presentan como una base general común a los principales sistemas operativos.
Vale la pena mencionar que esta semántica para el manejo de archivos presenta a cada archivo como si fuera una unidad de cinta, dentro de la cual la cabeza lectora/escritora simulada puede avanzar o retroceder.
2.2 Tablas de archivos abiertos
Tanto el sistema operativo como cada uno de los procesos mantienen normalmente tablas de archivos abiertos. Éstas mantienen información acerca de todos los archivos actualmente abiertos, presentándolos hacia el proceso por medio de un descriptor de archivo; una vez que un archivo fue abierto, las operaciones que se realizan dentro de éste no son empleando su nombre, sino que su descriptor de archivo.
En un sistema operativo multitareas, más de un proceso podría abrir el mismo archivo a la vez; lo que cada uno de ellos pueda hacer, y cómo esto impacte a lo que vean los demás procesos, depende de la semántica que implemente el sistema; un ejemplo de las diferentes semánticas posibles es el descrito en la sección DIRbloqarch.
Ahora, ¿por qué estas tablas son mantenidas tanto por el sistema operativo como por cada uno de los procesos? ¿No lleva esto a una situación de información redundante?
La respuesta es que la información que cada uno debe manejar es distinta. El sistema operativo necesita:
- Conteo de usuarios del archivo
- Cuando se solicita, por ejemplo, desmontar una partición (por ejemplo, para expulsar una unidad removible) o eliminar un archivo, el sistema debe poder determinar cuándo es momento de declarar la solicitud como efectuada. Si algún proceso tiene abierto a un archivo, y particularmente si tiene cambios pendientes de guardar, el sistema debe hacer lo posible por evitar que el archivo desaparezca de su visión.
- Modos de acceso
- Aunque un usuario tenga permisos de acceso a determinado recurso, el sistema puede determinar negarlo si llevaría a una inconsistencia. Por ejemplo, si dos procesos abren un mismo archivo en modo de escritura, es probable que los cambios que realice uno sobreescriban a los que haga el otro.
- Ubicación en disco
- El sistema mantiene esta infromación para evitar que cada proceso tenga que consultar las tablas en disco para encontrar al archivo, o cada uno de sus fragmentos.
- Información de bloqueo
- En caso de que los modos de acceso del archivo requieran protección mutua, puede implementarse por medio de un bloqueo.
Por otro lado, el proceso necesita:
- Descriptor de archivo
- Relación entre el nombre del archivo
abierto y el identificador numérico que maneja internamente el
proceso. Un archivo abierto por varios procesos tendrá
descriptores de archivo distintos en cada uno de ellos.
A nivel implementación, el descriptor de archivo otorgado por el sistema a un proceso es simplemente un número entero, que podría entenderse como el n-ésimo archivo empleado por el proceso.4
- Permisos
- Los modos válidos de acceso para un archivo. Esto no necesariamente es igual a los permisos que tiene el archivo en cuestión en disco, sino que el subconjunto de dichos permisos bajo los cuales está operando para este proceso en particular — Si un archivo fue abierto en modo de sólo lectura, por ejemplo, este campo sólo permitirá la lectura.
2.3 Acceso concurrente: Bloqueo de archivos
Dado que los archivos pueden emplearse como mecanismo de comunicación entre procesos que no guarden relación entre sí, incluso a lo largo del tiempo, y para emplear un archivo basta indicar su nombre o ruta, los sistemas operativos multitarea implementan mecanismos de bloqueo para evitar que varios procesos intentando emplear de forma concurrente a un archivo se corrompan mutuamente.
Algunos sistemas operativos permiten establecer bloqueos sobre determinadas regiones de los archivos, aunque la semántica más común es operar sobre el archivo entero.
En general, la nomenclatura que se sigue para los bloqueos es:
- Compartido
- (Shared lock) Podría verse como equivalente a un bloqueo (o candado) para realizar lectura — Varios procesos pueden adquirir al mismo tiempo un bloqueo de lectura, e indica que todos los que posean dicho candado tienen la expectativa de que el archivo no sufrirá modificaciones.
- Exclusivo
- (Exclusive lock) Un bloqueo o candado exclusivo puede ser adquirido por un sólo proceso, e indica que realizará operaciones que modifiquen al archivo (o, si la semántica del sistema operativo permite expresarlo, a la porción del archivo que indica).
Respecto al mecanismo de bloqueo, hay también dos tipos, dependiendo de qué tan explícito tiene que ser su manejo:
- Mandatorio u obligatorio
- (Mandatory locking) Una vez que un proceso adquiere un candado obligatorio, el sistema operativo se encargará de imponer las restricciones corresponidentes de acceso a todos los demás procesos, independientemente de si éstos fueron programados para considerar la existencia de dicho bloqueo o no.
- Consultivo o asesor
- (Advisory locking) Este tipo de bloqueos es manejado cooperativamente entre los procesos involucrados, y depende del programador de cada uno de los programas en cuestión el solicitar y respetar dicho bloqueo.
Haciendo un paralelo con los mecanismos presentados en el capítulo PROC, los mecanismos que emplean mutexes, semáforos o variables de condición serían consultivos, y únicamente los que emplean monitores (en que la única manera de llegar a la información es a través del mecanismo que la protege) serían mandatorios.
No todos los sistemas operativos implementan las cuatro posibles combinaciones (compartido mandatorio, o compartido compulsivo, exclusivo mandatorio y exclusivo consultivo). Como regla general, en los sistemas Windows se maneja un esquema de bloqueo obligatorio, y en sistemas Unix es de bloqueo consultivo.5
Cabe mencionar que el manejo de bloqueos con archivos requiere del mismo cuidado que el de bloqueo por recursos cubierto en la sección PROCbloqmutuos: Dos procesos intentando adquirir un candado exclusivo sobre dos archivos pueden caer en un bloqueo mutuo tal como ocurre con cualquier otro recurso.
2.4 Tipos de archivo
Si los archivos son la unidad lógica mínima con la que se puede guardar información en almacenamiento secundario, naturalmente sigue que existen archivos de diferentes tipos: Cada archivo podría ser un documento de texto, un binario ejecutable, un archivo de audio o video, o un larguísimo etcetera, e intentar emplear a un archivo como uno de un tipo distinto puede resultar desde una frustración al usuario porque el programa no responde como éste quiere, hasta en pérdidas económicas.6
Hay tres estrategias principales para que el sistema operativo reconozca al tipo de un archivo:
- Extensión
- En los sistemas CP/M de los 1970, el nombre de cada
archivo se dividía en dos porciones, empleando como
elemento separador al punto: El nombre del archivo y su
extensión. El sistema mantenía una lista de extensiones
conocidas, para las cuales sabría cómo actuar, y este
diseño se extendería a las aplicaciones, que sólo
abrirían a aquellos archivos cuyas extensiones
supieran manejar.
Esta estrategia fue heredada por VMS y MS-DOS, de donde la adoptó Windows; ya en el contexto de un entorno gráfico, Windows agrega, más allá de las extensiones directamente ejecutables, la relación de extensiones con los programas capaces de trabajar con ellas, permitiendo invocar a un programa con sólo dar ``doble click'' en un archivo.
Como nota, este esquema de asociación de tipo de archivo permite ocultar las extensiones toda vez que ya no requieren ser del conocimiento del usuario, sino que son gestionadas por el sistema operativo, abre una vía de ataque automatizado que se popularizó en su momento: El envío de correos con extensiones engañosas duplicadas — Esto es, el programa maligno (un programa troyano) se envía a todos los contactos del usuario infectado, presentándose por ejemplo como una imágen, con el nombre
inocente.png.exe
. Por el esquema de ocultamiento mencionado, éste se presenta al usuario comoinocente.png
, pero al abrirlo, el sistema operativo lo reconoce como un ejecutable, y lo ejecuta en vez de abrirlo en un visor de imágenes. - Números mágicos
- La alternativa que emplean los sistemas Unix es,
como siempre, simple y elegante, aunque indudablemente presenta
eventuales lagunas: El sistema mantiene una lista compilada de
las huellas digitales de los principales formatos que debe
manejar,7 para reconocer el contenido
de un archivo basado en sus primeros bytes.
Casi todos los formatos de archivo incluyen lo necesario para que se lleve a cabo este reconocimiento, y cuando no es posible hacerlo, se intenta por medio de ciertas reglas heurísticas. Por ejemplo, todos los archivos de imágen en formato de intercambio gráfico (GIF) inician con la cadena
GIF87a
oGIF89a
, dependiendo de la versión; los archivos del lenguaje de descripción de páginas PostScript inician con la cadena%!
, el Formato de Documentos Portátiles (PDF) con%PDF
, etcétera. Un documento en formatos definidos alrededor de XML inicia con<!DOCTYPE
. Algunos de estos formatos no están anclados al inicio, sino que en un punto específico del primer bloque.Un caso especial de números mágicos es el llamado hashbang (
#!
). Esto indica a un sistema Unix que el archivo en cuestión (típicamente un archivo de texto, incluyendo código fuente en algún lenguaje de script) debe tratarse como un ejecutable, y empleando como intérprete al comando indicado inmediatamente después del hashbang. Es por esto que se pueden ejecutar directamente, por ejemplo, los archivos que inician con#!/usr/bin/bash
: El sistema operativo invoca al programa/usr/bin/bash
, y le especifica como argumento al archivo en cuestión. - Metadatos externos
- Los sistemas de archivos empleado por las
Apple Macintosh desde 1984 separan en dos divisiones (forks)
la información de un archivo: Los datos que propiamente
constituyen al archivo en cuestión son la división de datos
(data fork), y la información acerca del archivo se guardan
en una estructura independiente llamada división de recursos
(resource fork).
Esta idea resultó fundamental para varias de las características amigables al usuario que presentó Macintosh desde su introducción — Particularmente, para presentar un entorno gráfico que respondiera ágilmente, sin tener que buscar los datos base de una aplicación dentro de un archivo de mucho mayor tamaño. La división de recursos cabe en pocos sectores de disco, y si se toma en cuenta que las primeras Macintosh funcionaban únicamente con discos flexibles, el tiempo invertido en leer una lista de iconos podría ser demasiada.
La división de recursos puede contener todo tipo de información; los programas ejecutables son los que le dan un mayor uso, dado que incluyen desde los aspectos gráficos (icono a mostrar para el archivo, ubicación de la ventana a ser abierta, etc.) hasta aspectos funcionales, como la traducción de sus cadenas al lenguaje particular del sistema en que está instalado. Esta división permite una gran flexibilidad, dado que no es necesario tener acceso al fuente del programa para crear traducciones y temas.
En el tema particular que concierne a esta sección, la división de recursos incluye un campo llamado creador, que indica cuál programa fue el que generó al archivo. Si el usuario solicita ejecutar un archivo de datos, el sistema operativo lanzaría al programa creador, indicándole que abra al archivo en cuestión.
Las versiones actuales de MacOS ya no emplean esta técnica, sino que una llamada appDirectory, para propósitos de esta discusión, la técnica base es la misma.
2.5 Estructura de los archivos y métodos de acceso
La razón principal de la existencia del sistema de archivos son los archivos. Un archivo almacena información de algún tipo, estructurado o no estructurado.
La mayor parte de los sistemas operativos maneja únicamente archivos sin estructura — Cada aplicación es responsable de preparar la información de forma congruente, y la responsabilidad del sistema operativo es únicamente entregarlo como un conjunto de bytes. Históricamente, hubo sistemas operativos, como IBM CICS (1968), IBM MVS (1974) o DEC VMS (1977), que administraban ciertos tipos de datos en un formato básico de base de datos.
El hecho de que el sistema operativo no imponga estructura a un archivo no significa, claro está, que la aplicación que lo genera no lo haga. La razón por la que los sistemas creados en los últimos 30 años no han implementado este esquema de base de datos es que le resta flexibilidad al sistema: El que una aplicación tuviera que ceñirse a los tipos de datos y alineación de campos del sistema operativo impedía su adecuación, y el que la funcionalidad de un archivo tipo base de datos dependiera de la versión del sistema operativo creaba un acoplamiento demasiado rígido entre el sistema operativo y las aplicaciones.
Esta práctica ha ido cediendo terreno a dejar esta responsabilidad en manos de procesos independientes en espacio de usuario (como sería un gestor de bases de datos tradicional), o de bibliotecas que ofrezcan la funcionalidad de manejo de archivos estructurados (como en el caso de SQLite, empleado tanto por herramientas de adquisición de datos de bajo nivel como systemtap como por herramientas tan de escritorio como el gestor de fotografías shotwell o el navegador Firefox).
En los sistemas derivados de MS-DOS puede verse aún un remanente de
los archivos estructurados: En estos sistemas, un archivo puede ser
de texto o binario. Un archivo de texto está compuesto por una
serie de caracteres que forman líneas, y la separación entre una
línea y otra constituye de un retorno de carro (CR
, caracter
ASCII 13) seguido de un salto de línea (LF
, caracter ASCII
10).8
El acceso a los archivos puede realizarse de diferentes maneras:
- Acceso secuencial
- Mantiene la semántica por medio de la cual
permite leer de nuestros archivos de forma equivalente a
unidad de cinta mencionados en la sección
DIRoperacionesconarchivos, y como lo ilustra la figura
DIRaccesosecuencial:
El mecanismo principal para leer o escribir es ir avanzando
consecutivamente por los bytes que conforman al archivo hasta
llegar a su final.
Típicamente se emplea este mecanismo de lectura para leer a memoria código (programas o bibliotecas) o documentos, sea enteros o fracciones de los mismos. Para un contenido estructurado, como una base de datos, resultaría absolutamente ineficiente, dado que no se conoce el punto de inicio o finalización de cada uno de los registros, y probablemente sería necesario que hacer barridos secuenciales del archivo completo para cada una de las búsquedas.
Archivo de acceso secuencial
- Acceso aleatorio
- El empleo de gestores como SQLite u otros
muchos motores de base de datos más robustos no exime al usuario de
pensar en el archivo como una tabla estructurada, como lo ilustra
la figura DIRaccesoaleatorio. Si la única semántica por
medio de la cual el sistema operativo permitiera trabajar con los
archivos fuera la equivalente a una unidad de cinta, implementar
el acceso a un punto determinado del archivo podría resultar
demasiado costoso.
Afortunadamente, que el sistema operativo no imponga registros de longitud fija no impide que el programa gestor lo haga. Si en el archivo al cual apunta el descriptor de archivo
FD
hay 2000 registros de 75 bytes cada uno y el usuario requiere recuperar el registro número 65 hacia el bufferregistro
, puede reposicionar el apuntador de lectura al byte(
seek(FD, 4875)
) y leer los siguientes 75 bytes enregistro
(read(FD, *registro, 75)
).
Archivo de acceso aleatorio
- Acceso relativo a índice
- En los últimos años se han popularizado
los gestores de base de datos débilmente estructurados u orientados a documentos, llamados genéricamente NoSQL. Estos gestores pueden
guardar registros de tamaño variable en disco, por lo que, como
lo ilustra la figura DIRaccesorelativoaindice, no
pueden encontrar la ubicación correcta por medio de los
mecanismos de acceso aleatorio.
Para implementar este acceso, se divide al conjunto de datos en dos secciones (incluso, posiblemente, en dos archivos independientes): La primer sección es una lista corta de identificadores, cada uno con el punto de inicio y término de los datos a los que apunta. Para leer un registro, se emplea acceso aleatorio sobre el índice, y el apuntador se avanza a la ubicación específica que se solicita.
En el transcurso de un uso intensivo de esta estructura, dado que la porción de índice es muy frecuentemente consultada y relativamente muy pequeña, muy probablemente se mantenga completa en memoria, y el acceso a cada uno de los registros puede resolverse en tiempo muy bajo.
La principal desventaja de este modelo de indexación sobre registros de longitud variable es que sólo resulta eficiente para contenido mayormente de lectura: Cada vez que se produce una escritura y cambia la longitud de los datos almacenados, se va generando fragmentación en el archivo, y para resolverla probablemente se hace necesario suspender un tiempo la ejecución de todos los procesos que lo estén empleando (e invalidar, claro, todas las copias en caché de los índices). Ahora bien, para los casos de uso en que el comportamiento predominante sea de lectura, este formato tendrá la ventaja de no desperdiciar espacio en los campos nulos o de valor irrelevante para algunos de los registros, y de permitir la flexibilidad de registrar datos originalmente no contemplados sin tener que modificar la estructura.
Es importante recalcar que la escritura en ambas partes de la base de datos (índice y datos) debe mantenerse con garantías de atomicidad — Si se pierde la sincronía entre ellas, el resultado será una muy probable corrupción de datos.
Acceso relativo a índice: Un índice apuntando al punto justo de un archivo sin estructura
2.6 Transferencias orientadas a bloques
Un sistema de archivos es la representación que se da a un conjunto de archivos y directorios sobre un dispositivo de bloques, esto es, un dispositivo que, para cualquier transferencia solicitada desde o hacia él, responderá con un bloque de tamaño predefinido.9
Esto es, si bien el sistema operativo presenta una abstracción por
medio de la cual la lectura (read()
) puede ser de un tamaño
arbitrario, todas las transferencias de datos desde cualquiera de los
discos serán de un múltiplo del tamaño de bloques, definido por el
hardware (típicamente 512 bytes).
Al leer, como en el ejemplo anterior, sólamente un registro
de 75 bytes, el sistema operativo lee el bloque completo y
probablemente lo mantiene en un caché en la memoria principal; si en
vez de una lectura, la operación efectuada fue una de escritura
(write()
), y el sector a modificar no ha sido leído aún a
memoria (o fue leído hace mucho, y puede haber sido expirado del
caché), el sistema tendrá que leerlo nuevamente, modificarlo en
memoria, y volver a guardarlo a disco.
3 Organización de archivos
Hasta este punto, el enfoque ha sido en qué es y cómo se maneja un archivo. Sin embargo, no tendría sentido hablar de sistemas de archivos si no hubiera una gran cantidad de archivos. Es común que un sólo medio de almacenamiento de un equipo de uso doméstico aloje decenas de miles de archivos, y en equipos dedicados, no está fuera de lugar tener cientos o miles de veces tanto. Por tanto, se tiene que ver también cómo organizar una gran cantidad de archivos.
3.1 Evolución del concepto de directorio
El concepto dominante en almacenaimiento hoy en día es el de directorios jerárquicos. Esto no siempre fue así; conviene revisar brevemente su historia para explicar el por qué de ciertos detalles de implementación del esquema actualmente dominante.
3.1.1 Convenciones de nomenclatura
Cada sistema de archivos puede determinar cuántos y qué caracteres
son válidos para designar a uno de sus elementos, y cuáles son
separadores válidos. El caracter que se emplea para separar los
elementos de un directorio no es un estándar a través de todos los
sistemas operativos — Los más comunes en uso hoy en día
son la diagonal (/
), empleada en sistemas tipo Unix y derivados
(incluyendo MacOS X y Android), y la diagonal invertida (),
empleada en CP/M y derivados, incluyendo MS-DOS y Windows.
Diversos sistemas han manejado otros caracteres (por ejemplo, el MacOS
histórico empleaba los dos puntos, :
), y aunque muchas veces los
mantenían ocultos del usuario a través de una interfaz gráfica rica,
los programadores siempre tuvieron que manejarlos explícitamente.
A lo largo del presente texto se empleará la diagonal (/
) como
separador de directorios.
3.1.2 Sistema de archivos plano
Los primeros sistemas de archivos limitaban el concepto de directorio a una representación plana de los archivos que lo conformaban, sin ningún concepto de jerarquía de directorios como el que hoy resulta natural a los usuarios. Esto se debía, en primer término, a lo limitado del espacio de almacenamiento de las primeras computadoras en implementar esta metáfora (por lo limitado del espacio de almacenamiento, los usuarios no dejaban sus archivos a largo plazo en el disco, sino que los tenían ahí meramente mientras los requerían), y en segundo término, a que no se había aún desarrollado un concepto de separación, permisos y privilegios como el que poco después aparecería.
En las computadoras personales los sistemas de archivos eran también planos en un primer momento, pero por otra razón: En los sistemas profesionales ya se había desarrollado el concepto; al aparecer la primer computadora personal en 1975, ya existían incluso las primeras versiones de Unix diseñadas para trabajo en red. La prioridad en los sistemas personales era mantener el código del sistema operativo simple, mínimo. Con unidades de disco capaces de manejar entre 80 y 160KB, no tenía mucho sentido implementar directorios — Si un usuario quisiera llevar a cabo una división temática de su trabajo, lo colocaría en distintos discos flexibles. El sistema operativo CP/M nunca soportó jerarquías de directorios, como tampoco lo hizo la primer versión de MS-DOS.10
El sistema de archivos original de la Apple Macintosh, MFS, estaba construido sobre un modelo plano, pero presentando la ilusión de directorios de una forma comparable a las etiquetas: Existían bajo ciertas vistas (pero notoriamente no en los diálogos de abrir y grabar archivos), pero el nombre de cada uno de los archivos tenía que ser único, dado que el direcorio al que pertenecía era básicamente sólo un atributo del archivo.
Y contrario a lo que dicta la intuición, el modelo de directorio plano no ha desaparecido: El sistema de almacenamiento en la nube ofrecido por el servicio Amazon S3 (Simple Storage Service, Servicio Simple de Almacenamiento) maneja únicamente objetos (comparable con nuestra definición de archivos) y cubetas (de cierto modo comparables con las unidades o volúmenes), y permite referirse a un objeto o un conjunto de objetos basado en filtros sobre el total que conforman a una cubeta.
Conforme se desarrollen nuevas interfaces al programador o al usuario, probablemente se popularicen más ofertas como la que hoy hace Amazon S3. Al día de hoy, sin embargo, el esquema jerárquico sigue, con mucho, siendo el dominante.
3.1.3 Directorios de profundidad fija
Las primeras implementaciones de directorios eran de un sólo nivel: El total de archivos en un sistema podía estar dividido en directorios, fuera por tipo de archivo (separando, por ejemplo, programas de sistema, programas de usuario y textos del correo), por usuario (facilitando una separación lógica de los archivos de un usuario de pertenecientes a los demás usuarios del sistema)
El directorio raiz (base) se llama en este esquema MFD (Master File Directory, Directorio Maestro de Archivos), y cada uno de los directorios derivados es un UFD (User File Directory, Directorio de Archivos de Usuario).
Directorio simple, limitado a un sólo nivel de profundidad
Este esquema resuelve el problema principal del nombre global único:
Antes de los directorios, cada usuario tenía que cuidar que los
nombres de sus archivos fueran únicos en el sistema, y ya teniendo
cada uno su propio espacio, se volvió una tarea mucho más simple. La
desventaja es que, si el sistema restringe a cada usuario a escribir
en su UFD, se vuelve fundamentalmente imposible trabajar en algún
proyecto conjunto: No puede haber un directorio que esté tanto dentro
de usr1
como de usr2
, y los usuarios encontrarán más dificil
llevar un proyecto conjunto.
3.1.4 Directorios estructurados en árbol
El siguiente paso natural para este esquema es permitir una jerarquía ilimitada: En vez de exigir que exista una capa de directorios, se le puede dar la vuelta al argumento, y permitir que cada directorio pueda contener a otros archivos o directorios a niveles arbitrarios. Esto permite que cada usuario (y que el administrador del sistema) estructure su información siguiendo criterios lógicos y piense en el espacio de almacenamiento como un espacio a largo plazo.
Directorio estucturado en árbol
Junto con esta estructura nacen las rutas de búsqueda (search path): Tanto los programas como las bibliotecas de sistema ahora pueden estar en cualquier lugar del sistema de archivos. Al definirle al sistema una ruta de búsqueda, el usuario operador puede desentenderse del lugar exacto en el que está determinado programa — El sistema se encargará de buscar en todos los directorios mencionados los programas o bibliotecas que éste requiera.11
3.1.5 El directorio como un grafo dirigido
Si bien parecería que muchos de los sistemas de archivos empleados hoy en día pueden modelarse suficientemente con un árbol, donde hay un sólo nodo raiz, y donde cada uno de los nodos tiene un sólo nodo padre, la semántica que ofrecen es en realidad un superconjunto estricto de esta: La de un grafo dirigido.
En un grafo dirigido como el presentado en la figura DIRdirectorioDAG, un mismo nodo puede tener varios directorios padre, permitiendo por ejemplo que un directorio de trabajo común sea parte del directorio personal de dos usuarios. Esto es, el mismo objeto está presente en más de un punto del árbol.
Directorio como un grafo dirigido acíclico: El directorio proyecto
está tanto en el directorio /home/usr1
como en el directorio /home/usr2
Un sistema de archivos puede permitir la organización como un grafo dirigido, aunque es común que la interfaz que presenta al usuario12 se restrinja a un grafo dirigido acíclico: Las ligas múltiples son permitidas, siempre y cuando no generen un ciclo.
La semántica de los sistemas Unix implementa directorios como grafos dirigidos por medio de dos mecanismos:
- Liga o enlace duro
- La entrada de un archivo en un directorio Unix es la
relación entre la ruta del archivo y el número de i-nodo en el sistema de archivos.13 Si a partir de un archivo
existente se crea una liga dura a él, ésta es
sencillamente otra entrada en el directorio apuntando
al mismo i-nodo. Ambas entradas, pues, son el mismo
archivo — No hay uno maestro y uno dependiente.
En un sistema Unix, este mecanismo tiene sólo dos restricciones:
- Sólo se pueden hacer ligas duras dentro del mismo volumen.
- No pueden hacerse ligas duras a directorios, sólo a archivos.14
- Liga o enlace simbólico
- Es un archivo especial, que meramente indica a
dónde apunta. El encargado de seguir este archivo
a su destino (esto es, de resolver la liga
simbólica) es el sistema operativo mismo; un
proceso no tiene que hacer nada especial para
seguir la liga.
Una liga simbólica puede apuntar a directorios, incluso creando ciclos, o a archivos en otros volúmenes.
Cuando se crea una liga simbólica, la liga y el archivo son dos entidades distintas. Si bien cualquier proceso que abra al archivo destino estará trabajando con la misma entidad, en caso de que éste sea renombrado o eliminado, la liga quedará rota (esto es, apuntará a una ubicación inexistente).
Si bien estos dos tipos de liga existen también en los sistemas
Windows15, en dichos sistemas sigue siendo más común emplear los
accesos directos. Se denomina así a un archivo (identificado por su
extensión, .lnk
), principalmente creado para poder apuntar a los
archivos desde el escritorio y los menúes — Si un proceso solicita al
sistema abrir el acceso directo, no obtendrá al archivo destino,
sino que al acceso directo mismo.
Ahora, si bien tanto las ligas duras como las ligas simbólicas existen también en Windows, su uso es muy poco frecuente. El API de Win32 ofrece las funciones necesarias, pero éstas no están reflejadas desde la interfaz usuario del sistema — Y son sistemas donde el usuario promedio no emplea una interfaz programador, sino que una interfaz gráfica. Las ligas, pues, no son más empleadas por cuestión cultural: En sus comunidades de usuarios, nunca fueron frecuentes, por lo cual se mantienen como conceptos empleados sólo por los usuarios avanzados.
Ya con el conocimiento de las ligas, y reelaborando la figura
DIRdirectorioDAG con mayor apego a la realidad: En los
sistemas operativos (tanto Unix como Windows), todo directorio tiene
dos entradas especiales: Los directorios .
y ..
, que aparecen tan
pronto como el directorio es creado, y resultan fundamentales para
mantener la navegabilidad del árbol.
Directorio como un grafo dirigido, mostrando los enlaces ocultos al directorio actual .
y al directorio padre ..
Como se puede ver en la figura DIRdirectorioDAGcompleto, en
todos los directorios, .
es una liga dura al mismo directorio, y
..
es una liga al directorio padre (de nivel jerárquico
inmediatamente superior). Claro está, como sólo puede
haber una liga ..
, un directorio enlazado desde dos lugares
distintos sólo apunta hacia uno de ellos con
su enlace ..
; en este caso, el directorio común proyecto
está
dentro del directorio /home/usr2
. La figura representa la liga simbólica desde /home/usr1
como una línea punteada.
Hay una excepción a esta regla: El directorio raiz. En este caso,
tanto .
como ..
apuntan al mismo directorio.
Esta es la razón por la cual no se puede tomar rigurosamente a un
árbol de archivos como a un grafo dirigido acíclico, ni en Windows
ni en Unix: Tanto las entradas .
(al apuntar al mismo directorio
donde están contentidas) como las entradas ..
(al apuntar al
directorio padre) crean ciclos.
3.2 Operaciones con directorios
Al igual que los archivos, los directorios tienen una semántica básica de acceso. Los directorios resultan también tipos de datos abstractos con algunas operaciones definidas. Muchas de las operaciones que pueden realizarse con los directorios son análogas a las empleadas para los archivos.16 Las operaciones básicas a presentar son:
- Abrir y cerrar
- Al igual que los archivos, los directorios deben
ser abiertos para trabajar con ellos, y cerrados cuando ya no
se les requiera. Para esto, en C, se emplean las funciones
opendir()
yclosedir()
. Estas funciones trabajan asociadas a un flujo de directorio (directory stream), que funciona de forma análoga a un descriptor de archivo. - Listado de archivos
- Para mostrar los archivos que conforman a un
directorio, el directorio se abre (tal como se haría con un
archivo, pero empleando la función
opendir()
en vez deopen()
), y va leyendo (conreaddir()
) cada una de sus entradas. Cada uno de los resultados es una estrcuturadirent
(directory entry, esto es, entrada de directorio), que contiene su nombre end_name
, un apuntador a su i-nodo end_ino
, y algunos datos adicionales del arcihvo en cuestión.Para presentar al usuario la lista de archivos que conforman un directorio, podría hacerse:
#include <stdio.h> #include <dirent.h> #include <sys/types.h> int main(int argc, char *argv[]) { struct dirent *archivo; DIR *dir; if (argc != 2) { printf("Indique el directorio a mostrar\n"); return 1; } dir = opendir(argv[1]); while ((archivo = readdir(dir)) != 0) { printf("%s\t", archivo->d_name); } printf("\n"); closedir(dir); }
Al igual que en al hablar de archivos se puede reposicionar (
seek()
) al descriptor de archivo, para rebobinar el descriptor del directorio al principio del listado se emplearewinddir()
. - Buscar un elemento
- Si bien en el transcurso del uso del sistema
operativo resulta una operación frecuente que el usuario solicite
el listado de archivos dentro de un directorio, resulta mucho más
frecuente buscar a un archivo en particular. La llamada
fopen()
antes descrita efectúa una búsqueda similar a la presentada en el ejemplo de código anterior, claro está, deteniéndose cuando encuentra al archivo en cuestión. - Crear, eliminar o renombrar un elemento
- Si bien estas operaciones
se llevan a cabo sobre el directorio, son invocadas a través de
la semántica orientada a archivos: Un archivo es creado con
fopen()
, eliminado conremove()
, y renombrado conrename()
.
3.2.1 Recorriendo los directorios
Es frecuente tener que aplicar una operación a todos los archivos dentro de cierto directorio — Por ejemplo, para agrupar a un directorio completo en un archivo comprimido, o para copiar todos sus contenidos a otro medio. Procesar todas las entradas de un directorio, incluyendo las de sus subdirectorios, se denomina recorrer el directorio (en inglés, directory traversal).
Si se trabaja sobre un sistema de archivos plano, la operación de recorrido completo puede realizarse con un programa tan simple como el presentado en la sección anterior.
Al hablar de un sistema de profundidad fija, e incluso de un directorio estructurado en árbol, la lógica se complica levemente, dado que para recorrer el directorio es necesario revisar, entrada por entrada, si esta es a su vez un directorio (y en caso de que así sea, entrar y procesar a cada uno de sus elementos). Hasta aquí, sin embargo, se puede recorrer el directorio sin requerir de mantener estructuras adicionales en memoria representando el estado.
Sin embargo, al considerar a los grafos dirigidos, se vuelve indispensable mantener en memoria la información de todos los nodos que ya han sido tocados — en caso contrario, al encontrar ciclo (incluso si este es creado por mecanismos como las ligas simbólicas), se corre el peligro de entrar en un bucle infinito.
Directorio basado en grafo dirigido que incluye ciclos
Para recorrer al directorio ilustrado como ejemplo en la figura
DIRarbolpararecorrer, no bastaría tomar nota de las rutas de
los archivos conforme son recorridas — Cada vez que los sean
procesados, su ruta será distinta. Al intentar respaldar al
directorio /home/jose/proyecto
, por ejemplo, el recorrido resultante
podría ser:
/home/jose/proyecto
/home/jose/proyecto/miembros
/home/jose/proyecto/miembros/jose
/home/jose/proyecto/miembros/jose/proyectos
/home/jose/proyecto/miembros/jose/proyectos/miembros
- …Y un etcétera infinito.
Para resolver esta situación, los programas que recorren directorios
en los sistemas de archivos reales deben emplear un indexado basado
en /i-nodo/17
identifica sin lugar a dudas a cada uno de los archivos. En el caso
presentado, si el i-nodo de jose
fuera 10543, al consultar a los
miembros de miembros
el sistema encontrará que su primer entrada
apunta al i-nodo 10543, por lo cual la registraría sólo como un
apuntador a datos ya archivados, y continuaría con la segunda
entrada del directorio, que apunta a pedro
.
3.2.2 Otros esquemas de organización
Por más que el uso de sistemas de archivos basados en directorios jerárquicos parece universal y es muy ampliamente aceptado, hay cada vez más casos de uso que apuntan a que se pueda estar por dar la bienvenida a una nueva metáfora de organización de archivos.
Hay distintas propuestas, y claro está, es imposible aún saber cuál dirección obtendrá el favor del mercado — O, dado que no necesariamente siga existiendo un modelo apto para todos los usos, de qué segmento del mercado.
3.3 Montaje de directorios
Para trabajar con el contenido de un sistema de archivos, el sistema operativo tiene que montarlo: Ubicarlo en algún punto del árbol de archivos visible al sistema y al usuario.
Es muy común, especialmente en los entornos derivados de Unix, que un sistema operativo trabaje con distintos sistemas de archivos al mismo tiempo. Esto puede obedecer a varias causas, entre las cuales se encuentran:
- Distintos medios físicos
- Si la computadora tiene más de una unidad de almacenamiento, el espacio dentro de cada uno de los discos se maneja como un sistema de archivos indepentiente. Esto es especialmente cierto en la presencia de unidades removibles (CDs, unidades USB, discos duros externos, etc.)
- Diferentes usos esperados
- Como se verá más adelante, distintos esquemas de organización (esto es, distintos sistemas de archivos) presentan ventajas para distintos patrones de uso. Por ejemplo, tiene sentido que una base de datos resida sobre una organización distinta a la de los programas ejecutables (binarios) del sistema.
- Abstracciones de sistemas no-físicos
- El sistema operativo puede
presentar diversas estructuras con una estructura de sistema de
archivos. El ejemplo más claro de esto es el sistema de archivos
virtual
/proc
, existente en los sistemas Unix, que permite ver diversos aspectos de los procesos en ejecución (y, en Linux, del sistema en general). Los archivos bajo/proc
no existen en ningún disco, pero se presentan como si fueran archivos estándar. - Razones administrativas
- El administrador del sistema puede
emplear sistemas de archivos distintos para aislar espacios de
usuarios entre sí: Por ejemplo, para evitar que un exceso de
mensajes enviados en la bitácora (típicamente bajo
/var/log
) saturen al sistema de archivos principal, o para determinar patrones de uso máximo por grupos de usuarios.
En los sistemas tipo Unix, el mecanismo para montar los archivos es el de un árbol con puntos de montaje. Esto es, todos los archivos y directorios del sistema operativo están estructurados en un único árbol. Cuando se solicita al sistema operativo montar un sistema de archivos en determinado lugar, éste se integra al árbol, ocultando todo lo que el directorio en cuestión previamente tuviera.18
Árbol formado del montaje de sda1
en la raiz, sda2
como /usr
, sdb1
como /home
, y el directorio virtual proc
La manera en que esto se presenta en sistemas Windows es muy distinta. Ahí, cada uno de los volumenes detectados recibe un identificador de volumen, y es montado automáticamente en un sistema de directorio estructurado como árbol de un sólo nivel representando a los dispositivos del sistema.19 Este árbol es presentado a través de la interfaz gráfica (aunque este nombre no significa nada para el API del sistema) como Mi PC.
Para especificar la ruta completa a determinado archivo, se inicia
con el identificador del volumen. De este modo, la especificación absoluta de un archivo es
una cadena como VOL:\Dir1\Dir2\Archivo.ext
— El caracter :
separa
al volumen del árbol del sistema de archivos, y el caracter
separa uno de otro a los directorios. Por convención, si
no se especifica la unidad, el sistema asumirá que se está haciendo
referencia a la unidad actual (a grandes rasgos, la última unidad en
ser utilizada).
Los identificadores de volumen están preasignados, muchos de ellos
según a un esquema heredado desde la época de las primeras PC: Los
volúmenes A
y B
están reservados para las unidades de disco
flexible; C
se refiere al disco duro de arranque, y las unidades
posteriores que va detectando el sistema son D
, E
, F
, etc.
Es posible modificar esta nomenclatura y configurar a los discos para estar en otra ubicación, pero muchas aplicaciones dependen ya de este comportamiento y configuración específica.
Vista de un sistema de archivos Windows
4 Sistemas de archivos remotos
Uno de los principales y primeros usos que se dio a la comunicación en red fue el de compartir archivos entre computadoras independientes. En un principio, esto se realizaba de forma explícita, con transferencias manuales a través de programas dedicados a ello, como sería hoy en día el FTP.
Por otro lado, desde mediados de los 1980, es posible realizar estas transferencias de forma implícita y automática, empleando sistemas de archivos sobre la red (o lo que es lo mismo, sistemas de archivos remotos). Éstos se presentan como caso particular de la abstracción de sistemas no-físicos que fueron mencionados en la sección anterior: Si bien el sistema operativo no tiene acceso directo a los archivos y directorios que le solicitará el usuario, a través de los módulos de red, sabe cómo obtenerlos y presentarlos como si fueran locales.
Al hablar de sistemas de archivos en red, casi siempre se hará siguiendo un modelo cliente-servidor. Estos términos no se refieren a las prestaciones relativas de una computadora, sino al rol que ésta juega dentro de cada conexión — Esto es, se designa como cliente a la computadora que solicita un servicio, y como servidor a la que lo provee; es frecuente que dos computadoras sean tanto servidor como cliente la una de la otra en distintos servicios.
4.1 Network File System (NFS)
El Sistema de Archivos en Red (Network File System, mejor conocido por sus siglas, NFS) fue creado por Sun Microsystems, y desde 1984 forma parte de su sistema operativo — Resultó una implementación tan exitosa que a los pocos años formaba parte de todos los sistemas tipo Unix.
NFS está construido sobre el mecanismo RPC (Remote Procedure Call, Llamada a Procedimientos Remotos), un mecanismo de mensajes y manejo básico de sesión que actúa como una capa superior a TCP/IP, incluyendo facilidades de descubrimiento de recursos y abstracción. RPC puede ser comparado con protocolos como DCE/RPC de OSF, DCOM de Microsoft, y hoy en día, SOAP y XML-RPC. Estos mecanismos permiten al programador delegar en un servicio el manejo de las conexiones de red, particularmente (en el caso particular aquí descrito) la persistencia de sesiones en caso de desconexión, y limitar su atención a una conexión virtual establecida.
La motivación de origen para la creación de NFS fue presentar una solución que aprovechara el hardware existente y centralizara la administración: Ofrecer las facilidades para contar con redes donde hubiera un servidor de archivos, y donde las estaciones de trabajo tuvieran únicamente una instalación básica,20 y el entorno de usuario completo estuviera disponible en cualquiera de las estaciones.
NFS ofrece sobre la red un sistema de archivos con la semántica Unix completa — Para montar un sistema remoto, basta montarlo21 y usarlo como si fuera local. El manejo de permisos, usuarios, e incluso las ligas duras y simbólicas se manejan exactamente como se haría localmente.
NFS es un protocolo muy ligero — No implementa cifrado ni verificaciones adicionales, pero al día de hoy, es uno de los mejores mecanismos para el envío de grandes cantidades de información — Pero siempre en redes que sean completamente confiables.
Ahora, NFS se presenta como uno de los componentes de una solución completa. Dado que se espera que la información de usuarios y permisos sea consistente en todos los clientes; Sun ofrecía también un esquema llamado Yellow Pages (posteriormente renombrado a NIS, Network Information System) para compartir la información de autenticación y listas de usuarios.
La desventaja, en entornos sin NIS, es que los permisos se manejan según el ID numérico del usuario. Si en diferentes sistemas el mismo usuario tiene diferentes IDs, los permisos no coincidirán. Es más, dado que el control de acceso principal es únicamente por dirección IP, para tener acceso irrestricto a los archivos de otros usuarios en NFS basta con tener control pleno de una computadora cualquiera en la red para poder asumir o usurpar la identidad de cualquier otro usuario.
Por último, para garantizar que las escrituras a archivos se llevaran a cabo cuando eran solicitadas (en contraposición a asumir éxito y continuar), todas las escrituras en un principio sobre NFS eran manejadas de forma síncrona, esto es, tras grabar un archivo, el cliente no continuaba con la ejecución hasta no tener confirmación por parte del servidor de que los datos estaban ya guardados en disco. Esto, si bien asegura que el usuario recibirá retroalimentación confiable respecto a la operación que realizó, ocasiona demoras que muchas veces son percibidas como excesivas.
Versiones posteriores del protocolo mejoraron sobre los puntos débiles aquí mencionados. Al día de hoy, casi 30 años después de su presentación, NFS es aún un sistema de archivos en red muy ampliamente empleado.
4.2 Common Internet File System (CIFS)
El equivalente a NFS en los entornos donde predominan los sistemas Windows es el protocolo CIFS (Common Internet File System, Sistema de Archivos Común para Internet). Aparece en los sistemas primarios de Microsoft alrededor de 199022, originalmente bajo el nombre SMB (Server Message Block, Bloque de Mensaje del Servidor).
Las primeras implementaciones estaban basadas en el protocolo NBF, frecuentemente conocido como NetBEUI, un protocolo no ruteable diseñado para redes pequeñas y entornos sencillos de oficina. A partir de Windows 2000 se ha reimplementado completamente para operar sobre TCP/IP. Es a partir de este momento que se le comienza a denominar CIFS, aunque el nombre SMB sigue siendo ampliamente utilizado.23
CIFS se ajusta mucho más a la semántica de los sistemas MS-DOS y Windows, aunque dado el lapso de tiempo que ha existido, ha pasado por varios cambios fundamentales, que al día de hoy complican su uso.
Para tener acceso a un volumen compartido por SMB se introdujo el
comando NET
;24 basta indicar a
DOS o Windows (desde la línea de comando) NET USE W: \\servidor\directorio
para que el recurso
compartido bajo el nombre directorio
dentro del equipo conocido como
servidor
aparezca en el árbol Mi PC, y el usuario pueda emplear
sus contenidos como si fuera un sistema de archivos local, con un
volumen asignado de W:
.
Cuando LAN Manager fue introducido al mercado, los sistemas Microsoft no manejaban aún el concepto de usuarios, por lo que la única medida de seguridad que implementaba SMB era el manejo de hasta dos contraseñas por directorio compartido: Con una, el usuario obtenía acceso de sólo lectura, y con la otra, de lectura y escritura. Tras la aparición de Windows NT, se agregó un esquema de identificación por usuaro/contraseña, que posibilita el otorgamiento de permisos con una granularidad mucho menor.25
SMB fue pensado originalmente para una red pequeña, con hasta un par de decenas de equipos. La mayor parte de los paquetes eran enviados en modo de difusión (broadcast), por lo que era fácil llegar a la saturación, y no existía un esquema centralizado de resolución de nombres, con lo que era frecuente no encontrar a determinado equipo.
Los cambios que CIFS presenta a lo largo de los años son muy profundos. Las primeras implementaciones presentan fuertes problemas de confiabilidad, rendimiento y seguridad, además de estar planteadas para su uso en un sólo tipo de sistema operativo; al día de hoy, estos puntos han todos mejorado fuertemente. En sistemas Unix, la principal implementación, Samba, fue creada haciendo ingeniería inversa sobre el protocolo; a lo largo de los años, se ha convertido en un esquema tan robusto que es hoy por hoy tomado como implementación refrencia.
4.3 Sistemas de archivos distribuídos: Andrew File System (AFS)
Los dos ejemplos de sistema de archivos en red presentados hasta ahora comparten una visión tradicional del modelo cliente-servidor: Al ver el comando que inicializa una conexión, e incluso a ver la información que guarda el núcleo del cliente respecto a cualquiera de los archivos, resulta claro cuál es el servidor para cada uno de ellos.
Andrew File System, desarrolaldo en la Carnegie Mellon University26 y publicado en 1989, plantea presentar un verdadero sistema de archivos distribuído, en el cual los recursos compartidos no tengan que estar en un servidor en particular, sino que un conjunto de equipos se repartan la carga (esto es, agnosticismo a la ubicación). AFS busca también una fácil escalabilidad, la capacidad de agregar tanto espacio de almacenamiento como equipos con rol de servidor. AFS permite inclusive migrar completamente un volumen mientras está siendo empleado, de forma transparente.
Ante la complejidad e inestabilidad adicional que presentan con tanta frecuencia las redes grandes27 (y lo hacían mucho más hace 30 años): AFS debe operar tan confiablemente como sea posible, incluso sin la certeza de que la red opera correctamente.
AFS construye fuertemente sobre el modelo de tickets y credenciales de Kerberos,28 pero se aleja sensiblemente de la semántica de operación de archivos que hasta ahora se han presentado. Muchos eventos, operaciones y estados van ligados al momento en el tiempo en que se presentan, a través de un modelo de consistencia débil (weak consistency model). Muy a grandes rasgos, esto significa que:
- Cuando se abre un archivo, éste se copia completo al cliente. Todas las lecturas y escrituras (a diferencia de los esquemas tradicionales, en que éstas son enviadas al servidor lo antes posible y de forma síncrona) se dirigen únicamente a la copia local.
- Al cerrar el archivo, éste se copia de vuelta al servidor de origen, el cual se compromete a notificar a los clientes si un archivo abierto fue modificado (esto es, a hacer una llamada o callback). Los clientes pueden entonces intentar incorporar los cambios a su versión de trabajo, o continuar con la copia ya obtenida — Es esperable que si un segundo cliente realiza alguna modificación, incorpore los cambios hechos por el primero, pero esta responsabilidad se deja a la implementación del programa en cuestión.
Esto significa en pocas palabras que los cambios a un archivo abierto por un usuario no son visibles a los demás de inmediato; sólo una vez que se cierra un archivo, los cambios hechos a éste son puestos a disposición de las sesiones abiertas actuales, y sólo son enviados como versión actual a las sesiones abiertas posteriormente.
Con este cambio semántico, debe quedar claro que AFS no busca ser un sistema para todo uso ni un reemplazo universal de los sistemas de archivos locales, en contraposición de los sistemas de archivos centralizados. AFS no plantea en ningún momento una operación diskless. Bajo el esquema aquí descrito, las lecturas y escrituras resultan baratas, porque se realizan exclusivamente sobre el caché local, pero abrir y cerrar un archivo puede ser muy caro, porque debe transferirse el archivo completo.
Hay aplicaciones que verdaderamente sufrirían si tuvieran que implementarse sobre un sistema de archivos distribuído — Por ejemplo, si una base de datos se distribuyera sobre AFS, la carencia de mecanismos de bloqueo sobre secciones del archivo, y el requisito de operar sobre archivos completos harían impracticable compartir un archivo de uso intensivo y aleatorio.
5 Otros recursos
- File System Interface: Functions for manipulating files
https://www.gnu.org/software/libc/manual/html_node/File-System-Interface.html
The GNU C Library manual (Free Software Foundation) - Disks from the Perspective of a File System
http://queue.acm.org/detail.cfm?id=2367378
Marshall Kirk McKusick (2012); ACM Queue- Traducción al español: Los discos desde la perspectiva de un sistema de archivos
http://cyanezfdz.me/post/los-discos-desde-la-perspectiva-de-un-sistema-de-archivos
César Yáñez (2013).
- Traducción al español: Los discos desde la perspectiva de un sistema de archivos
- File-system development with stackable layers
https://dl.acm.org/citation.cfm?id=174613.174616
Heidemann y Popek (1994); ACM Transactions on Computer Systems - Serverless network file systems
https://dl.acm.org/citation.cfm?doid=225535.225537
Thomas E. Anderson et. al. (1996); ACM Transactions on Computer Systems - OpenPlanets Results Evaluation Framework
http://data.openplanetsfoundation.org/ref/
David Tarrant (2012). Muestra la evolución a lo largo de los años de cómo reconocen archivos de tipos conocidos varias herramientas - Finding open files with lsof
http://www.ibm.com/developerworks/aix/library/au-lsof.html)
Sean A. Walberg (2006); IBM DeveloperWorks
Pies de página:
1 Existen otros mecanismos para su organización, pero estos no están tan ampliamente difundidos
2 Esto será abordado en la sección DIRmontajedirectorios
3 Como se verá en la sección FSvolumenescrudos, esto no es necesariamente así, sin embargo, el uso de los dispositivos en crudo es muy bajo. Este capítulo está enfocado exclusivamente al uso estructurado en sistemas de archivos.
4 No sólo los archivos reciben descriptores de
archivo. Por ejemplo, en todos los principales sistemas
operativos, los descriptores 0, 1 y 2 están relacionados a
flujos de datos: respectivamente, la entrada estándar
(STDIN
), la salida estándar (STDOUT
) y el error estándar
(STDERR
); si el usuario no lo indica de otro modo, la terminal
desde donde fue ejecutado el proceso.
5 Esto explica por qué en Windows es tan común que el sistema mismo rechace hacer determinada operación porque el archivo está abierto por otro programa (bloqueo mandatorio compartido), mientras que en Unix esta responsabilidad recae en cada uno de los programas de aplicación
6 Por ejemplo, imprimir un archivo binario resulta en una gran cantidad de hojas inútiles, particularmente tomando en cuenta que hay caracteres de control como el ASCII 12 (avance de forma, form feed), que llevan a las impresoras que operan en modo texto a iniciar una nueva página; llevar a un usuario a correr un archivo ejecutable disfrazado de un documento inocuo, como se verá a continuación, fue un importante vector de infección de muchos virus.
7 Una de las ventajas de este esquema es que cada administrador de sistema puede ampliar la lista con las huellas digitales que requiera localmente
8 Esta lógica es herencia de las máquinas de escribir manuales, en que el salto de línea (avanzar el rodillo a la línea siguiente) era una operación distinta a la del retorno de carro (devolver la cabeza de escritura al inicio de la línea). En la época de los teletipos, como medida para evitar que se perdieran caracteres mientras la cabeza volvía hasta la izquierda, se decidió separar el inicio de nueva línea en los dos pasos que tienen las máquinas de escribir, para inducir una demora que evitara la pérdida de información.
9 La sección HWsistunix define los dispositivos de caracteres y /de bloques.
10 El soporte de jerarquías de directorios fue introducido apenas en la versión 2, junto con el soporte a discos duros de 10MB, acompañando al lanzamiento de la IBM PC modelo XT.
11 La ruta de búsqueda refleja la organización del sistema de archivos en el
contexto de la instalación específica. Es común que la ruta de
búsqueda de un usuario estándar en Unix sea similar a
/usr/local/bin:/usr/bin:/bin:~/bin
— Esto significa que cualquier
comando que sea presentado es buscado, en el orden indicado, en los
cuatro directorios presentados (separados por el caracter :
, la
notación ~
indica el directorio personal del usuario activo). En
Windows, es común ver una ruta de búsqueda
c:\WINDOWS\system32;c:\WINDOWS
12 Esta simplificación es simplemente una abstracción, y contiene una pequeña mentira, que será desmentida en breve.
13 El significado y la estructura de un i-nodo se abordan en el capítulo FS.
14 Formalmente, puede haberlas, pero sólo el administrador puede crearlas; en la sección DIRdirtraversal se cubre la razón de esta restricción al hablar de recorrer los directorios.
15 Únicamente en aquellos que emplean el sistema de archivos NTFS, no en los que utilizan alguna de las variantes de FAT
16 De hecho, en muchos sistemas de archivos los directorios son meramente archivos de tipo especial, que son presentados al usuario de forma distinta. En la sección FSeldirectorio se presenta un ejemplo.
17 Que si bien no ha sido definido aún formalmente, para esta discusión bastará saber que es un númeo único por volumen.
18 Hay implementaciones que exigen que el montaje se realice exclusivamente en directorios vacíos; existen otras, como UnionFS, que buscan seguir presentando una interfaz de lectura a los objetos que existían en el directorio previo al montaje, pero realizan las escrituras únicamente en el sistema ya montado; estas complican fuertemente algunos aspectos semánticos, por lo cual resultan poco comunes.
19 En realidad, este árbol no sólo incluye a los volúmenes de almacenamiento, sino que a los demás dispositivos del sistema, como los distintos puertos, pero los oculta de la interfaz gráfica.
20 Incluso manejando estaciones de trabajo diskless, esto es, computadoras sin disco duro, cuyo sistema de arranque tiene la capacidad de solicitar al servidor le envíe incluso el núcleo del sistema operativo que ejecutará
21 Para
montar un sistema remoto, se emplea un comando como mount archivos.unam.mx:/ext/home /home
, con lo cual el directorio
/ext/home
ubicado en el servidor archivos.unam.mx
aparecerá
montado como directorio /home
local.
22 El desarrollo de SMB nació como LAN Manager, originalmente para OS/2
23 Es debido a este nombre que la implementación de CIFS para sistemas Unix, Samba, fue llamado de esta manera.
24 Este comando es empleado en MS-DOS, pero está también disponible en Windows, y al día de hoy es una de las principales herramientas para administrar usuarios.
25 Esto significa, que puede controlarse el acceso permitido más finamente, a nivel archivo individual y usuario individual.
26 Como parte del Proyecto Andrew, denominado así por el nombre de los fundadores de esta universidad: Andrew Carnegie y Andrew Mellon
27 El uso típico de AFS se planteaba para organizaciones grandes, del orden de decenas de miles de estaciones
28 Un sistema de autenticación y autorización centralizado para entornos corporativos.