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()
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>
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
)
168 /* That's simple too. */
171 romfs_statfs(struct super_block
*sb
, struct statfs
*buf
, int bufsize
)
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 */
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
)
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
);
201 return -1; /* error */
203 avail
= ROMBSIZE
- (offset
& ROMBMASK
);
204 maxsize
= min(count
, avail
);
205 res
= strnlen(((char *)bh
->b_data
)+(offset
&ROMBMASK
), maxsize
);
209 return res
; /* found all of it */
211 while (res
< count
) {
214 bh
= bread(i
->i_dev
, offset
>>ROMBSBITS
, ROMBSIZE
);
217 maxsize
= min(count
-res
, ROMBSIZE
);
218 avail
= strnlen(bh
->b_data
, maxsize
);
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
)
237 bh
= bread(i
->i_dev
, offset
>>ROMBSBITS
, ROMBSIZE
);
239 return -1; /* error */
241 avail
= ROMBSIZE
- (offset
& ROMBMASK
);
242 maxsize
= min(count
, avail
);
243 memcpy(dest
, ((char *)bh
->b_data
) + (offset
& ROMBMASK
), maxsize
);
246 res
= maxsize
; /* all of it */
248 while (res
< count
) {
252 bh
= bread(i
->i_dev
, offset
>>ROMBSBITS
, ROMBSIZE
);
255 maxsize
= min(count
-res
, ROMBSIZE
);
256 memcpy(dest
, bh
->b_data
, maxsize
);
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
;
271 char fsname
[ROMFS_MAXFN
]; /* XXX dynamic? */
273 if (!i
|| !S_ISDIR(i
->i_mode
))
276 maxoff
= i
->i_sb
->u
.romfs_sb
.s_maxsize
;
278 offset
= filp
->f_pos
;
280 offset
= i
->i_ino
& ROMFH_MASK
;
281 if (romfs_copyfrom(i
, &ri
, offset
, ROMFH_SIZE
) <= 0)
283 offset
= ntohl(ri
.spec
) & ROMFH_MASK
;
286 /* Not really failsafe, but we are read-only... */
288 if (!offset
|| offset
>= maxoff
) {
290 filp
->f_pos
= offset
;
293 filp
->f_pos
= offset
;
295 /* Fetch inode info */
296 if (romfs_copyfrom(i
, &ri
, offset
, ROMFH_SIZE
) <= 0)
299 j
= romfs_strnlen(i
, offset
+ROMFH_SIZE
, sizeof(fsname
)-1);
304 romfs_copyfrom(i
, fsname
, offset
+ROMFH_SIZE
, j
);
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) {
314 offset
= nextfh
& ROMFH_MASK
;
319 romfs_lookup(struct inode
*dir
, struct dentry
*dentry
)
321 unsigned long offset
, maxoff
;
324 char fsname
[ROMFS_MAXFN
]; /* XXX dynamic? */
325 struct romfs_inode ri
;
326 const char *name
; /* got from dentry */
330 if (!dir
|| !S_ISDIR(dir
->i_mode
))
333 res
= 0; /* instead of ENOENT */
334 offset
= dir
->i_ino
& ROMFH_MASK
;
335 if (romfs_copyfrom(dir
, &ri
, offset
, ROMFH_SIZE
) <= 0)
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
;
348 if (!offset
|| offset
>= maxoff
349 || romfs_copyfrom(dir
, &ri
, offset
, ROMFH_SIZE
) <= 0)
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
) {
356 /* both are shorter, and same size */
357 romfs_copyfrom(dir
, fsname
, offset
+ROMFH_SIZE
, len
+1);
358 if (strncmp (name
, fsname
, len
) == 0)
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);
365 romfs_copyfrom(dir
, fsname
, offset
+ROMFH_SIZE
, len
+1);
366 if (strncmp(name
, fsname
, len
) == 0)
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
) {
381 d_add(dentry
, inode
);
389 * Ok, we do readpage, to be able to execute programs. Unfortunately,
390 * we can't use bmap, since we have looser alignments.
394 romfs_readpage(struct inode
* inode
, struct page
* page
)
397 unsigned long offset
, avail
, readlen
;
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
);
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
);
431 romfs_readlink(struct inode
*inode
, char *buffer
, int len
)
434 char buf
[ROMFS_MAXFN
]; /* XXX dynamic */
436 if (!inode
|| !S_ISLNK(inode
->i_mode
)) {
441 mylen
= min(sizeof(buf
), inode
->i_size
);
443 if (romfs_copyfrom(inode
, buf
, inode
->u
.romfs_i
.i_dataoffset
, mylen
) <= 0) {
447 copy_to_user(buffer
, buf
, mylen
);
453 static struct dentry
*romfs_follow_link(struct inode
*inode
, struct dentry
*base
)
457 struct dentry
*dentry
;
461 dentry
= ERR_PTR(-EAGAIN
); /* correct? */
462 if (!(link
= kmalloc(len
+1, GFP_KERNEL
)))
465 cnt
= romfs_copyfrom(inode
, link
, inode
->u
.romfs_i
.i_dataoffset
, len
);
467 dentry
= ERR_PTR(-EIO
);
472 dentry
= lookup_dentry(link
, base
, 1);
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 */
491 NULL
, /* poll - default */
493 generic_file_mmap
, /* mmap */
498 NULL
, /* check_media_change */
499 NULL
/* revalidate */
502 static struct inode_operations romfs_file_inode_operations
= {
503 &romfs_file_operations
,
514 NULL
, /* follow_link */
515 romfs_readpage
, /* readpage */
516 NULL
, /* writepage */
517 NULL
, /* bmap -- not really */
519 NULL
, /* permission */
523 static struct file_operations romfs_dir_operations
= {
524 NULL
, /* lseek - default */
526 NULL
, /* write - bad */
527 romfs_readdir
, /* readdir */
528 NULL
, /* poll - default */
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
,
546 romfs_lookup
, /* lookup */
555 NULL
, /* follow_link */
557 NULL
, /* writepage */
560 NULL
, /* permission */
564 static struct inode_operations romfs_link_inode_operations
= {
565 NULL
, /* no file operations on symlinks */
575 romfs_readlink
, /* readlink */
576 romfs_follow_link
, /* follow_link */
578 NULL
, /* writepage */
581 NULL
, /* permission */
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
,
604 romfs_read_inode(struct inode
*i
)
607 struct romfs_inode ri
;
609 ino
= i
->i_ino
& ROMFH_MASK
;
613 /* Loop for finding the real hard link */
615 if (romfs_copyfrom(i
, &ri
, ino
, ROMFH_SIZE
) <= 0) {
616 printk("romfs: read error for inode 0x%x\n", ino
);
619 /* XXX: do romfs_checksum here too (with name) */
621 nextfh
= ntohl(ri
.next
);
622 if ((nextfh
& ROMFH_TYPE
) != ROMFH_HRD
)
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
);
638 ino
= ((ROMFH_SIZE
+ino
+1+ROMFH_PAD
)&ROMFH_MASK
);
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
) {
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 */
676 static struct file_system_type romfs_fs_type
= {
683 __initfunc(int init_romfs_fs(void))
685 return register_filesystem(&romfs_fs_type
);
690 /* Yes, works even as a module... :) */
697 return init_romfs_fs();
703 unregister_filesystem(&romfs_fs_type
);