Annotation of prex/usr/server/fs/ramfs/ramfs_vnops.c, Revision 1.1.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: /*
31: * rmafs_vnops.c - vnode operations for RAM file system.
32: */
33:
34: #include <prex/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);
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: strcpy(np->rn_name, name);
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: strcpy(np->rn_name, name);
190: } else {
191: /* Expand name buffer */
192: tmp = malloc(len + 1);
193: if (tmp == NULL)
194: return ENOMEM;
195: strcpy(tmp, name);
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 err;
268:
269: DPRINTF(("remove %s in %s\n", name, dvp->v_path));
270: err = ramfs_remove_node(dvp->v_data, vp->v_data);
271: if (err)
272: return err;
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)
283: {
284: struct ramfs_node *np;
285:
286: DPRINTF(("truncate %s\n", vp->v_path));
287: np = vp->v_data;
288: if (np->rn_buf != NULL) {
289: vm_free(task_self(), np->rn_buf);
290: np->rn_buf = NULL;
291: np->rn_bufsize = 0;
292: }
293: vp->v_size = 0;
294: return 0;
295: }
296:
297: /*
298: * Create empty file.
299: */
300: static int
301: ramfs_create(vnode_t dvp, char *name, mode_t mode)
302: {
303: struct ramfs_node *np;
304:
305: DPRINTF(("create %s in %s\n", name, dvp->v_path));
306: if (!S_ISREG(mode))
307: return EINVAL;
308:
309: np = ramfs_add_node(dvp->v_data, name, VREG);
310: if (np == NULL)
311: return ENOMEM;
312: return 0;
313: }
314:
315: static int
316: ramfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
317: {
318: struct ramfs_node *np;
319: off_t off;
320:
321: *result = 0;
322: if (vp->v_type == VDIR)
323: return EISDIR;
324: if (vp->v_type != VREG)
325: return EINVAL;
326:
327: off = fp->f_offset;
328: if (off >= (off_t)vp->v_size)
329: return 0;
330:
331: if (vp->v_size - off < size)
332: size = vp->v_size - off;
333:
334: np = vp->v_data;
335: memcpy(buf, np->rn_buf + off, size);
336:
337: fp->f_offset += size;
338: *result = size;
339: return 0;
340: }
341:
342: static int
343: ramfs_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
344: {
345: struct ramfs_node *np;
346: off_t file_pos, end_pos;
347: void *new_buf;
348: size_t new_size;
349: task_t task;
350:
351: *result = 0;
352: if (vp->v_type == VDIR)
353: return EISDIR;
354: if (vp->v_type != VREG)
355: return EINVAL;
356:
357: np = vp->v_data;
358: /* Check if the file position exceeds the end of file. */
359: end_pos = vp->v_size;
360: file_pos = (fp->f_flags & O_APPEND) ? end_pos : fp->f_offset;
361: if (file_pos + size > (size_t)end_pos) {
362: /* Expand the file size before writing to it */
363: end_pos = file_pos + size;
364: if (end_pos > (off_t)np->rn_bufsize) {
365: task = task_self();
366: /*
367: * We allocate the data buffer in page boundary.
368: * So that we can reduce the memory allocation unless
369: * the file size exceeds next page boundary.
370: * This will prevent the memory fragmentation by
371: * many malloc/free calls.
372: */
373: new_size = PAGE_ALIGN(end_pos);
374: if (vm_allocate(task, &new_buf, new_size, 1))
375: return EIO;
376: if (np->rn_size != 0) {
377: memcpy(new_buf, np->rn_buf, vp->v_size);
378: vm_free(task, np->rn_buf);
379: }
380: np->rn_buf = new_buf;
381: np->rn_bufsize = new_size;
382: }
383: np->rn_size = end_pos;
384: vp->v_size = end_pos;
385: }
386: memcpy(np->rn_buf + file_pos, buf, size);
387: fp->f_offset += size;
388: *result = size;
389: return 0;
390: }
391:
392: static int
393: ramfs_rename(vnode_t dvp1, vnode_t vp1, char *name1,
394: vnode_t dvp2, vnode_t vp2, char *name2)
395: {
396: struct ramfs_node *np, *old_np;
397: int err;
398:
399: if (vp2) {
400: /* Remove destination file, first */
401: err = ramfs_remove_node(dvp2->v_data, vp2->v_data);
402: if (err)
403: return err;
404: }
405: /* Same directory ? */
406: if (dvp1 == dvp2) {
407: /* Change the name of existing file */
408: err = ramfs_rename_node(vp1->v_data, name2);
409: if (err)
410: return err;
411: } else {
412: /* Create new file or directory */
413: old_np = vp1->v_data;
414: np = ramfs_add_node(dvp2->v_data, name2, VREG);
415: if (np == NULL)
416: return ENOMEM;
417:
418: if (vp1->v_type == VREG) {
419: /* Copy file data */
420: np->rn_buf = old_np->rn_buf;
421: np->rn_size = old_np->rn_size;
422: np->rn_bufsize = old_np->rn_bufsize;
423: }
424: /* Remove source file */
425: ramfs_remove_node(dvp1->v_data, vp1->v_data);
426: }
427: return 0;
428: }
429:
430: /*
431: * @vp: vnode of the directory.
432: */
433: static int
434: ramfs_readdir(vnode_t vp, file_t fp, struct dirent *dir)
435: {
436: struct ramfs_node *np, *dnp;
437: int i;
438:
439: mutex_lock(&ramfs_lock);
440:
441: if (fp->f_offset == 0) {
442: dir->d_type = DT_DIR;
443: strcpy((char *)&dir->d_name, ".");
444: } else if (fp->f_offset == 1) {
445: dir->d_type = DT_DIR;
446: strcpy((char *)&dir->d_name, "..");
447: } else {
448: dnp = vp->v_data;
449: np = dnp->rn_child;
450: if (np == NULL) {
451: mutex_unlock(&ramfs_lock);
452: return ENOENT;
453: }
454:
455: for (i = 0; i != (fp->f_offset - 2); i++) {
456: np = np->rn_next;
457: if (np == NULL) {
458: mutex_unlock(&ramfs_lock);
459: return ENOENT;
460: }
461: }
462: if (np->rn_type == VDIR)
463: dir->d_type = DT_DIR;
464: else
465: dir->d_type = DT_REG;
466: strcpy((char *)&dir->d_name, np->rn_name);
467: }
468: dir->d_fileno = fp->f_offset;
469: dir->d_namlen = strlen(dir->d_name);
470:
471: fp->f_offset++;
472:
473: mutex_unlock(&ramfs_lock);
474: return 0;
475: }
476:
477: int
478: ramfs_init(void)
479: {
480: return 0;
481: }
CVSweb