summaryrefslogtreecommitdiff
path: root/reference/C/CONTRIB/OR_USING_C/04.3.c
blob: 9c55974a19cbff0a0787238d6cf9bed9e7cd4d7c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <stdio.h>

char *modes[] = {
    "---", "--x", "-w-", "-wx",
    "r--", "r-x", "rw-", "rwx"
};

main(argc, argv)
int argc;
char **argv;
{
    struct stat sbuf;

    /*
     * If no arguments, list current directory.
     */
    if (argc < 2) {
        list(".");
        exit(0);
    }

    /*
     * Process arguments.
     */
    while (--argc) {
        /*
         * See what the file is.
         */
        if (stat(*++argv, &sbuf) < 0) {
            perror(*argv);
            continue;
        }

        /*
         * If it's a directory we list it,
         * otherwise just print the info about
         * the file.
         */
        if ((sbuf.st_mode & S_IFMT) == S_IFDIR)
            list(*argv);
        else
            printout(".", *argv);
    }

    exit(0);
}

/*
 * list--read a directory and list the files it
 *        contains.
 */
list(name)
char *name;
{
    DIR *dp;
    struct direct *dir;

    /*
     * Open the directory.
     */
    if ((dp = opendir(name)) == NULL) {
        fprintf(stderr, "%s: cannot open.\n", name);
        return;
    }

    /*
     * For each entry...
     */
    while ((dir = readdir(dp)) != NULL) {
        /*
         * Skip removed files.
         */
        if (dir->d_ino == 0)
            continue;

        /*
         * Print it out.
         */
        printout(name, dir->d_name);
    }

    closedir(dp);
}

/*
 * printout--print out the information about
 *            a file.
 */
printout(dir, name)
char *dir, *name;
{
    int i, j;
    char perms[10];
    struct stat sbuf;
    char newname[1024];

    /*
     * Make full path name, so
     * we have a legal path.
     */
    sprintf(newname, "%s/%s", dir, name);

    /*
     * At this point we know the file exists,
     * so this won't fail.
     */
    stat(newname, &sbuf);

    /*
     * Print size in kbytes.
     */
    printf("%5d ", (sbuf.st_size + 1023) / 1024);

    /*
     * Get the file type.  For convenience (and to
     * make this example universal), we ignore the
     * other types which are version-dependent.
     */
    switch (sbuf.st_mode & S_IFMT) {
    case S_IFREG:    putchar('-'); break;
    case S_IFDIR:    putchar('d'); break;
    case S_IFCHR:    putchar('c'); break;
    case S_IFBLK:    putchar('b'); break;
    default:         putchar('?'); break;
    }

    /*
     * Get each of the three groups of permissions
     * (owner, group, world).  Since they're just
     * bits, we can count in binary and use this
     * as a subscript (see the modes array, above).
     */
    *perms = NULL;
    for (i = 2; i >= 0; i--) {
        /*
         * Since we're subscripting, we don't
         * need the constants.  Just get a
         * value between 0 and 7.
         */
        j = (sbuf.st_mode >> (i*3)) & 07;

        /*
         * Get the perm bits.
         */
        strcat(perms, modes[j]);
    }

    /*
     * Handle special bits which replace the 'x'
     * in places.
     */
    if ((sbuf.st_mode & S_ISUID) != 0)
        perms[2] = 's';
    if ((sbuf.st_mode & S_ISGID) != 0)
        perms[5] = 's';
    if ((sbuf.st_mode & S_ISVTX) != 0)
        perms[8] = 't';

    /*
     * Print permissions, number of links,
     * user and group ids.
     */
    printf("%s%3d %5d/%-5d ", perms, sbuf.st_nlink, sbuf.st_uid,
        sbuf.st_gid);

    /*
     * Print the size of the file in bytes,
     * and the last modification time.  The
     * ctime routine converts a time to ASCII;
     * it is described in Chapter 7, Telling
     * Time and Timing Things.
     */
    printf("%7d %.12s ", sbuf.st_size, ctime(&sbuf.st_mtime)+4);

    /*
     * Finally, print the filename.
     */
    printf("%s\n", name);
}