最近两天学习了有关文件属性的获取和操作,下面是在学习过程中的一个例程。
Linux中有关文件属性的信息存储在struct 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 */
};我们可以通过系统API stat()获取文件的该结构体。例程中,我主要解析了st_mode这一结构体元素,该元素存储了有关文件类型和权限的信息。
类型和权限都是通过位标志进行存储和识别的:
S_IFMT 0170000 bit mask for the file type bit fields
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 FIFO
S_ISUID 0004000 set UID bit
S_ISGID 0002000 set-group-ID bit (see below)
S_ISVTX 0001000 sticky bit (see below)
S_IRWXU 00700 mask for file owner permissions
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 mask for group permissions
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 mask for permissions for others (not in group)
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission可以看到,文件类型和权限由不同的掩码进行控制,特定的类型和权限都对应不同的位,可以通过比对位标识识别某一文件的类型或是权限。
另外,文件类型除了用上述的方法进行识别外,linux中还提供了专门的带参宏定义,通过这些宏定义可以更加方便的识别文件类型:
S_ISREG(m) is it a regular file?
S_ISDIR(m) directory?
S_ISCHR(m) character device?
S_ISBLK(m) block device?
S_ISFIFO(m) FIFO (named pipe)?
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)m就是st_mode元素。这种方法在例程中也有使用。
例程如下:
#include
#include
#include
#include
#include
#include
int main(int argc,char *argv[])
{
int ret = -1;
struct stat buf;
memset(&buf,0,sizeof(struct stat));
ret = stat(argv[1],&buf);//获取结构体struct stat的信息
if(ret < 0)
{
perror("open");
exit(-1);
}
printf("ino_t:%d\n",buf.st_ino);//打印inode
if(1 == S_ISREG(buf.st_mode))//identify file types using macros,用带参宏定义判断文件类型
{
printf("%s is a regular file\n",argv[1]);
}
printf("S_ISLNK(buf.st_mode) is:%d\n",S_ISLNK(buf.st_mode));
if(1 == S_ISLNK(buf.st_mode))//can't pass the test,判断符号链接文件,但在测试的时候没有判断出来
{
printf("%s is a symbolic link\n",argv[1]);
}
printf("S_IFREG:%d,buf.st_mode:%d\n",S_IFREG,buf.st_mode);//打印st_mode信息
switch(S_IFMT & buf.st_mode)//用掩码和位标志判断文件类型
{
case S_IFREG:printf("%s is a regular file\n",argv[1]);break;
case S_IFDIR:printf("%s is a directory\n",argv[1]);break;
case S_IFSOCK:printf("%s is a socket file\n",argv[1]);break;
case S_IFLNK:printf("%s is a link file\n",argv[1]);break;
case S_IFBLK:printf("%s is a block device file\n",argv[1]);break;
case S_IFCHR:printf("%s is a character device file\n",argv[1]);break;
case S_IFIFO:printf("%s is a FIFO/pipe file\n",argv[1]);break;
default:printf("can't identify\n");
}
switch(S_IRWXU & buf.st_mode)//用位标志判断文件权限
{
case S_IRUSR|S_IWUSR|S_IXUSR:printf("owner of %s has rwx permission \n",argv[1]);break;
case S_IWUSR:printf("owner of %s has w permission\n",argv[1]);break;
case S_IXUSR:printf("owner of %s has x permission\n",argv[1]);break;
case S_IRUSR:printf("owner of %s has r permission \n",argv[1]);break;
case S_IWUSR|S_IXUSR:printf("owner of %s has wx permission \n",argv[1]);break;
case S_IRUSR|S_IXUSR:printf("owner of %s has rx permission \n",argv[1]);break;
case S_IRUSR|S_IWUSR:printf("owner of %s has rw permission \n",argv[1]);break;
default:printf("owner of %s has no permission\n");
}
return 0;
}
权限识别只是识别了文件属主对文件的操作权限,其它的组权限和其他权限如法炮制。由于权限是w r x的组合,而文件类型的位标识是单独的,所以两者在判断的时候略有不同。
测试时候的一个发现:有关符号链接文件(软连接文件)本身都是rwx属性,而且用chmod命令修改权限也是无效的。但其st_mode代表的则是所链接的文件的权限。换句话说符号连接文件本身都是可读可写可执行的,但其st_mode则和源文件保持一致。
测试发现的一个问题:符号链接文件被当作了普通文件,带参宏定义和位标志都无法正确识别符号连接文件。