#include <linux/buffer_head.h>
#include <linux/vfs.h>
#include <linux/parser.h>
+#include <linux/namei.h>
#include "befs.h"
#include "btree.h"
static void befs_destroy_inode(struct inode *inode);
static int befs_init_inodecache(void);
static void befs_destroy_inodecache(void);
-static int befs_readlink(struct dentry *, char __user *, int);
-static int befs_follow_link(struct dentry *, struct nameidata *nd);
+static void *befs_follow_link(struct dentry *, struct nameidata *);
+static void befs_put_link(struct dentry *, struct nameidata *, void *);
static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
char **out, int *out_len);
static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
/* slab cache for befs_inode_info objects */
static kmem_cache_t *befs_inode_cachep;
-struct file_operations befs_dir_operations = {
+static const struct file_operations befs_dir_operations = {
.read = generic_read_dir,
.readdir = befs_readdir,
};
-struct inode_operations befs_dir_inode_operations = {
+static struct inode_operations befs_dir_inode_operations = {
.lookup = befs_lookup,
};
-struct file_operations befs_file_operations = {
- .llseek = default_llseek,
- .read = generic_file_read,
- .mmap = generic_file_readonly_mmap,
-};
-
-struct address_space_operations befs_aops = {
+static struct address_space_operations befs_aops = {
.readpage = befs_readpage,
.sync_page = block_sync_page,
.bmap = befs_bmap,
};
static struct inode_operations befs_symlink_inode_operations = {
- .readlink = befs_readlink,
+ .readlink = generic_readlink,
.follow_link = befs_follow_link,
+ .put_link = befs_put_link,
};
/*
befs_ino->i_inode_num.allocation_group,
befs_ino->i_inode_num.start, befs_ino->i_inode_num.len);
- bh = befs_bread_iaddr(sb, befs_ino->i_inode_num);
+ bh = befs_bread(sb, inode->i_ino);
if (!bh) {
befs_error(sb, "unable to read inode block - "
"inode = %lu", inode->i_ino);
befs_ino->i_attribute = fsrun_to_cpu(sb, raw_inode->attributes);
befs_ino->i_flags = fs32_to_cpu(sb, raw_inode->flags);
- if (S_ISLNK(inode->i_mode) && !(inode->i_flags & BEFS_LONG_SYMLINK)) {
+ if (S_ISLNK(inode->i_mode) && !(befs_ino->i_flags & BEFS_LONG_SYMLINK)){
inode->i_size = 0;
inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE;
strncpy(befs_ino->i_data.symlink, raw_inode->data.symlink,
inode->i_mapping->a_ops = &befs_aops;
if (S_ISREG(inode->i_mode)) {
- inode->i_fop = &befs_file_operations;
+ inode->i_fop = &generic_ro_fops;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &befs_dir_inode_operations;
inode->i_fop = &befs_dir_operations;
{
befs_inode_cachep = kmem_cache_create("befs_inode_cache",
sizeof (struct befs_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, (SLAB_RECLAIM_ACCOUNT|
+ SLAB_MEM_SPREAD),
init_once, NULL);
if (befs_inode_cachep == NULL) {
printk(KERN_ERR "befs_init_inodecache: "
* The data stream become link name. Unless the LONG_SYMLINK
* flag is set.
*/
-static int
+static void *
befs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- struct super_block *sb = dentry->d_sb;
befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
char *link;
- int res;
if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
+ struct super_block *sb = dentry->d_sb;
befs_data_stream *data = &befs_ino->i_data.ds;
- befs_off_t linklen = data->size;
+ befs_off_t len = data->size;
befs_debug(sb, "Follow long symlink");
- link = kmalloc(linklen, GFP_NOFS);
- if (link == NULL)
- return -ENOMEM;
-
- if (befs_read_lsymlink(sb, data, link, linklen) != linklen) {
+ link = kmalloc(len, GFP_NOFS);
+ if (!link) {
+ link = ERR_PTR(-ENOMEM);
+ } else if (befs_read_lsymlink(sb, data, link, len) != len) {
kfree(link);
befs_error(sb, "Failed to read entire long symlink");
- return -EIO;
+ link = ERR_PTR(-EIO);
}
-
- res = vfs_follow_link(nd, link);
-
- kfree(link);
} else {
link = befs_ino->i_data.symlink;
- res = vfs_follow_link(nd, link);
}
- return res;
+ nd_set_link(nd, link);
+ return NULL;
}
-static int
-befs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+static void befs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
{
- struct super_block *sb = dentry->d_sb;
befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
- char *link;
- int res;
-
if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
- befs_data_stream *data = &befs_ino->i_data.ds;
- befs_off_t linklen = data->size;
-
- befs_debug(sb, "Read long symlink");
-
- link = kmalloc(linklen, GFP_NOFS);
- if (link == NULL)
- return -ENOMEM;
-
- if (befs_read_lsymlink(sb, data, link, linklen) != linklen) {
- kfree(link);
- befs_error(sb, "Failed to read entire long symlink");
- return -EIO;
- }
-
- res = vfs_readlink(dentry, buffer, buflen, link);
-
- kfree(link);
- } else {
- link = befs_ino->i_data.symlink;
- res = vfs_readlink(dentry, buffer, buflen, link);
+ char *p = nd_get_link(nd);
+ if (!IS_ERR(p))
+ kfree(p);
}
-
- return res;
}
/*
wchar_t uni;
int unilen, utflen;
char *result;
- int maxlen = in_len; /* The utf8->nls conversion can't make more chars */
+ /* The utf8->nls conversion won't make the final nls string bigger
+ * than the utf one, but if the string is pure ascii they'll have the
+ * same width and an extra char is needed to save the additional \0
+ */
+ int maxlen = in_len + 1;
befs_debug(sb, "---> utf2nls()");
}
/* convert from Unicode to nls */
- unilen = nls->uni2char(uni, &result[o], 1);
+ unilen = nls->uni2char(uni, &result[o], in_len - o);
if (unilen < 0) {
goto conv_err;
}
return o;
conv_err:
- befs_error(sb, "Name using charecter set %s contains a charecter that "
+ befs_error(sb, "Name using character set %s contains a character that "
"cannot be converted to unicode.", nls->charset);
befs_debug(sb, "<--- utf2nls()");
kfree(result);
* @sb: Superblock
* @src: Input string buffer in NLS format
* @srclen: Length of input string in bytes
- * @dest: The output string in UTF8 format
+ * @dest: The output string in UTF-8 format
* @destlen: Length of the output buffer
*
* Converts input string @src, which is in the format of the loaded NLS map,
wchar_t uni;
int unilen, utflen;
char *result;
- int maxlen = 3 * in_len;
+ /* There're nls characters that will translate to 3-chars-wide UTF-8
+ * characters, a additional byte is needed to save the final \0
+ * in special cases */
+ int maxlen = (3 * in_len) + 1;
befs_debug(sb, "---> nls2utf()\n");
static void
befs_put_super(struct super_block *sb)
{
- if (BEFS_SB(sb)->mount_opts.iocharset) {
- kfree(BEFS_SB(sb)->mount_opts.iocharset);
- BEFS_SB(sb)->mount_opts.iocharset = NULL;
- }
+ kfree(BEFS_SB(sb)->mount_opts.iocharset);
+ BEFS_SB(sb)->mount_opts.iocharset = NULL;
if (BEFS_SB(sb)->nls) {
unload_nls(BEFS_SB(sb)->nls);
BEFS_SB(sb)->nls = NULL;
}
- if (sb->s_fs_info) {
- kfree(sb->s_fs_info);
- sb->s_fs_info = NULL;
- }
+ kfree(sb->s_fs_info);
+ sb->s_fs_info = NULL;
return;
}
if (befs_check_sb(sb) != BEFS_OK)
goto unaquire_priv_sbp;
+ if( befs_sb->num_blocks > ~((sector_t)0) ) {
+ befs_error(sb, "blocks count: %Lu "
+ "is larger than the host can use",
+ befs_sb->num_blocks);
+ goto unaquire_priv_sbp;
+ }
+
/*
* set up enough so that it can read an inode
* Fill in kernel superblock fields from private sb
befs_sb->nls = load_nls(befs_sb->mount_opts.iocharset);
if (!befs_sb->nls) {
befs_warning(sb, "Cannot load nls %s"
- "loding default nls",
- befs_sb->mount_opts.iocharset);
+ " loading default nls",
+ befs_sb->mount_opts.iocharset);
befs_sb->nls = load_nls_default();
}
+ /* load default nls if none is specified in mount options */
+ } else {
+ befs_debug(sb, "Loading default nls");
+ befs_sb->nls = load_nls_default();
}
return 0;