操作系统真象还原[14章/十三]-任务的工作目录以及改变工作目录

        这节的内容也不多,先梳理一下14.14这节整体的思路我们再写代码。这里所说的任务的工作目录以及改变任务的工作目录的主体是任务,我们也是从这里作为起点开始捋一下思路。

        (1)任务就是指线程,每个线程都默认有个初始的工作目录,我们这里设置为根目录。因为线程相关的内容都存放到pcb中,所以我们给pcb增加了字段uint32_t cwd_inode_nr,来记录当前工作目录的inode号

        (2)pcb中的cwd_inode_nr需要被赋予初始值0(即根目录的inode编号),这一步是在init_thread函数中实现的,我自己把这个函数改名了叫init_thread_pcb

        (3)现在有了工作目录的inode号如何以字符串的形式展示当前目录的绝对路径呢?我们知道文件名或目录名都是存在于目录项中的,所以我们需要先获取到父目录的inode号,然后再在父目录的目录项中寻找对应当前目录inode号的目录名,然后逐层向上获取最终得到完整的绝对路径。这里就需要我们实现两个函数:1、根据子目录的inode号获取父目录的inode号 2、根据父目录和子目录的inode号,在父目录的硬盘数据块中查询子目录目录项中对应的名称。

        沿着上述的思路,我们就先进行pcb的修改(therad.h以及thread.c),然后再实现两个基础函数,最后实现sys_getcwd

/* 进程或线程的pcb,程序控制块 */
struct task_struct {
    uint32_t* self_kstack;
    pid_t pid;
    enum task_status status;
    uint32_t priority;
    char name[16];

    uint32_t ticks;
    uint32_t elapsed_ticks;
    struct list_elem thread_ready_list_tag;
    struct list_elem thread_all_list_tag;

    /* 用户进程 */
    uint32_t* pgdir;
    struct virtual_addr userprog_vaddr;
    struct mem_block_desc u_block_descs[DESC_CNT];

    /* 文件系统 */
    int32_t fd_table[MAX_FILES_OPEN_PER_PROC];
    uint32_t cwd_inode_nr;

    uint32_t stack_magic;

};
/* 初始化线程基本信息 */
void init_thread_pcb(struct task_struct* pthread, char* thread_name, uint8_t priority) {
    pthread->self_kstack = (uint32_t*) ((uint32_t) pthread + PG_SIZE);
    pthread->pid = allocate_pid();
    pthread->status = TASK_READY;
    pthread->priority = priority;
    strcpy(pthread->name, thread_name);
    pthread->stack_magic = (uint32_t) 0x19970814;
    pthread->ticks = priority;
    pthread->elapsed_ticks = 0;
    pthread->pgdir = NULL;
    /* 预留标准输入输出 */
    pthread->fd_table[0] = 0;
    pthread->fd_table[1] = 1;
    pthread->fd_table[2] = 2;
    uint8_t fd_idx = 3;
    while(fd_idx < MAX_FILES_OPEN_PER_PROC) {
        pthread->fd_table[fd_idx] = -1;
        fd_idx++;
    }
    pthread->cwd_inode_nr = 0;
}
/* 获取父目录的inode编号 */
static uint32_t get_parent_dir_inode_nr(uint32_t child_inode_nr, void* io_buf) {
    struct inode* child_dir_inode = inode_open(cur_part, child_inode_nr);
    uint32_t block_lba = child_dir_inode->i_sectors[0];
    ASSERT(block_lba != 0);
    inode_close(child_dir_inode);
    ide_read(cur_part->my_disk, block_lba, io_buf, 1);
    struct dir_entry* dir_e = (struct dir_entry*) io_buf;
    ASSERT(dir_e[1].i_no < 4096 && dir_e[1].f_type == FT_DIRECTORY);
    return dir_e[1].i_no;
}

/* 在inode编号为p_inode_nr目录中查找inode编号为c_inode_nr的子目录的名字
 * 将名字存入缓冲区path,成功返回0,失败返回-1
 * */
