文件类型信息包含在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;
}
编译与执行:
[root@localhost unixc]# cc x.4.3.1.c
[root@localhost 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
[root@localhost unixc]#