menu: do not go to free if there's nothing to free
[barebox-mini2440.git] / fs / ramfs.c
blob9ecb824d0be155e929a7e3f3d86bf8a8fbaf32c2
1 /*
2 * ramfs.c - a malloc based filesystem
4 * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
6 * See file CREDITS for list of people who contributed to this
7 * project.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <common.h>
24 #include <driver.h>
25 #include <init.h>
26 #include <malloc.h>
27 #include <fs.h>
28 #include <command.h>
29 #include <errno.h>
30 #include <linux/stat.h>
31 #include <xfuncs.h>
33 #define CHUNK_SIZE 512
35 struct ramfs_chunk {
36 char *data;
37 struct ramfs_chunk *next;
40 struct ramfs_inode {
41 char *name;
42 struct ramfs_inode *parent;
43 struct ramfs_inode *next;
44 struct ramfs_inode *child;
45 ulong mode;
47 struct handle_d *handle;
49 ulong size;
50 struct ramfs_chunk *data;
53 struct ramfs_priv {
54 struct ramfs_inode root;
57 /* ---------------------------------------------------------------*/
58 static struct ramfs_inode * lookup(struct ramfs_inode *node, const char *name)
60 debug("lookup: %s in %p\n",name, node);
61 if(!S_ISDIR(node->mode))
62 return NULL;
64 node = node->child;
65 if (!node)
66 return NULL;
68 while (node) {
69 debug("lookup: %s\n", node->name);
70 if (!strcmp(node->name, name)) {
71 debug("lookup: found: 0x%p\n",node);
72 return node;
74 node = node->next;
76 return NULL;
79 static struct ramfs_inode* rlookup(struct ramfs_priv *priv, const char *path)
81 struct ramfs_inode *node = &priv->root;
82 static char *buf;
83 char *part;
85 debug("rlookup %s in %p\n",path, node);
86 buf = strdup(path);
88 part = strtok(buf, "/");
89 if (!part)
90 goto out;
92 do {
93 node = lookup(node, part);
94 if (!node)
95 goto out;
96 part = strtok(NULL, "/");
97 } while(part);
99 out:
100 free(buf);
101 return node;
104 static struct ramfs_inode* rlookup_parent(struct ramfs_priv *priv, const char *pathname, char **file)
106 char *path;
107 struct ramfs_inode *node;
109 pathname++;
110 path = strdup(pathname);
112 if ((*file = strrchr((char *) pathname, '/'))) {
113 char *tmp;
114 (*file)++;
116 tmp = strrchr(path, '/');
117 *tmp = 0;
118 node = rlookup(priv, path);
119 if (!node) {
120 errno = -ENOENT;
121 goto out;
123 } else {
124 *file = (char *)pathname;
125 node = &priv->root;
128 out:
129 free(path);
130 return node;
133 static int chunks = 0;
135 static struct ramfs_chunk *ramfs_get_chunk(void)
137 struct ramfs_chunk *data = malloc(sizeof(struct ramfs_chunk));
138 if (!data)
139 return NULL;
141 data->data = malloc(CHUNK_SIZE);
142 if (!data->data) {
143 free(data);
144 return NULL;
146 data->next = NULL;
147 chunks++;
149 return data;
152 static void ramfs_put_chunk(struct ramfs_chunk *data)
154 free(data->data);
155 free(data);
156 chunks--;
159 static struct ramfs_inode* ramfs_get_inode(void)
161 struct ramfs_inode *node = xzalloc(sizeof(struct ramfs_inode));
162 return node;
165 static void ramfs_put_inode(struct ramfs_inode *node)
167 struct ramfs_chunk *data = node->data;
169 while (data) {
170 struct ramfs_chunk *tmp = data->next;
171 ramfs_put_chunk(data);
172 data = tmp;
175 free(node->name);
176 free(node);
179 static struct ramfs_inode* node_insert(struct ramfs_inode *parent_node, const char *filename, ulong mode)
181 struct ramfs_inode *node, *new_node = ramfs_get_inode();
182 new_node->name = strdup(filename);
183 new_node->mode = mode;
185 node = parent_node->child;
187 if (S_ISDIR(mode)) {
188 struct ramfs_inode *n = ramfs_get_inode();
189 n->name = strdup(".");
190 n->mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
191 n->child = n;
192 n->parent = new_node;
193 new_node->child = n;
194 n = ramfs_get_inode();
195 n->name = strdup("..");
196 n->mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
197 n->parent = new_node;
198 n->child = parent_node->child;
199 new_node->child->next = n;
202 while (node->next)
203 node = node->next;
205 node->next = new_node;
206 return new_node;
209 /* ---------------------------------------------------------------*/
211 static int ramfs_create(struct device_d *dev, const char *pathname, mode_t mode)
213 struct ramfs_priv *priv = dev->priv;
214 struct ramfs_inode *node;
215 char *file;
217 node = rlookup_parent(priv, pathname, &file);
218 if (node) {
219 node_insert(node, file, mode);
220 return 0;
222 return -ENOENT;
225 static int ramfs_unlink(struct device_d *dev, const char *pathname)
227 struct ramfs_priv *priv = dev->priv;
228 struct ramfs_inode *node, *lastnode;
229 char *file;
231 node = rlookup_parent(priv, pathname, &file);
233 lastnode = node->child->next;
234 node = lastnode->next;
236 while (node) {
237 if (!strcmp(node->name, file)) {
238 struct ramfs_inode *tmp;
239 tmp = node;
240 lastnode->next = node->next;
241 ramfs_put_inode(tmp);
242 return 0;
244 lastnode = node;
245 node = node->next;
247 return -ENOENT;
250 static int ramfs_mkdir(struct device_d *dev, const char *pathname)
252 return ramfs_create(dev, pathname, S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
255 static int ramfs_rmdir(struct device_d *dev, const char *pathname)
257 struct ramfs_priv *priv = dev->priv;
258 struct ramfs_inode *node, *lastnode;
259 char *file;
261 node = rlookup_parent(priv, pathname, &file);
263 lastnode = node->child->next;
264 node = lastnode->next;
266 while (node) {
267 if (!strcmp(node->name, file)) {
268 struct ramfs_inode *tmp;
269 tmp = node;
270 lastnode->next = node->next;
271 ramfs_put_inode(tmp->child->next);
272 ramfs_put_inode(tmp->child);
273 ramfs_put_inode(tmp);
274 return 0;
276 lastnode = node;
277 node = node->next;
279 return -ENOENT;
282 static int ramfs_open(struct device_d *dev, FILE *file, const char *filename)
284 struct ramfs_priv *priv = dev->priv;
285 struct ramfs_inode *node = rlookup(priv, filename);
287 if (!node)
288 return -ENOENT;
290 file->size = node->size;
291 file->inode = node;
292 return 0;
295 static int ramfs_close(struct device_d *dev, FILE *f)
297 return 0;
300 static int ramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize)
302 struct ramfs_inode *node = (struct ramfs_inode *)f->inode;
303 int chunk;
304 struct ramfs_chunk *data;
305 int ofs;
306 int now;
307 int pos = f->pos;
308 int size = insize;
310 chunk = f->pos / CHUNK_SIZE;
311 debug("%s: reading from chunk %d\n", __FUNCTION__, chunk);
313 /* Position ourself in stream */
314 data = node->data;
315 while (chunk) {
316 data = data->next;
317 chunk--;
319 ofs = f->pos % CHUNK_SIZE;
321 /* Read till end of current chunk */
322 if (ofs) {
323 now = min(size, CHUNK_SIZE - ofs);
324 debug("Reading till end of node. size: %d\n", size);
325 memcpy(buf, data->data + ofs, now);
326 size -= now;
327 pos += now;
328 buf += now;
329 if (pos > node->size)
330 node->size = now;
331 data = data->next;
334 /* Do full chunks */
335 while (size >= CHUNK_SIZE) {
336 debug("do full chunk. size: %d\n", size);
337 memcpy(buf, data->data, CHUNK_SIZE);
338 data = data->next;
339 size -= CHUNK_SIZE;
340 pos += CHUNK_SIZE;
341 buf += CHUNK_SIZE;
344 /* And the rest */
345 if (size) {
346 debug("do rest. size: %d\n", size);
347 memcpy(buf, data->data, size);
350 return insize;
353 static int ramfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t insize)
355 struct ramfs_inode *node = (struct ramfs_inode *)f->inode;
356 int chunk;
357 struct ramfs_chunk *data;
358 int ofs;
359 int now;
360 int pos = f->pos;
361 int size = insize;
363 chunk = f->pos / CHUNK_SIZE;
364 debug("%s: writing to chunk %d\n", __FUNCTION__, chunk);
366 /* Position ourself in stream */
367 data = node->data;
368 while (chunk) {
369 data = data->next;
370 chunk--;
372 ofs = f->pos % CHUNK_SIZE;
374 /* Write till end of current chunk */
375 if (ofs) {
376 now = min(size, CHUNK_SIZE - ofs);
377 debug("writing till end of node. size: %d\n", size);
378 memcpy(data->data + ofs, buf, now);
379 size -= now;
380 pos += now;
381 buf += now;
382 if (pos > node->size)
383 node->size = now;
384 data = data->next;
387 /* Do full chunks */
388 while (size >= CHUNK_SIZE) {
389 debug("do full chunk. size: %d\n", size);
390 memcpy(data->data, buf, CHUNK_SIZE);
391 data = data->next;
392 size -= CHUNK_SIZE;
393 pos += CHUNK_SIZE;
394 buf += CHUNK_SIZE;
397 /* And the rest */
398 if (size) {
399 debug("do rest. size: %d\n", size);
400 memcpy(data->data, buf, size);
403 return insize;
406 static off_t ramfs_lseek(struct device_d *dev, FILE *f, off_t pos)
408 f->pos = pos;
409 return f->pos;
412 static int ramfs_truncate(struct device_d *dev, FILE *f, ulong size)
414 struct ramfs_inode *node = (struct ramfs_inode *)f->inode;
415 int oldchunks, newchunks;
416 struct ramfs_chunk *data = node->data;
418 newchunks = (size + CHUNK_SIZE - 1) / CHUNK_SIZE;
419 oldchunks = (node->size + CHUNK_SIZE - 1) / CHUNK_SIZE;
421 if (newchunks < oldchunks) {
422 if (!newchunks)
423 node->data = 0;
424 while (newchunks--)
425 data = data->next;
426 while (data) {
427 struct ramfs_chunk *tmp;
428 tmp = data->next;
429 ramfs_put_chunk(data);
430 data = tmp;
434 if (newchunks > oldchunks) {
435 if (!data) {
436 node->data = ramfs_get_chunk();
437 if (!node->data)
438 return -ENOMEM;
439 data = node->data;
442 newchunks--;
443 while (data->next) {
444 newchunks--;
445 data = data->next;
448 while (newchunks--) {
449 data->next = ramfs_get_chunk();
450 if (!data->next)
451 return -ENOMEM;
452 data = data->next;
455 node->size = size;
456 return 0;
459 static DIR* ramfs_opendir(struct device_d *dev, const char *pathname)
461 DIR *dir;
462 struct ramfs_priv *priv = dev->priv;
463 struct ramfs_inode *node;
465 debug("opendir: %s\n", pathname);
467 node = rlookup(priv, pathname);
469 if (!node)
470 return NULL;
472 if (!S_ISDIR(node->mode))
473 return NULL;
475 dir = xmalloc(sizeof(DIR));
477 dir->priv = node->child;
479 return dir;
482 static struct dirent* ramfs_readdir(struct device_d *dev, DIR *dir)
484 struct ramfs_inode *node = dir->priv;
486 if (node) {
487 strcpy(dir->d.d_name, node->name);
488 dir->priv = node->next;
489 return &dir->d;
491 return NULL;
494 static int ramfs_closedir(struct device_d *dev, DIR *dir)
496 free(dir);
497 return 0;
500 static int ramfs_stat(struct device_d *dev, const char *filename, struct stat *s)
502 struct ramfs_priv *priv = dev->priv;
503 struct ramfs_inode *node = rlookup(priv, filename);
505 if (!node)
506 return -ENOENT;
508 s->st_size = node->size;
509 s->st_mode = node->mode;
511 return 0;
514 static int ramfs_probe(struct device_d *dev)
516 struct ramfs_inode *n;
517 struct ramfs_priv *priv = xzalloc(sizeof(struct ramfs_priv));
519 dev->priv = priv;
521 priv->root.name = "/";
522 priv->root.mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
523 priv->root.parent = &priv->root;
524 n = ramfs_get_inode();
525 n->name = strdup(".");
526 n->mode = S_IFDIR;
527 n->parent = &priv->root;
528 n->child = n;
529 priv->root.child = n;
530 n = ramfs_get_inode();
531 n->name = strdup("..");
532 n->mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
533 n->parent = &priv->root;
534 n->child = priv->root.child;
535 priv->root.child->next = n;
537 return 0;
540 static void ramfs_remove(struct device_d *dev)
542 free(dev->priv);
545 static struct fs_driver_d ramfs_driver = {
546 .type = FS_TYPE_RAMFS,
547 .create = ramfs_create,
548 .unlink = ramfs_unlink,
549 .open = ramfs_open,
550 .close = ramfs_close,
551 .truncate = ramfs_truncate,
552 .read = ramfs_read,
553 .write = ramfs_write,
554 .lseek = ramfs_lseek,
555 .mkdir = ramfs_mkdir,
556 .rmdir = ramfs_rmdir,
557 .opendir = ramfs_opendir,
558 .readdir = ramfs_readdir,
559 .closedir = ramfs_closedir,
560 .stat = ramfs_stat,
561 .flags = FS_DRIVER_NO_DEV,
562 .drv = {
563 .probe = ramfs_probe,
564 .remove = ramfs_remove,
565 .name = "ramfs",
566 .type_data = &ramfs_driver,
570 static int ramfs_init(void)
572 return register_fs_driver(&ramfs_driver);
575 coredevice_initcall(ramfs_init);