您的位置:首页 > 编程语言

UNIX环境高级编程-第4章-4.1~4.3

2016-06-06 23:14 435 查看

4.1 引言

从stat开始,逐个说明stat结构的每一个成员以了解文件的所有属性=>
说明修改文件属性的各个函数=>
说明UNIX文件系统的结构以及符号链接=>
介绍对目录操作的各个函数。


4.2 函数stat,fstat,lstat,fstatat

#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
int stat(const char*pathname,struct stat*buf);
int fstat(int fd,struct stat*buf);
int lstat(const char*pathname,struct stat*buf);

#include<fcntl.h>
#include<sys/stat.h>
int fstatat(int dirfd,const char*pathname,struct stat*buf,int flags);


这些函数返回一个文件的文件信息并写入到buf中。使用以上函数测试文件的属性的时候并不要求进程对该文件的权限,只要求进程对包含该文件的各级目录具有执行权限,即能够在该目录下面搜索该文件。

stat和fstatat检索pathname指定的文件的文件属性,他们的不同点在于:

lstat 和stat一样,除了lstat不会跟踪符号链接而是返回符号链接本身的信息。

fstat和stat是一样的,也会跟踪符号链接,只不过fstat是检索fd指定的文件的文件属性。

所有的这些函数都使用到了一个struct stat结构,其定义如下:
struct stat{
dev_t st_dev;//包含该文件的设备
ino_t st_ino;//该文件的inode节点编号
mode_t st_mode;//文件权限
nlink_t st_nlink;//硬链接数量
uid_t st_uid;//属主ID
gid_t st_gid;//属组ID
dev_t st_rdev;//特殊文件的设备ID编号
off_t st_size;//占用字节数
blksize_t st_blksize;//占用文件系统块数目
blkcnt_t st_blocks;//分配的512B大小块的数量
//从Linux2.6开始,内核对以下时间戳字典支持纳秒级别的精度
struct timespec st_atim;//最后访问时间
struct timespec st_mtim;//最后修改时间
struct timespec st_ctim;//属性最后改变时间
//后向兼容
#define st_atime st_atim.tv_sec
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};


st_atime 会因为文件访问而被改变,比如execve,mknod,pipe,utime,read等的操作,其他的操作如nmap,既有可能会,也可能不改变st_atime字段。

st_mtime 会因为文件修改而被改变,比如mknod,truncate,utime,和write。此外,目录的st_mtime会因为对目录里面文件的创建和删除而改变。如果是文件属主,属组,硬链接数量,mode权限的改变并不会影响该文件的st_mtime。

st_ctime 会因为被write或者inode节点被改变和改变。

下列掩码的值是为st_mode而设置的:
S_IFMT  0170000 文件类型位掩码,可以使用st_mode与其进行&运算并和下列宏进行比较
S_IFSOCK    0140000 socket类型
S_IFLNK     0120000 符号链接
S_IFREG     0100000 普通文件
S_IFBLK     0060000 块设备
S_IFDIR     0040000 目录
S_IFCHR     0020000 字符设备
S_IFIFO     0010000 FIFO
因为对文件类型的测试是普遍存在的,因此POSIX标准提供了针对st_mode字段的测试的宏定义:
S_ISREG(m)  测试是否是普通文件
S_ISDIR(m)  测试是否是目录
S_ISCHR(m)  是否是字符设备
S_ISBLK(m)  是否是块设备
S_ISFIFO(m) 是否时FIFO队列
S_ISLINK(m) 是否是符号链接
S_ISSOCK(m) 是否是套接字
以下掩码值是为st_mode定义的,st_mode是这些所有值的位或|:
S_ISUID     0004000     设置用户ID位
S_ISGID     0002000     设置组ID位
S_ISVTX     0001000     粘连位

S_IRWXU     00700       文件属主字段掩码
S_IRUSR     00400       属主具有读权限
S_IWUSR     00200       属主具有写权限
S_IXUSR     00100       属主具有执行权限

S_IRWXG     00070       属组权限掩码
S_IRGRP     00040       属组具有读权限
S_IWGRP     00020       属组具有写权限
S_IXGRP     00010       属组具有执行权限

S_IRWXO     00007       非属组用户权限掩码
S_IROTH     00004       其他用户具有读权限
S_IWOTH     00002       其他用户具有写权限
S_IXOTH     00001       其他用户具有执行权限

S_ISGID位有几个特殊的用处,对于一个目录,这意味着一个BSD语义被用在了该目录上:在该目录中创建的的属组ID继承了目录的属组ID,而不是来自于创建该文件的有效组ID,并且在该目录中创建的目录也会具有S_ISGID位被设置为1,对于一个没有设置属组执行权限的文件,那么S_ISGID位表示mandatory file/record locking。

粘连位S_ISVTX表示目录中的文件只能被文件属主,目录属主或具有权限的进程重命名和删除。

