20201220蔡笃俊《信息安全系统设计与实现》第七、八章学习笔记

一、任务内容

  • 自学教材第7,8章,提交学习笔记(10分)
  • 知识点归纳以及自己最有收获的内容 (3分)
  • 问题与解决思路(2分)
  • 实践内容与截图,代码链接(3分)
  • ...(知识的结构化,知识的完整性等,提交markdown文档,使用openeuler系统等)(2分)

二、知识点归纳以及自己最有收获的内容

(一)知识点归纳

第七章:文件操作

7.1 文件操作级别

文件操作级别
文件操作分为五个级别,按照从低到高的顺序排列如下:

  • 硬件级别:这个级别的文件操作包括:
    • fdisk∶将硬盘、U盘或SDC盘分区。
    • mkfs∶格式化磁盘分区,为系统做好准备。
    • fsck∶检查和维修系统。
    • 碎片整理∶压缩文件系统中的文件。
      
其中大多数是针对系统的实用程序。普通用户可能永远都不需要它们,但是它们是创建和维护系统不可缺少的工具。
  • 操作系统内核中的文件系统函数
    每个操作系统内核均可为基本文件操作提供支持。下面列出了类 Unix 系统内核中的一些函数,其中前缀k表示内核函数。
点我查看文件系统函数

kumount(),kumount()
                  (mount/umount file systems)
kmkdir(),krmdir()
                    (make/remove directory)
kchair(),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()                    
(Lseek/close file descriptors)
keymlink(),kreadlink ()
              (create/read symbolic 1ink files)

kstat(),kfstat(),klatat()            (get file status/information)
kopendir(),kreaddir()
                (open/read directories)

  • 系统调用∶用户模式程序使用系统调用来访问内核函数。
    open()、read()、lseek()和 close()函数都是C语言库函数。每个库函数都会发出一个系统调用,使进程进入内核模式来执行相应的内核函数,例如open可进入kopen(),read可进入kread()函数,等等。当进程结束执行内核函数时,会返回到用户模式,并得到所需的结果。在用户模式和内核模式之间切换需要大量的操作(和时间)。因此,内核和用户空间之间的数据传输成本昂贵。对于读/写文件,最好的方法是匹配内核的功能。内核会按数据块大小(从1KB到8KB)来读取/写入文件。(在Linux 中,硬盘的默认数据块大小是4KB,软盘的是1KB)

  • I/O库函数
    用户通常需要读/写单独的字符、行或数据结构记录等。如果只有系统调用,用户模式程序则必须自己从缓冲区执行这些操作。C语言库提供了一系列标准的I/O函数,同时也提高了运行效率。I/O库函数包括:

FILE mode I/O: fopen(), fread(), fwrite(), fseek(), fclose(),fflush()
char mode I/o: gete(), getchar(), ugetc(), putc(), putchar()
line mode I/O: gets(), fgets(), putc(), puts(), fputs()
formatted I/O: scanf(), fscanf(), sscanf(), printf(), fprintf(), sprintf()
  • 用户命令
    用户可以使用Unix/Linux命令来执行文件操作,而不是编写程序。

    更多文件命令操作可以参考https://www.runoob.com/linux/linux-command-manual.html

  • sh脚本
    sh语言包含所有的有效Unix/Linux命令,它还支持变量和控制语句,如if、do、for、while、case等。除此之外,Perl和Tcl等其他许多脚本语言也使用广泛。我们在面对复杂的GUI操作时可以采用sh脚本来帮助我们解决这个问题。

7.2 文件I/O操作

分为用户模式和内核模式操作:

7.3 低级别文件操作

这部分理论部分比较抽象,直接上实践图

虚拟磁盘映像创建

在磁盘映像文件上运行fdisk

帮助文档

分区:
格式化分区:fdisk只是将一个存储设备划分为多个分区。每个分区都有特定的文件系统类型,但是分区还不能使用。为了存储文件,必须先为特定的文件系统准备好分区。该操作习惯上称为格式化磁盘或磁盘分区。在Linux中,它被称为mkfs,表示Make文件系统。Linux支持多种不同类型的文件系统。下面使用1440个块把vdisk格式化为ext2文件系统:

