2011-02-14 23 views
9

Este es un programa en C que escribí para navegar y sacar recursivamente directorios y archivos regulares. Se compila y funciona bien en mi máquina Linux. Pero en Solaris, el cheque dit->d_type == 8 y los otros similares no funcionan porque no hay un campo d_type. Una respuesta que leí a este problema es usar las macros S_ISREG() y S_ISDIR(), pero no funcionan del todo como las tengo actualmente en mi código. Comentaba las líneas que funcionan en mi máquina Linux.Cómo usar S_ISREG() y S_ISDIR() POSIX Macros?

#include <sys/types.h> 
#include <sys/stat.h> 
#include <stdlib.h> 
#include <dirent.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 

void helper(DIR *, struct dirent *, struct stat, char *, int, char **); 
void dircheck(DIR *, struct dirent *, struct stat, char *, int, char **); 

int main(int argc, char *argv[]){ 

    DIR *dip; 
    struct dirent *dit; 
    struct stat statbuf; 
    char currentPath[FILENAME_MAX]; 
    int depth = 0; /*Used to correctly space output*/ 

    /*Open Current Directory*/ 
    if((dip = opendir(".")) == NULL) 
    return errno; 

    /*Store Current Working Directory in currentPath*/ 
    if((getcwd(currentPath, FILENAME_MAX)) == NULL) 
    return errno; 

    /*Read all items in directory*/ 
    while((dit = readdir(dip)) != NULL){ 
    /*Skips . and ..*/ 
    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0) 
     continue; 

    if(stat(currentPath, &statbuf) == -1){ 
     perror("stat"); 
     return errno; 
    } 

    /*Checks if current item is of the type file (type 8) and no command line arguments 
     if(dit->d_type == 8 && argv[1] == NULL)*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] == NULL) 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 

     /*If a command line argument is given, checks for filename match 
    if(dit->d_type == 8 && argv[1] != NULL)*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] != NULL) 
     if(strcmp(dit->d_name, argv[1]) == 0) 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 

     /*Checks if current item is of the type directory (type 4) 
     if(dit->d_type == 4)*/ 
    if(S_ISDIR(statbuf.st_mode)) 
     dircheck(dip, dit, statbuf, currentPath, depth, argv); 

    } 
    closedir(dip); 
    return 0; 
} 

/*Recursively called helper function*/ 
void helper(DIR *dip, struct dirent *dit, struct stat statbuf, 
    char currentPath[FILENAME_MAX], int depth, char *argv[]){ 
    int i = 0; 

    if((dip = opendir(currentPath)) == NULL) 
    printf("Error: Failed to open Directory ==> %s\n", currentPath); 

    while((dit = readdir(dip)) != NULL){ 

    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0) 
     continue; 

    stat(currentPath, &statbuf); 

    /*if(dit->d_type == 8 && argv[1] == NULL){*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] == NULL){ 
     for(i = 0; i < depth; i++) 
     printf(" "); 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 
    } 

    /*if(dit->d_type == 8 && argv[1] != NULL){*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] != NULL){ 
     if(strcmp(dit->d_name, argv[1]) == 0){ 
    for(i = 0; i < depth; i++) 
     printf(" "); 
    printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 
     } 
    } 

    /*if(dit->d_type == 4)*/ 
    if(S_ISDIR(statbuf.st_mode)) 
     dircheck(dip, dit, statbuf, currentPath, depth, argv); 

    } 
} 

void dircheck(DIR *dip, struct dirent *dit, struct stat statbuf, 
     char currentPath[FILENAME_MAX], int depth, char *argv[]){ 
    int i = 0; 

    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 

    /*If two directories exist at the same level the path 
    is built wrong and needs to be corrected*/ 
    if((chdir(currentPath)) == -1){ 
    chdir(".."); 
    getcwd(currentPath, FILENAME_MAX); 
    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 

    for(i = 0; i < depth; i++) 
     printf (" "); 
    printf("%s (subdirectory)\n", dit->d_name); 
    depth++; 
    helper(dip, dit, statbuf, currentPath, depth, argv); 
    } 

    else{ 
    for(i =0; i < depth; i++) 
     printf(" "); 
    printf("%s (subdirectory)\n", dit->d_name); 
    chdir(currentPath); 
    depth++; 
    helper(dip, dit, statbuf, currentPath, depth, argv); 
    } 

} 
+2

He restaurado el código original porque la pregunta ya no tenía sentido. Es genial que contribuyas código de trabajo, pero eso pertenece a una respuesta, no a la pregunta. Si cree que vale la pena publicar un código completo que implemente la solución de mu, publíquelo como respuesta. – Gilles

+0

Esto ha estado así durante más de un año y tiene una cantidad decente de puntos de vista. No hay ninguna razón para eliminar el código correcto ya que las personas que vengan aquí probablemente estén interesadas (y resolvió la pregunta). Tener la solución rota no ayuda a nadie. Si desea volver a cambiarlo, al menos pegue la solución como respuesta primero. – zalberico

+0

¿Es esto lo mismo que 'tree'? –

Respuesta

14

Estás usando S_ISREG() y S_ISDIR() correctamente, sólo estás usando ellos en el tema equivocado.

