檔案類型資訊包含在stat結構的st_mode成員中,大多數系統都在檔案<sys/stat.h>中定義了對應的類型字和類型判斷宏。
一、判斷檔案類型方法有兩種:
(1)用檔案類型判斷宏:例如S_ISREG(buf.st_mode)
(2)先用檔案類型屏蔽字(S_IFMT)與buf.st_mode進行“按位與”運算,然後再與對應的類型字相比較。例如:(buf.st_mode & S_IFMT) == S_IFREG。
二、相關宏的定義
(1)檔案:<bits/stat.h>
#define __S_IFMT 0170000 /* These bits determine file type. */
/* File types. */
#define __S_IFDIR 0040000 /* Directory. */
#define __S_IFCHR 0020000 /* Character device. */
#define __S_IFBLK 0060000 /* Block device. */
#define __S_IFREG 0100000 /* Regular file. */
#define __S_IFIFO 0010000 /* FIFO. */
#define __S_IFLNK 0120000 /* Symbolic link. */
#define __S_IFSOCK 0140000 /* Socket. */
/* POSIX.1b objects. Note that these macros always evaluate to zero. But
they do it by enforcing the correct use of the macros. */
#define __S_TYPEISMQ(buf) ((buf)->st_mode - (buf)->st_mode)
#define __S_TYPEISSEM(buf) ((buf)->st_mode - (buf)->st_mode)
#define __S_TYPEISSHM(buf) ((buf)->st_mode - (buf)->st_mode)
(2)檔案:sys/stat.h
#include <bits/stat.h>
#if defined __USE_BSD || defined __USE_MISC || defined __USE_XOPEN
# define S_IFMT __S_IFMT
# define S_IFDIR __S_IFDIR
# define S_IFCHR __S_IFCHR
# define S_IFBLK __S_IFBLK
# define S_IFREG __S_IFREG
# ifdef __S_IFIFO
# define S_IFIFO __S_IFIFO
# endif
# ifdef __S_IFLNK
# define S_IFLNK __S_IFLNK
# endif
# if (defined __USE_BSD || defined __USE_MISC || defined __USE_UNIX98) \
&& defined __S_IFSOCK
# define S_IFSOCK __S_IFSOCK
# endif
#endif
/* Test macros for file types. */
#define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))
#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
#define S_ISCHR(mode) __S_ISTYPE((mode), __S_IFCHR)
#define S_ISBLK(mode) __S_ISTYPE((mode), __S_IFBLK)
#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
#ifdef __S_IFIFO
# define S_ISFIFO(mode) __S_ISTYPE((mode), __S_IFIFO)
#endif
#ifdef __S_IFLNK
# define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
#endif
#if defined __USE_BSD && !defined __S_IFLNK
# define S_ISLNK(mode) 0
#endif
#if (defined __USE_BSD || defined __USE_UNIX98 || defined __USE_XOPEN2K) \
&& defined __S_IFSOCK
# define S_ISSOCK(mode) __S_ISTYPE((mode), __S_IFSOCK)
#elif defined __USE_XOPEN2K
# define S_ISSOCK(mode) 0
#endif
/* These are from POSIX.1b. If the objects are not implemented using separate
distinct file types, the macros always will evaluate to zero. Unlike the
other S_* macros the following three take a pointer to a `struct stat'
object as the argument. */
#ifdef __USE_POSIX199309
# define S_TYPEISMQ(buf) __S_TYPEISMQ(buf)
# define S_TYPEISSEM(buf) __S_TYPEISSEM(buf)
# define S_TYPEISSHM(buf) __S_TYPEISSHM(buf)
#endif
三、将相關類型判斷宏與類型判斷字清單如下
檔案類型 | 類型判斷宏 | 類型判斷字 | 判斷字指派(八進制) |
類型屏蔽字 | S_IFMT | 0170000 | |
FIFO | S_ISFIFO(st_mode) | S_IFIFO | 0010000 |
字元特殊檔案 | S_ISCHR(st_mode) | S_IFCHR | 0020000 |
目錄檔案 | S_ISDIR(st_mode) | S_IFDIR | 0040000 |
塊特殊檔案 | S_ISBLK(st_mode) | S_IFBLK | 0060000 |
普通檔案 | S_ISREG(st_mode) | S_IFREG | 0100000 |
符号連結 | S_ISLNK(st_mode) | S_IFLNK | 0120000 |
套接字 | S_ISSOCK(st_mode) | S_IFSOCK | 0140000 |
消息隊列 | S_TYPEISMQ(stat) | ||
信号量 | S_TYPEISSEM(stat) | ||
共享存儲對象 | S_TYPEISSHM(stat) | ||
說明:
類型判斷宏參數不都是一樣的:
基本檔案類型參數為st_mode,它是一個stat結構的st_mode成員;而程序間通信類型參數為stat結構
四、stat.st_mode分析
從上表個判斷字指派看以看出,stat.st_mode的bit12~bit15位包含着檔案類型資訊。檔案類型屏蔽字S_IFMT其八進制值為0170000,轉換為二進制為:1 111 000 000 000 000B,通過檔案類型屏蔽字與stat.st_mode進行與運算可以提取出檔案類型資訊(stat.st_mode & S_IFMT)。
五、執行個體分析
執行個體 x.4.3.1.c
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int shw_f_type(char *pathname);
int main(int argc, char *argv[])
{
int i;
for (i = 1; i < argc; i++) {
printf("%s:", argv[i]);
shw_f_type(argv[i]);
printf("\n");
}
exit(0);
}
int shw_f_type(char *pathname)
{
struct stat buf;
if (lstat(pathname, &buf) == -1) { /*取檔案屬性資料*/
printf("lstat error");
return 1;
}
if (S_ISREG(buf.st_mode)) /*普通檔案*/
printf("regular");
else if (S_ISDIR(buf.st_mode)) /*目錄檔案*/
printf("directory");
else if (S_ISCHR(buf.st_mode)) /*字元特殊檔案*/
printf("character special");
else if (S_ISBLK(buf.st_mode)) /*塊特殊檔案*/
printf("block special");
else if (S_ISFIFO(buf.st_mode)) /*管道或FIFO*/
printf("fifo");
else if (S_ISLNK(buf.st_mode)) /*符号連結*/
printf("symblic link");
else if (S_ISSOCK(buf.st_mode)) /*套接子*/
printf("socket");
else /*未知類型*/
printf("** unknown mode **");
return 0;
}
編譯與執行:
[[email protected] unixc]# cc x.4.3.1.c
[[email protected] unixc]# ./a.out /etc/passwd /etc /dev/log /dev/tty /dev/sda
/etc/passwd:regular
/etc:directory
/dev/log:socket
/dev/tty:character special
/dev/sda:block special
[[email protected] unixc]#