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字节

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被设置

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]; // 文件名
}
posted @ 2020-04-08 03:09  SteveYu  阅读(428)  评论(0编辑  收藏  举报