5.2 Directory Access Directories should not be accessed with the ordinary open, close and read functions. Instead, they require specialized functions whose corresponding names end with "dir": opendir, closedir and readdir.The opendir function provides a handle of type DIR * to a directory stream that is positioned at the first entry in the directory. SYNOPSIS #include <dirent.h> DIR *opendir(const char *dirname); POSIX
If successful, opendir returns a pointer to a directory object. If unsuccessful, opendir returns a null pointer and sets errno. The following table lists the mandatory errors for opendir.|
EACCES | search permission on a path prefix of dirname or read permission on dirname is denied | ELOOP | a loop exists in resolution of dirname | ENAMETOOLONG | the length of dirname exceeds PATH_MAX, or a pathname component is longer than NAME_MAX | ENOENT | a component of dirname does not name an existing directory | ENOTDIR | a component of dirname is not a directory | The DIR type, which is defined in dirent.h represents a directory stream. A directory stream is an ordered sequence of all of the directory entries in a particular directory. The order of the entries in a directory stream is not necessarily alphabetical by file name.The readdir function reads a directory by returning successive entries in a directory stream pointed to by dirp. The readdir returns a pointer to a struct dirent structure containing information about the next directory entry. The readdir moves the stream to the next position after each call. SYNOPSIS #include <dirent.h> struct dirent *readdir(DIR *dirp); POSIX
If successful, readdir returns a pointer to a struct dirent structure containing information about the next directory entry. If unsuccessful, readdir returns a NULL pointer and sets errno. The only mandatory error is EOVERFLOW, which indicates that the value in the structure to be returned cannot be represented correctly. The readdir function also returns NULL to indicate the end of the directory, but in this case it does not change errno.The closedir function closes a directory stream, and the rewinddir function repositions the directory stream at its beginning. Each function has a dirp parameter that corresponds to an open directory stream. SYNOPSIS #include <dirent.h> int closedir(DIR *dirp); void rewinddir(DIR *dirp); POSIX
If successful, the closedir function returns 0. If unsuccessful, it returns 1 and sets errno. The closedir function has no mandatory errors. The rewinddir function does not return a value and has no errors defined.Program 5.3 displays the filenames contained in the directory whose pathname is passed as a command-line argument.Program 5.3 shownames.c A program to list files in a directory. #include <dirent.h> #include <errno.h> #include <stdio.h> int main(int argc, char *argv[]) { struct dirent *direntp; DIR *dirp; if (argc != 2) { fprintf(stderr, "Usage: %s directory_name\n", argv[0]); return 1; } if ((dirp = opendir(argv[1])) == NULL) { perror ("Failed to open directory"); return 1; } while ((direntp = readdir(dirp)) != NULL) printf("%s\n", direntp->d_name); while ((closedir(dirp) == -1) && (errno == EINTR)) ; return 0; }
Exercise 5.7 Run Section 5.3.
5.2.1 Accessing file status information This section describes three functions for retrieving file status information. The fstat function accesses a file with an open file descriptor. The stat and lstat functions access a file by name.The lstat and stat functions each take two parameters. The path parameter specifies the name of a file or symbolic link whose status is to be returned. If path does not correspond to a symbolic link, both functions return the same results. When path is a symbolic link, the lstat function returns information about the link whereas the stat function returns information about the file referred to by the link. Section 5.4 explains symbolic links. The buf parameter points to a user-supplied buffer into which these functions store the information. SYNOPSIS #include <sys/stat.h> int lstat(const char *restrict path, struct stat *restrict buf); int stat(const char *restrict path, struct stat *restrict buf); POSIX
If successful, these functions return 0. If unsuccessful, they return 1 and set errno. The restrict modifier on the arguments specifies that path and buf are not allowed to overlap. The following table lists the mandatory errors for these functions.|
EACCES | search permission on a path component denied | EIO | an error occurred while reading from the file system | ELOOP | a loop exists in resolution of path | ENAMETOOLONG | the length of the pathname exceeds PATH_MAX (lstat), the length of path exceeds PATH_MAX (stat), or a pathname component is longer than NAME_MAX | ENOENT | a component of path does not name an existing file | ENOTDIR | a component of the path prefix is not a directory | EOVERFLOW | the file size in bytes, the number of blocks allocated to file or the file serial number cannot be represented in the structure pointed to by buf | The struct stat structure, which is defined in sys/stat.h, contains at least the following members. dev_t st_dev; /* device ID of device containing file */ ino_t st_ino; /* file serial number */ mode_t st_mode; /* file mode */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of file */ gid_t st_gid; /* group ID of file */ off_t st_size; /* file size in bytes (regular files) */ /* path size (symbolic links) */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last data modification */ time_t st_ctime; /* time of last file status change */
Example 5.8 printaccess.c The following function displays the time that the file path was last accessed. #include <stdio.h> #include <time.h> #include <sys/stat.h> void printaccess(char *path) { struct stat statbuf; if (stat(path, &statbuf) == -1) perror("Failed to get file status"); else printf("%s last accessed at %s", path, ctime(&statbuf.st_atime)); }
Exercise 5.9 printaccessmodbad.c What is wrong with the following function that attempts to print both the access time and the time of modification of a file? How would you fix it? #include <stdio.h> #include <time.h> #include <sys/stat.h> void printaccessmodbad(char *path) { struct stat statbuf; if (stat(path, &statbuf) == -1) perror("Failed to get file status"); else printf("%s accessed: %s modified: %s", path, ctime(&statbuf.st_atime), ctime(&statbuf.st_mtime)); }
Answer:The string returned by ctime ends with a newline, so the result is displayed on 2 lines. More importantly, ctime uses static storage to hold the generated string, so the second call to ctime will probably write over the string containing the access time. To solve the problem, save the access time in a buffer before calling ctime the second time, as in the following code. An alternative would be to use two separate print statements. After the strncpy call, the string is terminated at the position that would have contained the newline.printaccessmod.c #include <stdio.h> #include <string.h> #include <time.h> #include <sys/stat.h> #define CTIME_SIZE 26 void printaccessmod(char *path) { char atime[CTIME_SIZE]; /* 26 is the size of the ctime string */ struct stat statbuf; if (stat(path, &statbuf) == -1) perror("Failed to get file status"); else { strncpy(atime, ctime(&statbuf.st_atime), CTIME_SIZE - 1); atime[CTIME_SIZE - 2] = 0; printf("%s accessed: %s modified: %s", path, atime, ctime(&statbuf.st_mtime)); } }
The fstat function reports status information of a file associated with the open file descriptor fildes. The buf parameter points to a user-supplied buffer into which fstat writes the information. SYNOPSIS #include <sys/stat.h> int fstat(int fildes, struct stat *buf); POSIX
If successful, fstat returns 0. If unsuccessful, fstat returns 1 and sets errno. The following table lists the mandatory errors for fstat.|
EBADF | fildes is not a valid file descriptor | EIO | an I/O error occurred while reading from the file system | EOVERFLOW | the file size in bytes, the number of blocks allocated to file or the file serial number cannot be represented in the structure pointed to by buf |
5.2.2 Determining the type of a file The file mode member st_mode specifies the access permissions of the file and the type of file. Table 4.1 on page 105 lists the POSIX symbolic names for the access permission bits. POSIX specifies the macros of Chapter 6 discusses special files, and Chapter 14 discusses interprocess communication based on message queues, semaphores and shared memory.Example 5.10 isdirectory.c The isdirectory function returns true (nonzero) if path is a directory, and false (0) otherwise. #include <stdio.h> #include <time.h> #include <sys/stat.h> int isdirectory(char *path) { struct stat statbuf; if (stat(path, &statbuf) == -1) return 0; else return S_ISDIR(statbuf.st_mode); }
Table 5.1. POSIX macros for testing for the type of file. Here m is of type mode_t and the value of buf is a pointer to a struct stat structure.|
S_ISBLK(m) | block special file | S_ISCHR(m) | character special file | S_ISDIR(m) | directory | S_ISFIFO(m) | pipe or FIFO special file | S_ISLNK(m) | symbolic link | S_ISREG(m) | regular file | S_ISSOCK(m) | socket | S_TYPEISMQ(buf) | message queue | S_TYPEISSEM(buf) | semaphore | S_TYPEISSHM(buf) | shared memory object |
|