Add Book to My BookshelfPurchase This Book Online

Chapter 16 - Miscellaneous Routines

UNIX Systems Programming for SVR4
David A. Curry
 Copyright © 1996 O'Reilly & Associates, Inc.

Directory Trees
SVR4 provides three functions for traversing directory trees. Implementations of the ftw function are also available in the public domain.
    #include <ftw.h>
    int ftw(const char *path, int (*fn)(const char *,
            const struct stat *, int), int depth);
    int nftw(const char *path, int (*fn)(const char *,
            const struct stat *, int, struct FTW *),
            int depth, int flags);
    #include <libgen.h>
    char *pathfind(const char *path, const char *name,
            const char *mode);
The ftw function recursively descends the directory hierarchy rooted at path. For each object in the directory, it calls the user-defined function fn. This function takes three arguments: the first argument is the name of the object, the second argument is a pointer to a struct stat structure (see Chapter 5, Files and Directories), and the third argument is a flag. Possible values of the flag are:
FTW_F
The object is a file.
FTW_D
The object is a directory.
FTW_DNR
The object is a directory that cannot be read. Descendants of the directory will not be processed.
FTW_NS
The call to stat on the object failed, either because of permissions problems or because it is a symbolic link pointing to a non-existent file. The contents of the struct stat structure are undefined.
The last parameter to ftw is depth, a limit on the number of file descriptors ftw may use. It requires one file descriptor for each level in the tree. The traversal will visit a directory (call fn on it) before it visits subdirectories of that directory.
The traversal continues until the fn function returns a non-zero value, or some error occurs. If the tree is exhausted, ftw will return 0. If fn returns a non-zero value, ftw stops the traversal and returns that value.
Example 16-8 shows an example of the use of ftw.
Example 16-8:  ftw
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <ftw.h>
int process(const char *, const struct stat *, int);
int
main(int argc, char **argv)
{
    while (--argc) {
        printf("Directory %s:\n", *++argv);
        ftw(*argv, process, sysconf(_SC_OPEN_MAX) - 3);
        putchar('\n');
    }
    exit(0);
}
int
process(const char *path, const struct stat *st, int flag)
{
    printf("%-24s", path);
    switch (flag) {
    case FTW_F:
        printf("file, mode %o\n", st->st_mode & 07777);
        break;
    case FTW_D:
        printf("directory, mode %o\n", st->st_mode & 07777);
        break;
    case FTW_DNR:
        printf("unreadable directory, mode %o\n", st->st_mode & 07777);
        break;
    case FTW_NS:
        printf("unknown; stat() failed\n");
        break;
    }
    return(0);
}
    % ftw /tmp
    Directory /tmp:
    /tmp                    directory, mode 777
    /tmp/.X11-UNIX          directory, mode 777
    /tmp/.X11-UNIX/X0       file, mode 0
    /tmp/ps_data            file, mode 664
    /tmp/sh304.1            file, mode 640
    /tmp/sh309.1            file, mode 640
    /tmp/foo                file, mode 640
    /tmp/jreca002Ll         file, mode 640
    /tmp/zip                file, mode 640
    /tmp/foo.ps             file, mode 640
    /tmp/zip.ps             file, mode 640
    /tmp/jovea002Ll         file, mode 600
    /tmp/jreca002Ow         file, mode 640
    /tmp/jovea002Ow         file, mode 600
The nftw function is similar to ftw, except that it takes an additional argument, flags, which may specify any of the following values, or ed together:
FTW_PHYS
Perform a “physical” walk; do not follow symbolic links. By default, nftw follows symbolic links.
FTW_MOUNT
Do not cross filesystem mount points.
FTW_DEPTH
Perform a depth-first search; visit subdirectories of a directory before visiting the directory itself.
FTW_CHDIR
Change to each directory before reading it.
The fn function also has an additional parameter, a structure of type struct FTW:
    struct FTW {
        int    base;
        int    level;
    };
