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.
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
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()
33 * Jun 1998 2.1.106 from Avery Pennarun: glibc scandir()
34 * exposed a problem in readdir
35 * 2.1.107 code-freeze spellchecker run
36 * Aug 1998 2.1.118+ VFS changes
40 * - see Documentation/filesystems/romfs.txt
41 * - use allocated, not stack memory for file names?
42 * - considering write access...
43 * - network (tftp) files?
44 * - merge back some _op tables
48 * Sorry about some optimizations and for some goto's. I just wanted
49 * to squeeze some more bytes out of this code.. :)
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>
58 #include <linux/locks.h>
59 #include <linux/init.h>
61 #include <asm/uaccess.h>
63 static int inline min(int a
, int b
)
69 romfs_checksum(void *data
, int size
)
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
;
94 /* I would parse the options here, but there are none.. :) */
97 set_blocksize(dev
, ROMBSIZE
);
98 s
->s_blocksize
= ROMBSIZE
;
99 s
->s_blocksize_bits
= ROMBSBITS
;
100 bh
= bread(dev
, 0, ROMBSIZE
);
102 /* XXX merge with other printk? */
103 printk ("romfs: unable to read superblock\n");
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
) {
112 printk ("VFS: Can't find a romfs filesystem on dev "
113 "%s.\n", kdevname(dev
));
116 if (romfs_checksum(rsb
, min(sz
,512))) {
117 printk ("romfs: bad initial checksum on dev "
118 "%s.\n", kdevname(dev
));
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 */
129 strnlen(rsb
->name
, ROMFS_MAXFN
) + 1 + ROMFH_PAD
)
134 s
->s_op
= &romfs_ops
;
135 s
->s_root
= d_alloc_root(iget(s
, sz
), NULL
);
142 /* Ehrhm; sorry.. :) And thanks to Hans-Joachim Widmaier :) */
156 /* Nothing to do.. */
159 romfs_put_super(struct super_block
*sb
)
165 /* That's simple too. */
168 romfs_statfs(struct super_block
*sb
, struct statfs
*buf
, int bufsize
)
172 memset(&tmp
, 0, sizeof(tmp
));
173 tmp
.f_type
= ROMFS_MAGIC
;
174 tmp
.f_bsize
= ROMBSIZE
;
175 tmp
.f_blocks
= (sb
->u
.romfs_sb
.s_maxsize
+ROMBSIZE
-1)>>ROMBSBITS
;
176 tmp
.f_namelen
= ROMFS_MAXFN
;
177 return copy_to_user(buf
, &tmp
, bufsize
) ? -EFAULT
: 0;
180 /* some helper routines */
183 romfs_strnlen(struct inode
*i
, unsigned long offset
, unsigned long count
)
185 struct buffer_head
*bh
;
186 unsigned long avail
, maxsize
, res
;
188 maxsize
= i
->i_sb
->u
.romfs_sb
.s_maxsize
;
189 if (offset
>= maxsize
)
192 /* strnlen is almost always valid */
193 if (count
> maxsize
|| offset
+count
> maxsize
)
194 count
= maxsize
-offset
;
196 bh
= bread(i
->i_dev
, offset
>>ROMBSBITS
, ROMBSIZE
);
198 return -1; /* error */
200 avail
= ROMBSIZE
- (offset
& ROMBMASK
);
201 maxsize
= min(count
, avail
);
202 res
= strnlen(((char *)bh
->b_data
)+(offset
&ROMBMASK
), maxsize
);
206 return res
; /* found all of it */
208 while (res
< count
) {
211 bh
= bread(i
->i_dev
, offset
>>ROMBSBITS
, ROMBSIZE
);
214 maxsize
= min(count
-res
, ROMBSIZE
);
215 avail
= strnlen(bh
->b_data
, maxsize
);
225 romfs_copyfrom(struct inode
*i
, void *dest
, unsigned long offset
, unsigned long count
)
227 struct buffer_head
*bh
;
228 unsigned long avail
, maxsize
, res
;
230 maxsize
= i
->i_sb
->u
.romfs_sb
.s_maxsize
;
231 if (offset
>= maxsize
|| count
> maxsize
|| offset
+count
>maxsize
)
234 bh
= bread(i
->i_dev
, offset
>>ROMBSBITS
, ROMBSIZE
);
236 return -1; /* error */
238 avail
= ROMBSIZE
- (offset
& ROMBMASK
);
239 maxsize
= min(count
, avail
);
240 memcpy(dest
, ((char *)bh
->b_data
) + (offset
& ROMBMASK
), maxsize
);
243 res
= maxsize
; /* all of it */
245 while (res
< count
) {
249 bh
= bread(i
->i_dev
, offset
>>ROMBSBITS
, ROMBSIZE
);
252 maxsize
= min(count
-res
, ROMBSIZE
);
253 memcpy(dest
, bh
->b_data
, maxsize
);
261 romfs_readdir(struct file
*filp
, void *dirent
, filldir_t filldir
)
263 struct inode
*i
= filp
->f_dentry
->d_inode
;
264 struct romfs_inode ri
;
265 unsigned long offset
, maxoff
;
268 char fsname
[ROMFS_MAXFN
]; /* XXX dynamic? */
270 maxoff
= i
->i_sb
->u
.romfs_sb
.s_maxsize
;
272 offset
= filp
->f_pos
;
274 offset
= i
->i_ino
& ROMFH_MASK
;
275 if (romfs_copyfrom(i
, &ri
, offset
, ROMFH_SIZE
) <= 0)
277 offset
= ntohl(ri
.spec
) & ROMFH_MASK
;
280 /* Not really failsafe, but we are read-only... */
282 if (!offset
|| offset
>= maxoff
) {
284 filp
->f_pos
= offset
;
287 filp
->f_pos
= offset
;
289 /* Fetch inode info */
290 if (romfs_copyfrom(i
, &ri
, offset
, ROMFH_SIZE
) <= 0)
293 j
= romfs_strnlen(i
, offset
+ROMFH_SIZE
, sizeof(fsname
)-1);
298 romfs_copyfrom(i
, fsname
, offset
+ROMFH_SIZE
, j
);
301 nextfh
= ntohl(ri
.next
);
302 if ((nextfh
& ROMFH_TYPE
) == ROMFH_HRD
)
303 ino
= ntohl(ri
.spec
);
304 if (filldir(dirent
, fsname
, j
, offset
, ino
) < 0) {
308 offset
= nextfh
& ROMFH_MASK
;
312 static struct dentry
*
313 romfs_lookup(struct inode
*dir
, struct dentry
*dentry
)
315 unsigned long offset
, maxoff
;
318 char fsname
[ROMFS_MAXFN
]; /* XXX dynamic? */
319 struct romfs_inode ri
;
320 const char *name
; /* got from dentry */
323 res
= 0; /* instead of ENOENT */
324 offset
= dir
->i_ino
& ROMFH_MASK
;
325 if (romfs_copyfrom(dir
, &ri
, offset
, ROMFH_SIZE
) <= 0)
328 maxoff
= dir
->i_sb
->u
.romfs_sb
.s_maxsize
;
329 offset
= ntohl(ri
.spec
) & ROMFH_MASK
;
331 /* OK, now find the file whose name is in "dentry" in the
332 * directory specified by "dir". */
334 name
= dentry
->d_name
.name
;
335 len
= dentry
->d_name
.len
;
338 if (!offset
|| offset
>= maxoff
339 || romfs_copyfrom(dir
, &ri
, offset
, ROMFH_SIZE
) <= 0)
342 /* try to match the first 16 bytes of name */
343 fslen
= romfs_strnlen(dir
, offset
+ROMFH_SIZE
, ROMFH_SIZE
);
344 if (len
< ROMFH_SIZE
) {
346 /* both are shorter, and same size */
347 romfs_copyfrom(dir
, fsname
, offset
+ROMFH_SIZE
, len
+1);
348 if (strncmp (name
, fsname
, len
) == 0)
351 } else if (fslen
>= ROMFH_SIZE
) {
352 /* both are longer; XXX optimize max size */
353 fslen
= romfs_strnlen(dir
, offset
+ROMFH_SIZE
, sizeof(fsname
)-1);
355 romfs_copyfrom(dir
, fsname
, offset
+ROMFH_SIZE
, len
+1);
356 if (strncmp(name
, fsname
, len
) == 0)
361 offset
= ntohl(ri
.next
) & ROMFH_MASK
;
364 /* Hard link handling */
365 if ((ntohl(ri
.next
) & ROMFH_TYPE
) == ROMFH_HRD
)
366 offset
= ntohl(ri
.spec
) & ROMFH_MASK
;
368 if ((inode
= iget(dir
->i_sb
, offset
))==NULL
) {
371 d_add(dentry
, inode
);
379 * Ok, we do readpage, to be able to execute programs. Unfortunately,
380 * we can't use bmap, since we have looser alignments.
384 romfs_readpage(struct file
* file
, struct page
* page
)
386 struct dentry
*dentry
= file
->f_dentry
;
387 struct inode
*inode
= dentry
->d_inode
;
389 unsigned long offset
, avail
, readlen
;
392 atomic_inc(&page
->count
);
393 set_bit(PG_locked
, &page
->flags
);
395 buf
= page_address(page
);
396 clear_bit(PG_uptodate
, &page
->flags
);
397 clear_bit(PG_error
, &page
->flags
);
398 offset
= page
->offset
;
399 if (offset
< inode
->i_size
) {
400 avail
= inode
->i_size
-offset
;
401 readlen
= min(avail
, PAGE_SIZE
);
402 if (romfs_copyfrom(inode
, (void *)buf
, inode
->u
.romfs_i
.i_dataoffset
+offset
, readlen
) == readlen
) {
403 if (readlen
< PAGE_SIZE
) {
404 memset((void *)(buf
+readlen
),0,PAGE_SIZE
-readlen
);
406 set_bit(PG_uptodate
, &page
->flags
);
411 set_bit(PG_error
, &page
->flags
);
412 memset((void *)buf
, 0, PAGE_SIZE
);
415 clear_bit(PG_locked
, &page
->flags
);
416 wake_up(&page
->wait
);
423 romfs_readlink(struct dentry
*dentry
, char *buffer
, int len
)
425 struct inode
*inode
= dentry
->d_inode
;
427 char buf
[ROMFS_MAXFN
]; /* XXX dynamic */
429 if (!inode
|| !S_ISLNK(inode
->i_mode
)) {
434 mylen
= min(sizeof(buf
), inode
->i_size
);
436 if (romfs_copyfrom(inode
, buf
, inode
->u
.romfs_i
.i_dataoffset
, mylen
) <= 0) {
440 copy_to_user(buffer
, buf
, mylen
);
446 static struct dentry
*romfs_follow_link(struct dentry
*dentry
,
450 struct inode
*inode
= dentry
->d_inode
;
456 dentry
= ERR_PTR(-EAGAIN
); /* correct? */
457 if (!(link
= kmalloc(len
+1, GFP_KERNEL
)))
460 cnt
= romfs_copyfrom(inode
, link
, inode
->u
.romfs_i
.i_dataoffset
, len
);
462 dentry
= ERR_PTR(-EIO
);
467 dentry
= lookup_dentry(link
, base
, follow
);
479 /* Mapping from our types to the kernel */
481 static struct file_operations romfs_file_operations
= {
482 NULL
, /* lseek - default */
483 generic_file_read
, /* read */
484 NULL
, /* write - bad */
486 NULL
, /* poll - default */
488 generic_file_mmap
, /* mmap */
494 NULL
, /* check_media_change */
495 NULL
/* revalidate */
498 static struct inode_operations romfs_file_inode_operations
= {
499 &romfs_file_operations
,
510 NULL
, /* follow_link */
511 romfs_readpage
, /* readpage */
512 NULL
, /* writepage */
513 NULL
, /* bmap -- not really */
515 NULL
, /* permission */
519 static struct file_operations romfs_dir_operations
= {
520 NULL
, /* lseek - default */
522 NULL
, /* write - bad */
523 romfs_readdir
, /* readdir */
524 NULL
, /* poll - default */
532 NULL
, /* check_media_change */
533 NULL
/* revalidate */
536 /* Merged dir/symlink op table. readdir/lookup/readlink/follow_link
537 * will protect from type mismatch.
540 static struct inode_operations romfs_dir_inode_operations
= {
541 &romfs_dir_operations
,
543 romfs_lookup
, /* lookup */
552 NULL
, /* follow_link */
554 NULL
, /* writepage */
557 NULL
, /* permission */
561 static struct inode_operations romfs_link_inode_operations
= {
562 NULL
, /* no file operations on symlinks */
572 romfs_readlink
, /* readlink */
573 romfs_follow_link
, /* follow_link */
575 NULL
, /* writepage */
578 NULL
, /* permission */
582 static mode_t romfs_modemap
[] =
584 0, S_IFDIR
, S_IFREG
, S_IFLNK
+0777,
585 S_IFBLK
, S_IFCHR
, S_IFSOCK
, S_IFIFO
588 static struct inode_operations
*romfs_inoops
[] =
590 NULL
, /* hardlink, handled elsewhere */
591 &romfs_dir_inode_operations
,
592 &romfs_file_inode_operations
,
593 &romfs_link_inode_operations
,
594 &blkdev_inode_operations
, /* standard handlers */
595 &chrdev_inode_operations
,
601 romfs_read_inode(struct inode
*i
)
604 struct romfs_inode ri
;
606 ino
= i
->i_ino
& ROMFH_MASK
;
610 /* Loop for finding the real hard link */
612 if (romfs_copyfrom(i
, &ri
, ino
, ROMFH_SIZE
) <= 0) {
613 printk("romfs: read error for inode 0x%x\n", ino
);
616 /* XXX: do romfs_checksum here too (with name) */
618 nextfh
= ntohl(ri
.next
);
619 if ((nextfh
& ROMFH_TYPE
) != ROMFH_HRD
)
622 ino
= ntohl(ri
.spec
) & ROMFH_MASK
;
625 i
->i_nlink
= 1; /* Hard to decide.. */
626 i
->i_size
= ntohl(ri
.size
);
627 i
->i_mtime
= i
->i_atime
= i
->i_ctime
= 0;
628 i
->i_uid
= i
->i_gid
= 0;
630 i
->i_op
= romfs_inoops
[nextfh
& ROMFH_TYPE
];
632 /* Precalculate the data offset */
633 ino
= romfs_strnlen(i
, ino
+ROMFH_SIZE
, ROMFS_MAXFN
);
635 ino
= ((ROMFH_SIZE
+ino
+1+ROMFH_PAD
)&ROMFH_MASK
);
639 i
->u
.romfs_i
.i_metasize
= ino
;
640 i
->u
.romfs_i
.i_dataoffset
= ino
+(i
->i_ino
&ROMFH_MASK
);
642 /* Compute permissions */
643 ino
= S_IRUGO
|S_IWUSR
;
644 ino
|= romfs_modemap
[nextfh
& ROMFH_TYPE
];
645 if (nextfh
& ROMFH_EXEC
) {
652 else if (S_ISDIR(ino
))
653 i
->i_size
= i
->u
.romfs_i
.i_metasize
;
654 else if (S_ISBLK(ino
) || S_ISCHR(ino
)) {
655 i
->i_mode
&= ~(S_IRWXG
|S_IRWXO
);
656 ino
= ntohl(ri
.spec
);
657 i
->i_rdev
= MKDEV(ino
>>16,ino
&0xffff);
661 static struct super_operations romfs_ops
= {
662 romfs_read_inode
, /* read inode */
663 NULL
, /* write inode */
664 NULL
, /* put inode */
665 NULL
, /* delete inode */
666 NULL
, /* notify change */
667 romfs_put_super
, /* put super */
668 NULL
, /* write super */
669 romfs_statfs
, /* statfs */
673 static struct file_system_type romfs_fs_type
= {
680 __initfunc(int init_romfs_fs(void))
682 return register_filesystem(&romfs_fs_type
);
687 /* Yes, works even as a module... :) */
694 return init_romfs_fs();
700 unregister_filesystem(&romfs_fs_type
);