Tema 3. Manejo de Ficheros Ordinarios.

1. ENTRADA/SALIDA SOBRE FICHEROS ORDINARIOS

APERTURA DE UN FICHERO (OPEN)

Open es la llamada para indicarle al núcleo que habilite las estructuras necesarias para trabajar con un fichero especificado con una ruta. El núcleo devolverá un descriptor de fichero con el que podremos referenciar el fichero para las llamadas posteriores. La declaración de open es:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open (char *path, int flag [, mode_t mode]);

path puntero a la ruta del fichero que se quiere abrir. Puede ser absoluta o relativa y la longitud no puede exceder de PATH_MAX bytes.

Flags es una mascara de bits que le indica al núcleo como queremos que se abra el fichero. Solamente uno de los bits debe estar presente ( O_RDONLY, O_WRONLY u O_DRWR ) al componer la mascara, sino el modo de apertura quedaría indefinido. Los flags más significativos son:

  • O_RDONLY, abrir en modo sólo lectura.
  • O_WRONLY, abrir en modo sólo escritura.
  • O_RDWR, abrir para leer y escribir.
  • O_NDELAY, este indicador afectará a futuras llamadas de lectura/escritura.

    En relación con O_NDELAY, cuando abrimos una tubería con nombre y activamos el modo O_RDONLY u O_WRONLY:

    • Si O_NDELAY está activo: Un open en modo sólo lectura regresa inmediatamente. Un open en modo sólo escritura devuelve un error si en el instante de apertura no hay otro proceso que tenga abierta la tubería en modo sólo lectura.
    • Si O_NDELAY no está activo: Un open en modo sólo lectura no devuelve el control hasta que un proceso no abre la tubería para escribir en ella. Un open en modo sólo escritura no devuelve el control hasta que un proceso no abre la tubería para leer de ella.

      Si el fichero que queremos abrir está asociado con una línea de comunicaciones:
    • Si O_NDELAY está activo, open regresa sin esperar por la portadora -llamada no bloqueante--.
    • Si O_NDELAY está inactivo, open no regresa hasta que detecta la portadora -llamada bloqueante-
  • O_APPEND, el puntero de lectura/escritura del fichero se sitúa al final del mismo antes de empezar la escritura. Así garantizamos que lo escrito se añade al final del fichero.
  • O_CREAT, si el fichero que queremos abrir ya existe, este indicador no tiene efecto, excepto en lo que se indicará para el indicador O_EXCL.El fichero es creado en caso de que no exista y se creara con los permisos indicados en el parametro mode.
  • O_EXCL, si está presente el indicador O_CREAT,open devuelve un código de error cuando el fichero ya existe.
  • O_TRUNC, si el fichero existe, trunca su longitud a cero bytes, incluso si el fichero se abre para leer.

Mode es el tercer parámetro de open y sólo tiene significado cuando está activo el indicador O_CREAT. Le indica al núcleo qué permisos tendrá el fichero que va a crear. Mode es también una máscara de bits y se suele expresar en octal mediante un número de dígitos. El primero de los dígitos hace referencia a los permisos de lectura, escritura y ejecución para el propietario del fichero; el segundo se refiere a los mismos permisos para el grupo de usuarios al que pertenece el propietario, y el tercero se refiere a los permisos del resto de usuarios. Así, por ejemplo, 0644 -110 100 100- indica permisos de lectura y escritura para el propietario, y permiso de lectura para el grupo y para el resto de usuarios. Si el núcleo realiza satisfactoriamente la apertura del fichero, open devolverá un descriptor de fichero. En caso contrario, devolverá -1 y en la variable errno pondrá el valor del tipo de error producido.

Los siguientes son ejemplos de apertura de ficheros:

int fd;
----
fd = open ("mifichero", O_RDONLY); / / Abre un fichero para leer datos de él.
fd = open ("mifichero", O_WRONLYI O_TRUNC I O_CREAT, 0600);
/ / Abre un fichero para escribir datos en él. Si el fichero existe, trunca su tamaño
/ / a 0 bytes. Si el fichero no existe, lo crea con permiso de lectura y escritura para
/ / el propietario y ningún permiso para el grupo y demás usuarios.
fd = open ("miiichero", RDWR | O_APPEND);
/ / Abre un fichero en modo lectura/escritura y fuerza a que el puntero de
/ / Lectura/escritura se sitúe al final del fichero.

LECTURA DE DATOS DE UN FICHERO (READ)

Read es la llamada que emplearemos para leer datos de un fichero. Su declaración es la siguiente:

#include <unistd.h>
int read (int i ildes, char *bui, unsigned nbyte) ;

Read lee nbyte bytes del fichero asociado al descriptor fildes y los coloca en la memoria intermedia apuntada por buf. Si la lectura se lleva a cabo correctamente, read devuelve el número de bytes realmente leídos y copiados en la memoria intermedia. Este número puede ser menor que nbyte en el caso de que el fichero esté asociado a una línea de comunicaciones, o de que quedasen menos de nbyte bytes por leer.

Cuando se intenta leer más allá del final del fichero, read devuelve el valor O. Sólo en el caso de que read falle, devuelve el valor -1y errno contendrá el tipo de error que se ha producido. En los ficheros con capacidad de acceso aleatorio, la lectura empieza en la posición indicada por el puntero de lectura/escritura del fichero. Este puntero queda actualizado después de efectuar la lectura. En los ficheros asociados a dispositivos sin capacidad de acceso aleatorio -por ejemplo, líneas serie-, read siempre lee de la misma posición y el valor del puntero no tiene significado. Los siguientes ejemplos muestran algunas formas de invocar a read. En estos ejemplos suponemos que id es el descriptor de un fichero correctamente abierto.

char mem [4096];
int nbytes, fd;
.......
nbytes = read (fd, mem, sizeof (mem));

/ / Lee 4.096 bytes que se almacenan en mem La lectura no tenemos por qué hacerla siempre sobre un array de caracteres, también se puede hacer sobre una estructura. Supongamos que queremos leer 40 registros con un formato concreto de un fichero de datos. Si la composición de cada registro la tenemos definida en una estructura de nombre REGISTRO, una secuencia de código para efectuar esta lectura puede ser:

struct REGISTRO mem [40];
int nbytes, id;
nbytes = read (fd, mem, 40 * sizeof (REGISTRO));

ESCRITURA DE DATOS EN UN FICHERO (WRITE)

Utilizaremos la llamada write para escribir datos en un fichero. Su declaración es muy parecida a la de read:

int write (int fildes, char *buf, unsigned nbyte);

write escribe nbyte bytes de la memoria referenciada por buf en el fichero asociado al descriptor fildes. Si la escritura se lleva a cabo correctamente, write devuelve el número de bytes realmente escritos; en caso contrario, devuelve -1 y errno contendrá el tipo del error producido.

En los ficheros con capacidad de acceso aleatorio, la escritura se realiza en la posición indicada por el puntero de lectura/escritura del fichero. Después de la escritura, el puntero queda actualizado. En los ficheros sin capacidad de acceso aleatorio, la escritura siempre tiene efecto sobre la misma posición. Si el indicador O_APPENDestaba presente al abrir el fichero, el puntero se situará al final del mismo para que las llamadas de escritura añadan información al fichero.

En los ficheros ordinarios, la escritura se realiza a través del buffer caché, por lo que una llamada a write no implica una actualización inmediata del disco. Este mecanismo acelera la gestión del disco, pero presenta problemas de cara a la consistencia de los datos.

Si no ocurre ningún imprevisto, no hay nada que temer, pero en el caso de fallo no previsto -un corte de la alimentación del equipo, por ejemplo- es posible que se pierdan datos del buffer caché que no habían sido actualizados. Si al abrir el fichero estaba presente el indicador O_SYNC, forzamos que las llamadas a write no devuelvan el control hasta que se escriban los datos en el disco, asegurando así la consistencia. Naturalmente, este modo de trabajo está penalizado con un mayor tiempo de ejecución de nuestro proceso.

