Import 2.1.55pre1
[davej-history.git] / fs / romfs / inode.c
blob3c99d0d9f82201b711379880864e7116c5f11f11
1 /*
2 * ROMFS file system, Linux implementation
4 * Copyright (C) 1997 Janos Farkas <chexum@shadow.banki.hu>
6 * Using parts of the minix filesystem
7 * Copyright (C) 1991, 1992 Linus Torvalds
9 * and parts of the affs filesystem additionally
10 * Copyright (C) 1993 Ray Burr
11 * Copyright (C) 1996 Hans-Joachim Widmaier
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
18 * Changes
19 * Changed for 2.1.19 modules
20 * Jan 1997 Initial release
21 * Jun 1997 2.1.43+ changes
22 * Proper page locking in readpage
23 * Changed to work with 2.1.45+ fs
24 * Jul 1997 Fixed follow_link
25 * 2.1.47
26 * lookup shouldn't return -ENOENT
27 * from Horst von Brand:
28 * fail on wrong checksum
29 * double unlock_super was possible
30 * correct namelen for statfs
31 * spotted by Bill Hawes:
32 * readlink shouldn't iput()
35 /* todo:
36 * - see Documentation/filesystems/romfs.txt
37 * - use malloced memory for file names?
38 * - quicklist routines from fs/namei.c, get_page is possibly not
39 * intended to be used now
40 * - considering write access...
41 * - network (tftp) files?
42 * - in the ancient times something leaked to made umounts
43 * impossible, but I've not seen it in the last months
47 * Sorry about some optimizations and for some goto's. I just wanted
48 * to squeeze some more bytes out of this code.. :)
51 #include <linux/config.h>
52 #include <linux/module.h>
53 #include <linux/types.h>
54 #include <linux/errno.h>
55 #include <linux/malloc.h>
56 #include <linux/romfs_fs.h>
57 #include <linux/fs.h>
58 #include <linux/locks.h>
59 #include <linux/init.h>
61 #include <asm/uaccess.h>
63 static int inline min(int a, int b)
65 return a<b ? a : b;
68 static __s32
69 romfs_checksum(void *data, int size)
71 __s32 sum, *ptr;
73 sum = 0; ptr = data;
74 size>>=2;
75 while (size>0) {
76 sum += ntohl(*ptr++);
77 size--;
79 return sum;
82 static struct super_operations romfs_ops;
84 static struct super_block *
85 romfs_read_super(struct super_block *s, void *data, int silent)
87 struct buffer_head *bh;
88 kdev_t dev = s->s_dev;
89 struct romfs_super_block *rsb;
90 int sz;
92 MOD_INC_USE_COUNT;
94 /* I would parse the options here, but there are none.. :) */
96 lock_super(s);
97 set_blocksize(dev, ROMBSIZE);
98 s->s_blocksize = ROMBSIZE;
99 s->s_blocksize_bits = ROMBSBITS;
100 bh = bread(dev, 0, ROMBSIZE);
101 if (!bh) {
102 /* XXX merge with other printk? */
103 printk ("romfs: unable to read superblock\n");
104 goto outnobh;
107 rsb = (struct romfs_super_block *)bh->b_data;
108 sz = ntohl(rsb->size);
109 if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1
110 || sz < ROMFH_SIZE) {
111 if (!silent)
112 printk ("VFS: Can't find a romfs filesystem on dev "
113 "%s.\n", kdevname(dev));
114 goto out;
116 if (romfs_checksum(rsb, min(sz,512))) {
117 printk ("romfs: bad initial checksum on dev "
118 "%s.\n", kdevname(dev));
119 goto out;
122 s->s_magic = ROMFS_MAGIC;
123 s->u.romfs_sb.s_maxsize = sz;
125 s->s_flags |= MS_RDONLY;
127 /* Find the start of the fs */
128 sz = (ROMFH_SIZE +
129 strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD)
130 & ROMFH_MASK;
132 brelse(bh);
134 s->s_op = &romfs_ops;
135 s->s_root = d_alloc_root(iget(s, sz), NULL);
137 if (!s->s_root)
138 goto outnobh;
140 unlock_super(s);
142 /* Ehrhm; sorry.. :) And thanks to Hans-Joachim Widmaier :) */
143 if (0) {
144 out:
145 brelse(bh);
146 outnobh:
147 s->s_dev = 0;
148 unlock_super(s);
149 MOD_DEC_USE_COUNT;
150 s = NULL;
153 return s;
156 /* Nothing to do.. */
158 static void
159 romfs_put_super(struct super_block *sb)
161 lock_super(sb);
162 sb->s_dev = 0;
163 unlock_super(sb);
164 MOD_DEC_USE_COUNT;
165 return;
168 /* That's simple too. */
170 static int
171 romfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
173 struct statfs tmp;
175 memset(&tmp, 0, sizeof(tmp));
176 tmp.f_type = ROMFS_MAGIC;
177 tmp.f_bsize = ROMBSIZE;
178 tmp.f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
179 tmp.f_namelen = ROMFS_MAXFN;
180 return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
183 /* some helper routines */
185 static int
186 romfs_strnlen(struct inode *i, unsigned long offset, unsigned long count)
188 struct buffer_head *bh;
189 unsigned long avail, maxsize, res;
191 maxsize = i->i_sb->u.romfs_sb.s_maxsize;
192 if (offset >= maxsize)
193 return -1;
195 /* strnlen is almost always valid */
196 if (count > maxsize || offset+count > maxsize)
197 count = maxsize-offset;
199 bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
200 if (!bh)
201 return -1; /* error */
203 avail = ROMBSIZE - (offset & ROMBMASK);
204 maxsize = min(count, avail);
205 res = strnlen(((char *)bh->b_data)+(offset&ROMBMASK), maxsize);
206 brelse(bh);
208 if (res < maxsize)
209 return res; /* found all of it */
211 while (res < count) {
212 offset += maxsize;
214 bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
215 if (!bh)
216 return -1;
217 maxsize = min(count-res, ROMBSIZE);
218 avail = strnlen(bh->b_data, maxsize);
219 res += avail;
220 brelse(bh);
221 if (avail < maxsize)
222 return res;
224 return res;
227 static int
228 romfs_copyfrom(struct inode *i, void *dest, unsigned long offset, unsigned long count)
230 struct buffer_head *bh;
231 unsigned long avail, maxsize, res;
233 maxsize = i->i_sb->u.romfs_sb.s_maxsize;
234 if (offset >= maxsize || count > maxsize || offset+count>maxsize)
235 return -1;
237 bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
238 if (!bh)
239 return -1; /* error */
241 avail = ROMBSIZE - (offset & ROMBMASK);
242 maxsize = min(count, avail);
243 memcpy(dest, ((char *)bh->b_data) + (offset & ROMBMASK), maxsize);
244 brelse(bh);
246 res = maxsize; /* all of it */
248 while (res < count) {
249 offset += maxsize;
250 dest += maxsize;
252 bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
253 if (!bh)
254 return -1;
255 maxsize = min(count-res, ROMBSIZE);
256 memcpy(dest, bh->b_data, maxsize);
257 brelse(bh);
258 res += maxsize;
260 return res;
263 static int
264 romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
266 struct inode *i = filp->f_dentry->d_inode;
267 struct romfs_inode ri;
268 unsigned long offset, maxoff;
269 int j, ino, nextfh;
270 int stored = 0;
271 char fsname[ROMFS_MAXFN]; /* XXX dynamic? */
273 if (!i || !S_ISDIR(i->i_mode))
274 return -EBADF;
276 maxoff = i->i_sb->u.romfs_sb.s_maxsize;
278 offset = filp->f_pos;
279 if (!offset) {
280 offset = i->i_ino & ROMFH_MASK;
281 if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
282 return stored;
283 offset = ntohl(ri.spec) & ROMFH_MASK;
286 /* Not really failsafe, but we are read-only... */
287 for(;;) {
288 if (!offset || offset >= maxoff) {
289 offset = 0xffffffff;
290 filp->f_pos = offset;
291 return stored;
293 filp->f_pos = offset;
295 /* Fetch inode info */
296 if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
297 return stored;
299 j = romfs_strnlen(i, offset+ROMFH_SIZE, sizeof(fsname)-1);
300 if (j < 0)
301 return stored;
303 fsname[j]=0;
304 romfs_copyfrom(i, fsname, offset+ROMFH_SIZE, j);
306 ino = offset;
307 nextfh = ntohl(ri.next);
308 if ((nextfh & ROMFH_TYPE) == ROMFH_HRD)
309 ino = ntohl(ri.spec);
310 if (filldir(dirent, fsname, j, offset, ino) < 0) {
311 return stored;
313 stored++;
314 offset = nextfh & ROMFH_MASK;
318 static int
319 romfs_lookup(struct inode *dir, struct dentry *dentry)
321 unsigned long offset, maxoff;
322 int fslen, res;
323 struct inode *inode;
324 char fsname[ROMFS_MAXFN]; /* XXX dynamic? */
325 struct romfs_inode ri;
326 const char *name; /* got from dentry */
327 int len;
329 res = -EBADF;
330 if (!dir || !S_ISDIR(dir->i_mode))
331 goto out;
333 res = 0; /* instead of ENOENT */
334 offset = dir->i_ino & ROMFH_MASK;
335 if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
336 goto out;
338 maxoff = dir->i_sb->u.romfs_sb.s_maxsize;
339 offset = ntohl(ri.spec) & ROMFH_MASK;
341 /* ok, now find the file, whose name is in "dentry", in the
342 * directory specified by "dir". */
344 name = dentry->d_name.name;
345 len = dentry->d_name.len;
347 for(;;) {
348 if (!offset || offset >= maxoff
349 || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
350 goto out;
352 /* try to match the first 16 bytes of name */
353 fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE);
354 if (len < ROMFH_SIZE) {
355 if (len == fslen) {
356 /* both are shorter, and same size */
357 romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
358 if (strncmp (name, fsname, len) == 0)
359 break;
361 } else if (fslen >= ROMFH_SIZE) {
362 /* both are longer; XXX optimize max size */
363 fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, sizeof(fsname)-1);
364 if (len == fslen) {
365 romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
366 if (strncmp(name, fsname, len) == 0)
367 break;
370 /* next entry */
371 offset = ntohl(ri.next) & ROMFH_MASK;
374 /* Hard link handling */
375 if ((ntohl(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
376 offset = ntohl(ri.spec) & ROMFH_MASK;
378 if ((inode = iget(dir->i_sb, offset))==NULL) {
379 res = -EACCES;
380 } else {
381 d_add(dentry, inode);
384 out:
385 return res;
389 * Ok, we do readpage, to be able to execute programs. Unfortunately,
390 * we can't use bmap, since we have looser alignments.
393 static int
394 romfs_readpage(struct inode * inode, struct page * page)
396 unsigned long buf;
397 unsigned long offset, avail, readlen;
398 int result = -EIO;
400 atomic_inc(&page->count);
401 set_bit(PG_locked, &page->flags);
403 buf = page_address(page);
404 clear_bit(PG_uptodate, &page->flags);
405 clear_bit(PG_error, &page->flags);
406 offset = page->offset;
407 if (offset < inode->i_size) {
408 avail = inode->i_size-offset;
409 readlen = min(avail, PAGE_SIZE);
410 if (romfs_copyfrom(inode, (void *)buf, inode->u.romfs_i.i_dataoffset+offset, readlen) == readlen) {
411 if (readlen < PAGE_SIZE) {
412 memset((void *)(buf+readlen),0,PAGE_SIZE-readlen);
414 set_bit(PG_uptodate, &page->flags);
415 result = 0;
418 if (result) {
419 set_bit(PG_error, &page->flags);
420 memset((void *)buf, 0, PAGE_SIZE);
423 clear_bit(PG_locked, &page->flags);
424 wake_up(&page->wait);
425 free_page(buf);
427 return result;
430 static int
431 romfs_readlink(struct inode *inode, char *buffer, int len)
433 int mylen;
434 char buf[ROMFS_MAXFN]; /* XXX dynamic */
436 if (!inode || !S_ISLNK(inode->i_mode)) {
437 mylen = -EBADF;
438 goto out;
441 mylen = min(sizeof(buf), inode->i_size);
443 if (romfs_copyfrom(inode, buf, inode->u.romfs_i.i_dataoffset, mylen) <= 0) {
444 mylen = -EIO;
445 goto out;
447 copy_to_user(buffer, buf, mylen);
449 out:
450 return mylen;
453 static struct dentry *romfs_follow_link(struct inode *inode, struct dentry *base)
455 char *link;
456 int len, cnt;
457 struct dentry *dentry;
459 len = inode->i_size;
461 dentry = ERR_PTR(-EAGAIN); /* correct? */
462 if (!(link = kmalloc(len+1, GFP_KERNEL)))
463 goto outnobuf;
465 cnt = romfs_copyfrom(inode, link, inode->u.romfs_i.i_dataoffset, len);
466 if (len != cnt) {
467 dentry = ERR_PTR(-EIO);
468 goto out;
469 } else
470 link[len] = 0;
472 dentry = lookup_dentry(link, base, 1);
473 kfree(link);
475 if (0) {
476 out:
477 kfree(link);
478 outnobuf:
479 dput(base);
481 return dentry;
484 /* Mapping from our types to the kernel */
486 static struct file_operations romfs_file_operations = {
487 NULL, /* lseek - default */
488 generic_file_read, /* read */
489 NULL, /* write - bad */
490 NULL, /* readdir */
491 NULL, /* poll - default */
492 NULL, /* ioctl */
493 generic_file_mmap, /* mmap */
494 NULL, /* open */
495 NULL, /* release */
496 NULL, /* fsync */
497 NULL, /* fasync */
498 NULL, /* check_media_change */
499 NULL /* revalidate */
502 static struct inode_operations romfs_file_inode_operations = {
503 &romfs_file_operations,
504 NULL, /* create */
505 NULL, /* lookup */
506 NULL, /* link */
507 NULL, /* unlink */
508 NULL, /* symlink */
509 NULL, /* mkdir */
510 NULL, /* rmdir */
511 NULL, /* mknod */
512 NULL, /* rename */
513 NULL, /* readlink */
514 NULL, /* follow_link */
515 romfs_readpage, /* readpage */
516 NULL, /* writepage */
517 NULL, /* bmap -- not really */
518 NULL, /* truncate */
519 NULL, /* permission */
520 NULL, /* smap */
523 static struct file_operations romfs_dir_operations = {
524 NULL, /* lseek - default */
525 NULL, /* read */
526 NULL, /* write - bad */
527 romfs_readdir, /* readdir */
528 NULL, /* poll - default */
529 NULL, /* ioctl */
530 NULL, /* mmap */
531 NULL, /* open */
532 NULL, /* release */
533 NULL, /* fsync */
534 NULL, /* fasync */
535 NULL, /* check_media_change */
536 NULL /* revalidate */
539 /* Merged dir/symlink op table. readdir/lookup/readlink/follow_link
540 * will protect from type mismatch.
543 static struct inode_operations romfs_dir_inode_operations = {
544 &romfs_dir_operations,
545 NULL, /* create */
546 romfs_lookup, /* lookup */
547 NULL, /* link */
548 NULL, /* unlink */
549 NULL, /* symlink */
550 NULL, /* mkdir */
551 NULL, /* rmdir */
552 NULL, /* mknod */
553 NULL, /* rename */
554 NULL, /* readlink */
555 NULL, /* follow_link */
556 NULL, /* readpage */
557 NULL, /* writepage */
558 NULL, /* bmap */
559 NULL, /* truncate */
560 NULL, /* permission */
561 NULL, /* smap */
564 static struct inode_operations romfs_link_inode_operations = {
565 NULL, /* no file operations on symlinks */
566 NULL, /* create */
567 NULL, /* lookup */
568 NULL, /* link */
569 NULL, /* unlink */
570 NULL, /* symlink */
571 NULL, /* mkdir */
572 NULL, /* rmdir */
573 NULL, /* mknod */
574 NULL, /* rename */
575 romfs_readlink, /* readlink */
576 romfs_follow_link, /* follow_link */
577 NULL, /* readpage */
578 NULL, /* writepage */
579 NULL, /* bmap */
580 NULL, /* truncate */
581 NULL, /* permission */
582 NULL, /* smap */
585 static mode_t romfs_modemap[] =
587 0, S_IFDIR, S_IFREG, S_IFLNK+0777,
588 S_IFBLK, S_IFCHR, S_IFSOCK, S_IFIFO
591 static struct inode_operations *romfs_inoops[] =
593 NULL, /* hardlink, handled elsewhere */
594 &romfs_dir_inode_operations,
595 &romfs_file_inode_operations,
596 &romfs_link_inode_operations,
597 &blkdev_inode_operations, /* standard handlers */
598 &chrdev_inode_operations,
599 NULL, /* socket */
600 NULL, /* fifo */
603 static void
604 romfs_read_inode(struct inode *i)
606 int nextfh, ino;
607 struct romfs_inode ri;
609 ino = i->i_ino & ROMFH_MASK;
610 i->i_op = NULL;
611 i->i_mode = 0;
613 /* Loop for finding the real hard link */
614 for(;;) {
615 if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) {
616 printk("romfs: read error for inode 0x%x\n", ino);
617 return;
619 /* XXX: do romfs_checksum here too (with name) */
621 nextfh = ntohl(ri.next);
622 if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
623 break;
625 ino = ntohl(ri.spec) & ROMFH_MASK;
628 i->i_nlink = 1; /* Hard to decide.. */
629 i->i_size = ntohl(ri.size);
630 i->i_mtime = i->i_atime = i->i_ctime = 0;
631 i->i_uid = i->i_gid = 0;
633 i->i_op = romfs_inoops[nextfh & ROMFH_TYPE];
635 /* Precalculate the data offset */
636 ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
637 if (ino >= 0)
638 ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
639 else
640 ino = 0;
642 i->u.romfs_i.i_metasize = ino;
643 i->u.romfs_i.i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
645 /* Compute permissions */
646 ino = S_IRUGO|S_IWUSR;
647 ino |= romfs_modemap[nextfh & ROMFH_TYPE];
648 if (nextfh & ROMFH_EXEC) {
649 ino |= S_IXUGO;
651 i->i_mode = ino;
653 if (S_ISFIFO(ino))
654 init_fifo(i);
655 else if (S_ISDIR(ino))
656 i->i_size = i->u.romfs_i.i_metasize;
657 else if (S_ISBLK(ino) || S_ISCHR(ino)) {
658 i->i_mode &= ~(S_IRWXG|S_IRWXO);
659 ino = ntohl(ri.spec);
660 i->i_rdev = MKDEV(ino>>16,ino&0xffff);
664 static struct super_operations romfs_ops = {
665 romfs_read_inode, /* read inode */
666 NULL, /* write inode */
667 NULL, /* put inode */
668 NULL, /* delete inode */
669 NULL, /* notify change */
670 romfs_put_super, /* put super */
671 NULL, /* write super */
672 romfs_statfs, /* statfs */
673 NULL /* remount */
676 static struct file_system_type romfs_fs_type = {
677 "romfs",
678 FS_REQUIRES_DEV,
679 romfs_read_super,
680 NULL
683 __initfunc(int init_romfs_fs(void))
685 return register_filesystem(&romfs_fs_type);
688 #ifdef MODULE
690 /* Yes, works even as a module... :) */
692 EXPORT_NO_SYMBOLS;
695 init_module(void)
697 return init_romfs_fs();
700 void
701 cleanup_module(void)
703 unregister_filesystem(&romfs_fs_type);
705 #endif