finish exec5.1-4
This commit is contained in:
parent
1be2b1fcdf
commit
9862d87027
538
lab5/user/lab5/tmpfs/tmpfs.c
Normal file
538
lab5/user/lab5/tmpfs/tmpfs.c
Normal file
@ -0,0 +1,538 @@
|
||||
#include "tmpfs.h"
|
||||
|
||||
#include <defs.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <cpio.h>
|
||||
#include <launcher.h>
|
||||
|
||||
static struct inode *tmpfs_root;
|
||||
|
||||
/*
|
||||
* Helper functions to calucate hash value of string
|
||||
*/
|
||||
static inline u64 hash_chars(const char *str, ssize_t len)
|
||||
{
|
||||
u64 seed = 131; /* 31 131 1313 13131 131313 etc.. */
|
||||
u64 hash = 0;
|
||||
int i;
|
||||
|
||||
if (len < 0) {
|
||||
while (*str) {
|
||||
hash = (hash * seed) + *str;
|
||||
str++;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < len; ++i)
|
||||
hash = (hash * seed) + str[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/* BKDR hash */
|
||||
static inline u64 hash_string(struct string *s)
|
||||
{
|
||||
return (s->hash = hash_chars(s->str, s->len));
|
||||
}
|
||||
|
||||
static inline int init_string(struct string *s, const char *name, size_t len)
|
||||
{
|
||||
int i;
|
||||
|
||||
s->str = malloc(len + 1);
|
||||
if (!s->str)
|
||||
return -ENOMEM;
|
||||
s->len = len;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
s->str[i] = name[i];
|
||||
s->str[len] = '\0';
|
||||
|
||||
hash_string(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper functions to create instances of key structures
|
||||
*/
|
||||
static inline struct inode *new_inode(void)
|
||||
{
|
||||
struct inode *inode = malloc(sizeof(*inode));
|
||||
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
inode->type = 0;
|
||||
inode->size = 0;
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
static struct inode *new_dir(void)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
inode = new_inode();
|
||||
if (IS_ERR(inode))
|
||||
return inode;
|
||||
inode->type = FS_DIR;
|
||||
init_htable(&inode->dentries, 1024);
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
static struct inode *new_reg(void)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
inode = new_inode();
|
||||
if (IS_ERR(inode))
|
||||
return inode;
|
||||
inode->type = FS_REG;
|
||||
init_radix_w_deleter(&inode->data, free);
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
static struct dentry *new_dent(struct inode *inode, const char *name,
|
||||
size_t len)
|
||||
{
|
||||
struct dentry *dent;
|
||||
int err;
|
||||
|
||||
dent = malloc(sizeof(*dent));
|
||||
if (!dent)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
err = init_string(&dent->name, name, len);
|
||||
if (err) {
|
||||
free(dent);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
dent->inode = inode;
|
||||
|
||||
return dent;
|
||||
}
|
||||
|
||||
// this function create a file (directory if `mkdir` == true, otherwise regular
|
||||
// file) and its size is `len`. You should create an inode and corresponding
|
||||
// dentry, then add dentey to `dir`'s htable by `htable_add`.
|
||||
// Assume that no separator ('/') in `name`.
|
||||
static int tfs_mknod(struct inode *dir, const char *name, size_t len, int mkdir)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct dentry *dent;
|
||||
|
||||
BUG_ON(!name);
|
||||
|
||||
if (len == 0) {
|
||||
WARN("mknod with len of 0");
|
||||
return -ENOENT;
|
||||
}
|
||||
// TODO: write your code here
|
||||
|
||||
// 创建 inode
|
||||
if (mkdir) {
|
||||
inode = new_dir();
|
||||
} else {
|
||||
inode = new_reg();
|
||||
}
|
||||
|
||||
// 创建 dentry
|
||||
dent = malloc(sizeof(struct dentry));
|
||||
init_string(&dent->name, name, len);
|
||||
dent->inode = inode;
|
||||
|
||||
// 添加至哈希表
|
||||
htable_add(&dir->dentries, hash_chars(name, len), &dent->node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tfs_mkdir(struct inode *dir, const char *name, size_t len)
|
||||
{
|
||||
return tfs_mknod(dir, name, len, 1 /* mkdir */ );
|
||||
}
|
||||
|
||||
int tfs_creat(struct inode *dir, const char *name, size_t len)
|
||||
{
|
||||
return tfs_mknod(dir, name, len, 0 /* mkdir */ );
|
||||
}
|
||||
|
||||
// look up a file called `name` under the inode `dir`
|
||||
// and return the dentry of this file
|
||||
static struct dentry *tfs_lookup(struct inode *dir, const char *name,
|
||||
size_t len)
|
||||
{
|
||||
u64 hash = hash_chars(name, len);
|
||||
struct dentry *dent;
|
||||
struct hlist_head *head;
|
||||
|
||||
head = htable_get_bucket(&dir->dentries, (u32) hash);
|
||||
|
||||
for_each_in_hlist(dent, node, head) {
|
||||
if (dent->name.len == len && 0 == strcmp(dent->name.str, name))
|
||||
return dent;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Walk the file system structure to locate a file with the pathname stored in `*name`
|
||||
// and saves parent dir to `*dirat` and the filename to `*name`.
|
||||
// If `mkdir_p` is true, you need to create intermediate directories when it missing.
|
||||
// If the pathname `*name` starts with '/', then lookup starts from `tmpfs_root`,
|
||||
// else from `*dirat`.
|
||||
// Note that when `*name` ends with '/', the inode of last component will be
|
||||
// saved in `*dirat` regardless of its type (e.g., even when it's FS_REG) and
|
||||
// `*name` will point to '\0'
|
||||
int tfs_namex(struct inode **dirat, const char **name, int mkdir_p)
|
||||
{
|
||||
BUG_ON(dirat == NULL);
|
||||
BUG_ON(name == NULL);
|
||||
BUG_ON(*name == NULL);
|
||||
|
||||
char buff[MAX_FILENAME_LEN + 1];
|
||||
int buff_len;
|
||||
struct dentry *dent = NULL;
|
||||
int err;
|
||||
char ch;
|
||||
|
||||
if (**name == '/') {
|
||||
*dirat = tmpfs_root;
|
||||
// make sure `name` starts with actual name
|
||||
while (**name && **name == '/')
|
||||
++(*name);
|
||||
} else {
|
||||
BUG_ON(*dirat == NULL);
|
||||
BUG_ON((*dirat)->type != FS_DIR);
|
||||
}
|
||||
|
||||
// make sure a child name exists
|
||||
if (!**name)
|
||||
return -EINVAL;
|
||||
|
||||
// 遍历各级目录
|
||||
while (**name != '\0') {
|
||||
// 读文件名
|
||||
buff_len = 0;
|
||||
while ((ch = (*name)[buff_len]) && ch != '/') {
|
||||
buff[buff_len] = ch;
|
||||
buff_len++;
|
||||
}
|
||||
if (ch == '\0') {
|
||||
// 为文件名,直接结束循环
|
||||
break;
|
||||
}
|
||||
*name += buff_len;
|
||||
buff[buff_len] = '\0';
|
||||
// 确保父目录
|
||||
if ((*dirat)->type == FS_REG) {
|
||||
err = -ENOTDIR;
|
||||
goto output_err;
|
||||
}
|
||||
// 找文件
|
||||
dent = tfs_lookup(*dirat, buff, buff_len);
|
||||
if (dent == NULL) {
|
||||
if (mkdir_p) {
|
||||
err = tfs_mkdir(*dirat, buff, buff_len);
|
||||
if (err != 0) {
|
||||
goto output_err;
|
||||
}
|
||||
dent = tfs_lookup(*dirat, buff, buff_len);
|
||||
} else {
|
||||
err = -ENOTDIR;
|
||||
goto output_err;
|
||||
}
|
||||
}
|
||||
// 检查是否为目录
|
||||
if (**name == '/') {
|
||||
*dirat = dent->inode;
|
||||
dent = NULL;
|
||||
// 忽略连续 slash
|
||||
while (**name && **name == '/')
|
||||
++(*name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
output_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
int tfs_remove(struct inode *dir, const char *name, size_t len)
|
||||
{
|
||||
u64 hash = hash_chars(name, len);
|
||||
struct dentry *dent, *target = NULL;
|
||||
struct hlist_head *head;
|
||||
|
||||
BUG_ON(!name);
|
||||
|
||||
if (len == 0) {
|
||||
WARN("mknod with len of 0");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
head = htable_get_bucket(&dir->dentries, (u32) hash);
|
||||
|
||||
for_each_in_hlist(dent, node, head) {
|
||||
if (dent->name.len == len && 0 == strcmp(dent->name.str, name)) {
|
||||
target = dent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!target)
|
||||
return -ENOENT;
|
||||
|
||||
BUG_ON(!target->inode);
|
||||
|
||||
// remove only when file is closed by all processes
|
||||
if (target->inode->type == FS_REG) {
|
||||
// free radix tree
|
||||
radix_free(&target->inode->data);
|
||||
// free inode
|
||||
free(target->inode);
|
||||
// remove dentry from parent
|
||||
htable_del(&target->node);
|
||||
// free dentry
|
||||
free(target);
|
||||
} else if (target->inode->type == FS_DIR) {
|
||||
if (!htable_empty(&target->inode->dentries))
|
||||
return -ENOTEMPTY;
|
||||
|
||||
// free htable
|
||||
htable_free(&target->inode->dentries);
|
||||
// free inode
|
||||
free(target->inode);
|
||||
// remove dentry from parent
|
||||
htable_del(&target->node);
|
||||
// free dentry
|
||||
free(target);
|
||||
} else {
|
||||
BUG("inode type that shall not exist");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_tmpfs(void)
|
||||
{
|
||||
tmpfs_root = new_dir();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// write memory into `inode` at `offset` from `buf` for length is `size`
|
||||
// it may resize the file
|
||||
// `radix_get`, `radix_add` are used in this function
|
||||
// You can use memory functions defined in libc
|
||||
ssize_t tfs_file_write(struct inode * inode, off_t offset, const char *data,
|
||||
size_t size)
|
||||
{
|
||||
BUG_ON(inode->type != FS_REG);
|
||||
BUG_ON(offset > inode->size);
|
||||
|
||||
u64 page_no, page_off;
|
||||
u64 cur_off = offset;
|
||||
size_t to_write, cur_to_write;
|
||||
void *page;
|
||||
|
||||
// TODO: write your code here
|
||||
|
||||
// 计算长度
|
||||
to_write = size;
|
||||
|
||||
// 尝试写
|
||||
while (to_write > 0) {
|
||||
page_no = cur_off / PAGE_SIZE;
|
||||
page_off = cur_off & (PAGE_SIZE - 1);
|
||||
page = radix_get(&inode->data, page_no);
|
||||
// 计算读取大小
|
||||
cur_to_write = to_write;
|
||||
if (cur_to_write > PAGE_SIZE - page_off) {
|
||||
cur_to_write = PAGE_SIZE - page_off;
|
||||
}
|
||||
|
||||
// 不存在页就创建
|
||||
if (page == NULL) {
|
||||
page = calloc(1, PAGE_SIZE);
|
||||
radix_add(&inode->data, page_no, page);
|
||||
}
|
||||
// 写数据
|
||||
memcpy(page + page_off, data + cur_off, cur_to_write);
|
||||
|
||||
to_write -= cur_to_write;
|
||||
cur_off += cur_to_write;
|
||||
}
|
||||
|
||||
if (cur_off > inode->size) {
|
||||
inode->size = cur_off;
|
||||
}
|
||||
|
||||
printf("Size: %d\n", cur_off - offset);
|
||||
return cur_off - offset;
|
||||
}
|
||||
|
||||
// read memory from `inode` at `offset` in to `buf` for length is `size`, do not
|
||||
// exceed the file size
|
||||
// `radix_get` is used in this function
|
||||
// You can use memory functions defined in libc
|
||||
ssize_t tfs_file_read(struct inode * inode, off_t offset, char *buff,
|
||||
size_t size)
|
||||
{
|
||||
BUG_ON(inode->type != FS_REG);
|
||||
BUG_ON(offset > inode->size);
|
||||
|
||||
u64 page_no, page_off;
|
||||
u64 cur_off = offset;
|
||||
size_t to_read, cur_to_read;
|
||||
void *page;
|
||||
|
||||
// 计算未读取数量
|
||||
to_read = size;
|
||||
if (to_read > inode->size) {
|
||||
to_read = inode->size;
|
||||
}
|
||||
|
||||
// 尝试读取
|
||||
while (to_read > 0) {
|
||||
page_no = cur_off / PAGE_SIZE;
|
||||
page_off = cur_off & (PAGE_SIZE - 1);
|
||||
page = radix_get(&inode->data, page_no);
|
||||
// 计算读取大小
|
||||
cur_to_read = to_read;
|
||||
if (cur_to_read > PAGE_SIZE - page_off) {
|
||||
cur_to_read = PAGE_SIZE - page_off;
|
||||
}
|
||||
// 读取数据
|
||||
if (page == NULL) {
|
||||
memset(buff + cur_off, 0, cur_to_read);
|
||||
} else {
|
||||
memcpy(buff + cur_off, page + page_off, cur_to_read);
|
||||
}
|
||||
to_read -= cur_to_read;
|
||||
cur_off += cur_to_read;
|
||||
}
|
||||
|
||||
return cur_off - offset;
|
||||
}
|
||||
|
||||
// load the cpio archive into tmpfs with the begin address as `start` in memory
|
||||
// You need to create directories and files if necessary. You also need to write
|
||||
// the data into the tmpfs.
|
||||
int tfs_load_image(const char *start)
|
||||
{
|
||||
struct cpio_file *f;
|
||||
struct inode *dirat;
|
||||
struct dentry *dent;
|
||||
const char *leaf;
|
||||
size_t len;
|
||||
int err;
|
||||
ssize_t write_count;
|
||||
char pathname[MAX_FILENAME_LEN + 1];
|
||||
|
||||
BUG_ON(start == NULL);
|
||||
|
||||
cpio_init_g_files();
|
||||
cpio_extract(start, "/");
|
||||
|
||||
for (f = g_files.head.next; f; f = f->next) {
|
||||
// TODO: Lab5: your code is here
|
||||
// 忽略文件夹
|
||||
len = f->header.c_filesize;
|
||||
if (len == 0) {
|
||||
continue;
|
||||
}
|
||||
// 处理文件名
|
||||
pathname[0] = '/'; pathname[1] = '\0';
|
||||
strcat(pathname, f->name);
|
||||
leaf = pathname;
|
||||
printf("Load file: %s, %lx, %d\n", leaf, f->data, len);
|
||||
// 创建目录
|
||||
err = tfs_namex(&dirat, &leaf, 1);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
// 创建文件
|
||||
err = tfs_creat(dirat, leaf, strlen(leaf));
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
dent = tfs_lookup(dirat, leaf, strlen(leaf));
|
||||
if (dent == NULL) {
|
||||
return -EFAULT;
|
||||
}
|
||||
// 写入数据
|
||||
// printf("Created file: %s\n", leaf);
|
||||
if (len != tfs_file_write(dent->inode, 0, f->data, len)) {
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dirent_filler(void **dirpp, void *end, char *name, off_t off,
|
||||
unsigned char type, ino_t ino)
|
||||
{
|
||||
struct dirent *dirp = *(struct dirent **)dirpp;
|
||||
void *p = dirp;
|
||||
unsigned short len = strlen(name) + 1 +
|
||||
sizeof(dirp->d_ino) +
|
||||
sizeof(dirp->d_off) + sizeof(dirp->d_reclen) + sizeof(dirp->d_type);
|
||||
p += len;
|
||||
if (p > end)
|
||||
return -EAGAIN;
|
||||
dirp->d_ino = ino;
|
||||
dirp->d_off = off;
|
||||
dirp->d_reclen = len;
|
||||
dirp->d_type = type;
|
||||
strcpy(dirp->d_name, name);
|
||||
*dirpp = p;
|
||||
return len;
|
||||
}
|
||||
|
||||
int tfs_scan(struct inode *dir, unsigned int start, void *buf, void *end)
|
||||
{
|
||||
s64 cnt = 0;
|
||||
int b;
|
||||
int ret;
|
||||
ino_t ino;
|
||||
void *p = buf;
|
||||
unsigned char type;
|
||||
struct dentry *iter;
|
||||
|
||||
for_each_in_htable(iter, b, node, &dir->dentries) {
|
||||
if (cnt >= start) {
|
||||
type = iter->inode->type;
|
||||
ino = iter->inode->size;
|
||||
ret = dirent_filler(&p, end, iter->name.str,
|
||||
cnt, type, ino);
|
||||
if (ret <= 0) {
|
||||
return cnt - start;
|
||||
}
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
return cnt - start;
|
||||
|
||||
}
|
||||
|
||||
/* path[0] must be '/' */
|
||||
struct inode *tfs_open_path(const char *path)
|
||||
{
|
||||
struct inode *dirat = NULL;
|
||||
const char *leaf = path;
|
||||
struct dentry *dent;
|
||||
int err;
|
||||
|
||||
if (*path == '/' && !*(path + 1))
|
||||
return tmpfs_root;
|
||||
|
||||
err = tfs_namex(&dirat, &leaf, 0);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
dent = tfs_lookup(dirat, leaf, strlen(leaf));
|
||||
return dent ? dent->inode : NULL;
|
||||
}
|
165
lab5/user/lab5/tmpfs/tmpfs_server.c
Normal file
165
lab5/user/lab5/tmpfs/tmpfs_server.c
Normal file
@ -0,0 +1,165 @@
|
||||
#include "tmpfs_server.h"
|
||||
|
||||
#include <syscall.h>
|
||||
|
||||
// int fs_stat(const char *pathname, struct stat *statbuf);
|
||||
// int fs_getdents(int fd, struct dirent *dirp, size_t count);
|
||||
|
||||
int fs_server_init(u64 cpio_start)
|
||||
{
|
||||
init_tmpfs();
|
||||
usys_fs_load_cpio(cpio_start);
|
||||
return tfs_load_image((char *)cpio_start);
|
||||
}
|
||||
|
||||
int fs_server_mkdir(const char *path)
|
||||
{
|
||||
struct inode *dirat = NULL;
|
||||
const char *leaf = path;
|
||||
int err;
|
||||
|
||||
BUG_ON(!path);
|
||||
BUG_ON(*path != '/');
|
||||
|
||||
err = tfs_namex(&dirat, &leaf, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = tfs_mkdir(dirat, leaf, strlen(leaf));
|
||||
return err;
|
||||
}
|
||||
|
||||
int fs_server_creat(const char *path)
|
||||
{
|
||||
struct inode *dirat = NULL;
|
||||
const char *leaf = path;
|
||||
int err;
|
||||
|
||||
BUG_ON(!path);
|
||||
BUG_ON(*path != '/');
|
||||
|
||||
err = tfs_namex(&dirat, &leaf, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = tfs_creat(dirat, leaf, strlen(leaf));
|
||||
return err;
|
||||
}
|
||||
|
||||
int fs_server_unlink(const char *path)
|
||||
{
|
||||
struct inode *dirat = NULL;
|
||||
const char *leaf = path;
|
||||
int err;
|
||||
|
||||
BUG_ON(!path);
|
||||
BUG_ON(*path != '/');
|
||||
|
||||
err = tfs_namex(&dirat, &leaf, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = tfs_remove(dirat, leaf, strlen(leaf));
|
||||
return err;
|
||||
}
|
||||
|
||||
int fs_server_rmdir(const char *path)
|
||||
{
|
||||
struct inode *dirat = NULL;
|
||||
const char *leaf = path;
|
||||
int err;
|
||||
|
||||
BUG_ON(!path);
|
||||
BUG_ON(*path != '/');
|
||||
|
||||
dirat = tfs_open_path(path);
|
||||
if (dirat != NULL && dirat->type != FS_DIR) {
|
||||
return -ENOTDIR;
|
||||
}
|
||||
if (dirat != NULL && !htable_empty(&dirat->dentries)) {
|
||||
return -ENOTEMPTY;
|
||||
}
|
||||
|
||||
err = tfs_namex(&dirat, &leaf, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = tfs_remove(dirat, leaf, strlen(leaf));
|
||||
return err;
|
||||
}
|
||||
|
||||
/* use absolute path, offset and count to read directly */
|
||||
int fs_server_read(const char *path, off_t offset, void *buf, size_t count)
|
||||
{
|
||||
struct inode *inode;
|
||||
int ret = -ENOENT;
|
||||
|
||||
BUG_ON(!path);
|
||||
BUG_ON(*path != '/');
|
||||
|
||||
inode = tfs_open_path(path);
|
||||
if (inode) {
|
||||
ret = tfs_file_read(inode, offset, buf, count);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* use absolute path, offset and count to write directly */
|
||||
int fs_server_write(const char *path, off_t offset, const void *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct inode *inode;
|
||||
int ret = -ENOENT;
|
||||
|
||||
BUG_ON(!path);
|
||||
BUG_ON(*path != '/');
|
||||
|
||||
inode = tfs_open_path(path);
|
||||
if (inode) {
|
||||
ret = tfs_file_write(inode, offset, buf, count);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t fs_server_get_size(const char *path)
|
||||
{
|
||||
struct inode *inode;
|
||||
int ret = -ENOENT;
|
||||
|
||||
BUG_ON(!path);
|
||||
BUG_ON(*path != '/');
|
||||
|
||||
inode = tfs_open_path(path);
|
||||
if (inode)
|
||||
ret = inode->size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Scan several dirent structures from the directory referred to by the path
|
||||
* into the buffer pointed by dirp. The argument count specifies the size of
|
||||
* that buffer.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* On success, the number of items is returned. On end of directory, 0 is
|
||||
* returned. On error, -errno is returned.
|
||||
*
|
||||
* The caller should call this function over and over again until it returns 0
|
||||
* */
|
||||
int fs_server_scan(const char *path, unsigned int start, void *buf,
|
||||
unsigned int count)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
BUG_ON(!path);
|
||||
BUG_ON(*path != '/');
|
||||
|
||||
inode = tfs_open_path(path);
|
||||
if (inode) {
|
||||
if (inode->type == FS_DIR)
|
||||
return tfs_scan(inode, start, buf, buf + count);
|
||||
return -ENOTDIR;
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user