Algunos ejemplos de uso de write son:

char *str = "En un lugar de la Mancha...";
int nbytes,id;
nbytes = write (fd, str, strlen (str));

y para escritura con un formato concreto:

struct REGISTRO reg;
int nbytes, id;
nbytes = write (fd, ®, sizeof (reg));

CIERRE DE UN FICHERO (CLOSE)

Utilizaremos la llamada close para indicarle al núcleo que dejamos de trabajar con un fichero previamente abierto. El núcleo se encargará de liberar las estructuras que había montado para trabajar con el fichero. La declaración de close es:

#include <unistd.h>
int close (int fildes) ;

Si fildes es un descriptor de fichero correcto devuelto por una llamada a creat, open, dup, fcntlo pipa, close cierra su fichero asociado y devuelve el valor O; en caso contrario, devuelve -1 y errno contendrá el tipo de error producido. El único error que se puede producir en una llamada a close es que fildes no sea un descriptor válido.

Al cerrar un fichero, la entrada que ocupaba en la tabla de descriptores de ficheros del proceso queda libre para que la pueda utilizar una llamada posterior a open. Por otro lado, el núcleo analiza la entrada correspondiente en la tabla de ficheros del sistema y, si el contador que tiene asociado este fichero es 1 -esto quiere decir que no hay más procesos que estén unidos a esta entrada-, esa entrada también se libera.

Si un proceso no cierra los ficheros que tiene abiertos, al terminar su ejecución el núcleo analiza la tabla de descriptores y se encarga de cerrar los ficheros que aún estén abiertos.

CREACIÓN DE UN FICHERO (CREAT)

La llamada creat permite crear un fichero ordinario o rescribir sobre uno existente. Su declaración es:

#include <fcntl.h>
int creat (char *path, mode - t moda) ;

Path es un puntero al nombre del fichero que queremos crear.

Mode es una máscara de bit s con el mismo significado que vimos para la llamada open. En esta máscara se especifican los permisos de lectura, escritura y ejecución para el propietario, grupo al que pertenece el propietario y el resto de los usuarios. Si creat funciona correctamente, devuelve un descriptor de fichero y el fichero es abierto en modo sólo escritura, incluso si mode no permite este tipo de acceso. Si el fichero ya existe, su tamaño es truncado a O bytes y su puntero de escritura se sitúa al principio. Si la llamada a creat falla, por ejemplo, si no tenemos permiso para crear un fichero en el directorio en el que intentamos hacerlo, la función devolverá -1 y en errno estará el código del tipo de error producido. La llamada a creat tiene la misma funcionalidad que una llamada a open con los indicadores O_WRONLY | O_CREAT | O_TRUNC activos. Así, las siguientes llamadas tienen la misma funcionalidad:

fd = creat C "mif ichero" , 0666);
fd = open C"mifichero", O_WRONLY| I O_CREAT I O_TRUNC, 0666);

DUPLICADO DE UN DESCRIPTOR (DUP)

La llamada dup duplica un descriptor de fichero que ya ha sido asignado y que está ocupando una entrada en la tabla de descriptores de fichero. Su declaración es:

#include <unistd.h>
int dup Cint fildes);

fildes es un descriptor obtenido a través de una llamada previa a creat, open, dup, fcntl o pipe.

La llamada a dup recorre la tabla de descriptores y va a marcar como ocupada la primera entrada que encuentre libre, pasando a devolvemos el descriptor asociado a esa entrada. Si falla en su ejecución, devolverá el valor -1, indicando a través de errno el error producido. Los dos descriptores -original y duplicado- tienen en común que comparten el mismo fichero, por lo que a la hora de leer o escribir podemos usados indistintamente. Cuando estudiemos las tuberías sin nombre, veremos la utilidad de esta llamada.

ACCESO ALEATORIO (LSEEK)

