• No se han encontrado resultados

Concepto de archivo

In document Conceptos de Sistemas Operativos (página 141-146)

Las computadoras pueden almacenar información en varios medios diferentes, tales como discos magnéticos, cintas magnéticas, y discos ópticos. Para que al sistema le sea conveniente usar este sistema de archivos, el sistema operativo provee una vista uniforme de ésta información almacenada. El sistema operativo abstrae las propiedades físicas de los dispositivos de almacenamiento definiendo una unidad de almacenamiento lógico, el archivo. Los archivos son mapeados, por el sistema operativo, en dispositivos físicos. Estos dispositivos de almacenamiento son usualmente no volátiles, por lo que su contenido persiste aunque haya un fallo de energía y se deba reiniciar el sistema.

Un archivo es una colección de información relacionada que se graba sobre almacenamiento secundario. Comúnmente, los archivos representan programas (tanto de la forma fuente como de la forma objeto) y datos. Los archivos de datos pueden ser numéricos, alfabéticos, alfanuméricos, o binarios. Los archivos pueden ser de forma libre tales como los archivos de texto, o pueden estar rígidamente formateados. En general, un archivo es una secuencia de bits, bytes o líneas, el cual su significado esta definido por el creador de archivo y el usuario.

La información de un archivo esta definida por el creador. Muchos tipos diferentes de información se pueden almacenar en un archivo: programas fuente, programas objeto, programas ejecutables, datos numéricos, textos, imágenes grafica, sonidos, etc. Un archivo tiene una estructura definida de acuerdo a su tipo. Un archivo de texto es una secuencia de caracteres organizado en líneas (y posiblemente páginas); un archivo fuente es una secuencia de subrutinas y funciones, cada una además organizada como declaraciones seguidas de sentencias ejecutables; un archivo objeto es una secuencia de bytes organizados en bloques comprensibles para el linker del sistema, un archivo ejecutable es una serie de secciones de código que el cargador puede traer a memoria y ejecutar.

Atributos de un archivo: un archivo tiene un nombre y es referenciado por tal nombre. Un nombre es usualmente un string de caracteres. Cuando un archivo recibe un nombre, este se independiza del proceso, del usuario y aun del sistema donde fue creado. Por ejemplo, un usuario puede crear un archivo llamado “example.c”, mientras que otro usuario puede modificar dicho archivo por medio de especificar su nombre. El dueño del archivo puede escribir el archivo en un disquete y leerlo en otro sistema, donde aun este puede seguir llamándose “example.c”.

Un archivo tiene otros atributos que son:

Nombre. Tipo. Ubicación. Tamaño. Protección.

Hora, día, e identificación del usuario: esta información puede ser mantenida para la

creación, la ultima modificación, y el último uso. Estos datos son muy útiles para la protección, seguridad, y monitoreo del uso.

La información sobre todos los archivos es mantenida en la estructura de directorio que también reside en el almacenamiento secundario. Puede tomar desde 16 a más de 1000 bytes para grabar la información de cada archivo. En un sistema con muchos archivos, el tamaño del directorio puede ser de megabytes. Ya que los directorios, como los archivos, deben ser no volátiles, deben ser almacenados en el dispositivo secundario y traídos a memoria gradualmente a medida que se necesite.

Operaciones sobre los archivos: un archivo es un tipo de dato abstracto. Para definir un archivo, necesitamos considerar las operaciones que se pueden realizar sobre él. El sistema operativo provee llamadas al sistema para crear, escribir, leer, reubicación en el archivo, eliminar, y truncar un archivo. A continuación se verán cuales son las operaciones que debe tomar el sistema operativo para poder realizar cada una de las acciones anteriores:

Crear un archivo: Se necesitan dos pasos para crear un archivo. Primero, se debe encontrar espacio

en el sistema de archivos para este nuevo archivo. Segundo, se debe hacer en el directorio una nueva entrada para este nuevo archivo. Las entradas del directorio graban el nombre del archivo y el lugar en el sistema de archivo.

Escribir un archivo: Para escribir un archivo, se hace una llamada al sistema especificando tanto el

nombre del archivo, y la información a escribir en el archivo. Dando el nombre del archivo, el sistema busca en el directorio para localizar el archivo. El sistema debe mantener un puntero de escritura para ubicar en el archivo donde será la próxima escritura. El puntero de escritura debe ser cambiado siempre que ocurre una escritura.

Leer un archivo: Para leer desde un archivo, usamos una llamada al sistema que especifica el

