Search code examples
clinuxlsstat

C sys/stat.h not every field of stat structure is initialised


I have been trying to implement my own version of linux ls command recently. Everything works great, but when I try to use ls -l functionality, some fields of struct stat aren`t initialised - I get NULL pointers or garbage values, although it seems to happen only with certain files and directories, just as content of / and others, which belong to root, or root group. The fact I find strange is that writing permissions of the file is always successful. Here is the code of the faulty function:

void printFullList(struct dirent* pDirEnt) {
    struct stat fileStat;
    stat(pDirEnt->d_name, &fileStat);
    if(pDirEnt->d_type & DT_DIR)
        putchar('d');
    else 
        putchar('-');

    putchar((fileStat.st_mode & S_IRUSR) ? 'r' : '-');
    putchar((fileStat.st_mode & S_IWUSR) ? 'w' : '-');
    putchar((fileStat.st_mode & S_IXUSR) ? 'x' : '-');
    putchar((fileStat.st_mode & S_IRGRP) ? 'r' : '-');
    putchar((fileStat.st_mode & S_IWGRP) ? 'w' : '-');
    putchar((fileStat.st_mode & S_IXGRP) ? 'x' : '-');
    putchar((fileStat.st_mode & S_IROTH) ? 'r' : '-');
    putchar((fileStat.st_mode & S_IWOTH) ? 'w' : '-');
    putchar((fileStat.st_mode & S_IXOTH) ? 'x' : '-');

    struct passwd *pwd;
    pwd = getpwuid(fileStat.st_uid);
    struct group *gid = NULL; 
    gid = getgrgid(fileStat.st_gid);
    char date[15];
    strftime(date, 15, "%d-%m %H:%M", localtime(&(fileStat.st_ctime)));
    printf(" %d %s %s %5d %s %s\n", (int)fileStat.st_nlink, (pwd != NULL ? pwd->pw_name : "NO_PERM"), (gid != NULL ? gid->gr_name : "NO_PERM"), (int)fileStat.st_size, date, pDirEnt->d_name);
}

Thanks for help!

EDIT:

stat() returns -1. I set errno to 0 before every function call. I also print pDirEnt->d_name every time, as @chux adviced. Here`s the output for / :

mnt No such file or directory d---rw---- 16961624 root NO_PERM 1 27-03 08:13 mnt
usr No such file or directory d--x--x--- 16961648 root NO_PERM 1 27-03 08:13 usr 
root No such file or directory d--xr----- 16961672 root NO_PERM 1 27-03 08:13 root  
lost+found No such file or directory d-w------- 16961696 root NO_PERM 1 27-03 08:13 lost+found ...

Solution

  • I found the answer. Passing pointer to struct dirent only was the problem: d_name field stores name of file whilst stat() function requires path to the file. Now I pass file`s directory and dirent struct with its data and then merge them into path with:

    int pathLength;
    char path[PATH_MAX];
    pathLength = snprintf(path, PATH_MAX, "%s/%s", directory, pDirEnt->d_name);
    if(pathLength >= PATH_MAX)
    {
        fprintf(stderr, "Path was too long!");
        exit(EXIT_FAILURE);
    }
    

    and then I do:

    stat(path, &fileStat);
    

    which solves my problem.