格式化后的磁盘应是只包含根目录的空文件系统。但是,Linux的mkfs始终会在根目录下创建一个默认的lost+found目录。完成mkfs之后,设备就可以使用了。在Linux中,还不能访问新的文件系统。它必须挂载到根文件系统中的现有目录中。/mnt目录通常用于挂载其他文件系统。由于虚拟文件系统不是真正的设备,它们必须作为循环设备挂载。下面把vdisk挂载到/mnt目录里边。

df -h查看挂载点,然后卸载设备:

挂载分区

用dd命令创建一个虚拟磁盘映像:

在vdisk上运行fdisk来创建一个分区P1:

用以下扇区数在vdisk的分区1上创建一个循环设备并将所有循环设备显示为 /dev/loopN:

从下一步开始格式化/dev/loopN时,出现了错误。5号错误表示分区表无效或者被破坏。很可能是因为之前创建的分区提示的losetup: vdisk: Warning: file does not fit into a 512-byte sector; the end of the file will be ignored.导致的。

这一步导致了我无法把它格式化成EXT2文件系统,从而导致我无法挂载循环设备,显示缺失:

问题出在分区所分的空间不对,这个具体怎么计算的教材上摸棱两可的带过去了,导致我现在也很迷= =

7.4 EXT2文件系统

前面我们对它进行了部分的学习,接下来我们来继续了解一下。
首先是简单的EXT2文件系统布局中的磁盘块的内容:

  • Block#0:引导块,文件系统不会使用它。它用于容纳从磁盘引导操作系统的引导程序。
  • Block#1:超级块(在硬盘分区中字节偏移量为1024)。用于容纳关于整个文件系统的信息。
  • Block#2:块组描述块(硬盘上的s_first_data_blocks-1) EXT2将磁盘块分成几个组。每个组有8192个块(硬盘上的大小为32K)。每组用一个块组描述符结构体描述。
  • Block#8:块位图是用来表示某种项的位序列,例如:磁盘块或索引节点。
  • Block#9:索引节点位图,一个索引节点就是用来代表一个文件的数据结构。
  • Block#10:索引(开始)节点块,每个文件都用一个128节点的独特索引节点结构体表示。其中i_block[15]数组包括指向文件磁盘块的指针,这些磁盘块有:
    • 直接块:指向直接磁盘块;
    • 间接块:每个块编号指向一个磁盘块;
    • 双重间接块:每个块指向256个磁盘块;
    • 三重间接块:对于小型的“EXT2”文件系统,可以忽略这个块。
    • 数据块:紧跟在索引节点块后面的是文件存储块。

第八章:使用系统调用进行文件操作

常用系统调用:

stat     获取文件状态信息
open     打开一个文件进行读、写、追加
close    关闭打开的文件描述符
read     读取打开的文件描述符
write    写入打开的文件描述符
lseek    重新定位文件描述符的读/写偏移量
dup      将文件描述符复制到可用的最小描述编号中
dip2     将oldfd复制到newfd中,如果newfd一打开,先将其关闭
link     将新文件硬链接到旧文件
unlink   减少文件的链接数;如果链接数达到零,则删除文件
symlink  为文件创建一个符号链接
readlink 读取符号链接文件的内容
umask    设置文件创建掩码;文件权限为 (mask&~umasl)

8.3 使用系统调用进行文件操作

系统调用

以两种不同的模式运行,即内核模式和用户模式,用户模式的权限非常有限,不能执行任何需要特殊权限的操作,有特殊权限的操作必须在Kmode下执行。

系统调用必须由程序自身发出,实例如下

int syscall(int a,int b,int c,int d);

其中syscall() 执行一个系统调用,第一个参数是系统调用编号,后面的参数是对应内核函数的参数。