static int get_child_dir_name(uint32_t p_inode_nr, uint32_t c_inode_nr, char* path, void* io_buf) {
    /* 打开p_inode,取出所有数据块存入all_blocks中 */
    struct inode* parent_dir_inode = inode_open(cur_part, p_inode_nr);
    uint32_t* all_blocks = (uint32_t*) sys_malloc(48 + SECTOR_SIZE);
    uint32_t block_idx = 0;
    while(block_idx < 12) {
        all_blocks[block_idx] = parent_dir_inode->i_sectors[block_idx];
        block_idx++;
    }
    if(parent_dir_inode->i_sectors[12] != 0) {
        ide_read(cur_part->my_disk, parent_dir_inode->i_sectors[12], all_blocks + 12, 1);
    }
    inode_close(parent_dir_inode);

    /* 遍历每个数据块,查找编号为c_inode_nr的目录项 */
    block_idx = 0;
    uint32_t dir_entry_size = cur_part->sb->dir_entry_size;
    uint32_t max_dir_entries_per_sec = SECTOR_SIZE / dir_entry_size;
    struct dir_entry* dir_e = (struct dir_entry*) io_buf;
    while (block_idx < 140) {
        if(all_blocks[block_idx] == 0) {
            block_idx++;
            continue;
        }
        ide_read(cur_part->my_disk, all_blocks[block_idx], io_buf, 1);
        uint32_t dir_entry_idx = 0;
        while (dir_entry_idx < max_dir_entries_per_sec) {
            if(((dir_e + dir_entry_idx)->f_type == FT_DIRECTORY) && ((dir_e + dir_entry_idx)->i_no == c_inode_nr)) {
                strcat(path, "/");
                strcat(path, (dir_e + dir_entry_idx)->filename);
                sys_free(all_blocks);
                return 0;
            }
            dir_entry_idx++;
        }
        block_idx++;
    }
    sys_free(all_blocks);
    return -1;
}

        上面两个函数的实现都没太多难度,就不梳理流程了。后面的sys_getcwd函数也不太难就大概说一下,其实就分两步:

        (1)拿到当前线程的cwd_inode_nr后通过get_parent_dir_inode_nr函数以及get_child_dir_name函数拼接绝对路径,不过这一步拼接出来是反的

        (2)将路径反转并返回即可

char* sys_getcwd(char* buf, uint32_t size) {
    ASSERT(buf != NULL);
    void* io_buf = sys_malloc(SECTOR_SIZE);
    if(io_buf == NULL) {
        return NULL;
    }
    /* 拼接目录 */
    struct task_struct* cur_thread = running_thread();
    uint32_t parent_dir_inode_nr = 0;
    uint32_t child_dir_inode_nr = cur_thread->cwd_inode_nr;
    ASSERT(child_dir_inode_nr >= 0 && child_dir_inode_nr < 4096);
    if(child_dir_inode_nr == 0) {
        buf[0] = '/';
        buf[1] = 0;
        sys_free(io_buf);
        return buf;
    }
    memset(buf, 0, size);
    char full_path_reverse[MAX_PATH_LEN] = {0};
    while (child_dir_inode_nr) {
        parent_dir_inode_nr = get_parent_dir_inode_nr(child_dir_inode_nr, io_buf);
        if(get_child_dir_name(parent_dir_inode_nr, child_dir_inode_nr, full_path_reverse, io_buf) == -1) {
            sys_free(io_buf);
            return NULL;
        }
        child_dir_inode_nr = parent_dir_inode_nr;
    }
    ASSERT(strlen(full_path_reverse) <= size);

    /* 目录反转 */
    char* last_slash;
    while ((last_slash = strrchr(full_path_reverse, '/'))) {
        strcpy(buf + strlen(buf), last_slash);
        *last_slash = 0;
    }
    sys_free(io_buf);
    return buf;
}

        接下来说sys_chdir改变工作目录的函数,该函数的形式如下:

int32_t sys_chdir(const char* path)

        起始这个函数也很简单,就是检查一下path路径存不存在,如果存在path路径对应的是不是目录是目录就把搜索到的目录inode号赋值给当前线程的pcb的cwd_inode_nr字段,下次再调用sys_getcwd时就会以cwd_inode_nr字段的新值作为工作目录的inode号了,上代码(fs.c中)

int32_t sys_chdir(const char* path) {
    ASSERT(path != NULL);
    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));
    int32_t inode_no = search_file(path, &searched_record);
    int32_t ret = -1;
    if(inode_no == -1) {
        printk("sys_chdir: %s is not exist!\n", searched_record.searched_path);
    } else {
        uint32_t searched_path_depth = path_depth_cnt(searched_record.searched_path);
        uint32_t path_depth = path_depth_cnt(path);
        if(path_depth == searched_path_depth) {
            running_thread()->cwd_inode_nr = inode_no;
            ret = 0;
        } else {
            printk("sys_chdir: %s is regular file!\n", searched_record.searched_path);
        }
    }
    return ret;
}

        实验结果

#include "print.h"
#include "init.h"
#include "debug.h"
#include "memory.h"
#include "thread.h"
#include "interrupt.h"
#include "console.h"
#include "process.h"
#include "syscall.h"
#include "syscall-init.h"
#include "stdio.h"
#include "fs.h"
#include "dir.h"

int main(void)
{
    put_str("I am kernel\n");
    init_all();
    intr_enable();

    char cwd_buf[32] = {0};
    sys_getcwd(cwd_buf, 32);
    printf("cwd:%s\n", cwd_buf);
    sys_chdir("/dir1");
    printf("change cwd now \n");
    sys_getcwd(cwd_buf, 32);
    printf("cwd:%s\n", cwd_buf);

    while(1);
    return 0;
}

        本篇结束,还最后一篇获得文件属性,文件系统这一章终于要结束了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值