Exercise 8.5 - inode entry

Question

Modify the fsize program to print the other information contained in the inode entry.

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

#define NAME_MAX 14

typedef struct {
    long ino;
    char name[NAME_MAX + 1];
} Dirent;

typedef struct {
    int fd;
    Dirent d;
} MYDIR;

MYDIR *myopendir(char *dirname);

Dirent *myreaddir(MYDIR *dfd);

void myclosedir(MYDIR *dfd);

void fsize(char *);

void dirwalk(char *, void (*fcn)(char *));

/* stat from sys.stat.h has the following structure and these fields can be
accessed.
 *
struct stat {
        dev_t       st_dev;      [XSI] ID of device containing file
        ino_t       st_ino;      [XSI] File serial number
        mode_t      st_mode;     [XSI] Mode of file (see below)
        nlink_t     st_nlink;    [XSI] Number of hard links
        uid_t       st_uid;      [XSI] User ID of the file
        gid_t       st_gid;      [XSI] Group ID of the file
        dev_t       st_rdev;     [XSI] Device ID
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
        struct  timespec st_atimespec;   time of last access
        struct  timespec st_mtimespec;   time of last data modification
        struct  timespec st_ctimespec;   time of last status change
#else
        time_t      st_atime;    [XSI] Time of last access
        long        st_atimensec;    nsec of last access
        time_t      st_mtime;    [XSI] Last data modification time
        long        st_mtimensec;    last data modification nsec
        time_t      st_ctime;    [XSI] Time of last status change
        long        st_ctimensec;    nsec of last status change
#endif
        off_t       st_size;     [XSI] file size, in bytes
        blkcnt_t    st_blocks;   [XSI] blocks allocated for file
        blksize_t   st_blksize;  [XSI] optimal blocksize for I/O
        __uint32_t  st_flags;    user defined flags for file
        __uint32_t  st_gen;      file generation number
        __int32_t   st_lspare;   RESERVED: DO NOT USE!
        __int64_t   st_qspare[2];    RESERVED: DO NOT USE!
};
*/

/*fsize: print size of file "name" */
void fsize(char *name) {
    struct stat stbuf;

    if (stat(name, &stbuf) == -1) {
        fprintf(stderr, "fsize: can't access %s\n", name);
        return;
    }

    if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
        dirwalk(name, fsize);

    printf("%8ld - %8ld - %8ld - %8ld - %8ld - %8ld %s\n", stbuf.st_size,
           stbuf.st_blocks, stbuf.st_blksize, stbuf.st_flags, stbuf.st_gen,
           stbuf.st_nlink, name);
}

#define MAX_PATH 1024

void dirwalk(char *dir, void (*fcn)(char *)) {
    char name[MAX_PATH];
    Dirent *dp;
    MYDIR *dfd;

    if ((dfd = myopendir(dir)) == NULL) {
        fprintf(stderr, "dirwalk: cant open %s\n", dir);
        return;
    }

    while ((dp = myreaddir(dfd)) != NULL) {
        if (strcmp(dp->name, ".") == 0 || strcmp(dp->name, "..") == 0)
            continue;
        if (strlen(dir) + strlen(dp->name) + 2 > sizeof(name))
            fprintf(stderr, "dirwalk: name %s/%s too long\n", dir, dp->name);
        else {
            sprintf(name, "%s/%s", dir, dp->name);
            (*fcn)(name);
        }
    }
    myclosedir(dfd);
}

#ifndef DIRSIZ
#define DIRSIZE 14
#endif

struct direct { /* directory entry */
    ino_t d_ino;
    char d_name[DIRSIZE];
};

MYDIR *myopendir(char *dirname) {
    int fd;
    struct stat stbuf;
    MYDIR *dp;

    if ((fd = open(dirname, O_RDONLY, 0)) == -1 || fstat(fd, &stbuf) == -1 ||
        (stbuf.st_mode & S_IFMT) != S_IFDIR ||
        (dp = (MYDIR *) malloc(sizeof(MYDIR))) == NULL)
        return NULL;
    dp->fd = fd;
    return dp;
}

void myclosedir(MYDIR *dp) {
    if (dp) {
        close(dp->fd);
        free(dp);
    }
}

#include <sys/dir.h>

#define DIRSIZE 14

Dirent *myreaddir(MYDIR *dp) {
    struct direct dirbuf;
    static Dirent d;

    while (read(dp->fd, (char *) &dirbuf, sizeof(dirbuf)) == sizeof(dirbuf)) {
        if (dirbuf.d_ino == 0)
            continue;
        d.ino = dirbuf.d_ino;
        strncpy(d.name, dirbuf.d_name, DIRSIZE);
        d.name[DIRSIZE] = '\0';
        return &d;
    }
    return NULL;
}

int main(int argc, char *argv[]) {
    if (argc == 1)
        fsize(".");
    else
        while (--argc > 0)
            fsize(*++argv);
    return 0;
}

Explanation