root / prex-0.9.0 / usr / server / fs / ramfs / ramfs_vnops.c @ 03e9c04a
History | View | Annotate | Download (11.3 KB)
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 |
} |