nombre del archivo y donde (en memoria) será puesto el siguiente bloque de archivo. Una vez más, se debe hacer una búsqueda en el directorio y el sistema debe mantener un puntero de lectura para ubicar en el archivo donde tomara lugar la siguiente lectura. Una vez que la lectura toma lugar, se debe modificar el puntero de lectura. Ya que, en general, un archivo o esta siendo leído o esta siendo escrito, la mayoría de los sistemas mantienen un puntero a la ubicación actual en el archivo. Las operaciones de lectura y escritura usan el mismo puntero, ahorrando lugar y reduciendo la complejidad del sistema.

Reubicación en el archivo: Se busca en el directorio la entrada apropiada y la actual posición del

puntero en el archivo se setea al valor indicado. La reubicación en un archivo no necesita ninguna operación de I/O. Esta operación es conocida como seek.

Eliminar un archivo: Para eliminar un archivo, se busca en el directorio el nombre del archivo.

Habiendo encontrado éste, se libera todo el espacio que utilizaba el archivo (para que pueda ser usado por otros archivos) y se borra la entrada en el directorio.

Truncar un archivo: Existen ocasiones donde el usuario quiere que los atributos de un archivo

queden iguales, pero quiere borrar el contenido del archivo. En lugar de forzar al usuario a eliminar el archivo y luego recrearlo, ésta función permite que todos los atributos del archivo queden sin cambiar (excepto por el largo del archivo) pero el largo del archivo es reseteado a cero.

Estas seis operaciones básicas son el mínimo conjunto de operaciones requeridas para archivos. Otras operaciones comunes incluyen agregar nueva información al final de un archivo existente, y renombrar un archivo existente. Estas operaciones primitivas pueden entonces ser combinadas para realizar otras operaciones de archivos. Por ejemplo, crear una copia de un archivo, o copiar el archivo en otro dispositivo de I/O, tal como una impresora o una pantalla, puede ser llevado a cabo por medio de la creación de un nuevo archivo y leyendo desde el archivo vejo y escribiendo en el nuevo. También se desea que haya operaciones que permitan a un usuario obtener los atributos de un archivo y setear alguno de estos atributos. Por ejemplo, podemos desear tener una operación que permita a un usuario determinar el estado de un archivo, tal como su tamaño, y tener una operación que permita al usuario setear los atributos del archivo, tal como el dueño del mismo.

La mayoría de las operaciones de archivos mencionadas involucran la búsqueda en el directorio para la entrada asociada con el nombre del archivo. Para evitar esta constante búsqueda, muchos sistemas primero abrirán el archivo cuando es usado por primera vez. El sistema operativo mantiene una pequeña tabla conteniendo la información sobre todos los archivos abiertos (la tabla de archivos abiertos). Cuando se requiere una operación sobre un archivo, se usa un índice en esta tabla, por lo que no se requiere búsqueda alguna. Cuando un archivo no es usado por un largo tiempo, éste es cerrado por el proceso y el sistema operativo elimina su entrada de la tabla de archivos abiertos.

Algunos sistemas implícitamente abren un archivo cuando se hace la primer referencia. El archivo es automáticamente cerrado cuando el programa que lo abrió termina. La mayoría de los sistemas, sin embargo, requieren que el archivo sea abierto explícitamente por el programador por medio de una llamada al sistema (open) antes de que sea usado. La operación open toma un nombre de un archivo y busca en el directorio, copiando la entrada del directorio en la tabla de archivos abiertos, asumiendo que la protección del archivo permite hacer dicho acceso. La llamada al sistema open típicamente retornara un puntero a la entrada en la tabla de archivos abiertos. Este puntero, no el actual nombre de archivo, es usado en las operaciones de I/O, evitando cualquier búsqueda adicional, y simplificando la interfaz de la llamada al sistema.

La implementación de las operaciones open y close en un entorno multiusuario, tal como UNIX, es más complicada. En tales sistemas, varios usuarios pueden abrir el archivo al mismo tiempo. Típicamente, el sistema operativo usa dos niveles de tablas internas. Hay una tabla por proceso de todos los archivos que el proceso tiene abiertos. Almacenada en esa tabla esta la información con respecto al uso del archivo por el proceso. Por ejemplo, se encuentra el puntero actual del archivo, indicando el lugar en el archivo en el cual se realizara la siguiente lectura o escritura.

