《操作系统真象还原》第14章(下)
本篇博客对应书本14.11~14.15节
步骤:
1.创建目录
2.遍历目录
3.删除目录
4.任务的工作目录
5.获得文件属性
1.创建目录
①fs/fs.c,新增sys_mkdir()函数:

1 /* 创建目录pathname,成功返回0,失败返回-1 */
2 int32_t sys_mkdir(const char* pathname){
3 uint8_t rollback_step=0; // 用于操作失败时回滚各资源状态
4 void* io_buf=sys_malloc(SECTOR_SIZE*2);
5 if (io_buf==NULL){
6 printk("sys_mkdir: sys_malloc for io_buf failed\n");
7 return -1;
8 }
9
10 struct path_search_record searched_record;
11 memset(&searched_record,0,sizeof(struct path_search_record));
12 int inode_no=-1;
13 inode_no=search_file(pathname,&searched_record);
14 if (inode_no!=-1){
15 printk("sys_mkdir: file or directory %s exist!\n",pathname);
16 rollback_step=1;
17 goto rollback;
18 }else { // 若未找到,也要判断是在最终目录没找还是某个中间目录没找到
19 uint32_t pathname_depth=path_depth_cnt((char*)pathname);
20 uint32_t path_searched_depth=path_depth_cnt(searched_record.searched_path);
21 /* 先判断是否把pathname的各层目录都访问到了,即是否在某个中间目录就失败了 */
22 if (pathname_depth!=path_searched_depth){ // 说明没有访问到全部路径,即某个中间目录不存在
23 printk("sys_mkdir: cannot access %s: Not a directory, subpath %s isn't exist\n",pathname,searched_record.searched_path);
24 rollback_step=1;
25 goto rollback;
26 }
27 }
28
29 struct dir* parent_dir=searched_record.parent_dir;
30 /* 目录名称后可能会有字符 '/',所以最好直接用searched_record.searched_path,无'/' */
31 char* dirname=strrchr(searched_record.searched_path,'/')+1;
32
33 inode_no=inode_bitmap_alloc(cur_part);
34 if (inode_no==-1){
35 printk("sys_mkdir: allocate inode failed\n");
36 rollback_step=1;
37 goto rollback;
38 }
39
40 struct inode new_dir_inode;
41 inode_init(inode_no,&new_dir_inode); // 初始化inode
42
43 uint32_t block_bitmap_idx=0; // 用来记录block对应于block_bitmap中的索引
44 int32_t block_lba=-1;
45 /* 为目录分配一个块,用来写入目录 . 和 .. */
46 block_lba=block_bitmap_alloc(cur_part);
47 if (block_lba==-1){
48 printk("sys_mkdir: block_bitmap_alloc for create directory failed\n");
49 rollback_step=2;
50 goto rollback;
51 }
52 new_dir_inode.i_sectors[0]=block_lba;
53 /* 每分配一个块就将位图同步到硬盘 */
54 block_bitmap_idx=block_lba-cur_part->sb->data_start_lba;
55 ASSERT(block_bitmap_idx!=0);
56 bitmap_sync(cur_part,block_bitmap_idx,BLOCK_BITMAP);
57
58 /* 将当前目录的目录项'.'和'..'写入目录 */
59 memset(io_buf,0,SECTOR_SIZE*2); // 情况io_buf
60 struct dir_entry* p_de=(struct dir_entry*)io_buf;
61
62 /* 初始化当前目录"." */
63 memcpy(p_de->filename,".",1);
64 p_de->i_no=inode_no;
65 p_de->f_type=FT_DIRECTORY;
66
67 ++p_de;
68 /* 初始化当前目录".." */
69 memcpy(p_de->filename,"..",2);
70 p_de->i_no=parent_dir->inode->i_no;
71 p_de->f_type=FT_DIRECTORY;
72 ide_write(cur_part->my_disk,new_dir_inode.i_sectors[0],io_buf,1);
73
74 new_dir_inode.i_size=2*cur_part->sb->dir_entry_size;
75
76 /* 在父目录中添加自己的目录项 */
77 struct dir_entry new_dir_entry;
78 memset(&new_dir_entry,0,sizeof(struct dir_entry));
79 create_dir_entry(dirname,inode_no,FT_DIRECTORY,&new_dir_entry);
80 memset(io_buf,0,SECTOR_SIZE*2); // 清空io_buf
81 if (!sync_dir_entry(parent_dir,&new_dir_entry,io_buf)){
82 printk("sys_mkdir: sync_dir_entry to disk failed\n");
83 rollback_step=2;
84 goto rollback;
85 }
86
87 /* 父目录的inode同步到硬盘 */
88 memset(io_buf,0,SECTOR_SIZE*2);
89 inode_sync(cur_part,parent_dir->inode,io_buf);
90
91 /* 将新创建目录的inode同步到硬盘 */
92 memset(io_buf,0,SECTOR_SIZE*2);
93 inode_sync(cur_part,&new_dir_inode,io_buf);
94
95 /* 将inode位图同步到硬盘 */
96 bitmap_sync(cur_part,inode_no,INODE_BITMAP);
97
98 sys_free(io_buf);
99
100 /* 关闭所创建目录的父目录 */
101 dir_close(searched_record.parent_dir);
102 return 0;
103
104 /* 创建文件或目录需要创建相关的多个资源,若某步失败则hi执行到下面的回滚步骤 */
105 rollback: // 回滚
106 switch(rollback_step){
107 case 2:
108 bitmap_set(&cur_part->inode_bitmap,inode_no,0);
109 case 1:
110 /* 关闭所创建目录的父目录 */
111 dir_close(searched_record.parent_dir);
112 break;
113 }
114 sys_free(io_buf);
115 return -1;
116 }
更新一个我自己书写过程中的错误:在search_file()中第一个strcat()(约261行),应当与"/"相连接,而不是'/'。如果是'/',将为字符而非字符串,会出现错误,。之前竟然没有检测出来。。。
②fs/fs.h,增加一句函数声明:
int32_t sys_mkdir(const char* pathname);
③kernel/main.c:

1 int main(void){
2 put_str("Welcome,\nI am kernel!\n");
3 init_all();
4 intr_enable();
5 process_execute(u_prog_a, "u_prog_a");
6 process_execute(u_prog_b, "u_prog_b");
7 thread_start("k_thread_a", 31, k_thread_a, "I am thread_a");
8 thread_start("k_thread_b", 31, k_thread_b, "I am thread_b");
9
10 printf("/dir1/subdir1 create %s!\n",sys_mkdir("/dir1/subdir1")==0?"done":"fail");
11 printf("/dir1 create %s!\n",sys_mkdir("/dir1")==0?"done":"fail");
12 printf("now, /dir1/subdir1 create %s!\n",sys_mkdir("/dir1/subdir1")==0?"done":"fail");
13 int fd=sys_open("/dir1/subdir1/file2",O_CREAT|O_RDWR);
14 if (fd!=-1){
15 printk("/dir1/subdir1/file2 create done!\n");
16 sys_write(fd,"Catch me if u can!\n",19);
17 sys_lseek(fd,0,SEEK_SET);
18 char buf[32]={0};
19 sys_read(fd,buf,19);
20 printf("/dir1/subdir1/file2 says:\n%s",buf);
21 sys_close(fd);
22 }
23
24 while(1);
25 return 0;
26 }
功能验证:
由于已经是第二次运行了,所以会看到/dir1、/dir1/subdir1和/file2 均创建失败的情况,不过可以发现它们其实是已经都exist了的。
2.遍历目录
先从开关目录开始。
①fs/fs.c,增加开关目录函数:

1 /* 目录打开成功后返回目录指针,失败返回NULL */
2 struct dir* sys_opendir(const char* name){
3 ASSERT(strlen(name)<MAX_PATH_LEN);
4 /* 如果是根目录'.',直接返回&root_dir */
5 if (name[0]=='/' && (name[1]==0 || name[0]=='.')){
6 return &root_dir;
7 }
8
9 /* 先检查待打开的目录是否存在 */
10 struct path_search_record searched_record;
11 memset(&searched_record,0,sizeof(struct path_search_record));
12 int inode_no=search_file(name,&searched_record);
13 struct dir* ret=NULL;
14 if (inode_no==-1){ // 找不到目录
15 printk("In %s, sub path %s not exist\n, name, searched_record.searched_path");
16 }else {
17 if (searched_record.file_type==FT_REGULAR){
18 printk("%s is regular file!\n",name);
19 }else if (searched_record.file_type==FT_DIRECTORY){
20 ret=dir_open(cur_part,inode_no);
21 }
22 }
23 dir_close(searched_record.parent_dir);
24 return ret;
25 }
26
27 /* 成功关闭目录p_dir返回0,失败返回-1 */
28 int32_t sys_closedir(struct dir* dir){
29 int32_t ret=-1;
30 if (dir!=NULL){
31 dir_close(dir);
32 ret=0;
33 }
34 return ret;
35 }
②fs/fs.h,增加两句函数声明:
struct dir* sys_opendir(const char* name);
int32_t sys_closedir(struct dir* dir);
③kernel/main.c,还是修改main():

1 int main(void){
2 put_str("Welcome,\nI am kernel!\n");
3 init_all();
4 intr_enable();
5 process_execute(u_prog_a, "u_prog_a");
6 process_execute(u_prog_b, "u_prog_b");
7 thread_start("k_thread_a", 31, k_thread_a, "I am thread_a");
8 thread_start("k_thread_b", 31, k_thread_b, "I am thread_b");
9
10 struct dir* p_dir=sys_opendir("/dir1/subdir1");
11 if (p_dir){
12 printf("/dir1/subdir1 open done!\n");
13 if (sys_closedir(p_dir)==0){
14 printf("/dir1/subdir1 close done!\n");
15 }else {
16 printf("/dir1/subdir1 close fail!\n");
17 }
18 }else {
19 printf("/dir1/subdir1 open fail!\n");
20 }
21
22 while(1);
23 return 0;
24 }
运行结果如图:
成功地open和close了文件目录。
然后尝试读取一个目录项:
④fs/dir.c,添加dir_read()函数:

1 /* 读取目录,成功返回一个目录项,失败返回NULL */
2 struct dir_entry* dir_read(struct dir* dir){
3 struct dir_entry* dir_e=(struct dir_entry*)dir->dir_buf; //哈哈 目录项里面自己有缓冲区
4 struct inode* dir_inode=dir->inode;
5 uint32_t all_blocks[140]={0},block_cnt=12;
6 uint32_t block_idx=0,dir_entry_idx=0;
7 while (block_idx<12){
8 all_blocks[block_idx]=dir_inode->i_sectors[block_idx];
9 ++block_idx;
10 }
11 if (dir_inode->i_sectors[12]!=0){
12 ide_read(cur_part->my_disk,dir_inode->i_sectors[12],all_blocks+12,1);
13 block_cnt=140;
14 }
15 block_idx=0;
16
17 uint32_t cur_dir_entry_pos=0; // 当前目录项的偏移
18 uint32_t dir_entry_size=cur_part->sb->dir_entry_size;
19 uint32_t dir_entrys_per_sec=SECTOR_SIZE/dir_entry_size;
20 /* 在目录大小内遍历 */
21 while (dir->dir_pos<dir_inode->i_size){
22 if(dir->dir_pos>=dir_inode->i_size){
23 return NULL;
24 }
25 if(all_blocks[block_idx]==0){
26 ++block_idx;
27 continue;
28 }
29 memset(dir_e,0,SECTOR_SIZE);
30 ide_read(cur_part->my_disk,all_blocks[block_idx],dir_e,1);
31 dir_entry_idx=0;
32 /* 遍历扇区内所有目录项 */
33 while (dir_entry_idx<dir_entrys_per_sec){
34 if ((dir_e + dir_entry_idx)->f_type){
35 /* 已经遍历过 */
36 if (cur_dir_entry_pos<dir->dir_pos){
37 cur_dir_entry_pos+=dir_entry_size;
38 ++dir_entry_idx;
39 continue;
40 }
41 ASSERT(cur_dir_entry_pos==dir->dir_pos);
42 dir->dir_pos+=dir_entry_size; // 返回目录地址
43 return dir_e+dir_entry_idx;
44 }
45 ++dir_entry_idx;
46 }
47 ++block_idx;
48 }
49 return NULL;
50 }
⑤fs/dir.h,增加函数声明:
struct dir_entry* dir_read(struct dir* dir);
⑥kernel/main.c:

1 int main(void){
2 put_str("Welcome,\nI am kernel!\n");
3 init_all();
4 intr_enable();
5 process_execute(u_prog_a, "u_prog_a");
6 process_execute(u_prog_b, "u_prog_b");
7 thread_start("k_thread_a", 31, k_thread_a, "I am thread_a");
8 thread_start("k_thread_b", 31, k_thread_b, "I am thread_b");
9
10 struct dir* p_dir=sys_opendir("/dir1/subdir1");
11 if (p_dir){
12 printf("/dir1/subdir1 open done!\ncontent:\n");
13 char* type=NULL;
14 struct dir_entry* dir_e=NULL;
15 while ((dir_e=sys_readdir(p_dir))){
16 if (dir_e->f_type==FT_REGULAR){
17 type="regular";
18 }else {
19 type="directory";
20 }
21 printf(" %s %s\n",type,dir_e->filename);
22 }
23 if (sys_closedir(p_dir)==0){
24 printf("/dir1/subdir1 close done!\n");
25 }else {
26 printf("/dir1/subdir1 close fail!\n");
27 }
28 }else {
29 printf("/dir1/subdir1 open fail!\n");
30 }
31
32 while(1);
33 return 0;
34 }
输出信息为:
输出了三个文件“.”和“..”和刚刚创建的普通文件“file2”。结束。
3.删除目录
①fs/dir.c,增加dir_is_empty()和dir_remove():

1 /* 判断目录是否为空 */
2 bool dir_is_empty(struct dir* dir){
3 struct inode* dir_inode=dir->inode;
4 /* 若目录下只有'.'和'..'这两个目录项,则视为空 */
5 return (dir_inode->i_size==cur_part->sb->dir_entry_size*2);
6 }
7
8 /* 在父目录parent_dir中删除child_dir */
9 int32_t dir_remove(struct dir* parent_dir,struct dir* child_dir){
10 struct inode* child_dir_inode=child_dir->inode;
11 /* 空目录中只在inode->i_sectors[0]中有扇区,其它扇区都应该为空 */
12 int32_t block_idx=1;
13 while (block_idx<13){
14 ASSERT(child_dir_inode->i_sectors[block_idx]==0);
15 ++block_idx;
16 }
17 void* io_buf=sys_malloc(SECTOR_SIZE*2);
18 if (io_buf==NULL){
19 printk("dir_remove: malloc for io_buf failed!\n");
20 return -1;
21 }
22
23 /* 在父目录parent_dir中删除子目录child_dir对应的目录项 */
24 delete_dir_entry(cur_part,parent_dir,child_dir_inode->i_no,io_buf);
25
26 /* 回收inode中i_sectors中所占用的扇区,并同步inode_bitmap和block_bitmap */
27 inode_release(cur_part,child_dir_inode->i_no);
28 sys_free(io_buf);
29 return 0;
30 }
②fs/dir.h,增加两个函数声明:
bool dir_is_empty(struct dir* dir);
int32_t dir_remove(struct dir* parent_dir,struct dir* child_dir);
③fs/fs.c,增加sys_rmdir():

