Linux应用开发(文件属性)

第一节:umask权限屏蔽位

文件的类型:

符号 类型
- 普通文件
d 目录directory
l 软链接link
c 字符设备(终端/dev/tty)
b 块设备(磁盘/dev/sda)
p 管道fifo
s socket
umask权限屏蔽器
umask的本质是一个要减掉的位
umask函数:
复制代码
mode_t umask(mode_t mask);
  • 功能:设置新的屏蔽位
  • 返回值:返回之前的屏蔽位
  • 这个函数总是成功,没有失败的情况

核心公式:

复制代码
文件的最终权限 = ~umask & 你传给 open 的 mode

用大白话讲就是umask是要扣掉的分,取反就是能保留的分,和mode做按位与,就是结果

为什么要有umask这个奇怪的东西?

为了批量省事

场景:你写了一个程序要创建1000个临时文件,写mode太麻烦,系统给你一个默认值,你只要mode = 0666,最终就是0664,省事又安全

umask的返回值为什么重要

复制代码
mode_t old = umask(0777);

为什么要接住这个返回值?因为umask是全局设置,一旦改了就影响后面所有创建文件的操作

如果你想临时改、临时用完就还原,就必须记住旧值:

复制代码
mode_t old = umask(0777);
umask(old);

第二节:查文件的属性

access---试一下这个文件我能不能动

复制代码
int access(const char *pathname, int mode);

功能:检查文件的权限

四个mode参数:

mode 含义
F_OK File Okay,只测试文件是否存在
R_OK Read,只测试可读
W_OK Write,只测试可写
X_OK eXecute,只测试可执行
返回值:
  • 0:检查通过(文件存在、权限够)
  • -1:不通过,设置errno

🔴注意:access检查的是真实权限,不是有效权限

  • 真实权限:ls -l 显示的那个
  • 有效权限:你当前身份实际能用的权限

stat---拿到文件的所有档案

复制代码
int stat(const char *pathname, struct stat *statbuf);
  • 功能:把文件的全部属性填进statbuf指向的结构体
  • 成功:返回0
  • 失败:返回-1并设置errno

struct stat全字段解读

复制代码
struct stat {
	dev_t st_dev;          //设备的编号(文件在哪个磁盘分区上)
	ino_t st_ino;          //inode号---文件的身份证
	nlink_t st_nlink;      //硬链接个数
	uid_t st_uid;          //所有者uid
	gid_t st_gid;          //所属者gid
	off_t st_size;         //文件大小(字节) 
	blksize_t st_blksize;  //文件系统的块大小
	blkcnt_t st_blocks;    //占用多少个块
	struct timespec st_atim;  //最后访问时间
	struct timespec st_mtim;  //最后修改内容时间
	struct timespec st_ctim;  //最后改元数据时间(权限、大小变了)
}

三个时间戳的区别:

时间 名字 什么时候变
atime access time 你读了这个文件
mtime modify time 你改了这个内容
ctime change time 你改了元数据
举例:
  • 你cat一个文件:只有atime变
  • 你vi改内容保存:mtime变
  • 你chmod777:只有ctime变,mtime不变

inode:文件的身份证号

  • 文件名=人的名字,可以改,可重名(同一目录下不行,但不同目录可以)
  • inode号=人的身份证号,唯一,不可改

getpwuid/getgrgid---把数字翻译成名字

stat出来的uid/gid是数字,但是你想看的是名字,这就需要查表:

复制代码
struct passwd *getpwuid(uid_t uid);
struct group *getgrgid(gid_t gid);

fstat---已经打开的文件怎么查属性

复制代码
int fstat(int fd, struct stat *statbuf);

区别只有一个:参数从路径变成了fd

函数 参数 什么时候用
stat stat("a.txt",&st) 你知道文件名
fstat fstat(fd,&st) 文件已经打开,你手上有fd
为什么需要fstat?
  • 省掉路径拼接---你已经open过了,直接查fd就行
  • 防止竟态---如果你先用stat("a.txt")查到大小,再open("a.txt"),中间文件被别人改了你就错,用fstat就锁定的是这个fd,不受影响
  • 处理特殊情况---有些fd不是文件,没有路径只能用fstat

