|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/usr/server/fs/ramfs/ramfs_vnops.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
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] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |