LinuxC——2.文件属性
LinuxC——2.文件属性
0.❤️API
- stat、fstat、lstat
- umast
- chmod、fchmod
- chown、fchown、lchown
- link、unlink、remove、rename、symlink、readlink
- chdir、getcwd
1.🧡Linux的7种文件类型
-
普通文件
-
-
文本文件
存放文字编码,文本编辑器打开后,进行翻译成文字
-
二进制文件(机器码)
存放执行二进制机器码,使用文本编辑器查看是乱码
对于linux而言没有区别,至于文中数据由应用程序来解决
-
-
目录文件
d
目录是一种特殊文件,专门用于管理其他文件
-
字符设备文件
c
对接字符设备驱动,读取字符设备文件,是与字符设备驱动的交互
-
块设备
b
-
字符设备
以字节为单位操作数据,比如鼠标、键盘、显示器
-
块设备
块设备数据非常大,提高读写,以1024为单位。比如电脑磁盘、移动硬盘
-
-
Pipeline
p
管道文件,用于不同程序或进程的通信(使用一个管道文件进行交互)
-
Socket
s
套接字文件
-
符号链接
l
类似快捷图标
2.🧡基础知识
🤠使用file命令可查看文件类型,如file a.txt
-
Linux可执行文件:ELF文件(Executable and Linkable Format)
-
Windows可执行文件:PE文件(protable execute)
-
Mac可执行文件:Mach-O文件(match object)
🤠strip a.out
将这个a.out进行压缩,发布版本会进行压缩
3.💛stat、lstat、fstat
三个是兄弟函数,ls命令的底层是这个
🤠1. stat
- 获取文件属性信息
数据中转过程:
应用缓存<-内核缓存<-驱动程序<-块设备
- 函数原型
int stat(const char *path, struct stat *buf);
path: 路径名
struct stat {
dev_t st_dev; // 块设备号
ino_t st_ino; // 节点号
mode_t st_mode;// 文件类型和权限
nlink_t st_nlink; // 硬链接
uid_t st_uid; // 文件所属用户id
gid_t st_gid; // 文件所属组id
dev_t st_rdev; // 字符设备id
off_t st_size; // 文件大小
blksize_t st_blksize; // 每次IO块大小
blkcnt_t st_blocks; // 块索引
// windows下文件时间也是这三种
time_t st_atime; // 最后访问时间
time_t st_mtime; // 最后修改时间
time_t st_ctime; // 最后属性修改时间,如权限修改,文件所有者
}
制作一个my_ls
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
void print_error(char* str) {
perror(str);
exit(-1);
}
int main(int argc, char **argv) {
int ret = 0;
if(argc != 2) print_error("argc is wrong");
struct stat s = {0};
ret = stat(argv[1], &s);
if(-1 == ret) {
print_error("查看属性失败");
}
printf("%d %lu %d %ld %ld %ld\n", s.st_mode, s.st_nlink, s.st_gid,
s.st_uid, s.st_size, s.st_atime);
return 9;
}
🤠2.st_mode
文件权限16位,3位设置位,其余是-rwxrwxrwx形式
使用&进行提取位,一个数&(1<<n),得出这个的真值,所以,我们可以同理可写出
/* 打印文件类型 */
char file_type = '0';
if(S_ISLNK(s.st_mode)) file_type = 'l'; // link
else if(S_ISREG(s.st_mode)) file_type = '-'; // regular
else if(S_ISDIR(s.st_mode)) file_type = 'd'; // dictionary
else if(S_ISCHR(s.st_mode)) file_type = 'c'; // char
else if(S_ISBLK(s.st_mode)) file_type = 'b'; // block
else if(S_ISFIFO(s.st_mode)) file_type = 'p'; // pipe
else if(S_ISSOCK(s.st_mode)) file_type = 's'; // socket
putchar(file_type);
char buf[10] = { '\0' };
char tmp_buf[] = "rwxrwxrwx";
/*
太复杂,采用下面的
if(s.st_mode & S_IRUSR) buf[0] = 'r';
else buf[0] = '-';
if(s.st_mode & S_IWUSR) buf[1] = 'w';
else buf[1] = '=';
*/
int i = 0;
for(i = 0; i <= 8; i++) {
if(s.st_mode & (1 << (8 - i))) buf[i] = tmp_buf[i];
else buf[i] = '-';
}
printf("%s", buf);
putchar('\n');
权限在linux分16位,除了3位为信息位,1位为介绍属性位,其余12位代表用户、用户组、其他的权限
chmod a=rwx file # all
chmod u=rwx file # user
chmod g=rwx file # group
chmod o=rwx file # other
chmod a+x file # +代表增加权限
chmod a-w file # -代表减少权限
🤠3.lstat
- ln -s 命令
ln -s afile bfile
创建 afile 链接 bfile
- 介绍lstat
lstat与stat基本相同,我们发现使用ls的时候,链接文件的ls -a中间显示的是原文件,目的是调用了lstat函数,我们将上述的c文件的stat函数改为lstat,发现可以顺利解析link file。
ret = lstat(argv[1], &s);
// 解析运行
// 显示链接文件的状态
// 表名源码中的状态是调用了stat
🤠4.fstat
fstat与stat基本相同,相当于把path换为了文件描述符,通过fd进行查询文件属性
fd = open('xxx', O_RDWR)
ret = fstat(fd, &s);
4.💚Umask 和 truncate
🤠1.umask
open创建的一个问题
文件权限掩码,我们使用open函数创建一个文件,先通过掩码进行 & 掩码,掩码默认值为 2, 所以我们使用其他用户创建777权限,仅仅能得到775。
我们通过Umask进行修改文件掩码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = 0;
mode_t ret = 0;
// 掩码改为0
ret = umask(0);
printf("old mask: %d\n", ret);
fd = open("./new_file.txt", O_RDWR|O_CREAT, 0777);
if(-1 == fd) {
perror("open fail\n");
return 1;
}
return 0;
}
🤠2.truncate、ftruncate
截断函数,open的时候,指定O_TRUNC,如果有数据,会截断为0
truncate传的第一个参数是path,第二个是一个offsets
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = 0;
mode_t ret = 0;
truncate("new_file.txt", 10);
return 0;
}
ftruncate进行fd的截断
fd = open("./new_file.txt", O_RDWR|O_CREAT, 0777);
ftruncate(fd, 5);
5.💙空洞文件
假设开辟一定空间,不去使用。进行动态开辟空间。
我们使用truncate和ftruncate进行制作空洞文件
1.使用open创建文件
2.使用truncate进行截断8000个字符
我们发现,使用ls查看有8000,但是使用du命令看实际大小,为0,这是一个动态开辟的空间。
块字符是进行使用空洞文件进行存储
6.💜文件系统索引
1.只要是一个系统,所有索引都是使用树形结构进行管理的。
2.文件在块设备怎么存储
- 自举区
- 超级区:块设备的分配和释放
- inode节点区:空间大小相同的i节点,每个节点存储文件属性信息,每个大小512(0.5k),结构体中的st_dev
- 数据区:仅目录,链接文件、普通文件有数据,其余4个都没有数据。数据区每个分配4K字节
7.❤️link & unlink & remove & rename
int link(const char* oldpath, const char* newpath)
int unlink(const char* pathname)
进行硬链接(很easy,代码略),正确返回0,错误返回-1,errno被设置
int remove(const char* pathname)
删除文件,正确返回0,错误返回-1,errno被设置
int rename(const char* oldpath, const char* newpath)
重命名,正确返回0,错误返回-1,errno被设置
8.🧡符号连接 symlink & redline
1.硬链接,同一个文件有不同名字,指向同一个inode节点
2.符号链接(软链接)
- 2个文件,有自己的inode节点,指向文件名
3.不能给目录创建硬链接,可以创建符号链接
4.可以给符号链接创建硬连接
int symlink(const char* oldpath, const char* newpath)
创建一个符号连接,正确返回0,错误返回-1,errno被设置
int readlink(const char* path, char *buf, size_t bufsiz)
读取符号链接,正确返回0,错误返回-1,errno被设置
9.getcwd、chdir、mkdir、rmdir
int getcwd(char* buf, size_t size)
获取一个当前路径(pwd的实现)
Int chdir(char* buf)
更换到路径(类似cd命令)
int mkdir(const char* pathname, mode_t mode)
创建目录(mkdir命令)
int rmdir(const char* pathname)
删除目录(rmdir 命令)
10.opendir、readdir、chmod、fchm
DIR *opendir(const char *name)
打开目录
struct direct *readdir(Dir *dirp)
读取目录
chmod(const char* path, mode_t m)
修改权限
fchmod(int fd, mode_t m)
修改权限
struct dirent {
ino_t d_ino; // 编号
off_t d_off; // 偏移
unsigned short d_reclen; // 目录项大小
unsigned char d_type; // 文件类型
char d_name[256]; // 文件名
}