/* * fill in the superblock */ static int romfs_fill_super(struct super_block *sb, void *data, int silent) { struct romfs_super_block *rsb; struct inode *root; unsigned long pos, img_size; const char *storage; size_t len; int ret; #ifdef CONFIG_BLOCK if (!sb->s_mtd) { sb_set_blocksize(sb, ROMBSIZE); } else { sb->s_blocksize = ROMBSIZE; sb->s_blocksize_bits = blksize_bits(ROMBSIZE); } #endif sb->s_maxbytes = 0xFFFFFFFF; sb->s_magic = ROMFS_MAGIC; sb->s_flags |= MS_RDONLY | MS_NOATIME; sb->s_op = &romfs_super_ops; /* read the image superblock and check it */ rsb = kmalloc(512, GFP_KERNEL); if (!rsb) return -ENOMEM; sb->s_fs_info = (void *) 512; ret = romfs_dev_read(sb, 0, rsb, 512); if (ret < 0) goto error_rsb; img_size = be32_to_cpu(rsb->size); if (sb->s_mtd && img_size > sb->s_mtd->size) goto error_rsb_inval; sb->s_fs_info = (void *) img_size; if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1 || img_size < ROMFH_SIZE) { if (!silent) printk(KERN_WARNING "VFS:" " Can't find a romfs filesystem on dev %s.\n", sb->s_id); goto error_rsb_inval; } if (romfs_checksum(rsb, min_t(size_t, img_size, 512))) { printk(KERN_ERR "ROMFS: bad initial checksum on dev %s.\n", sb->s_id); goto error_rsb_inval; } storage = sb->s_mtd ? "MTD" : "the block layer"; len = strnlen(rsb->name, ROMFS_MAXFN); if (!silent) printk(KERN_NOTICE "ROMFS: Mounting image '%*.*s' through %s\n", (unsigned) len, (unsigned) len, rsb->name, storage); kfree(rsb); rsb = NULL; /* find the root directory */ pos = (ROMFH_SIZE + len + 1 + ROMFH_PAD) & ROMFH_MASK; root = romfs_iget(sb, pos); if (IS_ERR(root)) goto error; sb->s_root = d_alloc_root(root); if (!sb->s_root) goto error_i; return 0; error_i: iput(root); error: return -EINVAL; error_rsb_inval: ret = -EINVAL; error_rsb: kfree(rsb); return ret; }
static struct dentry * romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { unsigned long offset, maxoff; long res; int fslen; struct inode *inode = NULL; char fsname[ROMFS_MAXFN]; /* XXX dynamic? */ struct romfs_inode ri; const char *name; /* got from dentry */ int len; res = -EACCES; /* placeholder for "no data here" */ offset = dir->i_ino & ROMFH_MASK; lock_kernel(); if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) goto error; maxoff = romfs_maxsize(dir->i_sb); offset = be32_to_cpu(ri.spec) & ROMFH_MASK; /* OK, now find the file whose name is in "dentry" in the * directory specified by "dir". */ name = dentry->d_name.name; len = dentry->d_name.len; for(;;) { if (!offset || offset >= maxoff) goto success; /* negative success */ if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) goto error; /* try to match the first 16 bytes of name */ fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE); if (len < ROMFH_SIZE) { if (len == fslen) { /* both are shorter, and same size */ romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1); if (strncmp (name, fsname, len) == 0) break; } } else if (fslen >= ROMFH_SIZE) { /* both are longer; XXX optimize max size */ fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, sizeof(fsname)-1); if (len == fslen) { romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1); if (strncmp(name, fsname, len) == 0) break; } } /* next entry */ offset = be32_to_cpu(ri.next) & ROMFH_MASK; } /* Hard link handling */ if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD) offset = be32_to_cpu(ri.spec) & ROMFH_MASK; inode = romfs_iget(dir->i_sb, offset); if (IS_ERR(inode)) { res = PTR_ERR(inode); goto error; } success: d_add(dentry, inode); res = 0; error: unlock_kernel(); return ERR_PTR(res); }
/* * look up an entry in a directory */ static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { unsigned long offset, maxoff; struct inode *inode; struct romfs_inode ri; const char *name; /* got from dentry */ int len, ret; offset = dir->i_ino & ROMFH_MASK; ret = romfs_dev_read(dir->i_sb, offset, &ri, ROMFH_SIZE); if (ret < 0) goto error; /* search all the file entries in the list starting from the one * pointed to by the directory's special data */ maxoff = romfs_maxsize(dir->i_sb); offset = be32_to_cpu(ri.spec) & ROMFH_MASK; name = dentry->d_name.name; len = dentry->d_name.len; for (;;) { if (!offset || offset >= maxoff) goto out0; ret = romfs_dev_read(dir->i_sb, offset, &ri, sizeof(ri)); if (ret < 0) goto error; /* try to match the first 16 bytes of name */ ret = romfs_dev_strcmp(dir->i_sb, offset + ROMFH_SIZE, name, len); if (ret < 0) goto error; if (ret == 1) break; /* next entry */ offset = be32_to_cpu(ri.next) & ROMFH_MASK; } /* Hard link handling */ if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD) offset = be32_to_cpu(ri.spec) & ROMFH_MASK; inode = romfs_iget(dir->i_sb, offset); if (IS_ERR(inode)) { ret = PTR_ERR(inode); goto error; } goto outi; /* * it's a bit funky, _lookup needs to return an error code * (negative) or a NULL, both as a dentry. ENOENT should not * be returned, instead we need to create a negative dentry by * d_add(dentry, NULL); and return 0 as no error. * (Although as I see, it only matters on writable file * systems). */ out0: inode = NULL; outi: d_add(dentry, inode); ret = 0; error: return ERR_PTR(ret); }
static int romfs_fill_super(struct super_block *s, void *data, int silent) { struct buffer_head *bh; struct romfs_super_block *rsb; struct inode *root; int sz, ret = -EINVAL; /* I would parse the options here, but there are none.. :) */ sb_set_blocksize(s, ROMBSIZE); s->s_maxbytes = 0xFFFFFFFF; bh = sb_bread(s, 0); if (!bh) { /* XXX merge with other printk? */ printk ("romfs: unable to read superblock\n"); goto outnobh; } rsb = (struct romfs_super_block *)bh->b_data; sz = be32_to_cpu(rsb->size); if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1 || sz < ROMFH_SIZE) { if (!silent) printk ("VFS: Can't find a romfs filesystem on dev " "%s.\n", s->s_id); goto out; } if (romfs_checksum(rsb, min_t(int, sz, 512))) { printk ("romfs: bad initial checksum on dev " "%s.\n", s->s_id); goto out; } s->s_magic = ROMFS_MAGIC; s->s_fs_info = (void *)(long)sz; s->s_flags |= MS_RDONLY; /* Find the start of the fs */ sz = (ROMFH_SIZE + strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD) & ROMFH_MASK; s->s_op = &romfs_ops; root = romfs_iget(s, sz); if (IS_ERR(root)) { ret = PTR_ERR(root); goto out; } ret = -ENOMEM; s->s_root = d_alloc_root(root); if (!s->s_root) goto outiput; brelse(bh); return 0; outiput: iput(root); out: brelse(bh); outnobh: return ret; }