Linux环境编程之文件I/O(六):文件属性
引言:
在Linux中使用ls -l filename命令查看filename的属性时,会列出文件的9种属性,例如:ls -l /etc/fstab
-rw-r--r-- 1 root root 1102 2013-10-12 02:33 /etc/fstab
从左到右分别是类型与权限、文件个数、该文件或目录的拥有者、所属的组、文件大小、创建时间、文件名
以上这些文件属性的信息,都存放在一个stat的结构体中。下面就来分析一下这个结构体。
要想查看一个文件的stat结构体,可以通过stat类函数获得!
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf); //stat函数就返回此path所指命令文件有关的信息。
int fstat(int fd, struct stat *buf);
//fstat函数获取已在文件描述符fd上打开的有关信息。
int lstat(const char *path, struct stat *buf);//lstat函数类似于stat,当命名文件是一个符号链接时,lstat返回该符号链接的有关信息,而不是由该符号链接引用文件的信息。
以上三个函数,若成功则返回0, 若出错则返回-1。以上三个函数填写有buf指向的stat结构体。
struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device ID (if special file) */ off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for file system I/O */ blkcnt_t st_blocks; /* number of 512B 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 status change */ };
(一)
文件类型,对应stat结构中的st_mode成员,包括普通文件、目录文件、块特殊文件、字符特殊文件、FIFO(命名管道)、套接字、符号链接7种文件。文件类型信息包含在stat结构的st_mode成员中。一般用下表中的宏确定文件类型,这些宏的参数都是stat结构中的st_mode成员。
宏 | 文件类型 |
S_ISREG() | 普通文件 |
S_ISDIR() | 目录文件 |
S_ISCHR() | 字符特殊文件 |
S_ISBLK() | 块特殊文件 |
S_ISFIFO() | 管道或FIFO |
S_ISLNK() | 符号链接 |
S_ISSOCK() | 套接字 |
以宏S_ISREG()为例,说明上述各宏在<sys/stat.h>中是如何定义的
# define S_IFMT __S_IFMT #define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG) #define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))示例程序:
/*
*File Name : typedemo.c
*Author : libing
*Mail : libing1209@126.com
*Function : test the file type you input
*/
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.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){//获得stat结构体
printf("lstat error.\n");
continue;
}
//利用宏测试各种文件类型
if(S_ISREG(buf.st_mode))
printf("regular");
if(S_ISDIR(buf.st_mode))
printf("directory");
if(S_ISCHR(buf.st_mode))
printf("character special");
if(S_ISBLK(buf.st_mode))
printf("block special");
if(S_ISFIFO(buf.st_mode))
printf("fifo");
if(S_ISLNK(buf.st_mode))
printf("symbolic link");
if(S_ISSOCK(buf.st_mode))
printf("sock");
putchar(‘\n‘);
}
exit(0);
}
程序测试结果:
编译程序: gcc typedemo.c 执行程序: ./a.out /etc/fstab 结果显示: /etc/fstab regular
设置用户ID和设置组ID:与一个进程相关的ID有6个,列表如下:
实际用户ID 我们实际是谁 实际组ID |
有效用户ID 用于文件访问 有效组ID 权限检查 附加组ID |
保存的设置用户ID 由exec函数 保存的设置组ID 保存 |
(三)
文件访问权限,不只是普通文件,所有文件类型都有访问权限。每个文件有9个访问权限,如下表1:
st_mode屏蔽 | 意义 |
S_IRUSR S_IWUSR S_IXUSR |
用户-读 用户-写 用户-执行 |
S_IRGRP S_IWGRP S_IXGRP |
组-读 组-写 组-执行 |
S_IROTH S_IWOTH S_IXOTH |
其他-读 其他-写 其他-执行 |
/* * File Name : permdemo.c * Author : libing * Mail : libing1209@126.com * Function : test the file permation you input */ #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> int main(int argc, char *argv[]) { if(argc != 2){ printf("usage : %s filename.\n", argv[0]); exit(0); } printf("FileName : %s.\n", argv[1]); struct stat buf; if(lstat(argv[1], &buf) == -1){ printf("stat error.\n"); exit(0); } char perm[9] = {0}; strcpy(perm, "---------"); mode_t mode = buf.st_mode; if(mode & S_IRUSR) perm[0] = ‘r‘; if(mode & S_IWUSR) perm[1] = ‘w‘; if(mode & S_IXUSR) perm[2] = ‘x‘; if(mode & S_IRGRP) perm[3] = ‘r‘; if(mode & S_IWGRP) perm[4] = ‘w‘; if(mode & S_IXGRP) perm[5] = ‘x‘; if(mode & S_IROTH) perm[6] = ‘r‘; if(mode & S_IWOTH) perm[7] = ‘w‘; if(mode & S_IXOTH) perm[8] = ‘x‘; printf("File permission bits = %s.\n", perm); }编译程序测试:
编译程序: gcc permdemo.c 执行程序: ./a.out /etc/fstab 显示结果: FileName : /etc/fstab. File permission bits = rw-r--r--.
(四)
新文件和目录的所有权:新文件的用户ID设置为进程的有效用户ID。新文件的组ID可以是进程的有效组ID,也可以是它所在目录的组ID。
(五)
access函数时按实际用户ID和实际组ID进行访问权限测试的。注意与(三)中的有效用户ID访问权限测试做比较。
#include <unistd.h>
int access(const char *pathname, int mode); // 若成功则返回0, 若出错则返回-1。
参数mode定义在<unistd.h>文件中,如下表2:
mode | 说明 |
R_OK W_OK X_OK F_OK |
测试读权限 测试写权限 测试执行权限 测试文件是否存在 |
#include <fcntl.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { if(argc != 2) printf("usage: a.out pathname"); if(access(argv[1], R_OK) < 0) printf("access error for %s", argv[1]); else printf("read ok.\n"); if(open(argv[1], O_RDONLY) < 0) printf("open error for %s", argv[1]); else printf("open for reading OK\n"); exit(0); }程序测试:
编译程序: gcc access.c 执行程序: ./a.out /etc/fstab 显示结果: read ok. open for reading OK(六)
umask函数为进程设置文件模式创建屏蔽字,并返回以前的值。
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask); // 返回以前的文件模式创建屏蔽字
参数cmask是由上面的表1列出的9个常量中的若干个按位“或”构成的。对于任何在文件模式创建屏蔽字中为1的位,在文件mode中的相应位一定被关闭。
示例程序:
/* *File Name : umaskdemo.c *Author : libing *Mail : libing1209@126.com *Function : just the umask function */ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #define RWRWRW (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) int main(void) { umask(0); //设置文件模式创建屏蔽字 if(creat("foo", RWRWRW) < 0) printf("create foo error.\n"); umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); //设置文件模式创建屏蔽字 if(creat("far", RWRWRW) < 0) printf("create far error.\n"); exit(0); }程序测试显示 :
编译程序: gcc umask.c 执行程序: ./a.out 测试显示: ls -l far foo -rw------- 1 book book 0 2014-05-12 20:40 far -rw-rw-rw- 1 book book 0 2014-05-12 20:40 foo
(七)
chmod函数与fchmod函数可以更改现有文件的访问权限。chmod 函数在指定的文件上进行操作,而fchmod函数则对已打开的文件进行操作。
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
另外:stat结构体中的st_size成员表示以字节为单位的文件长度。