1 /*
2  * ROMFS file system, Linux implementation
3  *
4  * Copyright (C) 1997-1999  Janos Farkas <chexum@shadow.banki.hu>
5  *
6  * Using parts of the minix filesystem
7  * Copyright (C) 1991, 1992  Linus Torvalds
8  *
9  * and parts of the affs filesystem additionally
10  * Copyright (C) 1993  Ray Burr
11  * Copyright (C) 1996  Hans-Joachim Widmaier
12  *
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.
17  *
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()
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
37  *	Sep 1998	2.1.122		another VFS change (follow_link)
38  *	Apr 1999	2.2.7		no more EBADF checking in
39  *					  lookup/readdir, use ERR_PTR
40  *	Jun 1999	2.3.6		d_alloc_root use changed
41  *			2.3.9		clean up usage of ENOENT/negative
42  *					  dentries in lookup
43  *					clean up page flags setting
44  *					  (error, uptodate, locking) in
45  *					  in readpage
46  *					use init_special_inode for
47  *					  fifos/sockets (and streamline) in
48  *					  read_inode, fix _ops table order
49  *	Aug 1999	2.3.16		__initfunc() => __init change
50  *	Oct 1999	2.3.24		page->owner hack obsoleted
51  *	Nov 1999	2.3.27		2.3.25+ page->offset => index change
52  */
53 
54 /* todo:
55  *	- see Documentation/filesystems/romfs.txt
56  *	- use allocated, not stack memory for file names?
57  *	- considering write access...
58  *	- network (tftp) files?
59  *	- merge back some _op tables
60  */
61 
62 /*
63  * Sorry about some optimizations and for some goto's.  I just wanted
64  * to squeeze some more bytes out of this code.. :)
65  */
66 
67 #include <linux/module.h>
68 #include <linux/types.h>
69 #include <linux/errno.h>
70 #include <linux/slab.h>
71 #include <linux/romfs_fs.h>
72 #include <linux/fs.h>
73 #include <linux/locks.h>
74 #include <linux/init.h>
75 #include <linux/smp_lock.h>
76 
77 #include <asm/uaccess.h>
78 
79 static __s32
romfs_checksum(void * data,int size)80 romfs_checksum(void *data, int size)
81 {
82 	__s32 sum, *ptr;
83 
84 	sum = 0; ptr = data;
85 	size>>=2;
86 	while (size>0) {
87 		sum += ntohl(*ptr++);
88 		size--;
89 	}
90 	return sum;
91 }
92 
93 static struct super_operations romfs_ops;
94 
95 static struct super_block *
romfs_read_super(struct super_block * s,void * data,int silent)96 romfs_read_super(struct super_block *s, void *data, int silent)
97 {
98 	struct buffer_head *bh;
99 	kdev_t dev = s->s_dev;
100 	struct romfs_super_block *rsb;
101 	int sz;
102 
103 	/* I would parse the options here, but there are none.. :) */
104 
105 	set_blocksize(dev, ROMBSIZE);
106 	s->s_blocksize = ROMBSIZE;
107 	s->s_blocksize_bits = ROMBSBITS;
108 	s->u.generic_sbp = (void *) 0;
109 	s->s_maxbytes = 0xFFFFFFFF;
110 
111 	bh = sb_bread(s, 0);
112 	if (!bh) {
113 		/* XXX merge with other printk? */
114                 printk ("romfs: unable to read superblock\n");
115 		goto outnobh;
116 	}
117 
118 	rsb = (struct romfs_super_block *)bh->b_data;
119 	sz = ntohl(rsb->size);
120 	if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1
121 	   || sz < ROMFH_SIZE) {
122 		if (!silent)
123 			printk ("VFS: Can't find a romfs filesystem on dev "
124 				"%s.\n", kdevname(dev));
125 		goto out;
126 	}
127 	if (romfs_checksum(rsb, min_t(int, sz, 512))) {
128 		printk ("romfs: bad initial checksum on dev "
129 			"%s.\n", kdevname(dev));
130 		goto out;
131 	}
132 
133 	s->s_magic = ROMFS_MAGIC;
134 	s->u.romfs_sb.s_maxsize = sz;
135 
136 	s->s_flags |= MS_RDONLY;
137 
138 	/* Find the start of the fs */
139 	sz = (ROMFH_SIZE +
140 	      strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD)
141 	     & ROMFH_MASK;
142 
143 	brelse(bh);
144 
145 	s->s_op	= &romfs_ops;
146 	s->s_root = d_alloc_root(iget(s, sz));
147 
148 	if (!s->s_root)
149 		goto outnobh;
150 
151 	/* Ehrhm; sorry.. :)  And thanks to Hans-Joachim Widmaier  :) */
152 	if (0) {
153 out:
154 		brelse(bh);
155 outnobh:
156 		s = NULL;
157 	}
158 
159 	return s;
160 }
161 
162 /* That's simple too. */
163 
164 static int
romfs_statfs(struct super_block * sb,struct statfs * buf)165 romfs_statfs(struct super_block *sb, struct statfs *buf)
166 {
167 	buf->f_type = ROMFS_MAGIC;
168 	buf->f_bsize = ROMBSIZE;
169 	buf->f_bfree = buf->f_bavail = buf->f_ffree;
170 	buf->f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
171 	buf->f_namelen = ROMFS_MAXFN;
172 	return 0;
173 }
174 
175 /* some helper routines */
176 
177 static int
romfs_strnlen(struct inode * i,unsigned long offset,unsigned long count)178 romfs_strnlen(struct inode *i, unsigned long offset, unsigned long count)
179 {
180 	struct buffer_head *bh;
181 	unsigned long avail, maxsize, res;
182 
183 	maxsize = i->i_sb->u.romfs_sb.s_maxsize;
184 	if (offset >= maxsize)
185 		return -1;
186 
187 	/* strnlen is almost always valid */
188 	if (count > maxsize || offset+count > maxsize)
189 		count = maxsize-offset;
190 
191 	bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
192 	if (!bh)
193 		return -1;		/* error */
194 
195 	avail = ROMBSIZE - (offset & ROMBMASK);
196 	maxsize = min_t(unsigned long, count, avail);
197 	res = strnlen(((char *)bh->b_data)+(offset&ROMBMASK), maxsize);
198 	brelse(bh);
199 
200 	if (res < maxsize)
201 		return res;		/* found all of it */
202 
203 	while (res < count) {
204 		offset += maxsize;
205 
206 		bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
207 		if (!bh)
208 			return -1;
209 		maxsize = min_t(unsigned long, count - res, ROMBSIZE);
210 		avail = strnlen(bh->b_data, maxsize);
211 		res += avail;
212 		brelse(bh);
213 		if (avail < maxsize)
214 			return res;
215 	}
216 	return res;
217 }
218 
219 static int
romfs_copyfrom(struct inode * i,void * dest,unsigned long offset,unsigned long count)220 romfs_copyfrom(struct inode *i, void *dest, unsigned long offset, unsigned long count)
221 {
222 	struct buffer_head *bh;
223 	unsigned long avail, maxsize, res;
224 
225 	maxsize = i->i_sb->u.romfs_sb.s_maxsize;
226 	if (offset >= maxsize || count > maxsize || offset+count>maxsize)
227 		return -1;
228 
229 	bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
230 	if (!bh)
231 		return -1;		/* error */
232 
233 	avail = ROMBSIZE - (offset & ROMBMASK);
234 	maxsize = min_t(unsigned long, count, avail);
235 	memcpy(dest, ((char *)bh->b_data) + (offset & ROMBMASK), maxsize);
236 	brelse(bh);
237 
238 	res = maxsize;			/* all of it */
239 
240 	while (res < count) {
241 		offset += maxsize;
242 		dest += maxsize;
243 
244 		bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
245 		if (!bh)
246 			return -1;
247 		maxsize = min_t(unsigned long, count - res, ROMBSIZE);
248 		memcpy(dest, bh->b_data, maxsize);
249 		brelse(bh);
250 		res += maxsize;
251 	}
252 	return res;
253 }
254 
255 static unsigned char romfs_dtype_table[] = {
256 	DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_SOCK, DT_FIFO
257 };
258 
259 static int
romfs_readdir(struct file * filp,void * dirent,filldir_t filldir)260 romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
261 {
262 	struct inode *i = filp->f_dentry->d_inode;
263 	struct romfs_inode ri;
264 	unsigned long offset, maxoff;
265 	int j, ino, nextfh;
266 	int stored = 0;
267 	char fsname[ROMFS_MAXFN];	/* XXX dynamic? */
268 
269 	maxoff = i->i_sb->u.romfs_sb.s_maxsize;
270 
271 	offset = filp->f_pos;
272 	if (!offset) {
273 		offset = i->i_ino & ROMFH_MASK;
274 		if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
275 			return stored;
276 		offset = ntohl(ri.spec) & ROMFH_MASK;
277 	}
278 
279 	/* Not really failsafe, but we are read-only... */
280 	for(;;) {
281 		if (!offset || offset >= maxoff) {
282 			offset = maxoff;
283 			filp->f_pos = offset;
284 			return stored;
285 		}
286 		filp->f_pos = offset;
287 
288 		/* Fetch inode info */
289 		if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
290 			return stored;
291 
292 		j = romfs_strnlen(i, offset+ROMFH_SIZE, sizeof(fsname)-1);
293 		if (j < 0)
294 			return stored;
295 
296 		fsname[j]=0;
297 		romfs_copyfrom(i, fsname, offset+ROMFH_SIZE, j);
298 
299 		ino = offset;
300 		nextfh = ntohl(ri.next);
301 		if ((nextfh & ROMFH_TYPE) == ROMFH_HRD)
302 			ino = ntohl(ri.spec);
303 		if (filldir(dirent, fsname, j, offset, ino,
304 			    romfs_dtype_table[nextfh & ROMFH_TYPE]) < 0) {
305 			return stored;
306 		}
307 		stored++;
308 		offset = nextfh & ROMFH_MASK;
309 	}
310 }
311 
312 static struct dentry *
romfs_lookup(struct inode * dir,struct dentry * dentry)313 romfs_lookup(struct inode *dir, struct dentry *dentry)
314 {
315 	unsigned long offset, maxoff;
316 	int fslen, res;
317 	struct inode *inode;
318 	char fsname[ROMFS_MAXFN];	/* XXX dynamic? */
319 	struct romfs_inode ri;
320 	const char *name;		/* got from dentry */
321 	int len;
322 
323 	res = -EACCES;			/* placeholder for "no data here" */
324 	offset = dir->i_ino & ROMFH_MASK;
325 	if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
326 		goto out;
327 
328 	maxoff = dir->i_sb->u.romfs_sb.s_maxsize;
329 	offset = ntohl(ri.spec) & ROMFH_MASK;
330 
331 	/* OK, now find the file whose name is in "dentry" in the
332 	 * directory specified by "dir".  */
333 
334 	name = dentry->d_name.name;
335 	len = dentry->d_name.len;
336 
337 	for(;;) {
338 		if (!offset || offset >= maxoff)
339 			goto out0;
340 		if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
341 			goto out;
342 
343 		/* try to match the first 16 bytes of name */
344 		fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE);
345 		if (len < ROMFH_SIZE) {
346 			if (len == fslen) {
347 				/* both are shorter, and same size */
348 				romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
349 				if (strncmp (name, fsname, len) == 0)
350 					break;
351 			}
352 		} else if (fslen >= ROMFH_SIZE) {
353 			/* both are longer; XXX optimize max size */
354 			fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, sizeof(fsname)-1);
355 			if (len == fslen) {
356 				romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
357 				if (strncmp(name, fsname, len) == 0)
358 					break;
359 			}
360 		}
361 		/* next entry */
362 		offset = ntohl(ri.next) & ROMFH_MASK;
363 	}
364 
365 	/* Hard link handling */
366 	if ((ntohl(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
367 		offset = ntohl(ri.spec) & ROMFH_MASK;
368 
369 	if ((inode = iget(dir->i_sb, offset)))
370 		goto outi;
371 
372 	/*
373 	 * it's a bit funky, _lookup needs to return an error code
374 	 * (negative) or a NULL, both as a dentry.  ENOENT should not
375 	 * be returned, instead we need to create a negative dentry by
376 	 * d_add(dentry, NULL); and return 0 as no error.
377 	 * (Although as I see, it only matters on writable file
378 	 * systems).
379 	 */
380 
381 out0:	inode = NULL;
382 outi:	res = 0;
383 	d_add (dentry, inode);
384 
385 out:	return ERR_PTR(res);
386 }
387 
388 /*
389  * Ok, we do readpage, to be able to execute programs.  Unfortunately,
390  * we can't use bmap, since we may have looser alignments.
391  */
392 
393 static int
romfs_readpage(struct file * file,struct page * page)394 romfs_readpage(struct file *file, struct page * page)
395 {
396 	struct inode *inode = page->mapping->host;
397 	unsigned long offset, avail, readlen;
398 	void *buf;
399 	int result = -EIO;
400 
401 	page_cache_get(page);
402 	lock_kernel();
403 	buf = kmap(page);
404 	if (!buf)
405 		goto err_out;
406 
407 	/* 32 bit warning -- but not for us :) */
408 	offset = page->index << PAGE_CACHE_SHIFT;
409 	if (offset < inode->i_size) {
410 		avail = inode->i_size-offset;
411 		readlen = min_t(unsigned long, avail, PAGE_SIZE);
412 		if (romfs_copyfrom(inode, buf, inode->u.romfs_i.i_dataoffset+offset, readlen) == readlen) {
413 			if (readlen < PAGE_SIZE) {
414 				memset(buf + readlen,0,PAGE_SIZE-readlen);
415 			}
416 			SetPageUptodate(page);
417 			result = 0;
418 		}
419 	}
420 	if (result) {
421 		memset(buf, 0, PAGE_SIZE);
422 		SetPageError(page);
423 	}
424 	flush_dcache_page(page);
425 
426 	UnlockPage(page);
427 
428 	kunmap(page);
429 err_out:
430 	page_cache_release(page);
431 	unlock_kernel();
432 
433 	return result;
434 }
435 
436 /* Mapping from our types to the kernel */
437 
438 static struct address_space_operations romfs_aops = {
439 	readpage: romfs_readpage
440 };
441 
442 static struct file_operations romfs_dir_operations = {
443 	read:		generic_read_dir,
444 	readdir:	romfs_readdir,
445 };
446 
447 static struct inode_operations romfs_dir_inode_operations = {
448 	lookup:		romfs_lookup,
449 };
450 
451 static mode_t romfs_modemap[] =
452 {
453 	0, S_IFDIR+0644, S_IFREG+0644, S_IFLNK+0777,
454 	S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
455 };
456 
457 static void
romfs_read_inode(struct inode * i)458 romfs_read_inode(struct inode *i)
459 {
460 	int nextfh, ino;
461 	struct romfs_inode ri;
462 
463 	ino = i->i_ino & ROMFH_MASK;
464 	i->i_mode = 0;
465 
466 	/* Loop for finding the real hard link */
467 	for(;;) {
468 		if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) {
469 			printk("romfs: read error for inode 0x%x\n", ino);
470 			return;
471 		}
472 		/* XXX: do romfs_checksum here too (with name) */
473 
474 		nextfh = ntohl(ri.next);
475 		if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
476 			break;
477 
478 		ino = ntohl(ri.spec) & ROMFH_MASK;
479 	}
480 
481 	i->i_nlink = 1;		/* Hard to decide.. */
482 	i->i_size = ntohl(ri.size);
483 	i->i_mtime = i->i_atime = i->i_ctime = 0;
484 	i->i_uid = i->i_gid = 0;
485 
486         /* Precalculate the data offset */
487         ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
488         if (ino >= 0)
489                 ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
490         else
491                 ino = 0;
492 
493         i->u.romfs_i.i_metasize = ino;
494         i->u.romfs_i.i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
495 
496         /* Compute permissions */
497         ino = romfs_modemap[nextfh & ROMFH_TYPE];
498 	/* only "normal" files have ops */
499 	switch (nextfh & ROMFH_TYPE) {
500 		case 1:
501 			i->i_size = i->u.romfs_i.i_metasize;
502 			i->i_op = &romfs_dir_inode_operations;
503 			i->i_fop = &romfs_dir_operations;
504 			if (nextfh & ROMFH_EXEC)
505 				ino |= S_IXUGO;
506 			i->i_mode = ino;
507 			break;
508 		case 2:
509 			i->i_fop = &generic_ro_fops;
510 			i->i_data.a_ops = &romfs_aops;
511 			if (nextfh & ROMFH_EXEC)
512 				ino |= S_IXUGO;
513 			i->i_mode = ino;
514 			break;
515 		case 3:
516 			i->i_op = &page_symlink_inode_operations;
517 			i->i_data.a_ops = &romfs_aops;
518 			i->i_mode = ino | S_IRWXUGO;
519 			break;
520 		default:
521 			/* depending on MBZ for sock/fifos */
522 			nextfh = ntohl(ri.spec);
523 			nextfh = kdev_t_to_nr(MKDEV(nextfh>>16,nextfh&0xffff));
524 			init_special_inode(i, ino, nextfh);
525 	}
526 }
527 
528 static struct super_operations romfs_ops = {
529 	read_inode:	romfs_read_inode,
530 	statfs:		romfs_statfs,
531 };
532 
533 static DECLARE_FSTYPE_DEV(romfs_fs_type, "romfs", romfs_read_super);
534 
init_romfs_fs(void)535 static int __init init_romfs_fs(void)
536 {
537 	return register_filesystem(&romfs_fs_type);
538 }
539 
exit_romfs_fs(void)540 static void __exit exit_romfs_fs(void)
541 {
542 	unregister_filesystem(&romfs_fs_type);
543 }
544 
545 /* Yes, works even as a module... :) */
546 
547 EXPORT_NO_SYMBOLS;
548 
549 module_init(init_romfs_fs)
550 module_exit(exit_romfs_fs)
551 MODULE_LICENSE("GPL");
552