Unix基本系统数据类型和stat结构体
Unix基本系统数据类型
历史上,某些UNIX变量已与某些C数据类型联系在一起,例如,历史上主、次设备号存放在一个1 6位的短整型中, 8位表示主设备号,另外8位表示次设备号。但是,很多较大的系统需要用多于256个值来表示其设备号,于是,就需要有一种不同的技术。(确实, SVR4用32位表示设备号:14位用于主设备号,18位用于次设备号。) 头文件<sys/types.h >中定义了某些与实现有关的数据类型,它们被称之为基本系统数据类型(primitive system data type)。有很多这种数据类型定义在其他头文件中。在头文件中这些数据类型都是用C的typedef设施来定义的。它们绝大多数都以_t 结尾。用这种方式定义了这些数据类型后,在编译时就不再需要考虑随系统不同而变的实施细节
caddr_t 内存地址( 1 2 . 9节)
clock_t 时钟滴答计数器(进程时间)
comp_t 压缩的时钟滴答
dev_t 设备号(主和次)
fdse_t 文件描述符集
fpos_t 文件位置
gid_t 数值组ID
ino_t i节点编号
mode_t 文件类型,文件创建方式
nlink_t 目录项的连接计数
off_t 文件长度和位移量(带符号的)(lseek)
pid_t 进程I D和进程组I D(带符号的)
ptrdiff_t 两个指针相减的结果(带符号的)
rlim_t 资源限制
sigatomic_t 能原子地存取的数据类型
sigset_t 信号集
size_t 对象(例如字符串)长度(不带符号的)
ssize_t 返回字节计数的函数(带符号的)(read, write)
time_t 日历时间的秒计数器
uid_t 数值用户ID
wchar_t 能表示所有不同的字符码
用这种方式定义了这些数据类型后,在编译时就不再需要考虑随系统不同而变的实施细节,在本书中涉及到这些数据类型的地方,我们会说明为什么使用它们。
struct stat结构体
stat,lstat,fstat1 函数都是获取文件(普通文件,目录,管道,socket,字符,块()的属性。函数原型#include <sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf);提供文件名字,获取文件对应属性。
int fstat(int filedes, struct stat *buf);通过文件描述符获取文件对应的属性。
int lstat(const char *restrict pathname, struct stat *restrict buf);连接文件描述命,获取文件属性。2 文件对应的属性
struct stat {
mode_t st_mode; //文件对应的模式,文件,目录等
ino_t st_ino; //inode节点号
dev_t st_dev; //设备号码
dev_t st_rdev; //特殊设备号码
nlink_t st_nlink; //文件的连接数
uid_t st_uid; //文件所有者
gid_t st_gid; //文件所有者对应的组
off_t st_size; //普通文件,对应的文件字节数
time_t st_atime; //文件最后被访问的时间
time_t st_mtime; //文件内容最后被修改的时间
time_t st_ctime; //文件状态改变时间
blksize_t st_blksize; //文件内容对应的块大小
blkcnt_t st_blocks; //伟建内容对应的块数量
};
----------------------------------------------------------------------------------------
#include <unsitd.h>
#inlcude <sys/stat.h>
#include <sys/types.h>
int fstat(int filedes,struct stat *buf);
int stat(const char *path,struct stat *buf);
int lstat(const char *path,struct stat *buf);
这三个系统调用都可以返回指定文件的状态信息,这些信息被写到结构struct stat的缓冲区中。通过分析这个结构可以获得指定文件的信息。
void report(struct stat *ptr)
{
printf("The major device no is:%d\n",major(ptr->st_dev));//主设备号
printf("The minor device no is:%d\n",minor(ptr->st_dev));//从设备号
printf("The file's node number is:%d\n",ptr->st_ino);//文件节点号
printf("The file's access mode is:%d\n",ptr->st_mode);//文件的访问模式
printf("The file's hard link number is:%d\n",ptr->st_nlink);//文件的硬链接数目
printf("The file's user id is:%d\n",ptr->uid);//文件拥有者的ID
printf("The file's group id is:%d\n",ptr->gid);//文件的组ID
printf("The file's size is:%d\n",ptr->st_size);//文件的大小
printf("The block size is:%d\n",ptr->blksize);//文件占用的块数量
printf("The number of allocated blocks is:%d\n",ptr->st_blocks);//文件分配块数量
struct tm*accesstime,*lmodifytime,*lchangetime;//访问时间,修改时间,最后一个改变时间(属性)
accesstime=localtime(&(ptr->st_atime));
accesstime=localtime(&(ptr->st_mtime));
accesstime=localtime(&(ptr->st_ctime));
printf("The last access time is: %d::%d::%d\n",accesstime->hour,accesstime->min,accesstime->sec);
printf("The last modify time is:%d::%d::%d\n",lmodifytime->hour,lmodifytime->min,lmodifytime->sec);
printf("The last change time is:%d::%d::%d\n",lchangetime->hour,lchangetime->min,lchangetime->sec);
}
结构time_t可用用localtime转换成tm结构,获得本地时间。
使用stat结构体的三个系统调用(stat, fstat, lstat)
stat系统调用系列包括了fstat、stat和lstat,它们都是用来返回“相关文件状态信息”的,三者的不同之处在于设定源文件的方式不同。
1
首先隆重介绍的是一个非常重要的”VIP”人物,他是fstat, stat和lstat三者都要用到的一个结构体类型,名字叫做struct stat。可以说,没有这个struct stat的支持,上述三个系统调用将寸步难行。
这个struct stat结构体在不同的UNIX/Linux系统中的定义是有小的区别的,但你完全不用担心,这并不会影响我们的使用。
在struct stat结构体中我们常用的且各个平台都一定有的域是:
st_mode 文件权限和文件类型信息 (记住这个黑体橘红色)
st_ino 与该文件关联的inode
st_dev 保存文件的设备
st_uid 文件属主的UID号
st_gid 文件属主的GID号
st_atime 文件上一次被访问的时间
st_ctime 文件的权限、属主、组或内容上一次被修改的时间
st_mtime 文件的内容上一次被修改的时间。(和st_ctime的不同之处显而易见)
st_nlink 该文件上硬连接的个数
我分别提取了solaris(UNIX)和fedora(Linux)的struct stat结构体的原始定义:大家可以自己比对一下便可以发现两者确实有所不同,但主要的域是完全相同的。
solaris的struct stat定义:
struct stat { dev_t st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; off_t st_size; timestruc_t st_atim; timestruc_t st_mtim; timestruc_t st_ctim; blksize_t st_blksize; blkcnt_t st_blocks; char st_fstype[_ST_FSTYPSZ]; };
fedora的struct stat定义:
struct stat { __dev_t st_dev; unsigned short int __pad1; __ino_t st_ino; __mode_t st_mode; __nlink_t st_nlink; __uid_t st_uid; __gid_t st_gid; __dev_t st_rdev; unsigned short int __pad2; __off_t st_size; __blksize_t st_blksize; __blkcnt_t st_blocks; struct timespec st_atim; struct timespec st_mtim; struct timespec st_ctim; unsigned long int __unused4; unsigned long int __unused5; };
2
大家一定注意到了,在上面列举域的时候,我在st_mode处使用了黑体橘红色标识,原因在于这个域不像其他域那么容易使用,其他的域的值显而易见,而 st_mode域是需要一些宏予以配合才能使用的。其实,通俗说,这些宏就是一些特定位置为1的二进制数的外号,我们使用它们和st_mode进行”&”操作,从而就可以得到某些特定的信息。
文件类型标志包括:
S_IFBLK:文件是一个特殊的块设备
S_IFDIR:文件是一个目录
S_IFCHR:文件是一个特殊的字符设备
S_IFIFO:文件是一个FIFO设备
S_IFREG:文件是一个普通文件(REG即使regular啦)
S_IFLNK:文件是一个符号链接
其他模式标志包括:
S_ISUID:文件设置了SUID位
S_ISGID:文件设置了SGID位
S_ISVTX:文件设置了sticky位
用于解释st_mode标志的掩码包括:
S_IFMT:文件类型
S_IRWXU:属主的读/写/执行权限,可以分成S_IXUSR, S_IRUSR, S_IWUSR
S_IRWXG:属组的读/写/执行权限,可以分成S_IXGRP, S_IRGRP, S_IWGRP
S_IRWXO:其他用户的读/写/执行权限,可以分为S_IXOTH, S_IROTH, S_IWOTH
还有一些用于帮助确定文件类型的宏定义,这些和上面的宏不一样,这些是带有参数的宏,类似与函数的使用方法:
S_ISBLK:测试是否是特殊的块设备文件
S_ISCHR:测试是否是特殊的字符设备文件
S_ISDIR:测试是否是目录(我估计find . -type d的源代码实现中就用到了这个宏)
S_ISFIFO:测试是否是FIFO设备
S_ISREG:测试是否是普通文件
S_ISLNK:测试是否是符号链接
S_ISSOCK:测试是否是socket
3
我们已经学习完了struct stat和各种st_mode相关宏,现在就可以拿它们和stat系统调用相互配合工作了!
int fstat(int filedes, struct stat *buf);
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
聪明人一眼就能看出来fstat的第一个参数是和另外两个不一样的,对!fstat区别于另外两个系统调用的地方在于,fstat系统调用接受的是一个“文件描述符”,而另外两个则直接接受“文件全路径”。文件描述符是需要我们用open系统调用后才能得到的,而文件全路经直接写就可以了。
stat和lstat的区别:当文件是一个符号链接时,lstat返回的是该符号链接本身的信息;而stat返回的是该链接指向的文件的信息。(似乎有些晕吧,这样记,lstat比 stat多了一个l,因此它是有本事处理符号链接文件的,因此当遇到符号链接文件时,lstat当然不会放过。而 stat系统调用没有这个本事,它只能对符号链接文件睁一只眼闭一只眼,直接去处理链接所指文件喽)