《信息安全与设计》第七、八章学习笔记
第七章 文件操作
文件操作级别:
1.硬件操作级别
(1)-fdisk:将硬盘、u盘或SDC盘分区;
(2)-mkfs:格式化磁盘分区,为系统做好准备;
(3)-fsck:检查和维修系统;
(4)-碎片整理:压缩文件系统中的文件;
2.操作系统内核中的文件系统函数
以下是类unix系统内核中的一些函数,其中前缀k表示内核函数:
(1) kmount () ,kumount ( ) (mount/umount file systems)
(2) kmkdir(), krmdir() (make/ remove directory)
(3) kchdir(), kgetcwd () (change directory, get CWD pathname)
(4) klink(),kunlink() (hard link/unlink files)
(5) kchmod(), kchown(),kutime() (change r|w|x permissions, owner,time)
(6) kcreat (), kopen() (create/open file for R,W,RW,APPEND)
(7) kread(),kwrite() (read/write opened files)
(8) klseek(): kclose() (lseak/close file descriptors)
(9) ksymlink(), kreadlink () (create/read symbolic link files)
(10)kstat(), kfstat(),klstat() (get file status/information)
(11)kopendir(), kreaddiz() (open/read airectories)
3.系统调用
概念:用户模式程序使用系统调用来访问内核函数,其中,open(),read(),lseek()和close()都是c语言库函数。每个库函数都会发出一个系统调用,使进程进入内核模式来执行相应的内核函数,当进程结束执行内核函数使,会返回到用户模式,并得到所需的结果。
4.I/O库函数**
(1)FILE mode I/O: fopen(),fread();fwrite(),fseek(),fclose(),fflush()
(2)char mode I/O: getc(), getchar(); ugetc(); putc(),putchar()
(3)line mode I/O: gets() , fgets();puts( ) , fputs()
(4)formatted I/O: scanf(),fscanf().sscanf(); printf(),fprintf() , sprintf()
5.用户命令
概念:用户可以使用Unix/Linux命令来执行文件操作,而不是编写程序。每个用户命令实际上是一个可执行程序,通常会调用I/O库函数。
用户命令举例:mkdir,rmdir,cd,pwd,ls,link,unlink
处理顺序为:
Command => Library I/O function => system call => Kernel Function
Command ====================> system call => Kernel Function
6.sh脚本/font>
虽然比系统调用方便的多,但是必须要手动呼入命令,如果使用的是GUI,必须要拖放文件图标和点击指向设备来输入,操作繁琐而且耗时。
文件I/O操作
分为用户模式和内核模式
一、用户模式
(1)用户模式下的程序执行操作:
FILE *p = fopen("file", "r"); or FILE *p = fopen( "file", "w");
该操作可打开一个读或者写文件流,此函数为I/O库函数。
(2)fopen()在用户(heap)空间中创建一个FILE结构体:
typedef struct _iobuf {
int cnt; // 剩余的字符,如果是输入缓冲区,那么就表示缓冲区中还有多少个字符未被读取
char *ptr; // 下一个要被读取的字符的地址
char *base; // 缓冲区基地址
int flag; // 读写状态标志位
int fd; // 文件描述符
// 其他成员
} FILE;
该结构体包含一个文件描述符fd、一个fbuf[BLKSIZE]和一些控制变量。它会向内核中的kopen()发出一个fd =open("file",flags=READ or WRITE)
系统调用,构建一个OpenTable来表示打开文件示例。OpenTable的mptr指向内存中的文件INODE。对于非特殊文件,INODE 的i_block数组指向存储设备上的数据块。成功后,fp会指向FILE结构体,其中fd是open()系统调用返回的文件描述符。
(3)fread(ubuf, size,nitem, fp)
将nitem个size字节读取到ubuf上,通将数据从FILE结构体的fbuf上复制到ubuf上若数据足够、则返回。
如果fbuf没有更多数据,则执行(4a)。
(4a)发出read(fd, fbuf, BLKSIZE)//系统调用,将文件数据块从内核读取到fbuf上,然后将数据复制到ubuf上,直到数据足够或者文件无更多数据可复制。
(4b)fwrite(ubuf, size, nitem, fp)//将数据从ubuf复制到 fbuf。
若(fbuf有空间):将数据复制到fbuf上,并返回。
若(fbuf已满):发出 write(fd, fbuf, BLKSIZE)系统调用,将数据块写入内核,然后再次写入fbuf。
这样,fread()/fwrite()会向内核发出read(/write)系统调用,但仅在必要时发出,而且它们会以块集大小来传输数据,提高效率。同样,其他库I/O函数,如 fgetc /fputc、fgets/fputs、fscanf/fprintf等也可以在用户空间内的FILE结构体中对fbuf进行操作。
二、内核模式
(1)内核中的文件系统函数:
假设非特殊文件的read(fd, fbuf[], BLKSIZE)系统调用。
(2)在read()系统调用中,fd是一个打开的文件描述符,它是运行进程的fd数组中的一个索引,指向一个表示打开文件的 OpenTable。
(3)OpenTable包含文件的打开模式、一个指向内存中文件 INODE的指针和读/写文件的当前字节偏移量。从OpenTable的偏移量,
·计算逻辑块编号lbk。
·通过 INODE.i_block[]数组将逻辑块编号转换为物理块编号blk 。
(4)Minode包含文件的内存INODE。EMODE.i_block[]数组包含指向物理磁盘块的指针。文件系统可使用物理块编号从磁盘块直接读取数据或将数据直接写入磁盘块,但将会导致过多的物理磁盘I/O。
(5)为提高磁盘VO效率,操作系统内核通常会使用一组I/O缓冲区作为高速缓存,以减少物理I/O的数量。
(5a)对于read(fd, buf, BLKSIZE)系统调用,要确定所需的(dev, blk)编号,然后查询I/O缓冲区高速缓存,以执行以下操作:
.get a buffer = (dev, blk);
.if (buffer's data are invalid){
start_io on buffer;
wait for I/O completion;
}
.copy data from buffer to fbuf;
.release buffer to buffer cache;
(5b)对于write(fd, fbuf, BLKSIZE)系统调用,要确定需要的(dev, blk)编号,然后查询IO缓冲区高速缓存,以执行以下操作:
.get a buffer = (dev, blk);
.if (buffer's data are invalid){
start_io on buffer;
wait for I/O completion;
}
.copy data from buffer to fbuf;
.release buffer to buffer cache;
低级文件操作
1.分区
一个区块存储设备分为几个逻辑单元,成为分区。分区表位于第一个扇区的字节偏移446(0x1BE)处,该扇区称为设备的主引导记录(MBR),若MBR损坏则无法引导系统启动。
如果某分区是扩展类型(类型编号=5),那么它可以划分为更多分区(逻辑分区)。
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
};
u[num]-无符号整型 num为字节数
每个扩展分区的第一个扇区是一个本地MBR。每个本地MBR在字节偏移量0xIBE处也有一个分区表,只包含两个条目。第一个条目定义了扩展分区的起始扇区和大小。第二个条目指向下一个本地MBR。所有本地MBR的扇区编号都与P4的起始扇区有关。照例,链表以最后一个本地MBR中的0结尾。在分区表中,CHS值仅对小于8GB的磁盘有效。对大于8GB但小于4G扇区的磁盘,只有最后两个条目start _sector 和nr sector有意义。
2.格式化分区
fdisk只是将一个存储设备划分为多个分区。每个分区都有特定的文件系统类型,但是分区还不能使用。为了存储文件,必须先为特定的文件系统准备好分区。该操作习惯上称为格式化磁盘或磁盘分区。在Linux中,它被称为mkfs,表示make文件系统。
mkfs -t TYPE [-b bsize] device nblocks
在一个nblocks设备上创建一个TYPE文件系统,每个块都是bsize字节。如果bsize未绑定,则默认块大小为1KB。
在Linux中对新文件系统不能直接访问,必须挂载到根文件系统中/mnt,虚拟文件系统不是真正的设备,必须作为循环设备挂载、
sudo mount -o loop vdisk /mnt //挂载循环设备
sudo umount /mnt //卸载
3.挂载分区
man 8 losetup:显示用于系统管理的losetup 实用工具命令:
(1)用dd命令创建-一个虚拟磁盘映像:
dd if=/dev/zero of=vdisk bs=1024 count=32768 #32K (1KB) blocks
(2)在vdisk. 上运行fdisk来创建一一个分区P1:
fdisk vdisk
输人n(new)命令,使用默认的起始和最后扇区编号来创建一个分区Pl。然后,输人w命令将分区表写人vdisk并退出fdisko vdisk 应包含-个分区P1 [start=2048, end=65535]。该分区的大小是63488个扇区。
(3)使用以下扇区数在vdisk的分区1上创建一个循环设备 :
losetup -o $(expr 2048 * 512) --sizelimit $(expr 65535 * 512) /dev/1oop1vdisk
losetup需要分区的开始字节(start_ sector512) 和结束字节(end_ sector512)。 读者可手动计算这些数值,并在losetup命令中使用它们。可用类似方法设置其他分区的循环设备。循环设备创建完成后,读进程可以使用命令
losetup - a 将所有循环设备显示为/dev/loopN。
(4)格式化/dev/loop1,它是一个EXT2文件系统:
mke2fs -b 4096 /dev/loop1 7936 # mke2fs with 7936 4KB blocks
该分区的大小是63488个扇区。4KB块的扇区大小是63488 /8=7936
(5)挂载循环设备:
mount /dev/ 1oop1 /mnt # mount as loop device
(6)访问作为文件系统一部分的挂载设备:
(cd /mnt; mkdir bin boot dev etc user) # populate with DIRs
(7)设备使用完毕后,将其卸载。
umount /mnt
(8)循环设备使用完毕后,通过以下命令将其断开:
losetup -a /dev/loop1 # detach a loop device.
*EXT2文件系统
*1.文件系统组成
0 | 1 | 2 | 3-7 | 8 | 9 | 10-32 | 33-x |
---|---|---|---|---|---|---|---|
引导块 | 超级块 | 块组描述符 | 保留块 | 块位图 | 索引节点位图 | 索引节点 | 数据块 |
*2.引导块
容纳从磁盘引导操作系统的引导程序。
*3.超级块
容纳整个文件系统的信息。
struct et2_super block {
u32 s_inodes_count; /* Inodes count */
u32 s_blocks_count; /* Blocks count */
u32 s_r_blocks_count; /* Reserved blocks count */
u32 s_free blocks_count; /* Free blocks count */
u32 s_free_inodes_count; /* Free inodes count */
u32 s_first_data_block; /* First Data Block */
u32 s_log block_size; /* Block size */
u32 s_log_cluster_size; /* Al1ocation cluster size */
u32 s_blocks per_group; /* # Blocks per group * /
u32 s_clusters per_group; /* # Fragments per group */
u32 s_inodes_per_group; /* # Inodes per group * /
u32 s_mtime; /* Mount time * /
u32 s_wtime; /* write time */
u16 s_mnt_count; /* Mount coune* /
s16 s_max_ntcount; /* Maximal mount count */
u16 B_magic; /* Magic signature */
//more non-essential fields
u16 s_inode_size; /* size of inode structure*/
}
3.索引节点
每个文件都用一个128字节(EXT4中的是256字节)的独特索引节点结构体表示。
struct ext2_inode {
u16 i_mode; // 16 bits =|ttttlugs|rwx|rwx|rwxl
u16 i_uid; // owmer uid
u32 i_size; // file size in bytes
u32 i_atime; //time fields in seconds
u32 i_ctime; // since 00:00:00,1-1-1970
u32 i_mtime;
u32 _dtime;
u16 i_gid; // group ID
u16 i_links_count;// hard-link count
u32 i_blocks; // number of 512-byte sectors
u32 i_flags; //IGNORE
u32 i_reservedl;// IGNORE
u32 i_block[15];// See details below
u32 _pad[7]; // for inode size = 128 bytes
}
第八章 使用系统调用进行文件操作
*1.概念
在操作系统中,进程以两种不同的模式运行,即内核模式和用户模式,简称Kmode和Umode。在Umode中,进程的权限非常有限。它不能执行任何需要特殊权限的操作。特殊权限的操作必须在Kmode下执行。系统调用(简称syscall)是一种允许进程进入Kmode以执行Umode不允许操作的机制。复刻子进程、修改执行映像,甚至是终止等操作都必须在内核中执行。
在Unix以及大多版本的Linux中,在线手册页保存在/usr/man/目录中(Goldt等1995;Kerrisk 2010,2017)。而在Ubuntu Linux中,则保存在/usr/share/man目录中。man2子目录中列出了所有系统调用手册页。sh命令man 2 NAME显示了系统调用名称的手册页。
2.使用系统调用进行文件操作
系统调用 | 作用 |
---|---|
access | 检査对某个文件的权限 |
chdir | 更改目录 |
chmod | 更改某个文件的权限 |
chown | 更改文件所有人 |
chroot | 将(逻辑)根目录更改为路径名 |
getcwd | 获取CWD的绝对路径名 |
mkdir | 创建目录 |
rmdir | 移除目录(必须为空) |
3.其他常见系统调用
系统调用 | 作用 |
---|---|
stat(fstat,lstat) | 获取文件状态信息 |
open | 打开文件 |
close | 关闭打开的文件描述符 |
read | 读取文件 |
write | 写入文件 |
lseek | 重定位偏移量 |
dup | 将文件描述符复制到可用的最小描述符编号中 |
dup2 | 将旧文件描述符 复制到新文件描述符 |
link | 将新文件硬链接到旧文件 |
unlink | 取消链接,如果链接数为0,则删去文件 |
symlink | 创建一个符号链接 |
readlink | 读取符号链接文件的内容 |
umask | 设置文件创建掩码 |
实践
实践挂载虚拟磁盘分区:
1.创建虚拟磁盘映像
2.检查当前分区
- 创建主分区P1
4.格式化/dev/loop18(忘截图了)
代码:
sudo mke2fs -b 4096 /dev/loop18 7936
5.挂载循环设备和使用设备
6.卸载分区断开设备
问题
1.在使用系统调用进行文件操作的时候,链接文件有哪些分类?
链接文件时Linux文件系统的一个优势,如需要在系统上维护同一文件的两份或多分副本,除了保存多分单独的物理文件副本之外,还可以采用保存一份物理文件副本和多个虚拟副本的方法,这种虚拟的副本就称为链接,其是目录中指向文件真是位置的占位符。具体分为硬链接和软链接,硬链接:指向同一个inode(雇主)的多个文件路径,我们可以将它理解为一个指向原始 文件的指针,系统不为它分配独立的inode和文件。软链接:软链接仅仅包含所链接文件的路径名,因此能链接目录文件,也可以跨越文件系统进行链接。但是,当原始文件被删除后,链接文件也将失效。从这一点上来说与Windows系统中的“快捷方式”具有一样的性质。
2.在实践时,创建循环设备步骤中出现了“资源忙碌的”报错提示
通过上网找找资料后,找到的解决方法是输入sudo losetup -f
命令后,查找出空闲的设备,用上它即可,我找到的是loop18.