第三节:目录操作

目录和文件有什么不同?

文件你有open打开,目录呢?Linux里目录也是一个文件,但是它的内容不是普通字节,而是一张表

所以有一套专门的函数:

操作 文件用 目录用
打开 open opendir
读 read readdir
关闭 close closedir
得到一个流 FILE*/fd DIR*
DIR* 是目录专用的句柄类型,和FILE*、fd一样,是"打开后拿到的那个号码牌"

opendir打开目录

复制代码
DIR *opendir(const char *name);
  • 成功:返回DIR*
  • 失败:返回NULL并设置errno

readdir读目录

复制代码
struct dirent *readdir(DIR *dirp);

一次读一个目录项,也就是目录里的一个名字(可能是文件,也可能是子目录)

返回值有三种情况:

返回值 含义 errno状态
非NULL指针 成功,读到一个目录项 不变
NULL 读完了 不变(保持原值)
NULL 出错了 被设置
🔴区分读完了和出错了就看errno有没有被设置

closedir关闭目录

复制代码
int closedir(DIR *dirp);
  • 成功:返回0
  • 失败:返回-1并设置errno

readdir的正确用法

因为读完了也返回NULL,所以必须先清空errno

struct dirent结构体

复制代码
struct dirent {
	ino_t d_ino;              //inode号
	off_t d_off;               
	unsigned short d_reclen;  //这条记录有多长
	unsigned char d_type;     //文件类型
	char d_name[256];         //文件名/目录名
}

🔴只需要关心两个字段

d_name256---里面的名字,这可能是文件名,可能是子目录名,还可能是./...

d_type---文件类型

d_type 含义
DT_REG 普通文件regular
DT_DIR 目录Directory
DT_LNK 软链接Link
DT_CHR 字符设备
DT_BLK 块设备
DT_FIFO 管道
一个重要提醒:不是所有文件系统都支持d_type,有些文件系统的值是DT_UNKNOWN,这时候只能靠stat去查

必须认识的三个特殊名字

名字 是什么
. 当前目录
... 上一级目录

其他三个目录函数

mkdir创建目录

复制代码
int mkdir(const char *pathname, mode_t mode);
  • 成功:返回0
  • 失败:返回-1并设置errno
  • mode权限和open的第三个参数一样是八进制
    🔴mkdir的mode同样受umask影响,最终权限=~umask & mode

rmdir删除目录

复制代码
int rmdir(const char *pathname);
  • 成功:返回0
  • 失败:返回-1
    关键限制:rmdir只能删除空目录,如果目录里面还有文件,会失败返回-1
    🔴为什么?因为你让用户删除一个目录,他以为是删除这文件夹,结果文件全没了,那就太危险,所以强制要求先清空

chdir切换目录

复制代码
int chdir(const char *path);
  • 成功:返回0
  • 失败:返回-1
相关推荐
wuminyu1 小时前
JMM学习总结:深入理解happens-before关系
java·linux·c语言·jvm·c++
古法老登瞎折腾1 小时前
大数据智能运维实战(一):机器和任务数据都有了,如何用 MCP 搭建运维助手?
大数据·运维·spring boot·spring ai·mcp
开开心心就好2 小时前
多份文档怎么批量打印?支持多种格式
java·服务器·开发语言·pdf·ocr·散列表·启发式算法
海宇数据2 小时前
零信任架构实战:基于海宇入职背调报告构建自动化即时配送与网约车众包运力准入鉴权网关
运维·人工智能·架构·自动化
姜鱼问生2 小时前
每次开机手动检查 6 样东西?我写了个 2 秒自检脚本
运维·网络·nginx·docker·容器
wangqiaowq2 小时前
PostgresSQL server Docker 安装部署
运维·docker·容器
高晶3 小时前
ARM 嵌入式 Linux 文件系统从入门到实战:目录结构、权限管理、选型与挂载排查全攻略
linux·程序员
南棋网络安全3 小时前
ssrf跨站请求伪造(保姆级教程)
运维·服务器·网络·网络安全
运维全世界3 小时前
Slurm集群搭建实战踩坑:存储节点无RAID、跨节点GPU无法读取数据彻底解决
linux