Prex Home / Browse Source - Prex Version: 0.9.0

root/usr/server/fs/ramfs/ramfs_vnops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ramfs_allocate_node
  2. ramfs_free_node
  3. ramfs_add_node
  4. ramfs_remove_node
  5. ramfs_rename_node
  6. ramfs_lookup
  7. ramfs_mkdir
  8. ramfs_rmdir
  9. ramfs_remove
  10. ramfs_truncate
  11. ramfs_create
  12. ramfs_read
  13. ramfs_write
  14. ramfs_rename
  15. ramfs_readdir
  16. ramfs_init

   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 /*
  31  * rmafs_vnops.c - vnode operations for RAM file system.
  32  */
  33 
  34 #include <sys/prex.h>
  35 
  36 #include <sys/stat.h>
  37 #include <sys/vnode.h>
  38 #include <sys/file.h>
  39 #include <sys/mount.h>
  40 #include <sys/dirent.h>
  41 #include <sys/param.h>
  42 
  43 #include <errno.h>
  44 #include <string.h>
  45 #include <stdlib.h>
  46 #include <fcntl.h>
  47 
  48 #include "ramfs.h"
  49 
  50 #define ramfs_open      ((vnop_open_t)vop_nullop)
  51 #define ramfs_close     ((vnop_close_t)vop_nullop)
  52 static int ramfs_read   (vnode_t, file_t, void *, size_t, size_t *);
  53 static int ramfs_write  (vnode_t, file_t, void *, size_t, size_t *);
  54 #define ramfs_seek      ((vnop_seek_t)vop_nullop)
  55 #define ramfs_ioctl     ((vnop_ioctl_t)vop_einval)
  56 #define ramfs_fsync     ((vnop_fsync_t)vop_nullop)
  57 static int ramfs_readdir(vnode_t, file_t, struct dirent *);
  58 static int ramfs_lookup (vnode_t, char *, vnode_t);
  59 static int ramfs_create (vnode_t, char *, mode_t);
  60 static int ramfs_remove (vnode_t, vnode_t, char *);
  61 static int ramfs_rename (vnode_t, vnode_t, char *, vnode_t, vnode_t, char *);
  62 static int ramfs_mkdir  (vnode_t, char *, mode_t);
  63 static int ramfs_rmdir  (vnode_t, vnode_t, char *);
  64 #define ramfs_getattr   ((vnop_getattr_t)vop_nullop)
  65 #define ramfs_setattr   ((vnop_setattr_t)vop_nullop)
  66 #define ramfs_inactive  ((vnop_inactive_t)vop_nullop)
  67 static int ramfs_truncate(vnode_t, off_t);
  68 
  69 
  70 #if CONFIG_FS_THREADS > 1
  71 static mutex_t ramfs_lock = MUTEX_INITIALIZER;
  72 #endif
  73 
  74 /*
  75  * vnode operations
  76  */
  77 struct vnops ramfs_vnops = {
  78         ramfs_open,             /* open */
  79         ramfs_close,            /* close */
  80         ramfs_read,             /* read */
  81         ramfs_write,            /* write */
  82         ramfs_seek,             /* seek */
  83         ramfs_ioctl,            /* ioctl */
  84         ramfs_fsync,            /* fsync */
  85         ramfs_readdir,          /* readdir */
  86         ramfs_lookup,           /* lookup */
  87         ramfs_create,           /* create */
  88         ramfs_remove,           /* remove */
  89         ramfs_rename,           /* remame */
  90         ramfs_mkdir,            /* mkdir */
  91         ramfs_rmdir,            /* rmdir */
  92         ramfs_getattr,          /* getattr */
  93         ramfs_setattr,          /* setattr */
  94         ramfs_inactive,         /* inactive */
  95         ramfs_truncate,         /* truncate */
  96 };
  97 
  98 struct ramfs_node *
  99 ramfs_allocate_node(char *name, int type)
 100 {
 101         struct ramfs_node *np;
 102 
 103         np = malloc(sizeof(struct ramfs_node));
 104         if (np == NULL)
 105                 return NULL;
 106         memset(np, 0, sizeof(struct ramfs_node));
 107 
 108         np->rn_namelen = strlen(name);
 109         np->rn_name = malloc(np->rn_namelen + 1);
 110         if (np->rn_name == NULL) {
 111                 free(np);
 112                 return NULL;
 113         }
 114         strlcpy(np->rn_name, name, np->rn_namelen + 1);
 115         np->rn_type = type;
 116         return np;
 117 }
 118 
 119 void
 120 ramfs_free_node(struct ramfs_node *np)
 121 {
 122 
 123         free(np->rn_name);
 124         free(np);
 125 }
 126 
 127 static struct ramfs_node *
 128 ramfs_add_node(struct ramfs_node *dnp, char *name, int type)
 129 {
 130         struct ramfs_node *np, *prev;
 131 
 132         np = ramfs_allocate_node(name, type);
 133         if (np == NULL)
 134                 return NULL;
 135 
 136         mutex_lock(&ramfs_lock);
 137 
 138         /* Link to the directory list */
 139         if (dnp->rn_child == NULL) {
 140                 dnp->rn_child = np;
 141         } else {
 142                 prev = dnp->rn_child;
 143                 while (prev->rn_next != NULL)
 144                         prev = prev->rn_next;
 145                 prev->rn_next = np;
 146         }
 147         mutex_unlock(&ramfs_lock);
 148         return np;
 149 }
 150 
 151 static int
 152 ramfs_remove_node(struct ramfs_node *dnp, struct ramfs_node *np)
 153 {
 154         struct ramfs_node *prev;
 155 
 156         if (dnp->rn_child == NULL)
 157                 return EBUSY;
 158 
 159         mutex_lock(&ramfs_lock);
 160 
 161         /* Unlink from the directory list */
 162         if (dnp->rn_child == np) {
 163                 dnp->rn_child = np->rn_next;
 164         } else {
 165                 for (prev = dnp->rn_child; prev->rn_next != np;
 166                      prev = prev->rn_next) {
 167                         if (prev->rn_next == NULL) {
 168                                 mutex_unlock(&ramfs_lock);
 169                                 return ENOENT;
 170                         }
 171                 }
 172                 prev->rn_next = np->rn_next;
 173         }
 174         ramfs_free_node(np);
 175 
 176         mutex_unlock(&ramfs_lock);
 177         return 0;
 178 }
 179 
 180 static int
 181 ramfs_rename_node(struct ramfs_node *np, char *name)
 182 {
 183         size_t len;
 184         char *tmp;
 185 
 186         len = strlen(name);
 187         if (len <= np->rn_namelen) {
 188                 /* Reuse current name buffer */
 189                 strlcpy(np->rn_name, name, sizeof(np->rn_name));
 190         } else {
 191                 /* Expand name buffer */
 192                 tmp = malloc(len + 1);
 193                 if (tmp == NULL)
 194                         return ENOMEM;
 195                 strlcpy(tmp, name, len + 1);
 196                 free(np->rn_name);
 197                 np->rn_name = tmp;
 198         }
 199         np->rn_namelen = len;
 200         return 0;
 201 }
 202 
 203 static int
 204 ramfs_lookup(vnode_t dvp, char *name, vnode_t vp)
 205 {
 206         struct ramfs_node *np, *dnp;
 207         size_t len;
 208         int found;
 209 
 210         if (*name == '\0')
 211                 return ENOENT;
 212 
 213         mutex_lock(&ramfs_lock);
 214 
 215         len = strlen(name);
 216         dnp = dvp->v_data;
 217         found = 0;
 218         for (np = dnp->rn_child; np != NULL; np = np->rn_next) {
 219                 if (np->rn_namelen == len &&
 220                     memcmp(name, np->rn_name, len) == 0) {
 221                         found = 1;
 222                         break;
 223                 }
 224         }
 225         if (found == 0) {
 226                 mutex_unlock(&ramfs_lock);
 227                 return ENOENT;
 228         }
 229         vp->v_data = np;
 230         vp->v_mode = ALLPERMS;
 231         vp->v_type = np->rn_type;
 232         vp->v_size = np->rn_size;
 233 
 234         mutex_unlock(&ramfs_lock);
 235         return 0;
 236 }
 237 
 238 static int
 239 ramfs_mkdir(vnode_t dvp, char *name, mode_t mode)
 240 {
 241         struct ramfs_node *np;
 242 
 243         DPRINTF(("mkdir %s\n", name));
 244         if (!S_ISDIR(mode))
 245                 return EINVAL;
 246 
 247         np = ramfs_add_node(dvp->v_data, name, VDIR);
 248         if (np == NULL)
 249                 return ENOMEM;
 250         np->rn_size = 0;
 251         return 0;
 252 }
 253 
 254 /* Remove a directory */
 255 static int
 256 ramfs_rmdir(vnode_t dvp, vnode_t vp, char *name)
 257 {
 258 
 259         return ramfs_remove_node(dvp->v_data, vp->v_data);
 260 }
 261 
 262 /* Remove a file */
 263 static int
 264 ramfs_remove(vnode_t dvp, vnode_t vp, char *name)
 265 {
 266         struct ramfs_node *np;
 267         int error;
 268 
 269         DPRINTF(("remove %s in %s\n", name, dvp->v_path));
 270         error = ramfs_remove_node(dvp->v_data, vp->v_data);
 271         if (error)
 272                 return error;
 273 
 274         np = vp->v_data;
 275         if (np->rn_buf != NULL)
 276                 vm_free(task_self(), np->rn_buf);
 277         return 0;
 278 }
 279 
 280 /* Truncate file */
 281 static int
 282 ramfs_truncate(vnode_t vp, off_t length)
 283 {
 284         struct ramfs_node *np;
 285         void *new_buf;
 286         size_t new_size;
 287         task_t task;
 288 
 289         DPRINTF(("truncate %s length=%d\n", vp->v_path, length));
 290         np = vp->v_data;
 291 
 292         if (length == 0) {
 293                 if (np->rn_buf != NULL) {
 294                         vm_free(task_self(), np->rn_buf);
 295                         np->rn_buf = NULL;
 296                         np->rn_bufsize = 0;
 297                 }
 298         } else if (length > np->rn_bufsize) {
 299                 task = task_self();
 300                 new_size = round_page(length);
 301                 if (vm_allocate(task, &new_buf, new_size, 1))
 302                         return EIO;
 303                 if (np->rn_size != 0) {
 304                         memcpy(new_buf, np->rn_buf, vp->v_size);
 305                         vm_free(task, np->rn_buf);
 306                 }
 307                 np->rn_buf = new_buf;
 308                 np->rn_bufsize = new_size;
 309         }
 310         np->rn_size = length;
 311         vp->v_size = length;
 312         return 0;
 313 }
 314 
 315 /*
 316  * Create empty file.
 317  */
 318 static int
 319 ramfs_create(vnode_t dvp, char *name, mode_t mode)
 320 {
 321         struct ramfs_node *np;
 322 
 323         DPRINTF(("create %s in %s\n", name, dvp->v_path));
 324         if (!S_ISREG(mode))
 325                 return EINVAL;
 326 
 327         np = ramfs_add_node(dvp->v_data, name, VREG);
 328         if (np == NULL)
 329                 return ENOMEM;
 330         return 0;
 331 }
 332 
 333 static int
 334 ramfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
 335 {
 336         struct ramfs_node *np;
 337         off_t off;
 338 
 339         *result = 0;
 340         if (vp->v_type == VDIR)
 341                 return EISDIR;
 342         if (vp->v_type != VREG)
 343                 return EINVAL;
 344 
 345         off = fp->f_offset;
 346         if (off >= (off_t)vp->v_size)
 347                 return 0;
 348 
 349         if (vp->v_size - off < size)
 350                 size = vp->v_size - off;
 351 
 352         np = vp->v_data;
 353         memcpy(buf, np->rn_buf + off, size);
 354 
 355         fp->f_offset += size;
 356         *result = size;
 357         return 0;
 358 }
 359 
 360 static int
 361 ramfs_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
 362 {
 363         struct ramfs_node *np;
 364         off_t file_pos, end_pos;
 365         void *new_buf;
 366         size_t new_size;
 367         task_t task;
 368 
 369         *result = 0;
 370         if (vp->v_type == VDIR)
 371                 return EISDIR;
 372         if (vp->v_type != VREG)
 373                 return EINVAL;
 374 
 375         np = vp->v_data;
 376         /* Check if the file position exceeds the end of file. */
 377         end_pos = vp->v_size;
 378         file_pos = (fp->f_flags & O_APPEND) ? end_pos : fp->f_offset;
 379         if (file_pos + size > (size_t)end_pos) {
 380                 /* Expand the file size before writing to it */
 381                 end_pos = file_pos + size;
 382                 if (end_pos > (off_t)np->rn_bufsize) {
 383                         task = task_self();
 384                         /*
 385                          * We allocate the data buffer in page boundary.
 386                          * So that we can reduce the memory allocation unless
 387                          * the file size exceeds next page boundary.
 388                          * This will prevent the memory fragmentation by
 389                          * many malloc/free calls.
 390                          */
 391                         new_size = round_page(end_pos);
 392                         if (vm_allocate(task, &new_buf, new_size, 1))
 393                                 return EIO;
 394                         if (np->rn_size != 0) {
 395                                 memcpy(new_buf, np->rn_buf, vp->v_size);
 396                                 vm_free(task, np->rn_buf);
 397                         }
 398                         np->rn_buf = new_buf;
 399                         np->rn_bufsize = new_size;
 400                 }
 401                 np->rn_size = end_pos;
 402                 vp->v_size = end_pos;
 403         }
 404         memcpy(np->rn_buf + file_pos, buf, size);
 405         fp->f_offset += size;
 406         *result = size;
 407         return 0;
 408 }
 409 
 410 static int
 411 ramfs_rename(vnode_t dvp1, vnode_t vp1, char *name1,
 412              vnode_t dvp2, vnode_t vp2, char *name2)
 413 {
 414         struct ramfs_node *np, *old_np;
 415         int error;
 416 
 417         if (vp2) {
 418                 /* Remove destination file, first */
 419                 error = ramfs_remove_node(dvp2->v_data, vp2->v_data);
 420                 if (error)
 421                         return error;
 422         }
 423         /* Same directory ? */
 424         if (dvp1 == dvp2) {
 425                 /* Change the name of existing file */
 426                 error = ramfs_rename_node(vp1->v_data, name2);
 427                 if (error)
 428                         return error;
 429         } else {
 430                 /* Create new file or directory */
 431                 old_np = vp1->v_data;
 432                 np = ramfs_add_node(dvp2->v_data, name2, VREG);
 433                 if (np == NULL)
 434                         return ENOMEM;
 435 
 436                 if (vp1->v_type == VREG) {
 437                         /* Copy file data */
 438                         np->rn_buf = old_np->rn_buf;
 439                         np->rn_size = old_np->rn_size;
 440                         np->rn_bufsize = old_np->rn_bufsize;
 441                 }
 442                 /* Remove source file */
 443                 ramfs_remove_node(dvp1->v_data, vp1->v_data);
 444         }
 445         return 0;
 446 }
 447 
 448 /*
 449  * @vp: vnode of the directory.
 450  */
 451 static int
 452 ramfs_readdir(vnode_t vp, file_t fp, struct dirent *dir)
 453 {
 454         struct ramfs_node *np, *dnp;
 455         int i;
 456 
 457         mutex_lock(&ramfs_lock);
 458 
 459         if (fp->f_offset == 0) {
 460                 dir->d_type = DT_DIR;
 461                 strlcpy((char *)&dir->d_name, ".", sizeof(dir->d_name));
 462         } else if (fp->f_offset == 1) {
 463                 dir->d_type = DT_DIR;
 464                 strlcpy((char *)&dir->d_name, "..", sizeof(dir->d_name));
 465         } else {
 466                 dnp = vp->v_data;
 467                 np = dnp->rn_child;
 468                 if (np == NULL) {
 469                         mutex_unlock(&ramfs_lock);
 470                         return ENOENT;
 471                 }
 472 
 473                 for (i = 0; i != (fp->f_offset - 2); i++) {
 474                         np = np->rn_next;
 475                         if (np == NULL) {
 476                                 mutex_unlock(&ramfs_lock);
 477                                 return ENOENT;
 478                         }
 479                 }
 480                 if (np->rn_type == VDIR)
 481                         dir->d_type = DT_DIR;
 482                 else
 483                         dir->d_type = DT_REG;
 484                 strlcpy((char *)&dir->d_name, np->rn_name,
 485                         sizeof(dir->d_name));
 486         }
 487         dir->d_fileno = (uint32_t)fp->f_offset;
 488         dir->d_namlen = (uint16_t)strlen(dir->d_name);
 489 
 490         fp->f_offset++;
 491 
 492         mutex_unlock(&ramfs_lock);
 493         return 0;
 494 }
 495 
 496 int
 497 ramfs_init(void)
 498 {
 499         return 0;
 500 }

/* [<][>][^][v][top][bottom][index][help] */