Annotation of prex-old/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: #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