Team-FLY |
5.2 Directory AccessDirectories 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 .
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.cA 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.7Run Program 5.3 for different directories. Compare the output with that from running the ls shell command for the same directories. Why are they different? Answer: The ls command sorts filenames in alphabetical order. The readdir function displays filenames in the order in which they occur in the directory file. Program 5.3 does not allocate a struct dirent variable to hold the directory information. Rather, readdir returns a pointer to a static struct dirent structure. This return structure implies that readdir is not thread-safe. POSIX includes readdir_r as part of the POSIX:TSF Extension, to provide a thread-safe alternative. POSIX only requires that the struct dirent structure have a d_name member, representing a string that is no longer than NAME_MAX . POSIX does not specify where additional information about the file should be stored. Traditionally, UNIX directory entries contain only filenames and inode numbers . The inode number is an index into a table containing the other information about a file. Inodes are discussed in Section 5.3. 5.2.1 Accessing file status informationThis 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.
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.cThe 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.cWhat 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 .
5.2.2 Determining the type of a fileThe 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 Table 5.1 for testing the st_mode member for the type of file. A regular file is a randomly accessible sequence of bytes with no further structure imposed by the system. UNIX stores data and programs as regular files. Directories are files that associate filenames with locations, and special files specify devices. Character special files represent devices such as terminals; block special files represent disk devices. The ISFIFO tests for pipes and FIFOs that are used for interprocess communication.Chapter 6 discusses special files, and Chapter 14 discusses interprocess communication based on message queues, semaphores and shared memory. Example 5.10 isdirectory.cThe 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.
|
Team-FLY |