文件和目录之文件类型

时间:2024-04-16 11:38:12

本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

UNIX系统的大多数文件是普通文件或目录,但是也有另外一些文件类型。文件类型包括如下几种:

(1)普通文件(regular file)。这是最常见的文件类型,这种文件包含了某种形式的数据。至于这种数据是文本还是二进制数据对于UNIX内核而言并无区别。对普通文件的解释由处理该文件的应用程序进行。

一个值得注意的例外是二进制可执行文件。为了执行程序,内核必须理解其格式。所有二进制可执行文件都遵循一种格式,这种格式使内核能够确定程序文本和数据的加载位置。

(2)目录文件(directory file)。这种文件包含了其他文件的名字以及指向这些文件有关信息的指针。对一个目录文件具有读权限的任一进程都可以读该目录的内容,但只有内核可以直接写目录文件。进程必须使用特定的函数才能更改目录。

(3)块特殊文件(block special file)。这种文件类型提供对设备(例如磁盘)带缓冲的访问,每次访问以固定长度为单位进行。

(4)字符特殊文件(character special file)。这种文件类型提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件。

(5)FIFO。这种类型文件用于进程间通信,有时也将其称为命名管道(named pipe)。

(6)套接字(socket)。这种文件类型用于进程间的网络通信。套接字也可用于在一台宿主机上进程之间的非网络通信。

(7)符号链接(symbolic link)。这种文件类型指向另一个文件。

文件类型信息包含在stat结构的st_mode成员中。可以用表4-1中的宏确定文件类型。这些宏的参数都是stat结构中的st_mode成员。

表4-1 <sys/stat.h>中的文件类型宏

文件类型
S_ISREG() 普通文件
S_ISDIR() 目录文件
S_ISCHR() 字符特殊文件
S_ISBLK() 块特殊文件
S_ISFIFO() 管道或FIFO
S_ISLNK() 符号链接
S_ISSOCK() 套接字

 

POSIX.1允许实现将进程间通信(IPC)对象(例如,消息队列和信号量等)表示为文件。表4-2的宏用来确定IPC对象的类型。这些宏与表4-1中的不同,它们的参数并非st_mode而是指向stat结构的指针。

表4-2 <sys/stat.h>中的IPC类型宏

对象的类型
S_TYPEISMQ() 消息队列
S_TYPEISSEM() 信号量
S_TYPEISSHM() 共享存储对象

 

注:Linux系统并不将这些对象表示为文件。

程序清单4-1 对每个命令行参数打印文件类型

[root@localhost apue]# cat prog4-1.c 
#include "apue.h"

int 
main(int argc, char *argv[])
{
        int     i;
        struct stat buf;
        char    *ptr;

        for(i=0; i<argc; i++)
        {
                printf("%s: ", argv[i]);
                if(lstat(argv[i], &buf) < 0)
                {
                        err_ret("lstat error");
                        continue;
                }
                if(S_ISREG(buf.st_mode))
                        ptr = "regular";
                else if(S_ISDIR(buf.st_mode))
                        ptr = "directory";
                else if(S_ISCHR(buf.st_mode))
                        ptr = "character special";
                else if(S_ISBLK(buf.st_mode))
                        ptr = "block special";
                else if(S_ISFIFO(buf.st_mode))
                        ptr = "fifo";
                else if(S_ISLNK(buf.st_mode))
                        ptr = "symbolic link";
                else if(S_ISSOCK(buf.st_mode))
                        ptr = "socket";
                else
                        ptr = "** unknown mode **";
                printf("%s\n", ptr);
        }
        exit(0);
}

编译后运行该程序:

[root@localhost apue]# ./prog4-1 /etc/passwd /etc /dev/initctl /dev/log /dev/tty /dev/fd0 /dev/cdrom
./prog4-1: regular
/etc/passwd: regular
/etc: directory
/dev/initctl: fifo
/dev/log: socket
/dev/tty: character special
/dev/fd0: block special
/dev/cdrom: symbolic link

我们特地使用了lstat函数而不是stat函数以便检测符号链接。如若使用了stat函数,则不会观察到符号链接。

为了在Linux系统上编译该程序,必须定义_GUN_SOURCE,这样就能包括S_ISSOCK宏的定义。(我使用的是2.6.18内核Linux,编译上述程序时,并没有自己定义_GUN_SOURCE,编译通过且运行成功。)

早期的UNIX系统版本并不提供S_ISxxx宏,于是就需要将st_mode与屏蔽字S_FIMT进行逻辑“与”运算,然后与名为S_IFxxx的常量相比较。大多数系统在文件<sys/stat.h>中定义了此屏蔽字和相关的常量。如若查看此文件,则可找到S_ISDIR宏定义为:

#define S_ISDIR(mode)    (((mode) & S_IFMT) == S_IFDIR)