19.文件属性

获取文件信息:stat()

利用系统调用stat()lstat()、以及fstat(),可获取与文件有关的信息,其中大部分提取自文件i节点。

#include <sys/stat.h>
int stat(const char *pathname, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
int fstat(int fd. struct stat *statbuf);
		All returns 0 on success, or -1 on error.

以上3个系统调用之间仅有的区别在于对文件的描述方式不同。

  • stat()会返回所命名文件的相关信息。
  • lstat()stat()类似,区别在于如果文件属于符号链接,那么所返回的信息针对的是符号链接本身(而非符号链接所指向的文件)。
  • fstat()则会返回由某个打开文件描述符所指代文件的相关信息。

系统调用stat()lstat()无需对其所操作的文件本身拥有任何权限,但针对指定pathname的父目录要有执行(搜索)权限。而只要供之以有效的文件描述符,fstat()系统调用就总是成功。

上述所有系统调用都会在缓冲区返回一个由statbuf()指向的stat结构,其格式如下:

struct stat{
	dev_t	st_dev;		/*IDs of devices on which file resides */
	ino_t	st_ino;		/*I-node number of file*/
	mode_t	st_mode;	/*File type and permissions*/
	nlink_t	st_nlink;	/*Number if (hard) links to file*/
	uid_t	st_uid;		/*User ID of file owner*/
	gid_t	st_gid;		/*Group ID of file owner*/
	dev_t	st_rdev;	/*IDs for device special files*/
	off_t	st_size;	/*Total file size (bytes)*/
	blksize_t	st_blksize;	/*Optimal block size for I/O (bytes)*/
	blkcnt_t	st_blocks;	/*Number of (512B) blocks allocated*/
	time_t	st_atime;	/*Time of last file access*/
	time_t	st_mtime;	/*Time of last file modification*/
	time_t	st_ctime;	/*Time of last status change*/
};

关于其中一些重要字段,说明如下:

设备号和i节点号

st_dev字段标识文件所驻留的设备,st_ino字段标识文件的i节点号。
利用以上两者,可在文件系统中唯一标识某个文件。dev_t类型记录了设备的主、辅ID。

如果是针对设备的i节点,那么st_rdev字段则包含设备的主、辅ID。

利用宏major()minor(),可提取dev_t值的主、辅ID。获取对两个宏声明的头文件则随UNIX实现而异。在Linux系统上,若定义了_BSD_SOURCE宏,则两个宏定义于<sys/types.h>中。

major()minor()所返回的整型值大小也随UNIX实现的不同而各不相同。为保证可移植性,打印时应总是将返回值强制转换为long

文件所有权

st_uidst_gid字段分别标识文件的属主(用户ID)和属组(组ID)。

链接数

st_nlink字段包含了指向文件的(硬)链接数。

文件类型及权限

st_mode字段内含有位掩码,起标识文件类型和指定文件权限的双重作用。

请添加图片描述

与常量S_IFMT相与(&),可从该字段中提取文件类型。(Linux使用了st_mode字段中的4位来标识文件类型位。但由于SUSv3并未对文件类型位的表示方法做出任何规定,故而其具体实现细节随各实现而异。)将计算结果与一系列常量进行比较,即可确定文件类型。如下所示:

if( (statbuf.st_mode & S_IFMT) == S_IFREG)
		printf("regular file\n");

鉴于上述操作属于常见操作,因此可以利用标准宏将其简化为:

if(S_ISREG(statbuf.st_mode))
		printf("regular file\n");

下表所列为全套文件类型宏(定义于<sys/stat.h>)。这些宏均由SUSv3定义,并为Linux所支持。一些其他的UNIX还定义了别的文件类型。因为调用stat()时会循符号链接而直抵实际文件,所以只有在调用lstat()时才可能会返回类型S_IFLNK

  • 想从<sys/stat.h>中获得S_IFSOCKS_ISSOCK的定义,必须定义_BSD_SOURCE特性测试宏,或是将_XOPEN_SOURCE定义为不小于500的值。(具体规则随glibc版本而异。在某些情况下,需将X_OPEN_SOURCE的值定义为不小于600。)
常量测试宏文件类型
S_IFREGS_ISREG()常规文件
S_IFDIRS_ISDIR()目录
S_IFCHRS_ISCHR()字符设备
S_IFBLKS_ISBLK()块设备
S_IFIFOS_ISFIFO()FIFO或管道
S_IFSOCKS_ISSOCK()套接字
S_IFLNKS_ISLNK()符号链接

st_mode的低12位定义了文件权限。其中最低9位分别用来表示文件属主、属组以及其他用户的读、写、执行权限。

文件大小、已分配块以及最优I/O块大小

  • 对于常规文件,st_size字段表示文件的字节数。对于符号链接,则表示链接所指路径名的长度,以字节为单位。对于共享内存对象,该字段则表示对象的大小。

  • st_blocks字段表示分配给文件的总块数,块大小为512字节,其中包括了为指针块所分配的空间。更为现代的UNIX系统则使用更大尺寸的逻辑块。
    st_blocks记录了实际分配给文件的磁盘块的数量。如果文件含空洞,该值将小于相应文件字节数字段(st_size)的值。

  • st_blksize字段是针对文件系统上文件进行I/O时最优块大小,若I/O所采用的块大小小于该值,则被视为低效。一般而言,st_blksize的返回值为4096.

文件时间戳

st_atimest_mtimest_ctime字段,分别记录了对文件的上次访问时间、上次修改时间,以及文件状态发生改变的上次时间。这三个字段的类型均属time_t,是标准的UNIX时间格式,记录了自Epoch以来的秒数。

文件属主

新建文件的属主

  • 新建文件的用户ID,“取自”进程的有效用户ID。
  • 新建文件的组ID“,取自”进程的有效组ID(System V系统默认行为),或父目录的组ID(BSD系统默认)。

当为项目创建目录时,需要该目录下的所有文件隶属于某一特定组,并且可为该组所有成员访问。这是采用后一种行为就非常使用。

新建文件的组ID在这两者间如何取舍,由多种因素决定,新文件所在文件系统类型就是其中之一。

改变文件属主:chown()、fchown()和lchown()

系统调用chown()fchown()lchown()可用来改变文件的属主(用户ID)和属组(组ID)。

#include <unistd.h>

int chown(const char *pathname, uid_t owner, gid_t group);

#define _XOPEN_SOURCE 500	/*Or: #define _BSD_SOURCE*/
#include <unistd.h>

int lchown(const char *pathname, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
		All returns 0 on success, or -1 on error.

以上3个系统调用之间的区别类似于stat()系统调用一族。

  • chown()改变由pathname参数命名文件的所有权。
  • lchown()用途与chown()相同,不同之处在与若参数pathname为一符号链接,则将会改变链接文件本身的所有权,而与该链接所指代的文件无干。
  • fchown()也会改变文件的所有权,只是文件由打开文件描述符fd所引用。

参数ownergroup分别为文件指定新的用户ID和组ID。若只打算改变其中之一,只需将另一参数置为-1,即可令与之相关的ID保持不变。

只有特权级进程(CAP_CHOWN)才能使用chwon()改变文件的用户ID。非特权级进程,可使用chown()将自己所拥有文件的组ID改为其所从属的任一属组的ID,前提是进程的有效用户ID与文件的用户ID相匹配。特权级进程则可将文件的组ID修改为任意值。

文件权限

普通文件的权限

stat结构中st_mode字段的低12位定义了文件权限。前3位为专有位,分别是set-user-IDset-group-IDsticky位。

头文件<sys/stat.h>定义了可与stat结构中st_mode相与(&)的常量,用于检查特定权限位置位与否。

常量其他值权限位
S_ISUID04000Set-user-ID
S_ISGID02000Set-group-ID
S_ISVTX01000Sticky
————————————
S_IRUSR0400User-read
S_IWUSR0200User-write
S_IXUSR0100User-execute
————————————
S_IRGRP040Group-read
S_IWGRP020Group-write
S_IXGRP010Group-execute
————————————
S_IROTH04Other-read
S_IWOTH02Other-write
S_IXOTH01Other-execute

除表中常量外,还分别将各类权限掩码定义为常量:
S_IRWXU(0700)S_IRWXG(070)S_IRWXO(07)

使用示例

将文件权限掩码转换为ls风格的字符串。

#define FILE_PERMS_H
#include <sys/types.h>
#include <stdio.h>

#define FP_SPECIAL 1    /*Include set-user-ID, set-group-ID, and sticky
                            bit information in returned string */
char *filePermStr(mode_t perm, int flags);

#define STR_SIZE    sizeof("rwxrwxrwx")

char *  /*Returns ls(1)-style string for file permissions mask*/
filePermStr(mode_t perm, int flags)
{
    static char str[STR_SIZE];
    snprintf(str, STR_SIZE, "%c%c%c%c%c%c%c%c%c",
        (perm & S_IRUSR) ? 'r' : '-', (perm & S_IWUSR) ? 'w' : '-',
        (perm & S_IXUSR) ?
            (((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 's' : 'x'):
            (((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 'S' : '-'),

        (perm & S_IRGRP) ? 'r' : '-', (perm & S_IWGRP) ? 'w' : '-' ,
        (perm & S_IXGRP) ?
            (((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 's' : 'x'):
            (((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 'S' : '-'),

        (perm & S_IROTH) ? 'r' : '-', (perm & S_IWOTH) ? 'w' : '-',
        (perm & S_IXOTH) ?
            (((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 's' : 'x'):
            (((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 'S' : '-'),

    );
	return str;
}

更改文件权限:chmod()和fchmod()

#include <sys/stat.h>

int chmod(const char *pathname, mode_t mode);

#define _XOPEN_SOURCE 500	/*Or: #define _BSD_SOURCE*/
#include <sys/stat.h>

int fchmod(int fd, mode_t mode);
		Both returns 0 on success, or -1 on error
  • 系统调用chmod()更改由pathname参数所指定文件的权限。若该参数所指为符号链接,调用chmod()会改变符号链接所指代文件的访问权限,而非对符号链接自身的访问权限。(符号链接自创建起,其所有权限便为所有用户共享,且这些权限也不的更改。对符号链接解引用时,将忽略所有这些权限。)

  • 系统调用fchmod()更改由打开文件描述符fd所指代文件的权限。
    参数mode用于描述文件的新权限,可以采用八进制数字形式,或者时权限未相或(|)而成的掩码。要想更改文件权限,进程要么具有特权级别(CAP_FOWNER),要么其有效用户ID与文件的用户ID(属主)相匹配。(准确说来,对Linux系统上的非特权级进程,需与文件用户ID相匹配的是进程的文件系统用户ID,而非其有效用户ID。)

示例:将文件权限设为所有用户仅具有读权限:

if(chmod("myfile", S_IRUSR | S_IRGRP | S_IROTH) == -1)
		errExit("chmod");
/*Or equivalently: chmod("myfile", 0444);*/

要修改文件的特定权限位,需要先调用stat()来获取文件的现有权限,调整想修改的权限位,然后使用chmod()去更新权限。

struct stat sb;
mode_t mode;

if(stat("myfile", &sb) == -1)
		errExit("stat");
mode = (sb.st_mode | S_IWUSR) & ~S_IROTH;
	/*onwer-write on, other-read off, remaining bits unchanged*/
if(chmod("myfile", mode) == -1)
		errExit("chmod");

执行以上代码,等价于如下shell命令:

$chmod u+w,o-r myfile

i节点标志

体验极差,还比较难,以后再看…

参考资料:《Linux/UNIX系统编程手册》

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

barbyQAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值