首页 > 代码库 > Linux环境编程之文件I/O(六):文件属性

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     保存
每个文件都有一个所有者和组所有者,所有者由stat结构中的st_uid成员表示,组所有者由st_gid成员表示。当执行一个程序文件时,进程的有效用户ID通常就是实际用户ID,有效组ID通常是实际组ID。但可以在文件模式字(st_mode)中设置两位特殊标志,文件模式字中的这两位被称为设置用户ID位和设置组ID位。这两位可用常量S_ISUID和S_ISGID测试。

(三)

文件访问权限,不只是普通文件,所有文件类型都有访问权限。每个文件有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成员表示以字节为单位的文件长度。