LINUX第11章学习笔记——EX2文件系统
EX2文件系统
EX2文件系统数据结构
创建虚拟硬盘
mke2fs [-b blksize -N ninodes] device nblocks
虚拟磁盘布局
BLOCK#0:引导块
超级块
容纳整个文件系统的信息
超级块的重要字段:
__u32 s_inodes_count://文件系统中节点总数
__u32 s_blocks_count://文件系统中块总数
__u32 s_r_blocks_count://为超级用户保留的块数
__u32 s_free_blocks_count: //文件系统中空闲块总数
__u32 s_mtime://文件系统的挂接时间
__u32 s_wtime://最后一次对该超级块进行写操作的时间
__u32 s_magic ://魔数签名,用于确定文件系统版本的标志
__u32 s_inodes_per_group://表示每个组块的inode数目,查找文件inode所在块的位置很重要
__u32 s_mnt_count://文件系统挂接计数
__u32 s_max_mnt_count://文件系统最大挂接计数
__u32 s_state://文件系统的状态
块组描述符
BLOCK#2:块组描述符块
块和索引节点位图
BLOCK#8:块位图
BLOCK:9:索引节点位图
索引节点
BLOCK#10:索引节点
涉及i_mode数组内容:直接块,间接块,双重间接块,三重间接块
数据块
紧跟在索引节点块后面的是文件存储数据块
目录条目
包含dir_entry结构
邮差算法
Linear_address LA = N*block + house;
Block_address BA = (LA/N,LA%N);
C语言中的Test-Set-Clear位
C语言结合使用邮差算法和位屏蔽来进行下面的位操作
编程实例
显示位图实例
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/io.h>
#include <ext2fs/ext2_fs.h>
// Cypedef u8, ul6, u32 SUPER for convenience typedef typedef typedef
typedef unsigned char u8;
typedef unsigned short ul6;
typedef unsigned int u32;
typedef struct ext2_super_block SUPER;
SUPER *sp;
char buf[1024];
int fd, blksize, inodesize;
int print(char *s, u32 x)
{
printf("%-30s = %8d\n", s, x);
}
int super(char *device)
{
fd = open(device, O_RDONLY);
if (fd < 0)
{
printf("open %s failed\n", device);
exit(1);
}
lseek(fd, (long)1024*1, 0); // block 1 or offset 1024
read(fd, buf, 1024);
sp = (SUPER *)buf; // as a super block structure
// check for EXT2 FS magic number
printf("%-30s = %8x ", "s_magic", sp->s_magic);
if (sp->s_magic != 0xEF53)
{
printf("NOT an EXT2 FS\n"); exit(2);
}
printf("EXT2 FS OK\n");
print("s_inodes_count", sp->s_inodes_count);
print("s_blocks _count", sp->s_blocks_count);
print("s_r_blocks_count", sp->s_r_blocks_count);
print("s_free_inodes_count", sp->s_free_inodes_count);
print("s_free_blocks_count", sp->s_free_blocks_count);
print("s_first_data_blcok", sp->s_first_data_block);
print("s_log_block_s i z e", sp->s_log_block_size);
print("s_blocks_per_group", sp->s_blocks_per_group);
print("s_inodes_per_group", sp-> s_inodes_per_group);
print("s_mnt_count", sp->s_mnt_count);
print("s_max_mnt_count", sp-> s_max_mnt_count);
printf("%-30s = %8x\n", "s_magic", sp->s_magic);
printf ("s_mtime = %s\n", ctime ((const time_t *)&sp->s_mtime));
printf ("s_wtime = %s", ctime ((const time_t *)&sp->s_wtime));
blksize = 1024 * (1 << sp->s_log_block_size);
printf("block size = %d\n", blksize);
printf("inode size = %d\n", sp->s_inode_size);
}
char *device = "vdisk"; // default device name
int main(int argc, char *argv[])
{
if (argc>1)
device = argv[1];
super(device);
}
显示位图
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/io.h>
#include <ext2fs/ext2_fs.h>
typedef unsigned char u8;
typedef struct ext2_super_block SUPER;
typedef struct ext2_group_desc GD;
#define BLKSIZE 1024
SUPER *sp;
GD *gp;
char buf[BLKSIZE];
int fd;
// get_block() reads a disk block into a buf[]?
int get_block(int fd, int blk, char *buf)
{
lseek(fd, (long)blk*BLKSIZE, SEEK_SET);
return read(fd, buf, BLKSIZE);
}
int imap(char *device)
{
int i, ninodes, blksize, imapblk;
fd = open(device, O_RDONLY);
if (fd < 0)
{
printf("open %s failed\n", device);
exit(1);
}
get_block(fd, 1, buf); // get superblock
sp = (SUPER *)buf;
// check magic number to ensure itz s an EXT2 FS ninodes = sp->s_inodes_count //
ninodes = sp->s_inodes_count;
printf("ninodes = %d\n", ninodes);
get_block(fd, 2, buf); //
gp = (GD *)buf;
imapblk = gp->bg_inode_bitmap;
printf("imapblk = %d\n", imapblk);
get_block(fd, imapblk, buf);
for ( i = 0; i <= ninodes/8; i++)
{
printf("%02x ", (u8)buf[i]);
}
printf("\n");
}
char *dev = "mydisk";
int main(int argc, char*argv[])
{
if(argc>1) dev = argv[1];
imap(dev);
}
显示根索引节点
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/io.h>
#include <ext2fs/ext2_fs.h>
#define BLKSIZE 1024
typedef struct ext2_group_desc GD;
typedef struct ext2_super_block SUPER;
typedef struct ext2_dir_entry_2 DIR;
typedef struct ext2_inode INODE;
SUPER *sp;
GD *gp;
INODE *ip;
DIR *dp;
char buf[BLKSIZE];
int fd,firstdata, inodesize ,blksize, iblock;
char *dev = "mydisk";
int get_block(int fd, int blk, char *buf)
{
lseek(fd, blk*BLKSIZE, SEEK_SET);
return read(fd, buf, BLKSIZE);
}
int inode (char *dev)
{
int i;
fd = open(dev, O_RDONLY);
if(fd < 0)
{
printf("open faild\n");
exit(1);
}
get_block(fd, 2, buf);
gp = (GD *)buf;
printf("bmap_block=%d imap_block=%d inodes_table=%d \n",
gp->bg_block_bitmap,
gp->bg_inode_bitmap,
gp->bg_inode_table);
iblock = gp->bg_inode_table;
printf("----root inode information----\n");
get_block(fd, iblock, buf);
ip = (INODE *)buf;
ip++;
printf("mode = %4x ",ip->i_mode);
printf("uid = %d gid = %d\n", ip->i_uid, ip->i_gid);
printf("size = %d\n", ip->i_size);
//unsigned int tmp = ip->i_ctime;
printf("ctime = %s",ctime((const time_t *)&ip->i_ctime));
printf("links = %d\n", ip->i_links_count);
for ( i = 0; i < 15; i++)
{
if(ip->i_block[i])
{
printf("i_block[%d] = %d\n", i, ip->i_block[i]);
}
}
}
int main(int argc, char *argv[])
{
if(argc>1) dev = argv[1];
inode(dev);
}
*出现问题后续解决
显示目录条目
代码部分见上一周学习笔记
遍历算法
读取超级块和块组描述符块,之后重复循环,search()重复n次
路径名转换成索引节点
e.g INODE *path2inode(int fd,char *pathname)
返回一个指向文件索引节点的INODE指点
EX2文件系统实现
文件系统结构
PROC结构体
文件系统的根指针
open Table条目
内存索引节点
已挂载的文件系统表
文件系统的级别
- 第一级别:实现了基本文件系统树
- 第二级别:实现了文件内容读/写函数
- 第三级别:实现了文件系统的挂载、卸载和文件保护
基本文件系统
基本了解type.h文件和global.c文件
链接:https://blog.csdn.net/hao_le_er/article/details/6667388
实用程序函数
- get_block/put_block:假设某个块设备,例如真实磁盘或虚拟磁盘,只能以块大小为单位读写。对于真实磁盘,这是因为受到硬件的限制。对于虚拟磁盘,我们假设也是以块大小为单位读/写,这样就可以在需要时将代码移植到真实磁盘上。在虚拟磁盘上,我们先以读|写模式打开它,并使用文件描述符作为设备号。
- iget(dev,ino):该函数返回一个指针,指向包含INODE(dev, ino)的内存 minodeo返回的minode是唯一的,即内存中只存在一个INODE副本。在实际文件系统中, 返回的minode被锁定为独占使用,直到它被释放或解锁。
- input(INODE *mip):该函数会释放一个mip指向的用完的minode0每 个minode都有一个refCount,表示使用minode. iput()的用户数量为refCount减1。
- getino():getino()函数可实现文件系统树遍历算法。它会返回指定路径名的INODE编号(ino)。首先,假设在1级文件系统的实现中,文件系统属于单个根设备, 不存在挂载设备和挂载点交叉。因此,getino()函数本质上返回的是路径名的(dev, ino)。
基本文件系统的实现
暂无实例展示
1级文件系统函数
mkdir 算法
mkdir pathname
mkdir创建了一个带路径名的新目录,让新目录权限改成0755
mkdir算法:
mkdir folderName
mkdir parentFolder folderName
status = mkdir(___)
[status,msg] = mkdir(___)
[status,msg,msgID] = mkdir(___)
链接:https://ww2.mathworks.cn/help/matlab/ref/mkdir.html
creat算法
创建了一个空的普通文件
和普通的UNIX/LINUX算法不同的是不会以写模式打开文件
rmdir算法
rmdir dirname
命令参数
-p: 递归删除,删除目录之前是否删除父目录,如果父目录为空的话就删除
-v: 删除目录时,显示删除信息
--help: 显示此帮助信息并退出
--version: 输出版本信息并退出
link算法
unlink算法
unlink filename
symlink命令:symlink old_file new_file
创建一个从new_file到old_file的符号链接,与硬链接不同,可以链接任何对象
readlink算法
2级文件系统函数
open算法
int open(char *filename,int flags);
打开一个文件进行读或写
lseek
lseek(fd,position,whence);
将打开的文件描述符在OFT中的偏移量设置为文件开头或当前位置开始的字节位置
close算法
可关闭文件描述符
读取普通文件
int read(int fd,char *buf,int nbytes);
read()详细图解
写普通文件
int write(int fd,char buf[],int nbytes);
write()详细图解:
opendir-readdir
UNIX把所有目录看成一个文件,因此不需要一组单独的opendir()和readdir()函数
int openddir(pathname)
{return open(pathname,RD|O_DIR)}
3级文件系统
挂载算法
mount filesys mount_point
可将某个文件系统挂载到mount_point目录上
卸载算法同理
交叉挂载点
向下遍历
向上遍历
文件保护
9个权限位
文件系统项目拓展
多个组-4KB大小块-管道文件-I/O缓冲