The base field contains the offset of the filename in the pathname parameter, and the level field contains the current level in the tree.
The nftw function also allows two additional flags to be passed to fn:
FTP_DP
The object is a directory whose subdirectories have already been visited.
FTW_SL
The object is a symblic link to a non-existent file.
Example 16-9 shows a slightly different version of Example 16-8; this one uses nftw and shows the structure of the directory tree with indentation.
Example 16-9:  nftw
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <ftw.h>
int process(const char *, const struct stat *, int, struct FTW *);
int
main(int argc, char **argv)
{
    while (--argc) {
        printf("Directory %s:\n", *++argv);
        nftw(*argv, process, sysconf(_SC_OPEN_MAX) - 3, 0);
        putchar('\n');
    }
    exit(0);
}
int
process(const char *path, const struct stat *st, int flag, struct FTW *info)
{
    int i;
    for (i = 0; i < info->level; i++)
        printf("  ");
    printf("%-*s", 36 - 2 * info->level, &path[info->base]);
    switch (flag) {
    case FTW_F:
        printf("file, mode %o\n", st->st_mode & 07777);
        break;
    case FTW_D:
    case FTW_DP:
        printf("directory, mode %o\n", st->st_mode & 07777);
        break;
    case FTW_SL:
        printf("symbolic link to nowhere\n");
        break;
    case FTW_DNR:
        printf("unreadable directory, mode %o\n", st->st_mode & 07777);
        break;
    case FTW_NS:
        printf("unknown; stat() failed\n");
        break;
    }
    return(0);
}
    % nftp /tmp
    Directory /tmp:
    tmp                                 directory, mode 777
      .X11-UNIX                         directory, mode 777
        X0                              file, mode 0
      ps_data                           file, mode 664
      sh304.1                           file, mode 640
      sh309.1                           file, mode 640
      foo                               file, mode 640
      jreca002Ll                        file, mode 640
      zip                               file, mode 640
      foo.ps                            file, mode 640
      zip.ps                            file, mode 640
      jovea002Ll                        file, mode 600
      jreca002Ow                        file, mode 640
      jovea002Ow                        file, mode 600
The pathfind function is a library implementation of the find command. It could also be implemented fairly easily with ftw or nftw. To make use of the pathfind function, your program must be linked with the -lgen library.
    #include <libgen.h>
    char *pathfind(const char *path, const char *name, const char *mode);
The pathfind function searches the directories in path, which should be separated by colons, for a file whose name is name, and whose mode matches mode. The mode parameter is a string containing one or more of the following characters:
r
The object is readable by the user.
w
The object is writable by the user.
x
The object is executable by the user.
f
The object is a regular file.
b
The object is a block-special device file.
c
The object is a character-special device file.
d
The object is a directory.
p
The object is a FIFO (pipe).
u
The object has the set-user-id bit set.
g
The object has the set-group-id bit set.
k
The object has the “sticky” bit set.
s
The object has non-zero size.
If an item matching the requirements is found, pathfind returns the concatenation of path and name. If no object is found, pathfind returns NULL.
Example 16-10 shows a program that uses pathfind to tell the caller what version of a program he is using. The user's search path is used as the list of directories to search, and files with the execute bit set are of interest. This program is similar to the which command provided by most versions of UNIX.
The pathfind function is not available in HP-UX 10.x.
Example 16-10:  pathfind
#include <stdlib.h>
#include <libgen.h>
int
main(int argc, char **argv)
{
    char *p, *path;
    if ((path = getenv("PATH")) == NULL) {
        fprintf(stderr, "cannot find path in environment.\n");
        exit(1);
    }
    while (--argc) {
        if ((p = pathfind(path, *++argv, "x")) == NULL)
            printf("%s: not found in search path.\n", *argv);
        else
            printf("%s: %s\n", *argv, p);
    }
    exit(0);
}
    % pathfind ls
    ls: /usr/bin/ls

Previous SectionNext Section
Books24x7.com, Inc © 2000 –  Feedback