Cada entrada en la tabla de archivos del proceso a su vez apunta a una tabla de los archivos abiertos en el sistema (systemwide). Dicha tabla contiene la información del archivo que es independiente del proceso, tal como el lugar del archivo en el disco, días de acceso, y tamaño del archivo. Una vez que ya se abrió un archivo por el proceso, en caso de que otro proceso realice una llamada al sistema open con el mismo nombre de archivo, simplemente resultara agregar una nueva entrada en la tabla de archivos abiertos para el proceso, con un nuevo puntero de posición del archivo, y un puntero en la entrada correspondiente de la systemwide. Típicamente, la tabla de archivos abiertos del sistema tiene un contador para cada entrada, el cual indica la cantidad de procesos que tienen abierto dicho archivo. Cada llamada close decrementa dicha cantidad, y cuando el contador llega a cero significa que el archivo ya no esta en uso por lo que la entrada de tal en la tabla systemwide es eliminada. En resumen, existen varias piezas asociadas con cada archivo:

Puntero de archivo: el puntero es único para cada proceso operando en el archivo y, por lo tanto,

debe estar separado de los atributos del archivo que están en disco.

Contador de archivo abierto: a medida que los archivos se van cerrando, el sistema debe eliminar la

entrada de dicho archivo de la tabla systemwide. Ya que varios procesos pueden abrir el mismo archivo, el sistema debe esperar hasta el último close para poder eliminar la entrada para el archivo en la tabla de archivos abiertos del sistema. Este contador lleva pista del número de opens y closes, y alcanza un cero en el último close. Así, el sistema puede eliminar la entrada.

Ubicación en el disco del archivo: la mayoría de las operaciones que se hacen sobre un archivo

necesitan que se modifique el mismo. La información necesaria para ubicar el archivo en disco es mantenida en memoria para evitar tener que leerla desde el disco para cada operación que se haga. Algunos sistemas operativos proveen un mecanismo para bloquear secciones de archivos abiertos para los accesos de múltiples procesos, para compartir secciones de un archivo entre varios procesos, y aun para mapear secciones de un archivo en memoria en un sistema de memoria virtual. Esta última función es llamada memory mapping, y permite que parte del espacio de direcciones virtuales se asocie lógicamente con una sección del archivo. Las escrituras y lecturas a ésta región de memoria son tratadas como lecturas y escrituras en el archivo, simplificando en gran manera el uso del archivo. Cerrar el archivo significa que toda la parte de la memoria que fue mapeada es escrita en disco y se elimina de la memoria virtual del proceso. Múltiples procesos pueden estar autorizados a realizar el mapeo de la misma sección del archivo

en el espacio de memoria virtual de cada proceso, para conseguir compartir los datos. Cualquier escritura que se haga por algún proceso modifica los datos de la memoria virtual y puede ser vista por todos los demás procesos que mapearon la misma sección del archivo. Esta forma de compartir información se implementa de la siguiente manera (recordar capitulo 9): cada parte compartida del mapeo de la memoria virtual de cada proceso apunta a la misma página de la memoria física (la página que mantiene una copia del bloque del disco). Ya que los accesos a la parte compartida deben ser coordinados, los procesos involucrados pueden usar uno de los mecanismos de exclusión mutua que se vieron en el capítulo 6 (Figura 10.1).

Tipos de archivos: una consideración importante es si el sistema operativo puede reconocer tipos. Si un sistema operativo puede reconocer de qué tipo es un archivo, entonces puede operar sobre éste de diferentes maneras. Por ejemplo, un error común ocurre cuando un usuario trata de imprimir la forma de un programa en objeto binario. Este intento normalmente produce basura, pero puede ser prevenido si el sistema operativo sabe de que tipo es el archivo.

Una técnica común para implementar los tipos de archivos es que tengan el tipo como parte del nombre. El nombre se divide en dos partes (un nombre y una extensión separado por un punto). Así, un usuario y el sistema operativo pueden decir no solo cual es el nombre del archivo sino también de que tipo es. Por ejemplo, en MS-DOS el nombre consiste de hasta 8 caracteres seguidos de un punto y terminados por una extensión de 3 caracteres. El sistema usa la extensión para conocer el tipo de archivo y el tipo de operaciones que se le pueden aplicar. Por ejemplo, solo las extensiones “.com, “.ese”, o “.bat” pueden ser ejecutadas. MS-DOS reconoce poca cantidad de extensiones, pero los programas de aplicación también usan la extensión para indicar los tipos de archivos en el cual están interesados. Por ejemplo, los assemblers esperan tener como entrada un archivo de extensión “.asm”, y el procesador de texto WordPerfect espera que sus archivos terminen en “.wp”. Las extensiones no se requieren ya que el usuario se puede referir a un archivo sin la extensión y la aplicación buscara un archivo con el nombre dado. Ya que éstas extensiones no son soportadas por el sistema operativo, son consideradas como “indirectas” a las aplicaciones el cual operan sobre ellas.

Otro ejemplo de la utilidad de los tipos de archivos viene del sistema operativo TOPS-20. Si el usuario trata de ejecutar el programa objeto el cual su fuente ha sido modificado desde que el archivo objeto fue