Con la llamada lseek podremos modificar el puntero de lectura/escritura de un fichero.

Su declaración es la siguiente:

#include <sys/types.h> .
#include <unistd.h>
/ / Para las constantes simbólicas.
Off_t lseek C int f ildes, off - t off set, int whence) ;

Lseek modifica el puntero de lectura/escritura del fichero asociado a fildes de la siguiente forma:

  • Si whence vale SEEK_SET, el puntero avanza offset bytes con respecto al inicio del fichero.
  • Si whence vale SEEK_CUR, el puntero avanza offset bytes con respecto a su posición actual.
  • Si whence vale SEEK_END,el puntero avanza offset bytes con respecto al final del fichero.

Si offset es un número positivo, los avances deben entenderse en su sentido natural; es decir, desde el inicio del fichero hacia el final del mismo. Sin embargo, también se puede conseguir que el puntero retroceda pasándole a lseekun desplazamiento negativo.

Cuando lseek se ejecuta correctamente devuelve un numero entero no negativo que es la nueva posición del puntero medida con respecto al principio del fichero. Si falla devuelve -1 y en errno estará el código del error producido.

En algunos ficheros no esta permitido el acceso aleatorio y por lo tanto la llamada a lseek no tiene sentido. Ejemplos de esto son las tuberías con nombre y los ficheros de dispositivo en los que la lectura se realice siempre a través de un mismo registro o posición de memoria.

CONSISTENCIA DE UN FICHERO

La entrada-salida con el disco se realiza a través del buffer caché para agilizar la transferencia de datos. Hay aplicaciones cuyas especificaciones obligan a que se prescinda del buffer caché y que las escrituras en un fichero se reflejen de forma inmediata en el disco.

Se consigue pasándole a open, dependiendo del sistema, alguno de los indicadores (O_SYNC, O_SYNCW). Otra solución es hacer llamadas a fsync.

2. BIBLIOTECA ESTANDAR DE FUNCIONES DE ENTRADA/SALIDA

La biblioteca estándar de funciones de entrada/salida, que forma parte de la definición del C estándar ANSI, hace uso de las llamadas al sistema para presentarnos una interfaz de alto nivel que permite al programador trabajar con los ficheros desde un punto de vista mas abstracto.

INTERFAZ DE LA BIBLIOTECA ESTANDAR

Referencian los ficheros mediante punteros a estructuras de tipo FILE. Las cuatro primeras funciones son fopen, fread, fwrite y fclose.

Apertura (fopen)

Abre el fichero cuyo nombre esta apuntado por file_name y le asocia un flujo. El modo de acceso al fichero ,entre otros, puede tomar diferentes valores como estos:

  • r -- abrir para leer.
  • w -- abrir para escribir.
  • a -- abrir para escribir el final del fichero o crear el fichero.
  • R+ -- abrir el fichero y actualizarlo.
  • W+ -- abrir el fichero para leer y escribir pero antes truncando el tamaño a 0 bytes.

Cada proceso que se ejecuta en UNIX y que se esta enlazando con la biblioteca estándar C, tiene asociado una tabla de flujos que se define de la siguiente forma:

FILE _ _ iob[OPEN_MAX]; // tabla de flujos

