一、知识点归纳
(一)第七章
7.1 文件操作
文件操作可以分为以下五个级别,它们从低到高的顺序排列如下:
1. 硬件级别
硬件级别的文件操作包括以下几种:
- fdisk:将硬盘、U盘或SDC盘分区。
- mkfs:格式化磁盘分区,为系统做好准备。
- fsck:检查和维修系统。
- 碎片整理;压缩文件系统中的文件。
注意:其中大多数是针对系统的实用程序。普通用户可能永远都不需要它们,但是它们是创建和维护系统不可缺少的工具。
2. 操作系统内核中的文件系统函数
每个操作系统内核都可以为基本文件操作提供支持。以下是类Unix系统内核中的一些函数,其中前缀k
表示内核函数。
kmount () . kumount ( ) (mount/umount file systems)
kmkdir(), krmdir() (make/ remove directory)
kchdir(), kgetcwd () (change directory, get CWD pathname)
klink(),kunlink() (hard link/unlink files)
kchmod(), kchown(),kutime() (change r|w|x permissions, owner,time)
kcreat (), kopen() (create/open file for R,W,RW,APPEND)
kread(),kwrite() (read/write opened files)
klseek(): kclose() (lseak/close file descriptors)
ksymlink(), kreadlink () (create/read symbolic link files)
kstat(), kfstat(),klstat() (get file status/information)
kopendir(), kreaddiz() (open/read airectories)
3. 系统调用
用户模式程序使用系统调用来访问内核函数。例如open()
, read()
, lseek()
和close()
都是C语言库函数。每个库函数都会发出一个系统调用,使进程进入内核模式来执行相应的内核函数。
4. I/O库函数
系统调用可以让用户读/写多个数据块,这些数据块只是一系列字节。由于用户并不关心这些数据的意义,因此,C语言提供了一套标准的I/O函数,同时也提高了运行效率。
这些函数主要包括:
- FILE mode I/O:
fopen()
,fread()
,fwrite()
,fseek()
,fclose()
,fflush()
- char mode I/O:
getc()
,getchar()
,ugetc()
,putc()
,putchar()
- line mode I/O:
gets()
,fgets()
,puts()
,fputs()
- formatted I/O:
scanf()
,fscanf()
,sscanf()
,printf()
,fprintf()
,sprintf()
5. 用户命令
用户可以使用Unix/Linux命令来执行文件操作,而不是编写程序。例如:mkdir
,rmdir
,cd
,pwd
,ls
,link
,unlink
,rm
,cat
,cp
,mv
,chmod
,等等。
注意:每个用户命令实际上是一个可执行程序,通常为库I/O函数。其顺序如下:
Command => Library I/O function => System call => Kernel Function
7.2文件I/O操作
7.3低级别文件操作
(1)分区
一个块存储设备可以分为几个逻辑单元称为分区。各分区均可格式化为特定的文件系统,也可以安装在不同的操作系统上。分区表位于第一个扇区的字节偏移446(ox1BE)处,该扇区称为设备的主引导记录。表有4个条目,每个条目由一个16字节的分区结构体定义,即:
stuct partition {
u8 drive; // 0x80 - active
u8 head; // starting head
u8 sector; // starting sector
u8 cylinder; // starting cylinder
u8 sys_type; // partition type
u8 end_head; // end head
u8 end_sector; // end sector
u8 end_cylinder; // end cylinder
u32 start_sector; // starting sector counting from 0
u32 nr_sectors; // number of sectors in partition )
如果某分区是扩展类型(类型编号=5),那么它可以划分为更多分区。假设分区P4是扩展类型,它被划分为扩展分区P5、P6、P7。扩展分区在扩展分区区域内形成一个链表。
每个扩展分区的第一个扇区是一个本地MBR。每个本地MBR在字节偏移量0xIBE处也有一个分区表,只包含两个条目。第一个条目定义了扩展分区的起始扇区和大小。第二个条目指向下一个本地MBR。所有本地MBR的扇区编号都与P4的起始扇区有关。照例,链表以最后一个本地MBR中的0结尾。在分区表中,CHS值仅对小于8GB的磁盘有效。对大于8GB但小于4G扇区的磁盘,只有最后两个条目start _sector 和nr sector有意义。
(2)格式化分区
fdisk只是将一个存储设备划分为多个分区。每个分区都有特定的文件系统类型,但是分区还不能使用。为了存储文件,必须先为特定的文件系统准备好分区。该操作习惯上称为格式化磁盘或磁盘分区。在Linux中,命令
mkfs -t TYPE [-b bsize] device nblocks
在一个nblocks设备上创建一个TYPE文件系统,每个块都是bsize字节。如果bsize未指定,则默认大小为1KB。例如假设是EXT2/3文件系统,它作为Linux的默认文化系统,因此,
mkfs -t ext2 vdisk 1440
使用1440个块将vdisk格式化为EXT2文件系统。
在Linux中,还不能访问新的文件系统。它必须挂在到跟文件系统中的现有目录。由于细腻文件系统不是真正的设备i,他们必须作为循环设备挂载,如:
sudo mount -o loop vdisk /mnt
将 vdisk挂载到/mnt 目录中。不带任何参数的 mount命令会显示Linux系统的所有挂载设备。挂载完成后,挂载点/mnt 改变,与挂载设备的根目录相同。用户可以将目录(cd)更改为/mnt,像往常一样对设备进行平铺操作。挂载后的设备使用完成后,将cd从/mnt中取出,然后输入
sudo umount /mnt
以卸载设备,将其与根文件系统分离。设备上保存的文件应保留在该设备中。
(3)挂载分区
man 8 losetup:显示用于系统管理的losetup 实用工具命令(实践截图)
7.4 EXT2文件系统简介
(二)第八章 使用系统调用进行文件操作
本章主要介绍如何使用系统调用进行文件操作,探讨了系统调用的作用,并列举了常用的系统调用。此外,还具体介绍了stat
系统调用等内容。
8.1 系统调用及Linux在线手册
-
进程的运行模式:
- 操作系统中的进程在两种模式下运行:内核模式(Kmode)和用户模式(Umode)。
- 在Umode中,进程权限有限,不能执行特权操作。这些操作必须在Kmode下执行。
- 系统调用(syscall)允许进程从Umode切换到Kmode以执行特权操作。
-
在线手册的位置:
- Unix和大部分Linux版本:
/usr/man/
- Ubuntu Linux:
/usr/share/man
- 查看系统调用名称的手册页:
man 2 NAME
- Unix和大部分Linux版本:
8.2 使用系统调用进行文件操作
int syscall(int a, int b, int c, int d);
其中:
a:系统调用编号
b, c, d:对应内核函数的参数
8.3 链接文件
硬链接:
命令:ln oldpath newpath
系统调用:link(char *oldpath, char *newpath)
软链接(符号链接):
命令:ln -s oldpath newpath
系统调用:link(char *oldpath, char *newpath)
8.4 stat系统调用
(三)苏格拉底挑战
二、问题与解决思路
(一) 文件描述符与打开文件之间的关系
Linux系统中采用一个理念:一切皆文件。这包括普通文件、目录文件、链接文件和设备文件。为了理解文件描述符和打开文件之间的关系,我们需要深入研究以下几个方面:
1. 文件描述符
文件描述符(file descriptor)是Linux系统用于引用已经打开的文件的索引。它是一个非负整数,并通常是一个较小的数。例如,标准输入、标准输出和标准错误对应的文件描述符分别是0、1和2。当您打开一个新的文件时,它的文件描述符通常会是3(假设您没有关闭前面的描述符)。
2. 进程与文件的关系
- 同一文件可以被多次打开,无论是在同一个进程还是不同的进程。
- 每个进程有其独立的文件描述符表。
- 尽管在不同的进程中,文件描述符的数值可能相同(如3),但它们可以引用不同的文件。
3. 关键数据结构
为了理解文件描述符与打开文件之间的关系,我们需要深入了解Linux内核维护的以下三个数据结构:
-
进程级的文件描述符表:
- 它为每个进程维护一个独立的文件描述符表。
-
系统级的打开文件描述符表:
- 它为每个打开的文件都有一个条目。
- 这意味着,如果同一文件被多次打开(即使是由同一进程),在此表中都会有多个条目。
-
文件系统的i-node表:
- 每个文件在磁盘上都有一个与之对应的i-node,其中存储了文件的元数据,例如权限、大小和时间戳。
- 当文件被打开时,其i-node被加载到内存中。
通过这三个数据结构的互动,Linux系统能够高效地跟踪每个进程中打开的文件,并确保文件的并发访问不会导致数据冲突或不一致。
三、实践过程
(一)挂载分区