/*
#include <sys/stat.h>
int stat(const char *restrict pathname,struct stat * restrict buf);
int fstat(int fildes,struct stat *buf);
int lstat(const char *restrict pathname,struct stat *restrict buf);
三个函数的返回值:如成功则返回0,若失败则返回-1.
一旦给出了pathname,stat函数就返回与此命名有关的信息结构,fstat 函数获取已在描述符filedes打开文件的有关信息,lstat函数类似于stat,但是当命名文件是一个符号链接时,lstat返回该符号链接有关的信息,而不是由该符号链接引用文件的信息
第二个参数buf是指针,它指向一个我们必须提供的结构。这些函数填写由buf指向的结构。该结构的实际定义可能随实现有所不同
struct stat{
mode_t st_mode; file type & mode (permission)
ino_t st_ino; i-node number (serial number)
dev_t st_dev; device number(file system)
dev_t st_rdev; device number for special files
nlike_t st_nlink; number of links
uid_t st_uid; user ID of owner
gid_t st_gid; group ID of owner
off_t st_size; size in bytes,for regular files;
time_t st_atime; time of last access
time_t st_mtime; time of last access
time_t st_ctime; time of last file status change;
blksize_t st_blksize; best I/O block size
blkcnt_t st_blocks;
};
注意,该结构中的每一个成员都是基本系统数据类型,我们将说明此结构的每个成员以了解文件的属性
使用stat 函数最多的可能是ls -l命令,用其可以获得有关一个文件的所有信息
文件类型
我们已经介绍了两种不同的文件类型————普通文件和目录。unix系统的大多数文件是普通文件或目录,但是还有一些文件类型
1. 普通文件。这是最常用的文件类型,这种文件包含了某种形式的数据至于这种数据是文本还是二进制数据对于unix内核而言并无区别,对普通文件内容的解释由处理该文件的应用程序进行
注意:一个值得注意的例外是二进制可执行文件,为了执行程序,内核必须理解其格式,所有的二进制可执行文件都遵循一种格式,这种格式使内核能够确定程序文本和数据的加载位置
2. 目录文件 这种文件包含了其他文件的名字以及指向与这些文件有关信息的指针,对一个目录文件具有读权限的任一进程都可以读该目录的内容但只有内核可以直接写目录文件
3. 块特殊文件。这种文件了行提供对设备带缓冲区的访问,每次访问以固定长度为单位进行
4. 字符特殊文件 这种文件类型提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件。
5. FIFO. 这种类型文件用于进程间通信,有时也将其称为命名管道
6.套接字: 这种文件类型用于进程间的网络通信,套接字也可以哟你由于在一台宿主机器上进程之间的非网络通信
7. 符号链接:这种文件类型指向另一个文件,
文件类型信息包含在stat结构的st_mode成员中。可以用表4-1中的宏确定文件类型,这些宏的参数都是stat结构中的st_mode成员
<sys/stat.h>中的文件类型宏
S_ISREG() 普通文件
S_ISDIR() 目录文件
S_ISCHR() 字符特殊文件
S_ISBLK() 块特殊文件
S_ISFIFO() 管道或FIFO
S_ISLNK() 符号链接
S_ISSOCK() 套接字
8. POSIX.1允许实现将进程间通信(IPC)对象(例如,消息队列和信号量等)表示文件,下面的宏可用来确定IPC对象的类型,他们与上不同,他们的参数并未身体——MODE 而是指向stat结构的指针
<sys/stat.h>的IPC类型宏
S_TYPEISMQ() 消息队列
S_TYPEISSEM() 信号量
S_TYPEISSHM() 共享存储对象
消息队列、信号质量以及共享存储对象会在后面讨论,但是本书讨论的四种unix系统都不将这些对象表示为文件
*/
/* 对每个命令行参数打印文件类型*/
#include "apue.h"
#include <stdarg.h>
#include <errno.h>
/*
print a message and return to caller
caller specifies "errnoflag"
*/
static void err_doit(int errnoflag,int error,const char* fmt,va_list ap)
{
char buf[MAXLINE];
vsnprintf(buf,MAXLINE,fmt,ap);
if(errnoflag)
snprintf(buf+strlen(buf),MAXLINE-strlen(buf),"%s: ",strerror(error));
strcat(buf,"\n");
fflush(stdout); /*in case stdout and stderr are the same*/
fputs(buf,stderr);
fflush(NULL); /* flushes all stdio output streams */
}
void err_ret(const char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
err_doit(1,errno,fmt,ap);
va_end(ap);
}
int main(int argc,char *argv[])
{
int i;
struct stat buf;
char *ptr;
for( i = 1; i < argc; ++i)
{
printf("%s: ",argv[i]);
if(lstat(argv[i],&buf) < 0) // 返回与命名文件有关的信息结构,若当命名的文件是一个符号链接的时候,lstat返回该符号链接的有关信息,而不是该符号链接引用文件的信息
{
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 = "socket";
else
ptr = "** unknown mode **";
printf("%s\n",ptr);
}
exit(0);
}
/*
在终端中键入一个反斜杠,通知终端要在下一行继续键入命令
*/
#include <sys/stat.h>
int stat(const char *restrict pathname,struct stat * restrict buf);
int fstat(int fildes,struct stat *buf);
int lstat(const char *restrict pathname,struct stat *restrict buf);
三个函数的返回值:如成功则返回0,若失败则返回-1.
一旦给出了pathname,stat函数就返回与此命名有关的信息结构,fstat 函数获取已在描述符filedes打开文件的有关信息,lstat函数类似于stat,但是当命名文件是一个符号链接时,lstat返回该符号链接有关的信息,而不是由该符号链接引用文件的信息
第二个参数buf是指针,它指向一个我们必须提供的结构。这些函数填写由buf指向的结构。该结构的实际定义可能随实现有所不同
struct stat{
mode_t st_mode; file type & mode (permission)
ino_t st_ino; i-node number (serial number)
dev_t st_dev; device number(file system)
dev_t st_rdev; device number for special files
nlike_t st_nlink; number of links
uid_t st_uid; user ID of owner
gid_t st_gid; group ID of owner
off_t st_size; size in bytes,for regular files;
time_t st_atime; time of last access
time_t st_mtime; time of last access
time_t st_ctime; time of last file status change;
blksize_t st_blksize; best I/O block size
blkcnt_t st_blocks;
};
注意,该结构中的每一个成员都是基本系统数据类型,我们将说明此结构的每个成员以了解文件的属性
使用stat 函数最多的可能是ls -l命令,用其可以获得有关一个文件的所有信息
文件类型
我们已经介绍了两种不同的文件类型————普通文件和目录。unix系统的大多数文件是普通文件或目录,但是还有一些文件类型
1. 普通文件。这是最常用的文件类型,这种文件包含了某种形式的数据至于这种数据是文本还是二进制数据对于unix内核而言并无区别,对普通文件内容的解释由处理该文件的应用程序进行
注意:一个值得注意的例外是二进制可执行文件,为了执行程序,内核必须理解其格式,所有的二进制可执行文件都遵循一种格式,这种格式使内核能够确定程序文本和数据的加载位置
2. 目录文件 这种文件包含了其他文件的名字以及指向与这些文件有关信息的指针,对一个目录文件具有读权限的任一进程都可以读该目录的内容但只有内核可以直接写目录文件
3. 块特殊文件。这种文件了行提供对设备带缓冲区的访问,每次访问以固定长度为单位进行
4. 字符特殊文件 这种文件类型提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件。
5. FIFO. 这种类型文件用于进程间通信,有时也将其称为命名管道
6.套接字: 这种文件类型用于进程间的网络通信,套接字也可以哟你由于在一台宿主机器上进程之间的非网络通信
7. 符号链接:这种文件类型指向另一个文件,
文件类型信息包含在stat结构的st_mode成员中。可以用表4-1中的宏确定文件类型,这些宏的参数都是stat结构中的st_mode成员
<sys/stat.h>中的文件类型宏
S_ISREG() 普通文件
S_ISDIR() 目录文件
S_ISCHR() 字符特殊文件
S_ISBLK() 块特殊文件
S_ISFIFO() 管道或FIFO
S_ISLNK() 符号链接
S_ISSOCK() 套接字
8. POSIX.1允许实现将进程间通信(IPC)对象(例如,消息队列和信号量等)表示文件,下面的宏可用来确定IPC对象的类型,他们与上不同,他们的参数并未身体——MODE 而是指向stat结构的指针
<sys/stat.h>的IPC类型宏
S_TYPEISMQ() 消息队列
S_TYPEISSEM() 信号量
S_TYPEISSHM() 共享存储对象
消息队列、信号质量以及共享存储对象会在后面讨论,但是本书讨论的四种unix系统都不将这些对象表示为文件
*/
/* 对每个命令行参数打印文件类型*/
#include "apue.h"
#include <stdarg.h>
#include <errno.h>
/*
print a message and return to caller
caller specifies "errnoflag"
*/
static void err_doit(int errnoflag,int error,const char* fmt,va_list ap)
{
char buf[MAXLINE];
vsnprintf(buf,MAXLINE,fmt,ap);
if(errnoflag)
snprintf(buf+strlen(buf),MAXLINE-strlen(buf),"%s: ",strerror(error));
strcat(buf,"\n");
fflush(stdout); /*in case stdout and stderr are the same*/
fputs(buf,stderr);
fflush(NULL); /* flushes all stdio output streams */
}
void err_ret(const char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
err_doit(1,errno,fmt,ap);
va_end(ap);
}
int main(int argc,char *argv[])
{
int i;
struct stat buf;
char *ptr;
for( i = 1; i < argc; ++i)
{
printf("%s: ",argv[i]);
if(lstat(argv[i],&buf) < 0) // 返回与命名文件有关的信息结构,若当命名的文件是一个符号链接的时候,lstat返回该符号链接的有关信息,而不是该符号链接引用文件的信息
{
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 = "socket";
else
ptr = "** unknown mode **";
printf("%s\n",ptr);
}
exit(0);
}
/*
在终端中键入一个反斜杠,通知终端要在下一行继续键入命令
*/