1 /* 删除空目录,成功返回0,失败返回-1 */
2 int32_t sys_rmdir(const char* pathname){
3 /* 先检查要删除的文件是否存在 */
4 struct path_search_record searched_record;
5 memset(&searched_record,0,sizeof(struct path_search_record));
6 int inode_no=search_file(pathname,&searched_record);
7 ASSERT(inode_no!=0);
8 int retval=-1; // 默认return
9 if (inode_no==-1){
10 printk("In %s, sub path %s not exist.\n",pathname,searched_record.searched_path);
11 }else {
12 if (searched_record.file_type==FT_REGULAR){
13 printk("%s is regular file!\n",pathname);
14 }else{
15 struct dir* dir=dir_open(cur_part,inode_no);
16 if (!dir_is_empty(dir)){
17 printk("dir %s is not empty, it is not allowed to delete noempty directory!\n",pathname);
18 }else {
19 if (!dir_remove(searched_record.parent_dir,dir)){
20 retval=0;
21 }
22 }
23 dir_close(dir);
24 }
25 }
26 dir_close(searched_record.parent_dir);
27 return retval;
28 }
④fs/fs.h,增加一句函数声明:
int32_t sys_rmdir(const char* pathname);
⑤kernel/main.c,因为两对进程和线程的作用不大,所以我们忽略了:

1 int main(void){
2 put_str("Welcome,\nI am kernel!\n");
3 init_all();
4
5 printf("/dir1 content before delete /dir1/subdir1:\n");
6 struct dir* dir=sys_opendir("/dir1/");
7 char* type=NULL;
8 struct dir_entry* dir_e=NULL;
9 while ((dir_e=sys_readdir(dir))){
10 if (dir_e->f_type==FT_REGULAR){
11 type="regular";
12 }else {
13 type="directory";
14 }
15 printf(" %s %s\n",type,dir_e->filename);
16 }
17 printf("try to delete noempty directory /dir1/subdir1.\n");
18 if (sys_rmdir("/dir1/subdir1")==-1){
19 printf("sys_mrdir: /dir1/subdir1 delete fail!\n");
20 }
21
22 printf("try to delete /dir1/subdir1/file2.\n");
23 if (sys_rmdir("/dir1/subdir1/file2")==-1){
24 printf("sys_rmdir: /dir1/subdir1/file2 delete fail!\n");
25 }
26 if (sys_unlink("/dir1/subdir1/file2")==0){
27 printf("sys_unlink: /dir1/subdir1/file2 delete done.\n");
28 }
29
30 printf("try to delete directory /dir1/subdir1 again.\n");
31 if (sys_rmdir("/dir1/subdir1")==0){
32 printf("/dir1/subdir1 delete done.\n");
33 }
34
35 printf("/dir1 content after delete /dir1/subdir1:\n");
36 sys_rewinddir(dir);
37 while ((dir_e=sys_readdir(dir))){
38 if (dir_e->f_type==FT_REGULAR){
39 type="regular";
40 }else {
41 type="directory";
42 }
43 printf(" %s %s\n",type,dir_e->filename);
44 }
45
46 while(1);
47 return 0;
48 }
结果如下:
4.任务的工作目录
①fs/fs.c,直接将本节新增的四个函数一起放送出来:

1 /* 获得父目录的inode编号 */
2 static uint32_t get_parent_dir_inode_nr(uint32_t child_inode_nr,void* io_buf){
3 struct inode* child_dir_inode=inode_open(cur_part,child_inode_nr);
4 /* 目录中的目录项".."中包括父目录inode编号,".."位于目录的第0块 */
5 uint32_t block_lba=child_dir_inode->i_sectors[0];
6 ASSERT(block_lba>=cur_part->sb->data_start_lba);
7 inode_close(child_dir_inode);
8 ide_read(cur_part->my_disk,block_lba,io_buf,1);
9 struct dir_entry* dir_e=(struct dir_entry*)io_buf;
10 /* 第0个目录项是".",第一个目录项是".." */
11 ASSERT(dir_e[1].i_no<4096 && dir_e[1].f_type==FT_DIRECTORY);
12 return dir_e[1].i_no; // 返回..即父目录的inode编号
13 }
14
15 /* 在inode编号为p_inode_nr的目录中查找inode编号为c_inode_nr的子目录的名字,
16 * 将名字存入缓冲区path.成功则返回0,失败返回-1 */
17 static int get_child_dir_name(uint32_t p_inode_nr,uint32_t c_inode_nr,char* path,void* io_buf){
18 struct inode* parent_dir_inode=inode_open(cur_part,p_inode_nr);
19 /* 填充all_blocks,将该目录的所占扇区地址全部写入all_blocks */
20 uint8_t block_idx=0;
21 uint32_t all_blocks[140]={0},block_cnt=12;
22 while (block_idx<12){
23 all_blocks[block_idx]=parent_dir_inode->i_sectors[block_idx];
24 ++block_idx;
25 }
26 if (parent_dir_inode->i_sectors[12]){
27 ide_read(cur_part->my_disk,parent_dir_inode->i_sectors[12],all_blocks+12,1);
28 block_cnt=140;
29 }
30 inode_close(parent_dir_inode);
31
32 struct dir_entry* dir_e=(struct dir_entry*)io_buf;
33 uint32_t dir_entry_size=cur_part->sb->dir_entry_size;
34 uint32_t dir_entrys_per_sec=(512/dir_entry_size);
35 block_idx=0;
36 /* 遍历所有块 */
37 while (block_idx<block_cnt){
38 if (all_blocks[block_idx]){
39 ide_read(cur_part->my_disk,all_blocks[block_idx],io_buf,1);
40 uint8_t dir_e_idx=0;
41 /* 遍历每个目录项 */
42 while (dir_e_idx<dir_entrys_per_sec){
43 if ((dir_e+dir_e_idx)->i_no==c_inode_nr){
44 strcat(path,"/");
45 strcat(path,(dir_e+dir_e_idx)->filename);
46 return 0;
47 }
48 ++dir_e_idx;
49 }
50 }
51 ++block_idx;
52 }
53 return -1;
54 }
55
56 /* 把当前工作目录绝对路径写入buf,size是buf的大小,
57 * 当buf为NULL时,由操作系统分配存储工作路径的空间并返回地址,
58 * 失败则返回NULL */
59 char* sys_getcwd(char* buf,uint32_t size){
60 /* 确保buf不为空,若用户进程提供的buf为NULL,
61 * 系统调用getcwd中要为用户进程通过malloc分配内存 */
62 ASSERT(buf!=NULL);
63 void* io_buf=sys_malloc(SECTOR_SIZE);
64 if (io_buf==NULL){
65 return NULL;
66 }
67 struct task_struct* cur_thread=running_thread();
68 int32_t parent_inode_nr=0;
69 int32_t child_inode_nr=cur_thread->cwd_inode_nr;
70 ASSERT(child_inode_nr>=0 && child_inode_nr<4096);
71 /* 若当前目录是根目录,直接返回 '/' */
72 if (child_inode_nr==0){
73 buf[0]='/';
74 buf[1]=0;
75 sys_free(io_buf);
76 return buf;
77 }
78
79 memset(buf,0,size);
80 char full_path_reverse[MAX_PATH_LEN]={0}; // 用来作全路径缓冲区
81
82 /* 从下往上逐层找父目录,直到找到根目录为止,
83 * 当child_inode_nr为根目录的inode编号时停止,
84 * 即已经查看完根目录中的目录项 */
85 while ((child_inode_nr)){
86 parent_inode_nr=get_parent_dir_inode_nr(child_inode_nr,io_buf);
87 if (get_child_dir_name(parent_inode_nr,child_inode_nr,full_path_reverse,io_buf)==-1){
88 sys_free(io_buf);
89 return NULL;
90 }
91 child_inode_nr=parent_inode_nr;
92 }
93 ASSERT(strlen(full_path_reverse)<=size);
94 /* 至此full_path_reverse中的路径是反的,
95 * 即子目录在前,父目录在后
96 * 现将full_path_reverse中的路径反向 */
97 char* last_slash; // 用于记录字符串中最后一个斜杠地址
98 while ((last_slash=strrchr(full_path_reverse,'/'))){
99 uint16_t len=strlen(buf);
100 strcpy(buf+len,last_slash);
101 /* 在full_path_reverse中添加结束字符,作为下一次执行strcpy中last_slash的边界 */
102 *last_slash=0;
103 }
104 sys_free(io_buf);
105 return buf;
106 }
107
108 /* 更改当前工作目录为绝对路径path,成功则返回0,失败则返回-1 */
109 int32_t sys_chdir(const char* path){
110 int32_t ret=-1;
111 struct path_search_record searched_record;
112 memset(&searched_record,0,sizeof(struct path_search_record));
113 int inode_no=search_file(path,&searched_record);
114 if (inode_no!=-1){
115 if (searched_record.file_type==FT_DIRECTORY){
116 running_thread()->cwd_inode_nr=inode_no;
117 ret=0;
118 }else {
119 printk("sys_chdir: %s is regular file or other!\n",path);
120 }
121 }
122 dir_close(searched_record.parent_dir);
123 return ret;
124 }
②fs/fs.h,以及它们各自的函数声明,因为有两个是static函数,所以只需要声明另外两个:
char* sys_getcwd(char* buf,uint32_t size);
int32_t sys_chdir(const char* path);
③thread/thread.h,在pcb中添加cwd_inode_nr属性:
④thread/thread.c,并在init_thread()中将nr初始化为0:
⑤kernel/main.c:

1 int main(void){
2 put_str("Welcome,\nI am kernel!\n");
3 init_all();
4
5 char cwd_buf[32]={0};
6 sys_getcwd(cwd_buf,32);
7 printf("cwd: %s\n",cwd_buf);
8 sys_chdir("/dir1");
9 printf("change cwd now...\n");
10 sys_getcwd(cwd_buf,32);
11 printf("cwd: %s\n",cwd_buf);
12
13 while(1);
14 return 0;
15 }
运行结果:
这次简单,符合预期。
5.获得文件属性
①fs/fs.h,添加文件属性结构体和一句函数声明:

struct stat{
uint32_t st_ino; // inode编号
uint32_t st_size; // inode尺寸
enum file_types st_filetype; // indoe文件类型
};
int32_t sys_stat(const char* path,struct stat* buf);
②fs/fs.c,添加sys_stat(),以获取文件信息

1 /* 在buf中填充文件结构相关信息,成功返回0,失败返回-1 */
2 int32_t sys_stat(const char* path,struct stat* buf){
3 /* 若直接查看根目录 '.' */
4 if (!strcmp(path,".") || !strcmp(path,"/.") || !strcmp(path,"/..")){
5 buf->st_filetype=FT_DIRECTORY;
6 buf->st_ino=0;
7 buf->st_size=root_dir.inode->i_size;
8 return 0;
9 }
10
11 int32_t ret=-1; // 默认返回值
12 struct path_search_record searched_record;
13 memset(&searched_record,0,sizeof(struct path_search_record));
14 int inode_no=search_file(path,&searched_record);
15 if (inode_no!=-1){
16 struct inode* obj_inode=inode_open(cur_part,inode_no); // 只为获得文件大小
17 buf->st_size=obj_inode->i_size;
18 inode_close(obj_inode);
19 buf->st_filetype=searched_record.file_type;
20 buf->st_ino=inode_no;
21 ret=0;
22 }else {
23 printk("sys_stat: %s not found\n",path);
24 }
25 dir_close(searched_record.parent_dir);
26 return ret;
27 }
③kernel/main.c:

1 int main(void){
2 put_str("Welcome,\nI am kernel!\n");
3 init_all();
4
5 struct stat obj_stat;
6 sys_stat("/",&obj_stat);
7 printf("/'s info\n i_no: %d\n size: %d\n filetype: %s\n", \
8 obj_stat.st_ino,obj_stat.st_size, \
9 obj_stat.st_filetype==2?"directory":"regular");
10 sys_stat("/dir1",&obj_stat);
11 printf("/dir1's info\n i_no: %d\n size: %d\n filetype: %s\n", \
12 obj_stat.st_ino,obj_stat.st_size, \
13 obj_stat.st_filetype==2?"directory":"regular");
14
15 while(1);
16 return 0;
17 }
运行结果:
额。。。似乎根目录的size有点问题,怎么会是408呢。。。先放着,后续再改进。不过历时约一星期,总算是把文件系统搞完了,要是把这么庞大的一章放在本书的开头,那不知道要劝退多少人:)
参考博客:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库