系统调用可让进程从用户模式切换到内核模式,内核的系统调用处理程序根据系统调用编号number将调用路由到一个相应的内核函数。当进程结束执行内核函数后会返回到用户模式并得到所需结果;如果失败,错误编号会记录在errno中,可以通过strerror获取错误对应的描述字符串。成功返回0,失败返回-1。

因为没有新目录,所以系统调用成功,返回值为0.如果我们接下来再运行一次,就会因为目录存在而失败了:

8.5 链接文件

硬链接文件命令:ln oldpath newpath
软连接文件命令:ln -s oldpath newpath

8.6 stat系统调用

所有的stat系统调用都以stat结构体形式返回信息,其中包含以下片段:

struct stat{

dev_t    st_dev;

ino_t st_ino;

mode_t st_mode;

st_nlink; nlink_t

uid_t st_uid;

gia_t st_gid;

dev_t st_rdev;

off_t st_size;

u32     st_blksize;

u32     st_block8;

time_t  st_atime;time_E

st_mtime time_t st_ctime;

}

这部分书上主要是介绍了stat的具体结构,想要深入学习的话可以参考这篇链接:https://blog.csdn.net/qq_43471489/article/details/124935173

接下来看看opendir-readdir函数:
opendir()、readdir()和closedir()这三个函数主要用来遍历目录,使用前需要包括sys/types.h和dirent.h这两个头文件。closedir与opendir搭配使用,我们可以与C语言中的fopen和fclose函数联系,其作用是相同的。

8.7 open-close-lseek系统调用

  • open:打开一个文件进行读、写、追加

  • close:关闭打开的文件描述符

  • read:读取打开的文件描述符

  • write:写入打开的文件描述符

  • lseek:将文件描述符的字节偏移量重新定位成偏移量

  • umask:设置文件创建掩码;文件权限(mask&~umask)

这一部分也与c语言很类似,可以参考这个学习:https://blog.csdn.net/S5242/article/details/115719892

顺便附上read和write系统调用的参考学习的链接,其实这个调用也和c语言很类似:https://blog.csdn.net/qq_39755395/article/details/78516383?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-3-78516383-blog-115719892.pc_relevant_multi_platform_featuressortv2dupreplace&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-3-78516383-blog-115719892.pc_relevant_multi_platform_featuressortv2dupreplace&utm_relevant_index=4

(二)最有收获的内容

7、8章围绕着文件操作展开,让我们更加深入的了解了Linux的文件系统。最让我收获颇丰的应该是直接进行系统调用进行文件操作了。这让我深入了解了一个文件系统是怎么样进行文件操作的。之所以使用系统调用是因为系统资源的有限性以及内核管理的方便,系统调用将上层内的应用开发与底层的硬件实现分开,上层应用不需要关注底层硬件的具体实现。Linux的系统调用使用软中断实现,使用系统调用后,该程序的状态将从用户态切换到内核态。库函数实现最终也要调用系统调用函数,但它封装了系统调用操作,从而增加了代码的可移植性。

三、问题与解决思路

这两章比较抽象,难免遇到了一些问题
比如这个:

看报错知道是路径出了问题,但是按照tree显示的路径来输一直不正确,直到我进入文件直接把它的路径复制下来我才知道中间少了个username……

还有动态库的连接问题

挺抽象的,明明之前静态链接库使用绝对路径指定头文件目录都可以,为什么到动态库就不行了……解决方法很简单,就是用-Iinclude指定头文件的目录,这个也可以在静态链接库那里使用。

还有文件分区的问题,这个在上面提出来过了,解决方法应该是要计算好分区的大小再分区就行。

最后是软链接和硬链接,它们究竟有什么区别?
参考了这篇博客得以解决:https://blog.csdn.net/m0_60861848/article/details/125844816
简单的理解:软链接就像快捷方式,硬链接就像副本。

最后总结一下,这两章确实很抽象,但是我们只要多实践其实也能很好的理解Linux的文件系统和花里胡哨的文件操作方法。

posted @ 2022-09-25 14:18  acacacac  阅读(98)  评论(0编辑  收藏  举报