diff options
author | nthnluu <nate1299@me.com> | 2024-01-28 21:20:27 -0500 |
---|---|---|
committer | nthnluu <nate1299@me.com> | 2024-01-28 21:20:27 -0500 |
commit | c63f340d90800895f007de64b7d2d14624263331 (patch) | |
tree | 2c0849fa597dd6da831c8707b6f2603403778d7b /kernel/fs/ramfs/ramfs.c |
Created student weenix repository
Diffstat (limited to 'kernel/fs/ramfs/ramfs.c')
-rw-r--r-- | kernel/fs/ramfs/ramfs.c | 852 |
1 files changed, 852 insertions, 0 deletions
diff --git a/kernel/fs/ramfs/ramfs.c b/kernel/fs/ramfs/ramfs.c new file mode 100644 index 0000000..72547c4 --- /dev/null +++ b/kernel/fs/ramfs/ramfs.c @@ -0,0 +1,852 @@ +/* + * This is a special filesystem designed to be a test filesystem before s5fs has + * been written. It is an in-memory filesystem that supports almost all of the + * vnode operations. It has the following restrictions: + * + * o File sizes are limited to a single page (4096 bytes) in order + * to keep the code simple. + * + * o There is no support for fill_pframe, etc. + * + * o There is a maximum directory size limit + * + * o There is a maximum number of files/directories limit + */ + +#include "fs/ramfs/ramfs.h" +#include "errno.h" +#include "fs/dirent.h" +#include "fs/stat.h" +#include "fs/vfs.h" +#include "fs/vnode.h" +#include "globals.h" +#include "kernel.h" +#include "mm/kmalloc.h" +#include "mm/slab.h" +#include "util/debug.h" +#include "util/string.h" + +/* + * Filesystem operations + */ +static void ramfs_read_vnode(fs_t *fs, vnode_t *vn); + +static void ramfs_delete_vnode(fs_t *fs, vnode_t *vn); + +static long ramfs_umount(fs_t *fs); + +static fs_ops_t ramfs_ops = {.read_vnode = ramfs_read_vnode, + .delete_vnode = ramfs_delete_vnode, + .umount = ramfs_umount}; + +/* + * vnode operations + */ +static ssize_t ramfs_read(vnode_t *file, size_t offset, void *buf, + size_t count); + +static ssize_t ramfs_write(vnode_t *file, size_t offset, const void *buf, + size_t count); + +/* getpage */ +static ssize_t ramfs_create(vnode_t *dir, const char *name, size_t name_len, + vnode_t **result); + +static ssize_t ramfs_mknod(struct vnode *dir, const char *name, size_t name_len, + int mode, devid_t devid, struct vnode **out); + +static ssize_t ramfs_lookup(vnode_t *dir, const char *name, size_t namelen, + vnode_t **out); + +static long ramfs_link(vnode_t *dir, const char *name, size_t namelen, + vnode_t *child); + +static ssize_t ramfs_unlink(vnode_t *dir, const char *name, size_t name_len); + +static ssize_t ramfs_rename(vnode_t *olddir, const char *oldname, + size_t oldnamelen, vnode_t *newdir, + const char *newname, size_t newnamelen); + +static ssize_t ramfs_mkdir(vnode_t *dir, const char *name, size_t name_len, + struct vnode **out); + +static ssize_t ramfs_rmdir(vnode_t *dir, const char *name, size_t name_len); + +static ssize_t ramfs_readdir(vnode_t *dir, size_t offset, struct dirent *d); + +static ssize_t ramfs_stat(vnode_t *file, stat_t *buf); + +static void ramfs_truncate_file(vnode_t *file); + +static vnode_ops_t ramfs_dir_vops = {.read = NULL, + .write = NULL, + .mmap = NULL, + .mknod = ramfs_mknod, + .lookup = ramfs_lookup, + .link = ramfs_link, + .unlink = ramfs_unlink, + .rename = ramfs_rename, + .mkdir = ramfs_mkdir, + .rmdir = ramfs_rmdir, + .readdir = ramfs_readdir, + .stat = ramfs_stat, + .acquire = NULL, + .release = NULL, + .get_pframe = NULL, + .fill_pframe = NULL, + .flush_pframe = NULL, + .truncate_file = NULL}; + +static vnode_ops_t ramfs_file_vops = {.read = ramfs_read, + .write = ramfs_write, + .mmap = NULL, + .mknod = NULL, + .lookup = NULL, + .link = NULL, + .unlink = NULL, + .mkdir = NULL, + .rmdir = NULL, + .stat = ramfs_stat, + .acquire = NULL, + .release = NULL, + .get_pframe = NULL, + .fill_pframe = NULL, + .flush_pframe = NULL, + .truncate_file = ramfs_truncate_file}; + +/* + * The ramfs 'inode' structure + */ +typedef struct ramfs_inode +{ + size_t rf_size; /* Total file size */ + ino_t rf_ino; /* Inode number */ + char *rf_mem; /* Memory for this file (1 page) */ + ssize_t rf_mode; /* Type of file */ + ssize_t rf_linkcount; /* Number of links to this file */ +} ramfs_inode_t; + +#define RAMFS_TYPE_DATA 0 +#define RAMFS_TYPE_DIR 1 +#define RAMFS_TYPE_CHR 2 +#define RAMFS_TYPE_BLK 3 + +#define VNODE_TO_RAMFSINODE(vn) ((ramfs_inode_t *)(vn)->vn_i) +#define VNODE_TO_RAMFS(vn) ((ramfs_t *)(vn)->vn_fs->fs_i) +#define VNODE_TO_DIRENT(vn) ((ramfs_dirent_t *)VNODE_TO_RAMFSINODE(vn)->rf_mem) + +/* + * ramfs filesystem structure + */ +#define RAMFS_MAX_FILES 64 + +typedef struct ramfs +{ + ramfs_inode_t *rfs_inodes[RAMFS_MAX_FILES]; /* Array of all files */ +} ramfs_t; + +/* + * For directories, we simply store an array of (ino, name) pairs in the + * memory portion of the inode. + */ +typedef struct ramfs_dirent +{ + ssize_t rd_ino; /* Inode number of this entry */ + char rd_name[NAME_LEN]; /* Name of this entry */ +} ramfs_dirent_t; + +#define RAMFS_MAX_DIRENT ((size_t)(PAGE_SIZE / sizeof(ramfs_dirent_t))) + +/* Helper functions */ +static ssize_t ramfs_alloc_inode(fs_t *fs, ssize_t type, devid_t devid) +{ + ramfs_t *rfs = (ramfs_t *)fs->fs_i; + KASSERT((RAMFS_TYPE_DATA == type) || (RAMFS_TYPE_DIR == type) || + (RAMFS_TYPE_CHR == type) || (RAMFS_TYPE_BLK == type)); + /* Find a free inode */ + ssize_t i; + for (i = 0; i < RAMFS_MAX_FILES; i++) + { + if (NULL == rfs->rfs_inodes[i]) + { + ramfs_inode_t *inode; + if (NULL == (inode = kmalloc(sizeof(ramfs_inode_t)))) + { + return -ENOSPC; + } + + if (RAMFS_TYPE_CHR == type || RAMFS_TYPE_BLK == type) + { + /* Don't need any space in memory, so put devid in here */ + inode->rf_mem = (char *)(uint64_t)devid; + } + else + { + /* We allocate space for the file's contents immediately */ + if (NULL == (inode->rf_mem = page_alloc())) + { + kfree(inode); + return -ENOSPC; + } + memset(inode->rf_mem, 0, PAGE_SIZE); + } + inode->rf_size = 0; + inode->rf_ino = i; + inode->rf_mode = type; + inode->rf_linkcount = 1; + + /* Install in table and return */ + rfs->rfs_inodes[i] = inode; + return i; + } + } + return -ENOSPC; +} + +/* + * Function implementations + */ + +long ramfs_mount(struct fs *fs) +{ + /* Allocate filesystem */ + ramfs_t *rfs = kmalloc(sizeof(ramfs_t)); + if (NULL == rfs) + { + return -ENOMEM; + } + + memset(rfs->rfs_inodes, 0, sizeof(rfs->rfs_inodes)); + + fs->fs_i = rfs; + fs->fs_ops = &ramfs_ops; + + /* Set up root inode */ + ssize_t root_ino; + if (0 > (root_ino = ramfs_alloc_inode(fs, RAMFS_TYPE_DIR, 0))) + { + return root_ino; + } + + slab_allocator_t *allocator = + slab_allocator_create("ramfs_node", sizeof(vnode_t)); + fs->fs_vnode_allocator = allocator; + KASSERT(allocator); + + KASSERT(0 == root_ino); + ramfs_inode_t *root = rfs->rfs_inodes[root_ino]; + + /* Set up '.' and '..' in the root directory */ + ramfs_dirent_t *rootdent = (ramfs_dirent_t *)root->rf_mem; + rootdent->rd_ino = 0; + strcpy(rootdent->rd_name, "."); + rootdent++; + rootdent->rd_ino = 0; + strcpy(rootdent->rd_name, ".."); + + /* Increase root inode size accordingly */ + root->rf_size = 2 * sizeof(ramfs_dirent_t); + + /* Put the root in the inode table */ + rfs->rfs_inodes[0] = root; + + /* And vget the root vnode */ + fs->fs_root = vget(fs, 0); + + return 0; +} + +static void ramfs_read_vnode(fs_t *fs, vnode_t *vn) +{ + ramfs_t *rfs = VNODE_TO_RAMFS(vn); + ramfs_inode_t *inode = rfs->rfs_inodes[vn->vn_vno]; + KASSERT(inode && inode->rf_ino == vn->vn_vno); + + inode->rf_linkcount++; + + vn->vn_i = inode; + vn->vn_len = inode->rf_size; + + switch (inode->rf_mode) + { + case RAMFS_TYPE_DATA: + vn->vn_mode = S_IFREG; + vn->vn_ops = &ramfs_file_vops; + break; + case RAMFS_TYPE_DIR: + vn->vn_mode = S_IFDIR; + vn->vn_ops = &ramfs_dir_vops; + break; + case RAMFS_TYPE_CHR: + vn->vn_mode = S_IFCHR; + vn->vn_ops = NULL; + vn->vn_devid = (devid_t)(uint64_t)(inode->rf_mem); + break; + case RAMFS_TYPE_BLK: + vn->vn_mode = S_IFBLK; + vn->vn_ops = NULL; + vn->vn_devid = (devid_t)(uint64_t)(inode->rf_mem); + break; + default: + panic("inode %ld has unknown/invalid type %ld!!\n", + (ssize_t)vn->vn_vno, (ssize_t)inode->rf_mode); + } +} + +static void ramfs_delete_vnode(fs_t *fs, vnode_t *vn) +{ + ramfs_inode_t *inode = VNODE_TO_RAMFSINODE(vn); + ramfs_t *rfs = VNODE_TO_RAMFS(vn); + + if (0 == --inode->rf_linkcount) + { + KASSERT(rfs->rfs_inodes[vn->vn_vno] == inode); + + rfs->rfs_inodes[vn->vn_vno] = NULL; + if (inode->rf_mode == RAMFS_TYPE_DATA || + inode->rf_mode == RAMFS_TYPE_DIR) + { + page_free(inode->rf_mem); + } + /* otherwise, inode->rf_mem is a devid */ + + kfree(inode); + } +} + +static ssize_t ramfs_umount(fs_t *fs) +{ + /* We don't need to do any flushing or anything as everything is in memory. + * Just free all of our allocated memory */ + ramfs_t *rfs = (ramfs_t *)fs->fs_i; + + vput(&fs->fs_root); + + /* Free all the inodes */ + ssize_t i; + for (i = 0; i < RAMFS_MAX_FILES; i++) + { + if (NULL != rfs->rfs_inodes[i]) + { + if (NULL != rfs->rfs_inodes[i]->rf_mem && + (rfs->rfs_inodes[i]->rf_mode == RAMFS_TYPE_DATA || + rfs->rfs_inodes[i]->rf_mode == RAMFS_TYPE_DIR)) + { + page_free(rfs->rfs_inodes[i]->rf_mem); + } + kfree(rfs->rfs_inodes[i]); + } + } + + return 0; +} + +static ssize_t ramfs_create(vnode_t *dir, const char *name, size_t name_len, + vnode_t **result) +{ + vnode_t *vn; + size_t i; + ramfs_dirent_t *entry; + + /* Look for space in the directory */ + entry = VNODE_TO_DIRENT(dir); + for (i = 0; i < RAMFS_MAX_DIRENT; i++, entry++) + { + if (!entry->rd_name[0]) + { + break; + } + } + + if (i == RAMFS_MAX_DIRENT) + { + return -ENOSPC; + } + + /* Allocate an inode */ + ssize_t ino; + if (0 > (ino = ramfs_alloc_inode(dir->vn_fs, RAMFS_TYPE_DATA, 0))) + { + return ino; + } + + /* Get a vnode, set entry in directory */ + vn = vget(dir->vn_fs, (ino_t)ino); + + entry->rd_ino = vn->vn_vno; + strncpy(entry->rd_name, name, MIN(name_len, NAME_LEN - 1)); + entry->rd_name[MIN(name_len, NAME_LEN - 1)] = '\0'; + + VNODE_TO_RAMFSINODE(dir)->rf_size += sizeof(ramfs_dirent_t); + + *result = vn; + + return 0; +} + +static ssize_t ramfs_mknod(struct vnode *dir, const char *name, size_t name_len, + int mode, devid_t devid, struct vnode **out) +{ + size_t i; + ramfs_dirent_t *entry; + + /* Look for space in the directory */ + entry = VNODE_TO_DIRENT(dir); + for (i = 0; i < RAMFS_MAX_DIRENT; i++, entry++) + { + if (!entry->rd_name[0]) + { + break; + } + } + + if (i == RAMFS_MAX_DIRENT) + { + return -ENOSPC; + } + + ssize_t ino; + if (S_ISCHR(mode)) + { + ino = ramfs_alloc_inode(dir->vn_fs, RAMFS_TYPE_CHR, devid); + } + else if (S_ISBLK(mode)) + { + ino = ramfs_alloc_inode(dir->vn_fs, RAMFS_TYPE_BLK, devid); + } + else if (S_ISREG(mode)) + { + ino = ramfs_alloc_inode(dir->vn_fs, RAMFS_TYPE_DATA, devid); + } + else + { + panic("Invalid mode!\n"); + } + + if (ino < 0) + { + return ino; + } + + /* Set entry in directory */ + entry->rd_ino = ino; + strncpy(entry->rd_name, name, MIN(name_len, NAME_LEN - 1)); + entry->rd_name[MIN(name_len, NAME_LEN - 1)] = '\0'; + + VNODE_TO_RAMFSINODE(dir)->rf_size += sizeof(ramfs_dirent_t); + + vnode_t *child = vget(dir->vn_fs, ino); + + dbg(DBG_VFS, "creating ino(%ld), vno(%d) with path: %s\n", ino, + child->vn_vno, entry->rd_name); + + KASSERT(child); + *out = child; + return 0; +} + +static ssize_t ramfs_lookup(vnode_t *dir, const char *name, size_t namelen, + vnode_t **out) +{ + size_t i; + ramfs_inode_t *inode = VNODE_TO_RAMFSINODE(dir); + ramfs_dirent_t *entry = (ramfs_dirent_t *)inode->rf_mem; + + for (i = 0; i < RAMFS_MAX_DIRENT; i++, entry++) + { + if (name_match(entry->rd_name, name, namelen)) + { + if (dir->vn_vno != entry->rd_ino) + { + fs_t *fs = (dir)->vn_fs; + *out = vget(fs, entry->rd_ino); + } + else + { + vref(dir); + *out = dir; + } + return 0; + } + } + + return -ENOENT; +} + +static ssize_t ramfs_find_dirent(vnode_t *dir, const char *name, + size_t namelen) +{ + size_t i; + ramfs_inode_t *inode = VNODE_TO_RAMFSINODE(dir); + ramfs_dirent_t *entry = (ramfs_dirent_t *)inode->rf_mem; + + for (i = 0; i < RAMFS_MAX_DIRENT; i++, entry++) + { + if (name_match(entry->rd_name, name, namelen)) + { + return entry->rd_ino; + } + } + + return -ENOENT; +} + +static ssize_t ramfs_append_dirent(vnode_t *dir, const char *name, + size_t namelen, vnode_t *child) +{ + vnode_t *vn; + size_t i; + ramfs_dirent_t *entry; + + KASSERT(child->vn_fs == dir->vn_fs); + + /* Look for space in the directory */ + entry = VNODE_TO_DIRENT(dir); + for (i = 0; i < RAMFS_MAX_DIRENT; i++, entry++) + { + if (name_match(entry->rd_name, name, namelen)) + { + return -EEXIST; + } + + if (!entry->rd_name[0]) + { + break; + } + } + + if (i == RAMFS_MAX_DIRENT) + { + return -ENOSPC; + } + + /* Set entry in parent */ + entry->rd_ino = child->vn_vno; + strncpy(entry->rd_name, name, MIN(namelen, NAME_LEN - 1)); + entry->rd_name[MIN(namelen, NAME_LEN - 1)] = '\0'; + + VNODE_TO_RAMFSINODE(dir)->rf_size += sizeof(ramfs_dirent_t); + + /* Increase linkcount */ + VNODE_TO_RAMFSINODE(child)->rf_linkcount++; + + return 0; +} + +static ssize_t ramfs_delete_dirent(vnode_t *dir, const char *name, + size_t namelen, vnode_t *child) +{ + int found = 0; + size_t i; + ramfs_dirent_t *entry = VNODE_TO_DIRENT(dir); + for (i = 0; i < RAMFS_MAX_DIRENT; i++, entry++) + { + if (name_match(entry->rd_name, name, namelen)) + { + found = 1; + entry->rd_name[0] = '\0'; + break; + } + } + + if (!found) + { + return -EEXIST; + } + + VNODE_TO_RAMFSINODE(dir)->rf_size -= sizeof(ramfs_dirent_t); + VNODE_TO_RAMFSINODE(child)->rf_linkcount--; + + return 0; +} + +static long ramfs_link(vnode_t *dir, const char *name, size_t namelen, + vnode_t *child) +{ + return ramfs_append_dirent(dir, name, namelen, child); +} + +static ssize_t ramfs_unlink(vnode_t *dir, const char *name, size_t namelen) +{ + ssize_t ret; + size_t i; + ramfs_dirent_t *entry; + + vnode_t *vn = dir; + + long ino = ramfs_find_dirent(dir, name, namelen); + if (ino < 0) + { + return ino; + } + + vnode_t *child = vget_locked(dir->vn_fs, (ino_t)ino); + KASSERT(!S_ISDIR(child->vn_mode) && "handled at VFS level"); + + ret = ramfs_delete_dirent(dir, name, namelen, child); + KASSERT(ret == 0); + + vput_locked(&child); + + return 0; +} + +static ssize_t ramfs_rename(vnode_t *olddir, const char *oldname, + size_t oldnamelen, vnode_t *newdir, + const char *newname, size_t newnamelen) +{ + long ino = ramfs_find_dirent(olddir, oldname, oldnamelen); + if (ino < 0) + { + return ino; + } + + vnode_t *oldvn = vget_locked(olddir->vn_fs, (ino_t)ino); + if (S_ISDIR(oldvn->vn_mode)) + { + vput_locked(&oldvn); + return -EPERM; + } + if (S_ISDIR(oldvn->vn_mode)) + { + vput_locked(&oldvn); + return -EISDIR; + } + + /* Determine if an entry corresponding to `newname` already exists */ + ino = ramfs_find_dirent(newdir, newname, newnamelen); + if (ino != -ENOENT) + { + if (ino < 0) + { + return ino; + } + return -EEXIST; + } + + ssize_t ret = ramfs_append_dirent(newdir, newname, newnamelen, oldvn); + if (ret < 0) + { + vput_locked(&oldvn); + return ret; + } + + ret = ramfs_delete_dirent(olddir, oldname, oldnamelen, oldvn); + vput_locked(&oldvn); + + return ret; +} + +static ssize_t ramfs_mkdir(vnode_t *dir, const char *name, size_t name_len, + struct vnode **out) +{ + vnode_t *vn; + size_t i; + ramfs_dirent_t *entry; + + /* Look for space in the directory */ + entry = VNODE_TO_DIRENT(dir); + for (i = 0; i < RAMFS_MAX_DIRENT; i++, entry++) + { + if (!entry->rd_name[0]) + { + break; + } + } + + if (i == RAMFS_MAX_DIRENT) + { + return -ENOSPC; + } + + /* Allocate an inode */ + ssize_t ino; + if (0 > (ino = ramfs_alloc_inode(dir->vn_fs, RAMFS_TYPE_DIR, 0))) + { + return ino; + } + + /* Set entry in parent */ + entry->rd_ino = ino; + strncpy(entry->rd_name, name, MIN(name_len, NAME_LEN - 1)); + entry->rd_name[MIN(name_len, NAME_LEN - 1)] = '\0'; + + VNODE_TO_RAMFSINODE(dir)->rf_size += sizeof(ramfs_dirent_t); + + /* Set up '.' and '..' in the directory */ + entry = (ramfs_dirent_t *)VNODE_TO_RAMFS(dir)->rfs_inodes[ino]->rf_mem; + entry->rd_ino = ino; + strcpy(entry->rd_name, "."); + entry++; + entry->rd_ino = dir->vn_vno; + strcpy(entry->rd_name, ".."); + + /* Increase inode size accordingly */ + VNODE_TO_RAMFS(dir)->rfs_inodes[ino]->rf_size = 2 * sizeof(ramfs_dirent_t); + + /* This probably can't fail... (unless OOM :/) */ + *out = vget(dir->vn_fs, ino); + + return 0; +} + +static ssize_t ramfs_rmdir(vnode_t *dir, const char *name, size_t name_len) +{ + ssize_t ret; + size_t i; + ramfs_dirent_t *entry; + + KASSERT(!name_match(".", name, name_len) && + !name_match("..", name, name_len)); + + long ino = ramfs_find_dirent(dir, name, name_len); + if (ino < 0) + { + return ino; + } + + vnode_t *child = vget_locked(dir->vn_fs, (ino_t)ino); + if (!S_ISDIR(child->vn_mode)) + { + vput_locked(&child); + return -ENOTDIR; + } + + /* We have to make sure that this directory is empty */ + entry = VNODE_TO_DIRENT(child); + for (i = 0; i < RAMFS_MAX_DIRENT; i++, entry++) + { + if (!strcmp(entry->rd_name, ".") || !strcmp(entry->rd_name, "..")) + { + continue; + } + + if (entry->rd_name[0]) + { + vput_locked(&child); + return -ENOTEMPTY; + } + } + + /* Finally, remove the entry from the parent directory */ + entry = VNODE_TO_DIRENT(dir); + for (i = 0; i < RAMFS_MAX_DIRENT; i++, entry++) + { + if (name_match(entry->rd_name, name, name_len)) + { + entry->rd_name[0] = '\0'; + break; + } + } + VNODE_TO_RAMFSINODE(dir)->rf_size -= sizeof(ramfs_dirent_t); + + VNODE_TO_RAMFSINODE(child)->rf_linkcount--; + vput_locked(&child); + + return 0; +} + +static ssize_t ramfs_read(vnode_t *file, size_t offset, void *buf, + size_t count) +{ + ssize_t ret; + ramfs_inode_t *inode = VNODE_TO_RAMFSINODE(file); + + KASSERT(!S_ISDIR(file->vn_mode)); + + if (offset > inode->rf_size) + { + ret = 0; + } + else if (offset + count > inode->rf_size) + { + ret = inode->rf_size - offset; + } + else + { + ret = count; + } + + memcpy(buf, inode->rf_mem + offset, ret); + return ret; +} + +static ssize_t ramfs_write(vnode_t *file, size_t offset, const void *buf, + size_t count) +{ + ssize_t ret; + ramfs_inode_t *inode = VNODE_TO_RAMFSINODE(file); + + KASSERT(!S_ISDIR(file->vn_mode)); + + ret = MIN((size_t)count, (size_t)PAGE_SIZE - offset); + memcpy(inode->rf_mem + offset, buf, ret); + + KASSERT(file->vn_len == inode->rf_size); + file->vn_len = MAX(file->vn_len, offset + ret); + inode->rf_size = file->vn_len; + + return ret; +} + +static ssize_t ramfs_readdir(vnode_t *dir, size_t offset, struct dirent *d) +{ + ssize_t ret = 0; + ramfs_dirent_t *dir_entry, *targ_entry; + + KASSERT(S_ISDIR(dir->vn_mode)); + KASSERT(0 == offset % sizeof(ramfs_dirent_t)); + + dir_entry = VNODE_TO_DIRENT(dir); + dir_entry = (ramfs_dirent_t *)(((char *)dir_entry) + offset); + targ_entry = dir_entry; + + while ((offset < (size_t)(RAMFS_MAX_DIRENT * sizeof(ramfs_dirent_t))) && + (!targ_entry->rd_name[0])) + { + ++targ_entry; + offset += sizeof(ramfs_dirent_t); + } + + if (offset >= (size_t)(RAMFS_MAX_DIRENT * sizeof(ramfs_dirent_t))) + { + return 0; + } + + ret = sizeof(ramfs_dirent_t) + + (targ_entry - dir_entry) * sizeof(ramfs_dirent_t); + + d->d_ino = targ_entry->rd_ino; + d->d_off = 0; /* unused */ + strncpy(d->d_name, targ_entry->rd_name, NAME_LEN - 1); + d->d_name[NAME_LEN - 1] = '\0'; + return ret; +} + +static ssize_t ramfs_stat(vnode_t *file, stat_t *buf) +{ + ramfs_inode_t *i = VNODE_TO_RAMFSINODE(file); + memset(buf, 0, sizeof(stat_t)); + buf->st_mode = file->vn_mode; + buf->st_ino = (ssize_t)file->vn_vno; + buf->st_dev = 0; + if (file->vn_mode == S_IFCHR || file->vn_mode == S_IFBLK) + { + buf->st_rdev = (ssize_t)i->rf_mem; + } + buf->st_nlink = i->rf_linkcount - 1; + buf->st_size = (ssize_t)i->rf_size; + buf->st_blksize = (ssize_t)PAGE_SIZE; + buf->st_blocks = 1; + + return 0; +} + +static void ramfs_truncate_file(vnode_t *file) +{ + KASSERT(S_ISREG(file->vn_mode) && "This routine should only be called for regular files"); + ramfs_inode_t *i = VNODE_TO_RAMFSINODE(file); + i->rf_size = 0; + file->vn_len = 0; + memset(i->rf_mem, 0, PAGE_SIZE); +}
\ No newline at end of file |