[Linux-C/C++] sys/stat.h头文件解析

2019-06-30   111 次阅读


sys/stat.h头文件解析

** 目录:**

  1. stat结构体
struct stat
{
	unsigned long st_dev; //设备号(文件系统)
	unsigned long st_ino; //inode节点号
	unsigned int st_mode; //文件类型和权限信息
	unsigned int st_nlink; //文件的符号链接数
	uid_t st_uid; //用户ID
	gid_t st_gid; //组ID
	unsigned long st_rdev; //设备号用于特殊文件
	unsigned long __pad1;
	long st_size; //文件的大小(以字节为单位)
	int st_blksize; //best I/O block size
	int __pad2;
	long st_blocks;  //文件内容对应的块大小
	long st_atime;  //文件内容对应的块数量
	unsigned long st_atime_nsec;
	long st_mtime; //文件最后被访问的时间
	unsigned long st_mtime_nsec;
	long st_ctime; //文件内容最后被修改的时间
	unsigned long st_ctime_nsec;
	unsigned int __unused4; //未使用4,预留位
	unsigned int __unused5;
} 

st_mode 定义了下列数种情况:
S_IFMT 0170000 文件类型的位遮罩
S_IFSOCK 0140000 scoket
S_IFLNK 0120000 符号连接
S_IFREG 0100000 一般文件
S_IFBLK 0060000 区块装置
S_IFDIR 0040000 目录
S_IFCHR 0020000 字符装置
S_IFIFO 0010000 先进先出(命名管道)
和文件权限标识

主要函数


extern int chmod(const char*, mode_t);
extern int fchmod(int, mode_t);
extern int mkdir(const char*, mode_t);

extern int fstat(int, struct stat*);
extern int fstat64(int, struct stat64*);
extern int fstatat(int, const char*, struct stat*, int);
extern int fstatat64(int, const char*, struct stat64*, int);
extern int lstat(const char*, struct stat*);
extern int lstat64(const char*, struct stat64*);
extern int stat(const char*, struct stat*);
extern int stat64(const char*, struct stat64*);

extern int mknod(const char*, mode_t, dev_t);
extern mode_t umask(mode_t);

1. chmod()

函数定义:

int chmod(const char *path, mode_t mode); 
int fchmod(int fd, mode_t mode); 
int fchmodat(int fd, const char *pathname, mode_t mode, int flag);

函数说明:

chmod()会依参数mode 权限来更改参数path 指定文件的权限。
fchmod()会依参数mode 权限来更改参数fd 所指文件的权限。参数fd 为已打开文件的文件描述符。参数mode 和chmod ()函数一致。
fchmodat函数与chmod函数在下面两种情况下是相同的:

  1. pathname参数为绝对路径
  2. fd参数取值为AT_FDCWD而pathname参数为相对路径

否则,fchmodat计算相对于打开目录(由fd参数指向)的pathname。flag参数可以用于改变fchmodat的行为,当设置了AT_SYMLINK_NOFOLLOW标志时,fchmodat并不会跟随符号链接。

返回值:

权限改变成功则返回0, 失败返回-1, 错误原因存于errno

参数 mode 有下列数种组合:

规律:
S_I固定前缀+位标识
位标识:
SUID=set uid (设置uid位)
SGID=set gid (设置gid位)
SVTX 粘滞位
R读,W写,X可执行,USR用户,GRP组,OTH其他
使用RWXU表示用户(取首字母其他同理)读写执行权限
使用RUSR表示用户读权限,其他同理

S_ISUID 04000 文件的 (set user-id on execution)位
S_ISGID 02000 文件的 (set group-id on execution)位
S_ISVTX 01000 文件的sticky 位
S_IRWXU 00700 文件所有者拥有读写和执行操作权限
S_IRUSR 00400 文件所有者具可读取权限
S_IRGRP 00040 用户组具可读取权限
S_IROTH 00004 其他用户具可读取权限
S_IRWXG 00070 用户组拥有读写和执行操作权限
S_IRWXO 00007 其他用户拥有读写和执行操作权限
S_IWGRP 00020 用户组具可写入权限
S_IWOTH 00002 其他用户具可写入权限
S_IWUSR 00200 文件所有者具可写入权限
S_IXGRP 00010 用户组具可执行权限
S_IXOTH 00001 其他用户具可执行权限
S_IXUSR 00100 文件所有者具可执行权限

权限值 00000含义:首位0为前缀表示八进制,第二位为特殊权限(suid,sgid等),第三位之后分别为用户位,用户组位,其他用户位,

数字表示:读权限值位1,写2,执行4,将多种权限值相加后得到组合权限。

