File Operations

vfs_open

所有的檔案、資料夾、device files 的實體都是在 VFS Tree 上的 vnode。vfs_open 會將目標的 vnode 轉成 file object 回傳。

include/vfs.h

1
2
3
4
5
6
struct file {
    struct vnode* vnode;
    uint64_t f_pos;  // The next read/write position of this file descriptor
    struct file_operations* f_ops;
    int flags;
};

src/vfs.c

traversal 會遞迴尋找 pathname 直到到達目標資料夾。接著對該資料夾進行查找,若存在檔案的 vnode 即回傳該 vnode 的 file descriptor,若不存在且 O_CREAT 在 flag,就建立檔案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
struct file* create_fd(struct vnode* target) {
    struct file* fd = (struct file*)kmalloc(sizeof(struct file));
    fd->f_ops = target->f_ops;
    fd->vnode = target;
    fd->f_pos = 0;
    return fd;
}

struct file* vfs_open(const char* pathname, int flags) {
    // 1. Find target_dir node and target_path based on pathname
    struct vnode* target_dir;
    char target_path[128];
    traversal(pathname, &target_dir, target_path);
    // 2. Create a new file descriptor for this vnode if found.
    struct vnode* target_file;
    if (target_dir->v_ops->lookup(target_dir, &target_file, target_path) == 0) {
        return create_fd(target_file);
    }
    // 3. Create a new file if O_CREAT is specified in flags.
    else {
        if (flags & O_CREAT) {
            int res = target_dir->v_ops->create(target_dir, &target_file, target_path);
            if (res < 0) return NULL; // error
            target_file->dentry->type = REGULAR_FILE;
            return create_fd(target_file);
        }
        else {
            return NULL;
        }
    }
}

若為絕對路徑即對 root node 進行遞迴,若為相對路徑即對 pwd 進行遞迴

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
void traversal(const char* pathname, struct vnode** target_node, char* target_path) {
    if (pathname[0] == '/') {  // absolute path
        struct vnode* rootnode = rootfs->root->vnode;
        traversal_recursive(rootnode->dentry, pathname + 1, target_node, target_path);
    }
    else {  // relative path
        struct vnode* rootnode = current_task->pwd->vnode;
        traversal_recursive(rootnode->dentry, pathname, target_node, target_path);
    }
}

中止條件:找到 component name

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void traversal_recursive(struct dentry* node, const char* path, struct vnode** target_node, char* target_path) {
    // find next /
    int i = 0;
    while (path[i]) {
        if (path[i] == '/') break;
        target_path[i] = path[i];
        i++;
    }
    target_path[i++] = '\0';
    *target_node = node->vnode;
    // edge cases check
    if (!strcmp(target_path, "")) {
        return;
    }
    else if (!strcmp(target_path, ".")) {
        traversal_recursive(node, path + i, target_node, target_path);
        return;
    }
    else if (!strcmp(target_path, "..")) {
        if (node->parent == NULL) { // root directory TODO: mountpoint
            return;
        }
        traversal_recursive(node->parent, path + i, target_node, target_path);
        return;
    }
    // find in node's child
    struct list_head* p;
    list_for_each(p, &node->childs) {
        struct dentry* dent = list_entry(p, struct dentry, list);
        if (!strcmp(dent->name, target_path)) {
            if (dent->mountpoint != NULL) {
                traversal_recursive(dent->mountpoint->root, path + i, target_node, target_path);
            }
            else if (dent->type == DIRECTORY) {
                traversal_recursive(dent, path + i, target_node, target_path);
            }
            break;
        }
    }
}

tmpfs lookup

src/tmpfs.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
int tmpfs_lookup(struct vnode* dir, struct vnode** target, const char* component_name) {
    // component_name is empty, return dir vnode
    if (!strcmp(component_name, "")) {
        *target = dir;
        return 0;
    }
    // search component_name in dir
    struct list_head* p = &dir->dentry->childs;
    list_for_each(p, &dir->dentry->childs) {
        struct dentry* dentry = list_entry(p, struct dentry, list);
        if (!strcmp(dentry->name, component_name)) {
            *target = dentry->vnode;
            return 0;
        }
    }
    *target = NULL;
    return -1;
}

tmpfs create

include/tmpfs.h

1
2
3
4
5
6
#define REGULAR_FILE 0
#define TMP_FILE_SIZE 512

struct tmpfs_node {
    char buf[TMP_FILE_SIZE];
};

src/tmpfs.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int tmpfs_create(struct vnode* dir, struct vnode** target, const char* component_name) {
    // create tmpfs internal structure
    struct tmpfs_internal* file_node = (struct tmpfs_internal*)kmalloc(sizeof(struct tmpfs_internal));

    // create child dentry
    struct dentry* d_child = tmpfs_create_dentry(dir->dentry, component_name, REGULAR_FILE);
    d_child->vnode->internal = (void*)file_node;

    *target = d_child->vnode;
    return 0;
}

vfs_close

src/vfs.c

1
2
3
4
5
int vfs_close(struct file* file) {
    // 1. release the file descriptor
    kfree((void*)file);
    return 0;
}

vfs_read

src/vfs.c

1
2
3
4
5
6
7
8
9
int vfs_read(struct file* file, void* buf, uint64_t len) {
    if (file->vnode->dentry->type != REGULAR_FILE) {
        uart_printf("Read on non regular file\n");
        return -1;
    }
    // 1. read min(len, readable file data size) byte to buf from the opened file.
    // 2. return read size or error code if an error occurs.
    return file->f_ops->read(file, buf, len);
}

src/tmpfs.c

這邊應該要在 file structure 存讀到哪及檔案長度,不要用 EOF 判結束條件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int tmpfs_read(struct file* file, void* buf, uint64_t len) {
    struct tmpfs_internal* file_node = (struct tmpfs_internal*)file->vnode->internal;

    char* dest = (char*)buf;
    char* src = &file_node->buf[file->f_pos];
    uint64_t i = 0;
    for (; i < len && src[i] != (uint8_t)EOF; i++) {
        dest[i] = src[i];
    }
    return i;
}

vfs_write

src/vfs.c

1
2
3
4
5
6
7
8
9
int vfs_write(struct file* file, const void* buf, uint64_t len) {
    if (file->vnode->dentry->type != REGULAR_FILE) {
        uart_printf("Write to non regular file\n");
        return -1;
    }
    // 1. write len byte from buf to the opened file.
    // 2. return written size or error code if an error occurs.
    return file->f_ops->write(file, buf, len);
}

src/tmpfs.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int tmpfs_write(struct file* file, const void* buf, uint64_t len) {
    struct tmpfs_internal* file_node = (struct tmpfs_internal*)file->vnode->internal;

    char* dest = &file_node->buf[file->f_pos];
    char* src = (char*)buf;
    uint64_t i = 0;
    for (; i < len && src[i] != '\0'; i++) {
        dest[i] = src[i];
    }
    dest[i] = EOF;
    return i;
}
comments powered by Disqus