fstatat和stat的区别在于:
如果pathname是相对路径,那么它是相对于dirfd表示的目录而言的。
如果dirfd=AT_FDCWD,那么pathname相对路径是相对于当前工作目录而言的。
如果pathname是绝对路径,那么dirfd将会被忽略。
flags要么是0,要么被设置成为以下值:
AT_EMPTY_PATH:
如果pathname为空,fstatat将会操作dirfd指定的文件,如果dirfd=AT_FDCWD,将会处理当前工作目录,在这种情况下,dirfd将可以指向任何文件,并不仅仅是一个目录,该标志是linux特有的,如果定义了_GNU_SOURCE讲可以获取该定义。
AT_NO_AMOUNT:
该标志是Linux特有。
AT_SYMLINK_NOFOLLOW:
如果pathname是一个符号链接,不跟随该符号链接而是项lstat一样返回符号链接本身的属性。
如果成功调用返回0,否则返回-1,全局变量errno将会被设置。


//编写一个程序,对于每一个文件输出其i节点编号,硬链接数量,属主id,属组gid,字节数,占用文件系统磁盘块数量,占用512块数量和文件权限和文件类型

#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char**argv){
if(argc<2){
printf("用法: a.out 文件或者目录路径名称\n");
exit(0);
}
struct stat st;
int i=1;
for(i=1;i<argc;i++){
if(stat(argv[i],&st)<0){
perror(strcat(strcat("获取文件",argv[i]),"的属性失败\n"));
exit(0);
}
printf("文件%s的信息如下:\n--------------------\n",argv[i]);
printf("i节点编号:%ld\n",st.st_ino);
printf("硬链接数量:%ld\n",st.st_nlink);
printf("属主id:%ld\n",st.st_uid);
printf("属组id:%ld\n",st.st_gid);
printf("文件占用字节数量:%ld\n",st.st_size);
printf("文件占用磁盘数量:%ld\n",st.st_blksize);
printf("文件占用512字节块数量:%ld\n",st.st_blocks);
if(S_ISREG(st.st_mode)){
printf("该文件是一个普通文件\n");
}else if(S_ISDIR(st.st_mode)){
printf("该文件是一个目录\n");
}else if(S_ISCHR(st.st_mode)){
printf("该文件是一个字符设备\n");
}else if(S_ISBLK(st.st_mode)){
printf("该文件是一个块设备\n");
}else if(S_ISFIFO(st.st_mode)){
printf("该文件是一个FIFO队列\n");
}else if(S_ISLNK(st.st_mode)){
printf("该文件是一个符号链接\n");
}else if(S_ISSOCK(st.st_mode)){
printf("该文件是一个套接字\n");
}else{
printf("该文件类型未知\n");
}

if(st.st_mode&S_ISUID){
printf("该文件的用户ID位被设置\n");
}
if(st.st_mode&S_ISGID){
printf("该文件的组IID位被设置\n");
}
if(st.st_mode&S_IRWXU&S_IRUSR){
printf("该文件属主可读\n");
}
}
return 0;
}


//测试结果如下

xcl@xcl:~/桌面$ ./main / /etc /home /home/xcl /home/xcl/桌面\

/home/xcl/桌面/有用的文件1

文件/的信息如下:

i节点编号:2

硬链接数量:24

属主id:0

属组id:0

文件占用字节数量:4096

文件占用磁盘数量:4096

文件占用512字节块数量:8

该文件是一个目录

该文件属主可读

文件/etc的信息如下:

i节点编号:11665409

硬链接数量:160

属主id:0

属组id:0

文件占用字节数量:12288

文件占用磁盘数量:4096

文件占用512字节块数量:24

该文件是一个目录

该文件属主可读

文件/home的信息如下:

i节点编号:26476545

硬链接数量:4

属主id:0

属组id:0

文件占用字节数量:4096

文件占用磁盘数量:4096

文件占用512字节块数量:8

该文件是一个目录

该文件属主可读

文件/home/xcl的信息如下:

i节点编号:26476552

硬链接数量:67

属主id:1000

属组id:1000

文件占用字节数量:20480

文件占用磁盘数量:4096

文件占用512字节块数量:48

该文件是一个目录

该文件属主可读

文件/home/xcl/桌面的信息如下:

i节点编号:26476570

硬链接数量:5

属主id:1000

属组id:1000

文件占用字节数量:16384

文件占用磁盘数量:4096

文件占用512字节块数量:32

该文件是一个目录

该文件属主可读

文件/home/xcl/桌面/有用的文件1的信息如下:

i节点编号:26491698

硬链接数量:1

属主id:1000

属组id:1000

文件占用字节数量:19060

文件占用磁盘数量:4096

文件占用512字节块数量:56

该文件是一个普通文件

该文件属主可读
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息