9位字母表示:-------- 用户---,组---,其他---,r--读,-w-写,--x执行,
00755权限表示:rwxr-xr-x

错误代码:

EPERM 进程的有效用户识别码与欲修改权限的文件拥有者不同, 而且也不具root 权限.
EACCESS 参数path 所指定的文件无法存取.
EROFS 欲写入权限的文件存在于只读文件系统内.
EFAULT 参数path 指针超出可存取内存空间.
EINVAL 参数mode 不正确
ENAMETOOLONG 参数path 太长
ENOENT 指定的文件不存在
ENOTDIR 参数path 路径并非一目录
ENOMEM 核心内存不足
ELOOP 参数path 有过多符号连接问题.
EIO I/O 存取错误

示例代码

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>

int DtoO(int mode)//转换为8进制
{
    int tmp = 0;
    if(mode == 0)
        return 0;
    tmp = DtoO(mode/8)*10 + mode%8;
    return tmp;
}

int main(int argc, char *argv[])
{
    unsigned int mode = 0;
    char cmode[8] = {0};
    if(argc < 3)
    {
        fprintf(stderr, "Usage: %s mode filename\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    sprintf(cmode,"0%s",argv[1]);
    mode = (unsigned int)atoi(argv[1]);

    return 0;
}

2. mkdir()

函数定义:

int mkdir(const char *pathname, mode_t mode);
int mkdirat(int fd, const char *pathname, mode_t mode);  

函数说明:

mkdir()函数以mode方式创建一个以参数pathname命名的目录,mode定义新创建目录的权限。
mkdirat()函数和mkdir()唯一区别:前者是在fd文件描述指示的路径下建立还该目录即使用绝对路径。
获取fd目录文件描述符,需要使用dirfd(DIR *dp)函数;参数dp为目录指针,需要opendir(const char *str)函数打开str所指路径。

返回值:

若目录创建成功,则返回0;否则返回-1,并将错误记录到全局变量errno中。

示例代码

#include <sys/stat.h>
 
int main(char argc, char *argv[])
{
	int ok = 0;
	if((ok=mkdir(argv[1],0755)) != 0)
	{
		perror("mkdir %s", argv[1]);
	}
	return 0;	
}

注意事项

如果你希望创建一个755或更高的权限的目录。

需要先调用umask函数。
该函数原型:

mode_t umask(mode_t mask);

函数说明

umask()会将系统umask值设成参数mask&0777后的值,然后将先前的umask值返回。在使用open()建立新文件时,该参数mode并非真正建立文件的权限,而是(mode&~umask)的权限值。

例如,在建立文件时指定文件权限为0666,通常umask值默认为022,则该文件的真正权限则为0666&~022=0644,也就是rw-r--r--

返回值此调用不会有错误值返回。
返回值为原先系统的umask值。

因此,创建755的目录,需要先执行umask(0) 然后再调用mkdir函数。

3. stat()

函数定义

int stat(const char *restrict pathname,struct stat *restrict buf);
int fstat(int fields,struct stat *buf);
int lstat(const char *restrict pathname,struct stat *restrict buf);
int fstatat...

函数说明

给出一个文件(文件、文件夹),一旦给出pathname,stat函数就返回与此命名文件有关的信息结构,fstat函数获取已在描述符fields上打开文件的有关信息。lstat函数类似于stat.但是当命名的文件是一个符号链接时,lstat返回该符号链接的有关信息,而不是由该符号链接引用文件的信息。第二个参数buf是指针,它指向一个我们必须提供的结构,这些函数填写由buf指向的结构。该结构的实际定义可能随实现有所不同.

4. mknod()

用来创建文件的,其原型是:

int mknod(const char *path, mode_t mode, dev_t dev);
int mknodat(int fd, const char *path, mode_t mode, dev_t dev)

函数说明

第一个参数表示你要创建的文件的名称,第二个参数表示文件类型,第三个参数表示该文件对应的设备文件的设备号。只有当文件类型为 S_IFCHR 或 S_IFBLK 的时候该文件才有设备号,创建普通文件时传入0即可。

该函数最主要的用途就是创建FIFO文件,比如你的代码:

mknod(FIFO_FILE,S_IFIFO|0666,0);
FIFO_FILE是一个字符指针,指向文件名,S_IFIFO表示要创建一个FIFO文件,0666表示该文件的权限是所有人可读可写,0表示该文件不是一个设备文件

其他函数

mkfifo

int mkfifo(const char*, mode_t);
//创建命名管道

utimensat和futimens是以纳秒级的精度改变文件的时间戳

int utimensat(int dirfd, const char *pathname,const struct timespec times[2], int flags);
int futimens(int fd, const struct timespec times[2]);

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议