Annotation of prex-old/usr/server/fs/ramfs/ramfs_vnops.c, Revision 1.1
1.1 ! nbrk 1: /*
! 2: * Copyright (c) 2006-2007, Kohsuke Ohtani
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. Neither the name of the author nor the names of any co-contributors
! 14: * may be used to endorse or promote products derived from this software
! 15: * without specific prior written permission.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: */
! 29:
! 30: #include <prex/prex.h>
! 31:
! 32: #include <sys/stat.h>
! 33: #include <sys/vnode.h>
! 34: #include <sys/file.h>
! 35: #include <sys/mount.h>
! 36: #include <sys/dirent.h>
! 37: #include <sys/param.h>
! 38:
! 39: #include <errno.h>
! 40: #include <string.h>
! 41: #include <stdlib.h>
! 42: #include <fcntl.h>
! 43:
! 44: #include "ramfs.h"
! 45:
! 46: #define ramfs_open ((vnop_open_t)vop_nullop)
! 47: #define ramfs_close ((vnop_close_t)vop_nullop)
! 48: static int ramfs_read(vnode_t, file_t, void *, size_t, size_t *);
! 49: static int ramfs_write(vnode_t, file_t, void *, size_t, size_t *);
! 50: #define ramfs_seek ((vnop_seek_t)vop_nullop)
! 51: #define ramfs_ioctl ((vnop_ioctl_t)vop_einval)
! 52: #define ramfs_fsync ((vnop_fsync_t)vop_nullop)
! 53: static int ramfs_readdir(vnode_t, file_t, struct dirent *);
! 54: static int ramfs_lookup(vnode_t, char *, vnode_t);
! 55: static int ramfs_create(vnode_t, char *, mode_t);
! 56: static int ramfs_remove(vnode_t, vnode_t, char *);
! 57: static int ramfs_rename(vnode_t, vnode_t, char *, vnode_t, vnode_t, char *);
! 58: static int ramfs_mkdir(vnode_t, char *, mode_t);
! 59: static int ramfs_rmdir(vnode_t, vnode_t, char *);
! 60: #define ramfs_getattr ((vnop_getattr_t)vop_nullop)
! 61: #define ramfs_setattr ((vnop_setattr_t)vop_nullop)
! 62: #define ramfs_inactive ((vnop_inactive_t)vop_nullop)
! 63: static int ramfs_truncate(vnode_t);
! 64:
! 65:
! 66: #if CONFIG_FS_THREADS > 1
! 67: static mutex_t ramfs_lock = MUTEX_INITIALIZER;
! 68: #endif
! 69:
! 70: /*
! 71: * vnode operations
! 72: */
! 73: struct vnops ramfs_vnops = {
! 74: ramfs_open, /* open */
! 75: ramfs_close, /* close */
! 76: ramfs_read, /* read */
! 77: ramfs_write, /* write */
! 78: ramfs_seek, /* seek */
! 79: ramfs_ioctl, /* ioctl */
! 80: ramfs_fsync, /* fsync */
! 81: ramfs_readdir, /* readdir */
! 82: ramfs_lookup, /* lookup */
! 83: ramfs_create, /* create */
! 84: ramfs_remove, /* remove */
! 85: ramfs_rename, /* remame */
! 86: ramfs_mkdir, /* mkdir */
! 87: ramfs_rmdir, /* rmdir */
! 88: ramfs_getattr, /* getattr */
! 89: ramfs_setattr, /* setattr */
! 90: ramfs_inactive, /* inactive */
! 91: ramfs_truncate, /* truncate */
! 92: };
! 93:
! 94: struct ramfs_node *
! 95: ramfs_allocate_node(char *name, int type)
! 96: {
! 97: struct ramfs_node *node;
! 98:
! 99: node = malloc(sizeof(struct ramfs_node));
! 100: if (node == NULL)
! 101: return NULL;
! 102: memset(node, 0, sizeof(struct ramfs_node));
! 103:
! 104: node->namelen = strlen(name);
! 105: node->name = malloc(node->namelen + 1);
! 106: if (node->name == NULL) {
! 107: free(node);
! 108: return NULL;
! 109: }
! 110: strcpy(node->name, name);
! 111: node->type = type;
! 112: return node;
! 113: }
! 114:
! 115: void
! 116: ramfs_free_node(struct ramfs_node *node)
! 117: {
! 118:
! 119: free(node->name);
! 120: free(node);
! 121: }
! 122:
! 123: static struct ramfs_node *
! 124: ramfs_add_node(struct ramfs_node *dir_node, char *name, int type)
! 125: {
! 126: struct ramfs_node *node, *prev;
! 127:
! 128: node = ramfs_allocate_node(name, type);
! 129: if (node == NULL)
! 130: return NULL;
! 131:
! 132: mutex_lock(&ramfs_lock);
! 133:
! 134: /* Link to the directory list */
! 135: if (dir_node->child == NULL) {
! 136: dir_node->child = node;
! 137: } else {
! 138: prev = dir_node->child;
! 139: while (prev->next != NULL)
! 140: prev = prev->next;
! 141: prev->next = node;
! 142: }
! 143: mutex_unlock(&ramfs_lock);
! 144: return node;
! 145: }
! 146:
! 147: static int
! 148: ramfs_remove_node(struct ramfs_node *dir_node, struct ramfs_node *node)
! 149: {
! 150: struct ramfs_node *prev;
! 151:
! 152: if (dir_node->child == NULL)
! 153: return EBUSY;
! 154:
! 155: mutex_lock(&ramfs_lock);
! 156:
! 157: /* Unlink from the directory list */
! 158: if (dir_node->child == node) {
! 159: dir_node->child = node->next;
! 160: } else {
! 161: for (prev = dir_node->child; prev->next != node;
! 162: prev = prev->next) {
! 163: if (prev->next == NULL) {
! 164: mutex_unlock(&ramfs_lock);
! 165: return ENOENT;
! 166: }
! 167: }
! 168: prev->next = node->next;
! 169: }
! 170: ramfs_free_node(node);
! 171:
! 172: mutex_unlock(&ramfs_lock);
! 173: return 0;
! 174: }
! 175:
! 176: static int
! 177: ramfs_rename_node(struct ramfs_node *node, char *name)
! 178: {
! 179: size_t len;
! 180: char *tmp;
! 181:
! 182: len = strlen(name);
! 183: if (len <= node->namelen) {
! 184: /* Reuse current name buffer */
! 185: strcpy(node->name, name);
! 186: } else {
! 187: /* Expand name buffer */
! 188: tmp = malloc(len + 1);
! 189: if (tmp == NULL)
! 190: return ENOMEM;
! 191: strcpy(tmp, name);
! 192: free(node->name);
! 193: node->name = tmp;
! 194: }
! 195: node->namelen = len;
! 196: return 0;
! 197: }
! 198:
! 199: static int
! 200: ramfs_lookup(vnode_t dvp, char *name, vnode_t vp)
! 201: {
! 202: struct ramfs_node *node, *dir_node;
! 203: size_t len;
! 204:
! 205: if (*name == '\0')
! 206: return ENOENT;
! 207:
! 208: mutex_lock(&ramfs_lock);
! 209:
! 210: len = strlen(name);
! 211: dir_node = dvp->v_data;
! 212: for (node = dir_node->child; node != NULL; node = node->next) {
! 213: if (node->namelen == len &&
! 214: memcmp(name, node->name, len) == 0)
! 215: break;
! 216: }
! 217: if (node == NULL) {
! 218: mutex_unlock(&ramfs_lock);
! 219: return ENOENT;
! 220: }
! 221: vp->v_data = node;
! 222: vp->v_mode = ALLPERMS;
! 223: vp->v_type = node->type;
! 224: vp->v_size = node->size;
! 225:
! 226: mutex_unlock(&ramfs_lock);
! 227: return 0;
! 228: }
! 229:
! 230: static int
! 231: ramfs_mkdir(vnode_t dvp, char *name, mode_t mode)
! 232: {
! 233: struct ramfs_node *node;
! 234:
! 235: dprintf("mkdir %s\n", name);
! 236: if (!S_ISDIR(mode))
! 237: return EINVAL;
! 238:
! 239: node = ramfs_add_node(dvp->v_data, name, VDIR);
! 240: if (node == NULL)
! 241: return ENOMEM;
! 242: node->size = 0;
! 243: return 0;
! 244: }
! 245:
! 246: /* Remove a directory */
! 247: static int
! 248: ramfs_rmdir(vnode_t dvp, vnode_t vp, char *name)
! 249: {
! 250:
! 251: return ramfs_remove_node(dvp->v_data, vp->v_data);
! 252: }
! 253:
! 254: /* Remove a file */
! 255: static int
! 256: ramfs_remove(vnode_t dvp, vnode_t vp, char *name)
! 257: {
! 258: struct ramfs_node *node;
! 259: int err;
! 260:
! 261: dprintf("remove %s in %s\n", name, dvp->v_path);
! 262: err = ramfs_remove_node(dvp->v_data, vp->v_data);
! 263: if (err)
! 264: return err;
! 265:
! 266: node = vp->v_data;
! 267: if (node->buf != NULL)
! 268: vm_free(task_self(), node->buf);
! 269: return 0;
! 270: }
! 271:
! 272: /* Truncate file */
! 273: static int
! 274: ramfs_truncate(vnode_t vp)
! 275: {
! 276: struct ramfs_node *node;
! 277:
! 278: dprintf("truncate %s\n", vp->v_path);
! 279: node = vp->v_data;
! 280: if (node->buf != NULL) {
! 281: vm_free(task_self(), node->buf);
! 282: node->buf = NULL;
! 283: node->bufsize = 0;
! 284: }
! 285: vp->v_size = 0;
! 286: return 0;
! 287: }
! 288:
! 289: /*
! 290: * Create empty file.
! 291: */
! 292: static int
! 293: ramfs_create(vnode_t dvp, char *name, mode_t mode)
! 294: {
! 295: struct ramfs_node *node;
! 296:
! 297: dprintf("create %s in %s\n", name, dvp->v_path);
! 298: if (!S_ISREG(mode))
! 299: return EINVAL;
! 300:
! 301: node = ramfs_add_node(dvp->v_data, name, VREG);
! 302: if (node == NULL)
! 303: return ENOMEM;
! 304: return 0;
! 305: }
! 306:
! 307: static int
! 308: ramfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
! 309: {
! 310: struct ramfs_node *node;
! 311: off_t off;
! 312:
! 313: *result = 0;
! 314: if (vp->v_type == VDIR)
! 315: return EISDIR;
! 316: if (vp->v_type != VREG)
! 317: return EINVAL;
! 318:
! 319: off = fp->f_offset;
! 320: if (off >= (off_t)vp->v_size)
! 321: return 0;
! 322:
! 323: if (vp->v_size - off < size)
! 324: size = vp->v_size - off;
! 325:
! 326: node = vp->v_data;
! 327: memcpy(buf, node->buf + off, size);
! 328:
! 329: fp->f_offset += size;
! 330: *result = size;
! 331: return 0;
! 332: }
! 333:
! 334: static int
! 335: ramfs_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
! 336: {
! 337: struct ramfs_node *node;
! 338: off_t file_pos, end_pos;
! 339: void *new_buf;
! 340: size_t new_size;
! 341: task_t task;
! 342:
! 343: *result = 0;
! 344: if (vp->v_type == VDIR)
! 345: return EISDIR;
! 346: if (vp->v_type != VREG)
! 347: return EINVAL;
! 348:
! 349: node = vp->v_data;
! 350: /* Check if the file position exceeds the end of file. */
! 351: end_pos = vp->v_size;
! 352: file_pos = (fp->f_flags & O_APPEND) ? end_pos : fp->f_offset;
! 353: if (file_pos + size > (size_t)end_pos) {
! 354: /* Expand the file size before writing to it */
! 355: end_pos = file_pos + size;
! 356: if (end_pos > (off_t)node->bufsize) {
! 357: task = task_self();
! 358: /*
! 359: * We allocate the data buffer in page boundary.
! 360: * So that we can reduce the memory allocation unless
! 361: * the file size exceeds next page boundary.
! 362: * This will prevent the memory fragmentation by
! 363: * many malloc/free calls.
! 364: */
! 365: new_size = PAGE_ALIGN(end_pos);
! 366: if (vm_allocate(task, &new_buf, new_size, 1))
! 367: return EIO;
! 368: if (node->size != 0) {
! 369: memcpy(new_buf, node->buf, vp->v_size);
! 370: vm_free(task, node->buf);
! 371: }
! 372: node->buf = new_buf;
! 373: node->bufsize = new_size;
! 374: }
! 375: node->size = end_pos;
! 376: vp->v_size = end_pos;
! 377: }
! 378: memcpy(node->buf + file_pos, buf, size);
! 379: fp->f_offset += size;
! 380: *result = size;
! 381: return 0;
! 382: }
! 383:
! 384: static int
! 385: ramfs_rename(vnode_t dvp1, vnode_t vp1, char *name1,
! 386: vnode_t dvp2, vnode_t vp2, char *name2)
! 387: {
! 388: struct ramfs_node *node, *old_node;
! 389: int err;
! 390:
! 391: if (vp2) {
! 392: /* Remove destination file, first */
! 393: err = ramfs_remove_node(dvp2->v_data, vp2->v_data);
! 394: if (err)
! 395: return err;
! 396: }
! 397: /* Same directory ? */
! 398: if (dvp1 == dvp2) {
! 399: /* Change the name of existing file */
! 400: err = ramfs_rename_node(vp1->v_data, name2);
! 401: if (err)
! 402: return err;
! 403: } else {
! 404: /* Create new file or directory */
! 405: old_node = vp1->v_data;
! 406: node = ramfs_add_node(dvp2->v_data, name2, VREG);
! 407: if (node == NULL)
! 408: return ENOMEM;
! 409:
! 410: if (vp1->v_type == VREG) {
! 411: /* Copy file data */
! 412: node->buf = old_node->buf;
! 413: node->size = old_node->size;
! 414: node->bufsize = old_node->bufsize;
! 415: }
! 416: /* Remove source file */
! 417: ramfs_remove_node(dvp1->v_data, vp1->v_data);
! 418: }
! 419: return 0;
! 420: }
! 421:
! 422: /*
! 423: * @vp: vnode of the directory.
! 424: */
! 425: static int
! 426: ramfs_readdir(vnode_t vp, file_t fp, struct dirent *dir)
! 427: {
! 428: struct ramfs_node *node, *dir_node;
! 429: int i;
! 430:
! 431: mutex_lock(&ramfs_lock);
! 432:
! 433: if (fp->f_offset == 0) {
! 434: dir->d_type = DT_DIR;
! 435: strcpy((char *)&dir->d_name, ".");
! 436: } else if (fp->f_offset == 1) {
! 437: dir->d_type = DT_DIR;
! 438: strcpy((char *)&dir->d_name, "..");
! 439: } else {
! 440: dir_node = vp->v_data;
! 441: node = dir_node->child;
! 442: if (node == NULL) {
! 443: mutex_unlock(&ramfs_lock);
! 444: return ENOENT;
! 445: }
! 446:
! 447: for (i = 0; i != (fp->f_offset - 2); i++) {
! 448: node = node->next;
! 449: if (node == NULL) {
! 450: mutex_unlock(&ramfs_lock);
! 451: return ENOENT;
! 452: }
! 453: }
! 454: if (node->type == VDIR)
! 455: dir->d_type = DT_DIR;
! 456: else
! 457: dir->d_type = DT_REG;
! 458: strcpy((char *)&dir->d_name, node->name);
! 459: }
! 460: dir->d_fileno = fp->f_offset;
! 461: dir->d_namlen = strlen(dir->d_name);
! 462:
! 463: fp->f_offset++;
! 464:
! 465: mutex_unlock(&ramfs_lock);
! 466: return 0;
! 467: }
! 468:
! 469: int
! 470: ramfs_init(void)
! 471: {
! 472: return 0;
! 473: }
CVSweb