En su while((dit = readdir(dip)) != NULL) bucle en main, que está llamando en statcurrentPath una y otra vez sin cambiar currentPath:

if(stat(currentPath, &statbuf) == -1) { 
    perror("stat"); 
    return errno; 
} 

No deberías estar anexar una barra y dit->d_name a currentPath para obtener la ruta completa al archivo que desea stat? Me parece que también se necesitan cambios similares a sus otras llamadas stat.

+0

Gracias, ese parece ser el problema. ¿Alguna idea sobre cómo hacer el cambio sin romper todo lo demás? Simplemente usando strcat para agregar a/y dit-> d_name cada iteración construye la ruta incorrecta, pero también arruina el resto del código. – zalberico

+2

En realidad solo creo que lo descubrí, publicaré el código actualizado en un momento para ayudar a otras personas en una situación similar. Gracias. – zalberico

3

[Publicado en nombre de fossuser] Gracias a "mu es demasiado corto" pude solucionar el error. Aquí está mi código de trabajo editado para aquellos que buscan un buen ejemplo (ya que no pude encontrar otros en línea).

#include <sys/types.h> 
#include <sys/stat.h> 
#include <stdlib.h> 
#include <dirent.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 

void helper(DIR *, struct dirent *, struct stat, char *, int, char **); 
void dircheck(DIR *, struct dirent *, struct stat, char *, int, char **); 

int main(int argc, char *argv[]){ 

    DIR *dip; 
    struct dirent *dit; 
    struct stat statbuf; 
    char currentPath[FILENAME_MAX]; 
    int depth = 0; /*Used to correctly space output*/ 

    /*Open Current Directory*/ 
    if((dip = opendir(".")) == NULL) 
    return errno; 

    /*Store Current Working Directory in currentPath*/ 
    if((getcwd(currentPath, FILENAME_MAX)) == NULL) 
    return errno; 

    /*Read all items in directory*/ 
    while((dit = readdir(dip)) != NULL){ 

    /*Skips . and ..*/ 
    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0) 
     continue; 

    /*Correctly forms the path for stat and then resets it for rest of algorithm*/ 
    getcwd(currentPath, FILENAME_MAX); 
    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 
    if(stat(currentPath, &statbuf) == -1){ 
     perror("stat"); 
     return errno; 
    } 
    getcwd(currentPath, FILENAME_MAX); 


    /*Checks if current item is of the type file (type 8) and no command line arguments*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] == NULL) 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 

    /*If a command line argument is given, checks for filename match*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] != NULL) 
     if(strcmp(dit->d_name, argv[1]) == 0) 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 

    /*Checks if current item is of the type directory (type 4)*/ 
    if(S_ISDIR(statbuf.st_mode)) 
     dircheck(dip, dit, statbuf, currentPath, depth, argv); 

    } 
    closedir(dip); 
    return 0; 
} 

/*Recursively called helper function*/ 
void helper(DIR *dip, struct dirent *dit, struct stat statbuf, 
     char currentPath[FILENAME_MAX], int depth, char *argv[]){ 
    int i = 0; 

    if((dip = opendir(currentPath)) == NULL) 
    printf("Error: Failed to open Directory ==> %s\n", currentPath); 

    while((dit = readdir(dip)) != NULL){ 

    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0) 
     continue; 

    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 
    stat(currentPath, &statbuf); 
    getcwd(currentPath, FILENAME_MAX); 

    if(S_ISREG(statbuf.st_mode) && argv[1] == NULL){ 
     for(i = 0; i < depth; i++) 
    printf(" "); 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 
    } 

    if(S_ISREG(statbuf.st_mode) && argv[1] != NULL){ 
     if(strcmp(dit->d_name, argv[1]) == 0){ 
    for(i = 0; i < depth; i++) 
     printf(" "); 
    printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 
     } 
    } 

    if(S_ISDIR(statbuf.st_mode)) 
     dircheck(dip, dit, statbuf, currentPath, depth, argv); 
    } 
    /*Changing back here is necessary because of how stat is done*/ 
    chdir(".."); 
    closedir(dip); 
} 

void dircheck(DIR *dip, struct dirent *dit, struct stat statbuf, 
      char currentPath[FILENAME_MAX], int depth, char *argv[]){ 
    int i = 0; 

    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 

    /*If two directories exist at the same level the path 
    is built wrong and needs to be corrected*/ 
    if((chdir(currentPath)) == -1){ 
    chdir(".."); 
    getcwd(currentPath, FILENAME_MAX); 
    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 

    for(i = 0; i < depth; i++) 
     printf (" "); 
    printf("%s (subdirectory)\n", dit->d_name); 
    depth++; 
    helper(dip, dit, statbuf, currentPath, depth, argv); 
    } 

    else{ 
    for(i =0; i < depth; i++) 
     printf(" "); 
    printf("%s (subdirectory)\n", dit->d_name); 
    chdir(currentPath); 
    depth++; 
    helper(dip, dit, statbuf, currentPath, depth, argv); 
    } 
} 
+0

intenta abrir un objeto de biblioteca como un directorio, y luego segfaults: 'Error: no se pudo abrir Directorio ==>/SDL_shaders_gl.lo' ... ' Error de segmentación (núcleo volcado) ' – carefulnow1