version 1.1.1.1, 2008/06/03 10:38:51 |
version 1.1.1.1.2.1, 2008/08/13 17:12:44 |
|
|
* SUCH DAMAGE. |
* SUCH DAMAGE. |
*/ |
*/ |
|
|
|
/* |
|
* rmafs_vnops.c - vnode operations for RAM file system. |
|
*/ |
|
|
#include <prex/prex.h> |
#include <prex/prex.h> |
|
|
#include <sys/stat.h> |
#include <sys/stat.h> |
|
|
|
|
#define ramfs_open ((vnop_open_t)vop_nullop) |
#define ramfs_open ((vnop_open_t)vop_nullop) |
#define ramfs_close ((vnop_close_t)vop_nullop) |
#define ramfs_close ((vnop_close_t)vop_nullop) |
static int ramfs_read(vnode_t, file_t, void *, size_t, size_t *); |
static int ramfs_read (vnode_t, file_t, void *, size_t, size_t *); |
static int ramfs_write(vnode_t, file_t, void *, size_t, size_t *); |
static int ramfs_write (vnode_t, file_t, void *, size_t, size_t *); |
#define ramfs_seek ((vnop_seek_t)vop_nullop) |
#define ramfs_seek ((vnop_seek_t)vop_nullop) |
#define ramfs_ioctl ((vnop_ioctl_t)vop_einval) |
#define ramfs_ioctl ((vnop_ioctl_t)vop_einval) |
#define ramfs_fsync ((vnop_fsync_t)vop_nullop) |
#define ramfs_fsync ((vnop_fsync_t)vop_nullop) |
static int ramfs_readdir(vnode_t, file_t, struct dirent *); |
static int ramfs_readdir(vnode_t, file_t, struct dirent *); |
static int ramfs_lookup(vnode_t, char *, vnode_t); |
static int ramfs_lookup (vnode_t, char *, vnode_t); |
static int ramfs_create(vnode_t, char *, mode_t); |
static int ramfs_create (vnode_t, char *, mode_t); |
static int ramfs_remove(vnode_t, vnode_t, char *); |
static int ramfs_remove (vnode_t, vnode_t, char *); |
static int ramfs_rename(vnode_t, vnode_t, char *, vnode_t, vnode_t, char *); |
static int ramfs_rename (vnode_t, vnode_t, char *, vnode_t, vnode_t, char *); |
static int ramfs_mkdir(vnode_t, char *, mode_t); |
static int ramfs_mkdir (vnode_t, char *, mode_t); |
static int ramfs_rmdir(vnode_t, vnode_t, char *); |
static int ramfs_rmdir (vnode_t, vnode_t, char *); |
#define ramfs_getattr ((vnop_getattr_t)vop_nullop) |
#define ramfs_getattr ((vnop_getattr_t)vop_nullop) |
#define ramfs_setattr ((vnop_setattr_t)vop_nullop) |
#define ramfs_setattr ((vnop_setattr_t)vop_nullop) |
#define ramfs_inactive ((vnop_inactive_t)vop_nullop) |
#define ramfs_inactive ((vnop_inactive_t)vop_nullop) |
|
|
struct ramfs_node * |
struct ramfs_node * |
ramfs_allocate_node(char *name, int type) |
ramfs_allocate_node(char *name, int type) |
{ |
{ |
struct ramfs_node *node; |
struct ramfs_node *np; |
|
|
node = malloc(sizeof(struct ramfs_node)); |
np = malloc(sizeof(struct ramfs_node)); |
if (node == NULL) |
if (np == NULL) |
return NULL; |
return NULL; |
memset(node, 0, sizeof(struct ramfs_node)); |
memset(np, 0, sizeof(struct ramfs_node)); |
|
|
node->namelen = strlen(name); |
np->rn_namelen = strlen(name); |
node->name = malloc(node->namelen + 1); |
np->rn_name = malloc(np->rn_namelen + 1); |
if (node->name == NULL) { |
if (np->rn_name == NULL) { |
free(node); |
free(np); |
return NULL; |
return NULL; |
} |
} |
strcpy(node->name, name); |
strcpy(np->rn_name, name); |
node->type = type; |
np->rn_type = type; |
return node; |
return np; |
} |
} |
|
|
void |
void |
ramfs_free_node(struct ramfs_node *node) |
ramfs_free_node(struct ramfs_node *np) |
{ |
{ |
|
|
free(node->name); |
free(np->rn_name); |
free(node); |
free(np); |
} |
} |
|
|
static struct ramfs_node * |
static struct ramfs_node * |
ramfs_add_node(struct ramfs_node *dir_node, char *name, int type) |
ramfs_add_node(struct ramfs_node *dnp, char *name, int type) |
{ |
{ |
struct ramfs_node *node, *prev; |
struct ramfs_node *np, *prev; |
|
|
node = ramfs_allocate_node(name, type); |
np = ramfs_allocate_node(name, type); |
if (node == NULL) |
if (np == NULL) |
return NULL; |
return NULL; |
|
|
mutex_lock(&ramfs_lock); |
mutex_lock(&ramfs_lock); |
|
|
/* Link to the directory list */ |
/* Link to the directory list */ |
if (dir_node->child == NULL) { |
if (dnp->rn_child == NULL) { |
dir_node->child = node; |
dnp->rn_child = np; |
} else { |
} else { |
prev = dir_node->child; |
prev = dnp->rn_child; |
while (prev->next != NULL) |
while (prev->rn_next != NULL) |
prev = prev->next; |
prev = prev->rn_next; |
prev->next = node; |
prev->rn_next = np; |
} |
} |
mutex_unlock(&ramfs_lock); |
mutex_unlock(&ramfs_lock); |
return node; |
return np; |
} |
} |
|
|
static int |
static int |
ramfs_remove_node(struct ramfs_node *dir_node, struct ramfs_node *node) |
ramfs_remove_node(struct ramfs_node *dnp, struct ramfs_node *np) |
{ |
{ |
struct ramfs_node *prev; |
struct ramfs_node *prev; |
|
|
if (dir_node->child == NULL) |
if (dnp->rn_child == NULL) |
return EBUSY; |
return EBUSY; |
|
|
mutex_lock(&ramfs_lock); |
mutex_lock(&ramfs_lock); |
|
|
/* Unlink from the directory list */ |
/* Unlink from the directory list */ |
if (dir_node->child == node) { |
if (dnp->rn_child == np) { |
dir_node->child = node->next; |
dnp->rn_child = np->rn_next; |
} else { |
} else { |
for (prev = dir_node->child; prev->next != node; |
for (prev = dnp->rn_child; prev->rn_next != np; |
prev = prev->next) { |
prev = prev->rn_next) { |
if (prev->next == NULL) { |
if (prev->rn_next == NULL) { |
mutex_unlock(&ramfs_lock); |
mutex_unlock(&ramfs_lock); |
return ENOENT; |
return ENOENT; |
} |
} |
} |
} |
prev->next = node->next; |
prev->rn_next = np->rn_next; |
} |
} |
ramfs_free_node(node); |
ramfs_free_node(np); |
|
|
mutex_unlock(&ramfs_lock); |
mutex_unlock(&ramfs_lock); |
return 0; |
return 0; |
} |
} |
|
|
static int |
static int |
ramfs_rename_node(struct ramfs_node *node, char *name) |
ramfs_rename_node(struct ramfs_node *np, char *name) |
{ |
{ |
size_t len; |
size_t len; |
char *tmp; |
char *tmp; |
|
|
len = strlen(name); |
len = strlen(name); |
if (len <= node->namelen) { |
if (len <= np->rn_namelen) { |
/* Reuse current name buffer */ |
/* Reuse current name buffer */ |
strcpy(node->name, name); |
strcpy(np->rn_name, name); |
} else { |
} else { |
/* Expand name buffer */ |
/* Expand name buffer */ |
tmp = malloc(len + 1); |
tmp = malloc(len + 1); |
if (tmp == NULL) |
if (tmp == NULL) |
return ENOMEM; |
return ENOMEM; |
strcpy(tmp, name); |
strcpy(tmp, name); |
free(node->name); |
free(np->rn_name); |
node->name = tmp; |
np->rn_name = tmp; |
} |
} |
node->namelen = len; |
np->rn_namelen = len; |
return 0; |
return 0; |
} |
} |
|
|
static int |
static int |
ramfs_lookup(vnode_t dvp, char *name, vnode_t vp) |
ramfs_lookup(vnode_t dvp, char *name, vnode_t vp) |
{ |
{ |
struct ramfs_node *node, *dir_node; |
struct ramfs_node *np, *dnp; |
size_t len; |
size_t len; |
|
int found; |
|
|
if (*name == '\0') |
if (*name == '\0') |
return ENOENT; |
return ENOENT; |
|
|
mutex_lock(&ramfs_lock); |
mutex_lock(&ramfs_lock); |
|
|
len = strlen(name); |
len = strlen(name); |
dir_node = dvp->v_data; |
dnp = dvp->v_data; |
for (node = dir_node->child; node != NULL; node = node->next) { |
found = 0; |
if (node->namelen == len && |
for (np = dnp->rn_child; np != NULL; np = np->rn_next) { |
memcmp(name, node->name, len) == 0) |
if (np->rn_namelen == len && |
|
memcmp(name, np->rn_name, len) == 0) { |
|
found = 1; |
break; |
break; |
|
} |
} |
} |
if (node == NULL) { |
if (found == 0) { |
mutex_unlock(&ramfs_lock); |
mutex_unlock(&ramfs_lock); |
return ENOENT; |
return ENOENT; |
} |
} |
vp->v_data = node; |
vp->v_data = np; |
vp->v_mode = ALLPERMS; |
vp->v_mode = ALLPERMS; |
vp->v_type = node->type; |
vp->v_type = np->rn_type; |
vp->v_size = node->size; |
vp->v_size = np->rn_size; |
|
|
mutex_unlock(&ramfs_lock); |
mutex_unlock(&ramfs_lock); |
return 0; |
return 0; |
|
|
static int |
static int |
ramfs_mkdir(vnode_t dvp, char *name, mode_t mode) |
ramfs_mkdir(vnode_t dvp, char *name, mode_t mode) |
{ |
{ |
struct ramfs_node *node; |
struct ramfs_node *np; |
|
|
dprintf("mkdir %s\n", name); |
DPRINTF(("mkdir %s\n", name)); |
if (!S_ISDIR(mode)) |
if (!S_ISDIR(mode)) |
return EINVAL; |
return EINVAL; |
|
|
node = ramfs_add_node(dvp->v_data, name, VDIR); |
np = ramfs_add_node(dvp->v_data, name, VDIR); |
if (node == NULL) |
if (np == NULL) |
return ENOMEM; |
return ENOMEM; |
node->size = 0; |
np->rn_size = 0; |
return 0; |
return 0; |
} |
} |
|
|
|
|
static int |
static int |
ramfs_remove(vnode_t dvp, vnode_t vp, char *name) |
ramfs_remove(vnode_t dvp, vnode_t vp, char *name) |
{ |
{ |
struct ramfs_node *node; |
struct ramfs_node *np; |
int err; |
int err; |
|
|
dprintf("remove %s in %s\n", name, dvp->v_path); |
DPRINTF(("remove %s in %s\n", name, dvp->v_path)); |
err = ramfs_remove_node(dvp->v_data, vp->v_data); |
err = ramfs_remove_node(dvp->v_data, vp->v_data); |
if (err) |
if (err) |
return err; |
return err; |
|
|
node = vp->v_data; |
np = vp->v_data; |
if (node->buf != NULL) |
if (np->rn_buf != NULL) |
vm_free(task_self(), node->buf); |
vm_free(task_self(), np->rn_buf); |
return 0; |
return 0; |
} |
} |
|
|
|
|
static int |
static int |
ramfs_truncate(vnode_t vp) |
ramfs_truncate(vnode_t vp) |
{ |
{ |
struct ramfs_node *node; |
struct ramfs_node *np; |
|
|
dprintf("truncate %s\n", vp->v_path); |
DPRINTF(("truncate %s\n", vp->v_path)); |
node = vp->v_data; |
np = vp->v_data; |
if (node->buf != NULL) { |
if (np->rn_buf != NULL) { |
vm_free(task_self(), node->buf); |
vm_free(task_self(), np->rn_buf); |
node->buf = NULL; |
np->rn_buf = NULL; |
node->bufsize = 0; |
np->rn_bufsize = 0; |
} |
} |
vp->v_size = 0; |
vp->v_size = 0; |
return 0; |
return 0; |
|
|
static int |
static int |
ramfs_create(vnode_t dvp, char *name, mode_t mode) |
ramfs_create(vnode_t dvp, char *name, mode_t mode) |
{ |
{ |
struct ramfs_node *node; |
struct ramfs_node *np; |
|
|
dprintf("create %s in %s\n", name, dvp->v_path); |
DPRINTF(("create %s in %s\n", name, dvp->v_path)); |
if (!S_ISREG(mode)) |
if (!S_ISREG(mode)) |
return EINVAL; |
return EINVAL; |
|
|
node = ramfs_add_node(dvp->v_data, name, VREG); |
np = ramfs_add_node(dvp->v_data, name, VREG); |
if (node == NULL) |
if (np == NULL) |
return ENOMEM; |
return ENOMEM; |
return 0; |
return 0; |
} |
} |
|
|
static int |
static int |
ramfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result) |
ramfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result) |
{ |
{ |
struct ramfs_node *node; |
struct ramfs_node *np; |
off_t off; |
off_t off; |
|
|
*result = 0; |
*result = 0; |
|
|
if (vp->v_size - off < size) |
if (vp->v_size - off < size) |
size = vp->v_size - off; |
size = vp->v_size - off; |
|
|
node = vp->v_data; |
np = vp->v_data; |
memcpy(buf, node->buf + off, size); |
memcpy(buf, np->rn_buf + off, size); |
|
|
fp->f_offset += size; |
fp->f_offset += size; |
*result = size; |
*result = size; |
|
|
static int |
static int |
ramfs_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result) |
ramfs_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result) |
{ |
{ |
struct ramfs_node *node; |
struct ramfs_node *np; |
off_t file_pos, end_pos; |
off_t file_pos, end_pos; |
void *new_buf; |
void *new_buf; |
size_t new_size; |
size_t new_size; |
|
|
if (vp->v_type != VREG) |
if (vp->v_type != VREG) |
return EINVAL; |
return EINVAL; |
|
|
node = vp->v_data; |
np = vp->v_data; |
/* Check if the file position exceeds the end of file. */ |
/* Check if the file position exceeds the end of file. */ |
end_pos = vp->v_size; |
end_pos = vp->v_size; |
file_pos = (fp->f_flags & O_APPEND) ? end_pos : fp->f_offset; |
file_pos = (fp->f_flags & O_APPEND) ? end_pos : fp->f_offset; |
if (file_pos + size > (size_t)end_pos) { |
if (file_pos + size > (size_t)end_pos) { |
/* Expand the file size before writing to it */ |
/* Expand the file size before writing to it */ |
end_pos = file_pos + size; |
end_pos = file_pos + size; |
if (end_pos > (off_t)node->bufsize) { |
if (end_pos > (off_t)np->rn_bufsize) { |
task = task_self(); |
task = task_self(); |
/* |
/* |
* We allocate the data buffer in page boundary. |
* We allocate the data buffer in page boundary. |
|
|
new_size = PAGE_ALIGN(end_pos); |
new_size = PAGE_ALIGN(end_pos); |
if (vm_allocate(task, &new_buf, new_size, 1)) |
if (vm_allocate(task, &new_buf, new_size, 1)) |
return EIO; |
return EIO; |
if (node->size != 0) { |
if (np->rn_size != 0) { |
memcpy(new_buf, node->buf, vp->v_size); |
memcpy(new_buf, np->rn_buf, vp->v_size); |
vm_free(task, node->buf); |
vm_free(task, np->rn_buf); |
} |
} |
node->buf = new_buf; |
np->rn_buf = new_buf; |
node->bufsize = new_size; |
np->rn_bufsize = new_size; |
} |
} |
node->size = end_pos; |
np->rn_size = end_pos; |
vp->v_size = end_pos; |
vp->v_size = end_pos; |
} |
} |
memcpy(node->buf + file_pos, buf, size); |
memcpy(np->rn_buf + file_pos, buf, size); |
fp->f_offset += size; |
fp->f_offset += size; |
*result = size; |
*result = size; |
return 0; |
return 0; |
|
|
ramfs_rename(vnode_t dvp1, vnode_t vp1, char *name1, |
ramfs_rename(vnode_t dvp1, vnode_t vp1, char *name1, |
vnode_t dvp2, vnode_t vp2, char *name2) |
vnode_t dvp2, vnode_t vp2, char *name2) |
{ |
{ |
struct ramfs_node *node, *old_node; |
struct ramfs_node *np, *old_np; |
int err; |
int err; |
|
|
if (vp2) { |
if (vp2) { |
|
|
return err; |
return err; |
} else { |
} else { |
/* Create new file or directory */ |
/* Create new file or directory */ |
old_node = vp1->v_data; |
old_np = vp1->v_data; |
node = ramfs_add_node(dvp2->v_data, name2, VREG); |
np = ramfs_add_node(dvp2->v_data, name2, VREG); |
if (node == NULL) |
if (np == NULL) |
return ENOMEM; |
return ENOMEM; |
|
|
if (vp1->v_type == VREG) { |
if (vp1->v_type == VREG) { |
/* Copy file data */ |
/* Copy file data */ |
node->buf = old_node->buf; |
np->rn_buf = old_np->rn_buf; |
node->size = old_node->size; |
np->rn_size = old_np->rn_size; |
node->bufsize = old_node->bufsize; |
np->rn_bufsize = old_np->rn_bufsize; |
} |
} |
/* Remove source file */ |
/* Remove source file */ |
ramfs_remove_node(dvp1->v_data, vp1->v_data); |
ramfs_remove_node(dvp1->v_data, vp1->v_data); |
|
|
static int |
static int |
ramfs_readdir(vnode_t vp, file_t fp, struct dirent *dir) |
ramfs_readdir(vnode_t vp, file_t fp, struct dirent *dir) |
{ |
{ |
struct ramfs_node *node, *dir_node; |
struct ramfs_node *np, *dnp; |
int i; |
int i; |
|
|
mutex_lock(&ramfs_lock); |
mutex_lock(&ramfs_lock); |
|
|
dir->d_type = DT_DIR; |
dir->d_type = DT_DIR; |
strcpy((char *)&dir->d_name, ".."); |
strcpy((char *)&dir->d_name, ".."); |
} else { |
} else { |
dir_node = vp->v_data; |
dnp = vp->v_data; |
node = dir_node->child; |
np = dnp->rn_child; |
if (node == NULL) { |
if (np == NULL) { |
mutex_unlock(&ramfs_lock); |
mutex_unlock(&ramfs_lock); |
return ENOENT; |
return ENOENT; |
} |
} |
|
|
for (i = 0; i != (fp->f_offset - 2); i++) { |
for (i = 0; i != (fp->f_offset - 2); i++) { |
node = node->next; |
np = np->rn_next; |
if (node == NULL) { |
if (np == NULL) { |
mutex_unlock(&ramfs_lock); |
mutex_unlock(&ramfs_lock); |
return ENOENT; |
return ENOENT; |
} |
} |
} |
} |
if (node->type == VDIR) |
if (np->rn_type == VDIR) |
dir->d_type = DT_DIR; |
dir->d_type = DT_DIR; |
else |
else |
dir->d_type = DT_REG; |
dir->d_type = DT_REG; |
strcpy((char *)&dir->d_name, node->name); |
strcpy((char *)&dir->d_name, np->rn_name); |
} |
} |
dir->d_fileno = fp->f_offset; |
dir->d_fileno = fp->f_offset; |
dir->d_namlen = strlen(dir->d_name); |
dir->d_namlen = strlen(dir->d_name); |