La tres primeras entradas de la tabla de flujos están ocupadas por los ficheros estándar (#define stdin, #define stdout, #define stderr). El resto de los elementos quedaran iniciados a cero ya que se produce una variante global y esa zona además la memoria se inicializa a cero.

Lectura de datos (fread)

La declaración es:

#include <stdio.h>
size_t fread (char ptr, size_t size,size___t nitems, FILE * stream);

Fread copia en el array apuntando por ptr un total de nitems bloques de datos procedentes del fichero apuntado por stream. Fread termina su lectura cuando encuentra el fichero final y su lectura se realiza correctamente.

Escritura de datos (fwrite)

Permite escribir datos en un fichero a través de su flujo asociado. La declaración es:

#include <stdio.h>
size_t fwrite(const char * ptr, size_t size,size_t nitems, FILE* streams);

Fwrite copia en el fichero apuntado por stream el número de bloques indicado en nitems, cada uno de un tamaño byte.

Cierre (fclose)

Fclose cierra un fichero que ha sido abierto con fopen. La declaración es:

#include <stdio.h>
int fclose (FILE*stream);

fclose hace que toda memoria intermedia de datos asociada a streams sea escrita en el disco, que el espacio de memoria reservado para las memorias intermedias sea liberado y que el flujo sea cerrado, devuelve cero si la llamada funciona correctamente y EOF si se produce algún error.

ENTRADA / SALIDA DE CARACTERES CON LA BIBLIOTECA ESTANDAR

Hay dos funciones para leer y escribir caracteres y son fgetc(lectura de caracteres) y fputc(escritura de caracteres).

Fgetc devuelve el carácter siguiente al ultimo leído del fichero asociado a stream.

Fgetc lee caracteres del fichero, devuelve un entero y consigue 2 objetivos: el byte leido se devuelve como un carácter sin signo, o que, se detecta el final del fichero se puede devolver EOF(-1) sin que haya lugar a confundirlo con un dato valido.

En fputc se quiere escribir en el fichero y tiene dos marcos equivalentes: getc y putc. Estos actúan sobre la entrada estándar y la salida estándar, pueden codificarse como marcos a partir de getc y putc:

#define getchar() getc (stdin)
#define putchar(c) putc((c) , stdout)

IMPLEMENTACION DE LA BIBLIOTECA ESTANDAR DE ENTRADA \ SALIDA

Para que nuestras funciones no interfieran con las que ya existen, las nombraremos de igual forma que a las funciones estándar pero anteponiendo en carácter m a cada nombre.

3. CONTROL DE FICHEROS ABIERTOS (fcntl)

Con fcntl se puede controlar un fichero abierto mediante una llamada previa a open, creat, dup, la propia fcntl o pipe. Consiste en las posibilidades de cambiar los modos permitidos de acceso al fichero y de bloquear el acceso a parte del mismo o a su totalidad.

Si no implementamos ningún mecanismo de sincronización, puede darse el caso de que el proceso lector lea una información parcialmente actualizada. Esto ocurrirá cuando el proceso que actualiza interrumpa al proceso lector en mitad de una operación de consulta de la base de datos. La declaración es:

#include<sys/types.h>
#include<stdio.h>
#include<fcntl.h>
int fcntl (int fildes, int cmd, union {int val; struct flock*lockdes}arg);

Los siguientes son valores permitidos para cmd:

  • F_DUPFD - la llamada devuelve el descriptor de un fichero que se encuentra libre en este instante.
  • F_GETFD - la función devuelve el valor del indicador close-on-exec asociado al descriptor fildes.
  • F_SETFD - fija el indicador close-on-exec asociado a fildes de acuerdo con el bit menos significativo de arg.val.
  • F_GETFL - devuelve los indicadores de estado de fildes y modo de acceso del fichero referenciado por fildes: O_RDONLY, O_WRONLY, O_RDWR,O_NDELAY, O_APPEND.
  • F_SETFL - fija los indicadores de estado de fildes de acuerdo con el valor de arg.val.
  • F_GETFLK - devuelve el primer cerrojo que se encuentra bloqueando la región del fichero referenciado por fildes
  • F_SETLK - activa o desactiva un cerrojo sobre la región del fichero referenciado por fildes y descrita por la estructura de tipo de struct flock.
  • F_SETLKW - esta orden es la misma que F_SETLK con la diferencia de que si no se establecer algún cerrojo el proceso se podrá dormir.

Un cerrojo de lectura indica que el proceso actual esta leyendo del fichero y ningún otro proceso podrá escribir en el área bloqueada.

Un cerrojo de escritura indica que el proceso esta escribiendo en el fichero y ningún otro proceso se debe leer o escribir del área bloqueada.

Los cerrojos fijados por un proceso sobre un fichero se borran cuando el proceso termina. Si fcntl no se ejecuta satisfactoriamente, devuelve el valor -1 y en errno estará codificado el tipo de error producido.

La función getpid, devuelve el valor del identificador del proceso que la llama. La ejecución del programa arroja resultados comos los siguientes:

$ fcntl & fcntl &
PID = 154, nro = 1 PID = 154, nro = 6
PID = 155, nro = 1 PID = 155, nro = 6
PID = 154, nro = 2 PID = 154, nro = 7
PID = 155, nro = 2 PID = 155, nro = 7
PID = 154, nro = 3 PID = 154, nro = 8
PID = 155, nro = 3 PID = 155, nro = 8
PID = 154, nro = 4 PID = 154, nro = 9
PID = 155, nro = 4 PID = 155, nro = 9
PID = 154, nro = 5 PID = 154, nro = 10
PID = 155, nro = 5 PID = 155, nro = 10

Si la lectura como la escritura la realizamos con bloqueo, el resultado es:

$ fcntl & fcntl &
PID = 154, nro = 1 PID = 154, nro = 11
PID = 155, nro = 2 PID = 155, nro = 12
PID = 154, nro = 3 PID = 154, nro = 13
PID = 155, nro = 4 PID = 155, nro = 14
PID = 154, nro = 5 PID = 154, nro = 15
PID = 155, nro = 6 PID = 155, nro = 16
PID = 154, nro = 7 PID = 154, nro = 17
PID = 155, nro = 8 PID = 155, nro = 18
PID = 154, nro = 9 PID = 154, nro = 19
PID = 155, nro = 10 PID = 155, nro = 20

4. ADMINISTRACION DE FICHEROS

STAT, LSTAT Y FSTAT

Estas llamadas devuelven la información que se almacena en la tabla de nodos-i sobre el estado de un fichero concreto. Su declaración:

#include <sys/types.h>
#include <sys/stat.h>
int stat (char *path, struct stat *buf);
int lstat (int fildes, struct stat *buf);
int fstat (int fildes, struct stat *buf);

La diferencia entra stat y fstat es que la primera recibe como primer parámetro un puntero al nombre del fichero, mientras que la segunda trabaja con un fichero ya abierto y le debemos pasar su descriptor.

Ambas devuelven la información estadística del fichero.

Lstat trabaja de forma parecida a stat. , menos cuando el nombre del fichero corresponde a un enlace simbólico.

La información administrativa del fichero se almacena en una estructura de tipo struct stat. Esta definido en el fichero sys/stat.h.

Algunos de los campos estándar de esta estructura junto con su tipo asociado:

  • dev_t st_dev, número del dispositivo que contiene al nodo-i. Aquí están codificados el minor number y el major number del dispositivo.
  • ino_t st_ino, número del nodo-i.
  • ushort st_mode, 16 bits que codifican el modo del fichero.
  • uid_t st_uid, identificador de usuario -UID- del propietario del fichero.
  • gid_t st_gid, identificador del grupo -GID- al que pertenece el propietario del fichero.
  • dev_t st_rdev, identificador de dispositivo. Tiene significado únicamente para los ficheros especiales en modo carácter y en modo bloque.
  • off_t st_size, tamaño, en bytes, del fichero.
  • time_t st_atime, fecha del último acceso al fichero -lectura-.
  • time_t st_mtime, fecha de la última del fichero.
  • time_t st_ctime, fecha del último cambio de la información administrativa del fichero.

MODOS DE UN FICHERO

Si queremos saber si un fichero es un directorio o no, se debe usar una expresión como:

Bits para la información de ficheros

If ((mode & S_IFMT) == S_IFDIR)
Porque si utilizamos,
If ((mode & S_IFDIR) == S_IFDIR)
Nos dará también el valor lógico VERDAD cuando ese fichero sea de tipo especial modo bloque.

Hay 3 bits cuyo significado no se ha definido de momento, son: S_ISUIS-nº11-,S_ISGID -nº10- y S_ISVTX -nº9-. Significan:

  • S_ISUID - Cambiar el identificador del usuario en ejecución. Esto tiene aplicación cuando intentamos acceder a ficheros que son de otro usuario y no tenemos permiso para escribir en ellos. Como por ejemplo la orden passwd.

    Constantes definidas en sys/stat.h para el modo de un fichero:

    Tabla con las constantes definidas en sys/stat.h

  • S-ISGID - cambiar el identificador del grupo en ejecución. Cuando ejecutamos un programa que tiene activo este bit, nuestro GID toma el valor del GID del propietario del programa.
  • S_ISVTX - Bit pertinaz. Indica al núcleo que este fichero es un programa con capacidad para que varios procesos compartan su segmento de código y que este segmento se debe mantener en memoria, aun cuando alguno de los procesos que lo utiliza deje de ejecutarse o pase al área de intercambio.

Cambio de modo : chmod y fchmod

Estas llamadas se utilizan para cambiar el modo de un fichero. Sus declaraciones son:

#include <sys/types.h>
#include <sys/stat.h>
int chmod (char *path, mode_t mode);
int fchmod (int fildes, mode_t mode) ;

En chmod especificamos el fichero por su ruta, path, y con fchmod actuamos sobre un fichero ya abierto y que tiene asociado el descriptor fildes.

Accesibilidad (access)

Determina la accesibilidad de un fichero por parte de un proceso. Declaración:

#include <unistd.h>
int access (char *path, int amode);

Path es un puntero a la ruta del fichero al que queremos acceder, amode es una máscara que codifica el tipo de acceso por el que preguntamos. En unistd.h están definidos los siguientes valores para mode:

R_Ok permiso para leer.
W_OK permiso para escribir.
X_OK permiso para ejecutar.

Máscara de permisos (umask)

La usamos para definir la máscara de permisos que tendrá asociado un proceso a la hora de crear ficheros. Declaración:

#include <sys/types.h>
#include <sys/stat.h>
mode_t umask (mode_t cmask);

La nueva máscara por defecto se indica en cmask y umask devuelve el valor que tenía la máscara anterior.

CAMBIO DE LA INFORMACIÓN ESTADÍSTICA DE UN FICHERO

Cambio del nombre de un fichero (rename)

Declaración:

#include <stdio.h>
int rename (const char *source, const char *target);

El argumento source apunta al nombre inicial del fichero y target al nuevo nombre.

Cambio del propietario y del grupo de un fichero: chown y fchown

Sirven tanto para cambiar el identificador del propietario de un fichero como el identificador del grupo. Declaración:

#include <sys/types.h>
int chown (char *path, uid_t owner, gid_t group);
int fchown (int fildes, uid_t owner, gid_t group);

La diferencia entre chown y fchown es que la primera trabaja con la ruta -path- de un fichero mientras que la segunda lo hace con el descriptor -fildes- de un fichero ya abierto.

Cambio de la fecha de un fichero (utime)

Declaración:

#include <sys/types.h> #include <utime.h> int utime (char *path, struct utimebuf *times);

path es el puntero al nombre del fichero cuyas fechas queremos cambiar, times es un puntero a una estructura de tipo struct utimebuf definida en <utime.h>.

Tanto actime como modotime se expresan en segundos. El cambio de fecha solo puede ser ejecutado por el propietario del fichero y por el superusuario.

Si utime se ejecuta correctamente nos devuelve el valor 0 pero si por el contrario no se ejecuta correctamente devuelve el valor -1 junto con errno (contiene el código del tipo del error).

Longitud de un fichero: truncate y ftruncate.

Se puede modificar la longitud de un fichero para que este tome cualquier valor comprendido entre la longitud nula y la actual del fichero mediante las siguientes sintaxis:

Truncate ( char *path, unsigned long length );
Ftruncate ( int fildes, unsigned long length );

En donde length es la nueva longitud del fichero ( bytes ). Truncate trabaja con un fichero mediante la especificación de su nombre ( path ) y ftruncate trabaja con un fichero ya abierto en modo lectura ( fildes ).

Si se ejecutan correctamente devuelven el valor 0, y en caso contrario, -1 junto con errno y el código del tipo del error.

Getpwuid y getgrgid

Getpwuid y getgrgid son dos funciones de biblioteca. La primera de ellas sirve para leer información relativa al propietario del fichero y se ubica en / etc / passwd

#include <pwd.h>
struct passwd *getpwuid ( uid_t uid );

El campo pw_name contiene el nombre del usuario.

La función getgrgid sirve para buscar información sobre el grupo al que pertenece su propietario. Esta búsqueda se realiza en / etc / group.

#include <grp.h>
struct group *getgrgid ( gid_t gid);

El campo gr_name contiene el nombre del grupo

5. COMPARTICION Y BLOQUEO DE FICHEROS

Hay dos tipos de bloqueos:

Bloqueo consultivo: el sistema conoce que recursos están bloqueados y que procesos los bloquean pero permite que estos recursos sean usados por otros procesos. Solo se puede trabajar con los recursos en caso de que estos se encuentren libres. Bloqueo adecuado a procesos cooperativos.

Bloqueo obligatorio: el sistema comprueba los accesos a los recursos compartidos para denegarle el acceso a procesos no autorizados. No hace falta mirar el estado del recurso ya que el sistema impedirá utilizarlos.

La función lockf bloquea total o parcialmente un fichero impidiendo que oros procesos accedan a esa región. La sintaxis es:

#include <unistd.h>
int lockf ( int fildes, int function, long size );

Cuando un proceso termina su ejecución se eliminan todos los cerrojos definidos sobre el fichero. Los ficheros deben estar en modo escritura o lectura / escritura para poder definir los cerrojos:

  • F_ULOCK: desbloquea región previamente bloqueada.
  • F_LOCK: bloquea una región para uso exclusivo del proceso que invoca a lockf.
  • F_TLOCK: comprueba si la región esta disponible, en caso contrario devuelve -1 y errno con el código del error.
  • F_TEST: ver si la región esta bloqueada por otro proceso. Si es accesible devuelve 0, en caso contrario -1 y errno con el error.

Size indica los bytes contiguos que se van a bloquear o desbloquear. El bloqueo empieza en el puntero hasta donde indique size. Si size vale 0 el bloqueo es hasta el final del fichero.

La mejor solución para realizar cerrojos es con F_TLOCK ya que sus cerrojos son no bloqueantes y si el proceso no puede seguir adelante con el bloqueo no se queda durmiendo en espera de fijar el cerrojo.

Con las funciones creat y open la única forma de bloquear un fichero es haciendo uno auxiliar. Si las llamadas a creat y open fallan significa que el fichero ha sido bloqueado por otro proceso, pero en caso contrario, el fichero se bloqueo por nuestro proceso. Para quitar el bloqueo basta con borrar el fichero auxiliar.

La función lockf que se ha implementado es compatible con todas las versiones UNÍX que admitan la llamada open con parámetros como O_CREAT | O_EXCL. Pero lockf tiene también inconvenientes como:

  • Con una caída del sistema los ficheros auxiliares de bloqueo no se borran, por lo que hay que hacerlo manualmente. La solución es situarlos en el directorio / usr / tmp.
  • Con el proceso bloqueado, si un proceso quiere bloquearlo en modo F_LOCK debera esperar. El problema es que no sabemos cuanto tiempo por lo que la solucion es poner a dormir el proceso hasta que algún mecanismo le notifique que despierte.
  • El proceso que tiene bloqueado un fichero puede terminar su ejecución sin desbloquearlo por lo que la solución es escribir en el fichero auxiliar el PID del proceso que bloquea y mediante la llamada a kill determinar si el proceso existe.

Bajate esta documentación en un archivo Acrobat Reader

Imagen que hace referencia a un archivo para Acrobat Reader