ENUNCIADO

Esta es una práctica que no hay que entregar. Esta práctica vale doble en cuanto al mejor que la entregue. El programa que hay que realizar no admite ningún argumento por la línea de órdenes de la shell. El programa listará el nombre de todos los ficheros del directorio actual que no posean más de un enlace duro. Hacer una comprobación no paranoica de errores.

COMENTARIOS

La práctica con 0.50 es la de Tiosoni y Peco ;) :
/* Sección de compatibilidad con Linux y HPUX */
#ifndef _HPUX_SOURCE
#    ifndef __USE_BSD
#        define __USE_BSD
#    endif
#endif

#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>

#if defined _HPUX_SOURCE
struct direct
   {
    unsigned long  d_fileno; /* inodo aprox. */
    unsigned short d_reclen; /* longitud de la estructura */
    unsigned short d_namlen; /* longitud del nombre */
    char           d_name[MAXNAMLEN + 1];  /* nombre del fichero */
    }; 

int getdirentries(int fildes, struct direct *buf, size_t nbytes,
                  off_t *basep);

#   define DIR direct
#   define CAST (struct direct *)
#else
#   define DIR dirent
#   define CAST
#endif

int main(int argc, char **argv)
{
    char mens_error[80], *buffer_getd;
    int filedes, val_ret, parte_actual;
    long tam;
    struct DIR *sdpt, *sdpt_origen;
    struct stat buffer_stat;
    off_t posic;

    if (argc > 1)
    {
        fprintf(stderr, "\nError de sintaxis.");
        fprintf(stderr, "\nUso: %s\n", argv[0]);
        return 1;
    }
    
    /* No hace falta complicarse la vida: "." es el directorio actual */
    if ((filedes = open(".", O_RDONLY)) == -1)
    {
        /* La macro __LINE__ la define el propio compilador como la línea actual. */
        /* No aporta mucho al programa. */
        sprintf(mens_error, "%s(line[%d]): open", argv[0], __LINE__-2);
        perror(mens_error);
        return 2;
    }
    
    /* Aprovechamos el descriptor de fichro abierto */
    if ((val_ret = fstat(filedes, &buffer_stat)) == -1)
    {
        sprintf(mens_error, "%s(line[%d]): fstat", argv[0], __LINE__-2);
        perror(mens_error);
        return 3;
    }
    
    /* Puede dar problemas de portabilidad elegir un búfer más grande. */
    tam = 5 * buffer_stat.st_blksize;
    if ((buffer_getd = (char *)calloc(tam, sizeof(char))) == NULL)
    {
        sprintf(mens_error, "%s(line[%d]): calloc", argv[0], __LINE__-2);
        perror(mens_error);
        return 4;
    }
    
    /* Este es uno de los pocos casos en que recomiendo una asignación  */
    /* y una comparación en la misma línea. Es muy fácil olvidar los    */
    /* paréntesis debido a que == tiene más precedencia que = y el      */
    /* poner las cosas así no aporta nada. En este caso, sin embargo,   */
    /* te ahorras tener que escribir dos veces la llamada a getdiren... */
    while ((val_ret = getdirentries(filedes, CAST buffer_getd,
                                    (size_t)tam, &posic)) != 0) 
    {
        if (val_ret == -1)
        {
            sprintf(mens_error, "%s(line[%d]): getdirentries", argv[0],
                                 __LINE__-11);
            perror(mens_error);
            return 5;
        }

        /* En C, el operador de asignación (=) también devuelve un valor. */
        /* Eso permite hacer dobles, triples... asignaciones como la siguiente. */
        sdpt_origen = sdpt = (struct DIR *)buffer_getd;
        parte_actual = val_ret;
        /* La variable sdpt_origen no aporta nada más que confusión al código. */
        while (((char *)sdpt - (char *)sdpt_origen) < parte_actual)
        {
            if ((val_ret = stat(sdpt->d_name, &buffer_stat)) == -1)
            {
                 sprintf(mens_error, "%s(line[%d]): stat", argv[0], 
                                     __LINE__-2);
                 perror(mens_error);
                 /* De siempre hacer lo mismo, no nos paramos a pensar: */
                 /* ¿Es necesario parar todo el programa porque un sólo */
                 /*  fichero falle en su stat?                          */
                 return 7;
            }

            /* La macro S_ISDIR devuelve verdadero si tenemos */
            /* un directorio. Aquí no vale para nada. Todos   */
            /* los dirs tienen al menos 2 enlaces: ellos      */
            /* mismos y el ".." dentro de ellos.              */
            if (!(S_ISDIR(buffer_stat.st_mode)) && (buffer_stat.st_nlink < 2))
                printf("%s\n", sdpt->d_name);

            sdpt = (struct DIR *)((char *)sdpt + (sdpt->d_reclen));
        }
    }

    close(filedes);
    free(buffer_getd);

    return 0;
}   


MENCIONES ESPECIALES


© 2000 Guillermo González Talaván.