4.2 stat,lstat 和fstat函数
/***********************
* 函数功能: 描述文件属性
* stat函数返回与pathname命名文件的相关信息结构;
* fstat函数获取已在描述符filedes上打开的文件信息;
* lstat函数获取符号连接的相关信息;
*
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
*/
int stat(const char *pathname, struct stat *buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
/**************************
* 参数说明
* pathname 文件名
* filed 文件描述符
* buf 指向buffer的指针
* */
//buf指针指向的struct stat的结构
struct stat{
mode_t st_mode; /* file type */
ino_t st_ino; /* i-node number */
dev_t st_dev; /* device number */
dev_t st_rdev; /* device number for special file */
nlink_t st_nlink; /* number of hard link */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group Id of owner */
off_t st_size; /* total size in bytes for regular files */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last change */
};
测试程序:
#include "apue.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
void stat_buf(char*,struct stat *);
int main(int argc, char *argv[])
{
struct stat buf;
if(argc != 2)
err_quit("usage: a.out <pathname>");
if(stat(argv[1],&buf) != -1)
{
stat_buf(argv[1],&buf);
}
else
err_ret("error");
exit(0);
}
void stat_buf(char *fname,struct stat *buf)
{
printf("mode: %o\n", buf->st_mode); /*显示文件模式字段*/
printf("links:%d\n", buf->st_nlink); /*显示链接数*/
printf("user : %d\n", buf->st_uid); /*显示用户名ID*/
printf("group : %d\n", buf->st_gid); /*显示组ID*/
printf("size: %d\n", buf->st_size); /*显示文件大小*/
printf("modtime: %d\n", buf->st_mtime); /*显示文件的最后修改时间*/
printf("name:%s\n", fname); /*显示文件名*/
}
4.3 文件类型
st_mode文件类型有以下七种:
st_mode文件类型宏:
/*
* S_ISREG 普通文件;
* S_ISBLK 块特殊文件;
* S_ISCHR 字符特殊文件;
* S_ISDIR 目录文件;
* S_ISLNK 符号链接;
* S_ISFIFO 命令管道;
* S_ISSOCK 套接字;
*/
//测试程序,取命令行参数,针对每个命令行参数打印其文件类型,代码如下:
#include "apue.h"
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("last error.");
continue;
}
if(S_ISREG(buf.st_mode))
ptr = "regular file.";
else if(S_ISDIR(buf.st_mode))
ptr = "directory file.";
else if(S_ISCHR(buf.st_mode))
ptr = "character special file";
else if(S_ISBLK(buf.st_mode))
ptr = "block special file";
else if(S_ISFIFO(buf.st_mode))
ptr = "FIFO file";
else if(S_ISLNK(buf.st_mode))
ptr = "symbolic link file";
else if(S_ISSOCK(buf.st_mode))
ptr = "sock file";
else
ptr ="** unknown mode **";
printf("%s\n",ptr);
}
exit(0);
}
4.4 设置用户ID(UID)和设置组ID(GID)
与一个进程相关联的ID有6个或更多,它们如下:
通常,有效用户ID等于实际用户ID,有效组ID等于实际组ID。但是,可以在文件模式字(st_mode)中设置一个特殊标志,其含义是“当执行此文件时,将进程的有效用户ID设置为文件所有者的UID。”对于有效组ID也可以设置。
4.5 文件访问权限
文件访问权限,/*****************************
* 文件访问权限
* st_mode屏蔽 意义
* S_IRUSR 用户-读
* S_IWUSR 用户-写
* S_IXUSR 用户-执行
*****************************
* S_IRGRP 组-读
* S_IWGRP 组-写
* S_IXGRP 组-执行
*****************************
* S_IROTH 其他-读
* S_IWOTH 其他-写
* S_IXOTH 其他-执行
*****************************
*/
对于目录的读权限:允许读目录,即获得该目录下所有文件名的列表。
对于目录的写权限:允许对目录进行增删文件。
对于目录的执行权限:允许进入目录。当一个目录是我们要访问的文件的路径名的一个组成部分时,需要该目录有可执行权限。
当一个进程每次打开,创建或者删除一个文件时,内核需要进行文件访问权限测试,这种测试可能涉及到文件的UID和GID,进程的有效ID和附加组ID。具体测试过程如下:
4.6 新文件与目录的所有权
/*****************************
* 新文件和目录的所有权
* 新文件的用户ID设置为进程的有效用户ID;
* 新文件的组ID为以下之一:
* (1)可以是进程的有效组ID;
* (2)可以是所在目录的组ID;
* ***************************
*/
4.7 access函数
当用open函数打开一个文件时,内核以进程的有效用户ID和有效组ID为基础执行其访问权限测试。有时,进程希望按其实际用户ID和实际组ID来测试其访问能力。access函数就是按实际用户ID和实际组ID进行访问权限测试的。
/* access 函数 */
/******************
*功能:按照实际用户ID和实际组ID进行访问权限测试。
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
* int access(const char *pathname,int mode);
**********************/
/**********************
*参数说明
*pathname是文件名
*mode是一下常量
*(1)R_OK 测试读权限
*(2)W_OK 测试写权限
*(3)X_OK 测试执行权限
*(4)F_OK 测试文件是否存在
* *********************/
#include "apue.h"
#include <fcntl.h>
int main(int argc, char*argv[])
{
if(argc != 2)
err_quit("usage: a.out <pathname>");
if(access(argv[1],R_OK) < 0)
err_ret("access error for %s",argv[1]);
else
printf("read access ok.\n");
if(open(argv[1],O_RDONLY) < 0)
err_ret("open error for %s",argv[1]);
else
printf("open for reading ok.\n");
exit(0);
}