diff options
Diffstat (limited to 'src/sys/fs')
-rw-r--r-- | src/sys/fs/tmpfs.c | 133 |
1 files changed, 129 insertions, 4 deletions
diff --git a/src/sys/fs/tmpfs.c b/src/sys/fs/tmpfs.c index 4a5c607..3048fb4 100644 --- a/src/sys/fs/tmpfs.c +++ b/src/sys/fs/tmpfs.c @@ -47,7 +47,9 @@ struct tmpfs_node { char name[TMPFS_NAMEMAX]; char *data; size_t len; + size_t real_len; int ref; + vtype_t vtype; /* vnode vtype mapping */ TAILQ_ENTRY(tmpfs_node) link; }; @@ -61,13 +63,14 @@ static struct vop tmpfs_vops; * Create a new tmpfs node * * @name: Name of node to create + * @type: Type of vnode file should be associated with * @np_res: Result pointer is written here * * Returns zero on success, otherwise a less than * zero value on failure */ static int -tmpfs_new(const char *name, struct tmpfs_node **np_res) +tmpfs_new(const char *name, vtype_t type, struct tmpfs_node **np_res) { struct tmpfs_node *np; size_t name_len; @@ -93,8 +96,10 @@ tmpfs_new(const char *name, struct tmpfs_node **np_res) return -ENOMEM; } + np->real_len = 0; np->len = TMPFS_INIT_SIZE; np->ref = 1; + np->vtype = type; memset(np->data, 0, TMPFS_INIT_SIZE); memcpy(np->name, name, name_len); @@ -160,7 +165,7 @@ tmpfs_lookup(struct vop_lookup_args *args) return error; } - error = vfs_valloc(&vp, VTYPE_FILE, 0); + error = vfs_valloc(&vp, np->vtype, 0); if (error < 0) { return error; } @@ -195,7 +200,16 @@ tmpfs_create(struct vop_create_args *args) return -EEXIST; } - return tmpfs_new(ndp->path, NULL); + /* Only accept the types we support */ + switch (args->vtype) { + case VTYPE_FILE: + case VTYPE_SOCK: + break; + default: + return -ENOTSUP; + } + + return tmpfs_new(ndp->path, args->vtype, NULL); } /* @@ -232,6 +246,114 @@ tmpfs_mount(struct fs_info *fip, struct mount_args *margs) return 0; } +/* + * Write to the filesystem + */ +static ssize_t +tmpfs_write(struct vop_rw_data *data) +{ + struct vnode *vp; + struct tmpfs_node *np; + char *dest; + void *p; + size_t node_len, len; + size_t overflow_window; + + if (data == NULL) { + return -EINVAL; + } + + if ((vp = data->vp) == NULL) { + return -EIO; + } + + /* We need the vnode for lengths */ + if ((np = vp->data) == NULL) { + return -EIO; + } + + /* + * Check if there is going to be any overflows + * and if so, get the overflow window and expand + * the buffer by it. + */ + len = data->len; + if ((len + data->off) > np->len) { + overflow_window = (len + data->off) - np->len; + np->len += overflow_window + 1; + + p = np->data; + np->data = krealloc(np->data, np->len); + if (np->data == NULL) { + np->data = p; + return -ENOMEM; + } + } + + np->real_len += len; + node_len = np->len; + dest = np->data + data->off; + memcpy(dest, data->data, len); + return len; +} + +static ssize_t +tmpfs_read(struct vop_rw_data *data) +{ + struct vnode *vp; + struct tmpfs_node *np; + size_t len; + char *dest, *src; + + if (data == NULL) { + return -1; + } + + if ((vp = data->vp) == NULL) { + return -EIO; + } + + if ((np = vp->data) == NULL) { + return -EIO; + } + + /* Return EOF if the offset is too far */ + len = data->len; + if (data->off >= np->real_len) { + return 0; /* EOF */ + } + + /* Is there any data to read? */ + if ((len + data->off) > np->len) { + len = np->len; + } + if (len == 0) { + return 0; + } + + dest = data->data; + src = np->data + data->off; + memcpy(dest, src, len); + return len; +} + +static int +tmpfs_getattr(struct vnode *vp, struct vattr *res) +{ + struct tmpfs_node *np; + + if (vp == NULL || res == NULL) { + return -EINVAL; + } + + if ((np = vp->data) == NULL) { + return -EIO; + } + + res->size = np->real_len; + return 0; +} + static int tmpfs_reclaim(struct vnode *vp, int flags) { @@ -241,7 +363,10 @@ tmpfs_reclaim(struct vnode *vp, int flags) static struct vop tmpfs_vops = { .lookup = tmpfs_lookup, .create = tmpfs_create, - .reclaim = tmpfs_reclaim + .reclaim = tmpfs_reclaim, + .write = tmpfs_write, + .read = tmpfs_read, + .getattr = tmpfs_getattr }; struct vfsops g_tmpfs_vfsops = { |