天天看點

4.3 檔案類型判斷宏與檔案類型常量

檔案類型資訊包含在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]#

繼續閱讀