1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 3 6 2 4 5 1 Memoria virtual del proceso A Memoria virtual del proceso B Archivo en disco Memoria física

realizado, el archivo fuente será recompilado automáticamente. Esta función asegura que el usuario siempre correrá la versión más actual del archivo objeto. Note que esta opción es posible solo si el sistema operativo discrimina el archivo fuente del archivo objeto, ya que debe chequear la fecha de cada archivo de la última modificación o creación, y determinar el lenguaje del programa fuente (para elegir el compilador correcto).

Consideremos el sistema operativo Macintosh. En este sistema, cada archivo tiene un tipo, tal como “text” o “pict”. Cada archivo tiene un atributo creador el cual contiene el nombre del programa que lo creo. Este atributo es seteado por el sistema operativo durante la llamada de creación. Por ejemplo, un archivo producido por un procesador de texto tiene el nombre del procesador de texto como su creador. Cuando el usuario lo abre, haciendo doble clic del mouse en el icono, el procesador de texto es invocado automáticamente, y el archivo se carga, listo para ser editado.

El sistema UNIX es incapaz de proveer tales características ya que utiliza un número mágico almacenado en el comienzo de algún archivo que indica el tipo de archivo: programa ejecutable, archivo batch, etc. No todos los archivos tienen este número mágico, por lo que las características del sistema no se pueden basar solo en este tipo de información. UNIX no registra el nombre del creador del programa.

Estructura del archivo: Los tipos de archivos también pueden ser usados para indicar la estructura interna del archivo. Los archivos objeto y fuente tiene estructuras que coinciden con la forma que esperan los programas que leen estos tipos de archivos. Además, algunos archivos se deben ajustar a ciertas estructuras que es conocida por el sistema operativo. Por ejemplo, el sistema operativo puede requerir que un archivo ejecutable tenga una estructura especifica para que pueda determinar donde cargarlo en memoria y donde se encuentra la primer instrucción.

Aparece la primer desventaja de que un sistema operativo soporte varias estructuras de archivos: el tamaño del sistema operativo es incomodo. Si el sistema operativo define cinco tipos diferentes de estructuras, necesita contener el código para soportar estos cinco tipos. Graves problemas pueden surgir de que nuevas aplicaciones requieran información estructurada en formas de que el sistema operativo no soporta.

Por ejemplo, asumamos que el sistema operativo soporta dos tipos de archivos: archivos de texto (compuestos por caracteres ASCII separados por espacios y enters) y archivos binarios ejecutables. Ahora, si nosotros como usuarios queremos crear otra estructura de archivo, el cual no se parece a un archivo de texto ni a un archivo binario, debemos engañar o emplear de mala manera los mecanismos de tipos de archivos del sistema operativo (ya que debemos elegir uno de los dos tipos), o modificar o abandonar nuestro proyecto de nueva estructura de archivo.

Algunos sistemas operativos soportan una pequeña cantidad de estructuras de archivos. Este es el caso de UNIX y MS-DOS. UNIX considera a cada archivo como una secuencia de bytes de 8 bits cada byte; la interpretación de estos bytes no es realizada por el sistema operativo. Este esquema provee máxima flexibilidad pero poco soporte. Cada programa de aplicación debe incluir su propio código para ser interpretado y ubicar el archivo en la estructura apropiada. Sin embargo, todos los sistemas operativos deben soportar al menos una estructura (que es un archivo ejecutable) para que el sistema sea capaz de cargar y correr programas.

Estructura interna del archivo: internamente, ubicar un offset en el archivo puede ser complicado para el sistema operativo. Los sistemas de disco tienen un tamaño de bloque bien definido (registro físico), y todos los bloques son del mismo tamaño. No es seguro que el tamaño del registro físico coincida exactamente con el tamaño del registro lógico. Además, los registros lógicos pueden variar en tamaño. Empaquetar un número de registros lógicos en bloques físicos es una solución común para este problema. Por ejemplo, UNIX define a todos los archivos para que sean un stream de bytes. Cada byte es individualmente direccionable por su offset desde el inicio (o fin) del archivo. En este caso, el registro lógico es 1 byte. El sistema de archivo automáticamente empaqueta o des-empaqueta los bytes en un bloque de disco físico (digamos, 512 bytes por bloque) como sea necesario.

El tamaño del registro lógico, el tamaño del registro físico, y la técnica de empaquetamiento determinan cuantos registros lógicos habrá en cada bloque físico. El empaquetado puede ser realizado por alguna

In document Conceptos de Sistemas Operativos (página 141-146)