원문중 파일/디렉토리 핸들링 부분만 발췌하였음.
Files and directories
All of the regular C functions from the standard library are available to UNIX programmers. The standard functions only address the issue of reading and writing to files however, they do not deal with operating system specific attributes such as file permissions and file types. Nor is there a mechanisms for obtaining lists of files within a directory. The reason for these omissions is that they are operating system dependent. To find out about these other attributes POSIX describes some standard UNIX system calls.
opendir, readdir
Files and directories are handled by functions defined in the header file `dirent.h'. In earlier UNIX systems the file `dir.h' was used -- and the definitions were slightly different, but not much. To get a list of files in a directory we must open the directory and read from it -- just like a file. (A directory is just a file which contains data on its entries). The commands are
opendir closedir readdir
See the manual pages for dirent. These functions return pointers to a dirent
structure which is defined in the file `/usr/include/dirent.h'. Here is an example ls
command which lists the contents of the directory `/etc'. This header defines a structure
struct dirent { off_t d_off; /* offset of next disk dir entry */ unsigned long d_fileno; /* file number of entry */ unsigned short d_reclen; /* length of this record */ unsigned short d_namlen; /* length of string in d_name */ char d_name[255+1]; /* name (up to MAXNAMLEN + 1) */ };
which can be used to obtain information from the directory nodes.
#include <stdio.h> #include <dirent.h> main () { DIR *dirh; struct dirent *dirp; static char mydir[20] = "/etc"; if ((dirh = opendir(mydir)) == NULL) { perror("opendir"); return; } for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh)) { printf("Got dir entry: %s\n",dirp->d_name); } closedir(dirh); }
Notice that reading from a directory is like reading from a file with fgets()
, but the entries are filenames rather than lines of text.
stat()
To determine the file properties or statistics we use the function call `stat()' or its corollary `lstat()'. Both these functions find out information about files (permissions, owner, filetype etc). The only difference between them is the way in which they treat symbolic links. If `stat' is used on a symbolic link, it stats the file the link points to rather than the link itself. If `lstat' is used, the data refer to the link. Thus, to detect a link, we must use `lstat', See section lstat and readlink.
The data in the `stat' structure are defined in the file `/usr/include/sys/stat.h'. Here are the most important structures.
struct stat { dev_t st_dev; /* device number*/ ino_t st_ino; /* file inode */ mode_t st_mode; /* permission */ short st_nlink; /* Number of hardlinks to file */ uid_t st_uid; /* user id */ gid_t st_gid; /* group id */ dev_t st_rdev; off_t st_size; /* size in bytes */ time_t st_atime; /* time file last accessed */ time_t st_mtime; /* time file contents last modified */ time_t st_ctime; /* time last attribute change */ long st_blksize; long st_blocks; };
lstat and readlink
The function `stat()' treats symbolic links as though they were the files they point to. In other words, if we use `stat()' to read a symbolic link, we end up reading the file the link points to and not the link itself--- we never see symbolic links. To avoid this problem, there is a different version of the stat function called `lstat()' which is identical to `stat()' except that it treats links as links and not as the files they point to. This means that we can test whether a file is a symbolic link, only if we use `lstat()'. (See the next paragraph.)
Once we have identified a file to be a symbolic link, we use the `readlink()' function to obtain the name of the file the link points to.
#define bufsize 512 char buffer[bufsize]; readlink("/path/to/file",buffer,bufsize);
The result is returned in the string buffer.
stat()
test macros
As we have already mentioned, the UNIX mode bits contain not only information about what permissions a file has, but also bits describing the type of file -- whether it is a directory or a link etc. There are macros defined in UNIX to extract this information from the `st_mode' member of the `stat' structure. They are defined in the `stat.h' headerfile. Here are some examples.
#define S_ISBLK(m) /* is block device */ #define S_ISCHR(m) /* is character device */ #define S_ISDIR(m) /* is directory */ #define S_ISFIFO(m) /* is fifo pipe/socket */ #define S_ISREG(m) /* is regular (normal) file */ #define S_ISLNK(m) /* is symbolic link */ /* Not POSIX */ #define S_ISSOCK(m) /* is a lock */ #define S_IRWXU /* rwx, owner */ #define S_IRUSR /* read permission, owner */ #define S_IWUSR /* write permission, owner */ #define S_IXUSR /* execute/search permission, owner */ #define S_IRWXG /* rwx, group */ #define S_IRGRP /* read permission, group */ #define S_IWGRP /* write permission, grougroup */ #define S_IXGRP /* execute/search permission, group */ #define S_IRWXO /* rwx, other */ #define S_IROTH /* read permission, other */ #define S_IWOTH /* write permission, other */ #define S_IXOTH /* execute/search permission, other */
These return true or false when acting on the mode member. Here is an example See section Example filing program.
struct stat statvar; stat("file",&statvar); /* test return values */ if (S_ISDIR(statvar.st_mode)) { printf("Is a directory!"); }
Example filing program
The following example program demonstrates the use of the directory functions in dirent
and the stat
function call.
/********************************************************************/ /* */ /* Reading directories and `statting' files */ /* */ /********************************************************************/ #include <stdio.h> #include <dirent.h> #include <sys/types.h> #include <sys/stat.h> #define DIRNAME "/." #define bufsize 255 /********************************************************************/ main () { DIR *dirh; struct dirent *dirp; struct stat statbuf; char *pathname[bufsize]; char *linkname[bufsize]; if ((dirh = opendir(DIRNAME)) == NULL) { perror("opendir"); exit(1); } for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh)) { if (strcmp(".",dirp->d_name) == 0 || strcmp("..",dirp->d_name) == 0) { continue; } if (strcmp("lost+found",dirp->d_name) == 0) { continue; } sprintf(pathname,"%s/%s",DIRNAME,dirp->d_name); if (lstat(pathname,&statbuf) == -1) /* see man stat */ { perror("stat"); continue; } if (S_ISREG(statbuf.st_mode)) { printf("%s is a regular file\n",pathname); }; if (S_ISDIR(statbuf.st_mode)) { printf("%s is a directory\n",pathname); } if (S_ISLNK(statbuf.st_mode)) { bzero(linkname,bufsize); /* clear string */ readlink(pathname,linkname,bufsize); printf("%s is a link to %s\n",pathname,linkname); } printf("The mode of %s is %o\n\n",pathname,statbuf.st_mode & 07777); } closedir(dirh); }