diff options
Diffstat (limited to 'ANDROID_3.4.5/fs/omfs/dir.c')
-rw-r--r-- | ANDROID_3.4.5/fs/omfs/dir.c | 475 |
1 files changed, 0 insertions, 475 deletions
diff --git a/ANDROID_3.4.5/fs/omfs/dir.c b/ANDROID_3.4.5/fs/omfs/dir.c deleted file mode 100644 index f00576ec..00000000 --- a/ANDROID_3.4.5/fs/omfs/dir.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * OMFS (as used by RIO Karma) directory operations. - * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com> - * Released under GPL v2. - */ - -#include <linux/fs.h> -#include <linux/ctype.h> -#include <linux/buffer_head.h> -#include "omfs.h" - -static int omfs_hash(const char *name, int namelen, int mod) -{ - int i, hash = 0; - for (i = 0; i < namelen; i++) - hash ^= tolower(name[i]) << (i % 24); - return hash % mod; -} - -/* - * Finds the bucket for a given name and reads the containing block; - * *ofs is set to the offset of the first list entry. - */ -static struct buffer_head *omfs_get_bucket(struct inode *dir, - const char *name, int namelen, int *ofs) -{ - int nbuckets = (dir->i_size - OMFS_DIR_START)/8; - int bucket = omfs_hash(name, namelen, nbuckets); - - *ofs = OMFS_DIR_START + bucket * 8; - return omfs_bread(dir->i_sb, dir->i_ino); -} - -static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, - const char *name, int namelen, - u64 *prev_block) -{ - struct buffer_head *bh; - struct omfs_inode *oi; - int err = -ENOENT; - *prev_block = ~0; - - while (block != ~0) { - bh = omfs_bread(dir->i_sb, block); - if (!bh) { - err = -EIO; - goto err; - } - - oi = (struct omfs_inode *) bh->b_data; - if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, block)) { - brelse(bh); - goto err; - } - - if (strncmp(oi->i_name, name, namelen) == 0) - return bh; - - *prev_block = block; - block = be64_to_cpu(oi->i_sibling); - brelse(bh); - } -err: - return ERR_PTR(err); -} - -static struct buffer_head *omfs_find_entry(struct inode *dir, - const char *name, int namelen) -{ - struct buffer_head *bh; - int ofs; - u64 block, dummy; - - bh = omfs_get_bucket(dir, name, namelen, &ofs); - if (!bh) - return ERR_PTR(-EIO); - - block = be64_to_cpu(*((__be64 *) &bh->b_data[ofs])); - brelse(bh); - - return omfs_scan_list(dir, block, name, namelen, &dummy); -} - -int omfs_make_empty(struct inode *inode, struct super_block *sb) -{ - struct omfs_sb_info *sbi = OMFS_SB(sb); - struct buffer_head *bh; - struct omfs_inode *oi; - - bh = omfs_bread(sb, inode->i_ino); - if (!bh) - return -ENOMEM; - - memset(bh->b_data, 0, sizeof(struct omfs_inode)); - - if (S_ISDIR(inode->i_mode)) { - memset(&bh->b_data[OMFS_DIR_START], 0xff, - sbi->s_sys_blocksize - OMFS_DIR_START); - } else - omfs_make_empty_table(bh, OMFS_EXTENT_START); - - oi = (struct omfs_inode *) bh->b_data; - oi->i_head.h_self = cpu_to_be64(inode->i_ino); - oi->i_sibling = ~cpu_to_be64(0ULL); - - mark_buffer_dirty(bh); - brelse(bh); - return 0; -} - -static int omfs_add_link(struct dentry *dentry, struct inode *inode) -{ - struct inode *dir = dentry->d_parent->d_inode; - const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; - struct omfs_inode *oi; - struct buffer_head *bh; - u64 block; - __be64 *entry; - int ofs; - - /* just prepend to head of queue in proper bucket */ - bh = omfs_get_bucket(dir, name, namelen, &ofs); - if (!bh) - goto out; - - entry = (__be64 *) &bh->b_data[ofs]; - block = be64_to_cpu(*entry); - *entry = cpu_to_be64(inode->i_ino); - mark_buffer_dirty(bh); - brelse(bh); - - /* now set the sibling and parent pointers on the new inode */ - bh = omfs_bread(dir->i_sb, inode->i_ino); - if (!bh) - goto out; - - oi = (struct omfs_inode *) bh->b_data; - memcpy(oi->i_name, name, namelen); - memset(oi->i_name + namelen, 0, OMFS_NAMELEN - namelen); - oi->i_sibling = cpu_to_be64(block); - oi->i_parent = cpu_to_be64(dir->i_ino); - mark_buffer_dirty(bh); - brelse(bh); - - dir->i_ctime = CURRENT_TIME_SEC; - - /* mark affected inodes dirty to rebuild checksums */ - mark_inode_dirty(dir); - mark_inode_dirty(inode); - return 0; -out: - return -ENOMEM; -} - -static int omfs_delete_entry(struct dentry *dentry) -{ - struct inode *dir = dentry->d_parent->d_inode; - struct inode *dirty; - const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; - struct omfs_inode *oi; - struct buffer_head *bh, *bh2; - __be64 *entry, next; - u64 block, prev; - int ofs; - int err = -ENOMEM; - - /* delete the proper node in the bucket's linked list */ - bh = omfs_get_bucket(dir, name, namelen, &ofs); - if (!bh) - goto out; - - entry = (__be64 *) &bh->b_data[ofs]; - block = be64_to_cpu(*entry); - - bh2 = omfs_scan_list(dir, block, name, namelen, &prev); - if (IS_ERR(bh2)) { - err = PTR_ERR(bh2); - goto out_free_bh; - } - - oi = (struct omfs_inode *) bh2->b_data; - next = oi->i_sibling; - brelse(bh2); - - if (prev != ~0) { - /* found in middle of list, get list ptr */ - brelse(bh); - bh = omfs_bread(dir->i_sb, prev); - if (!bh) - goto out; - - oi = (struct omfs_inode *) bh->b_data; - entry = &oi->i_sibling; - } - - *entry = next; - mark_buffer_dirty(bh); - - if (prev != ~0) { - dirty = omfs_iget(dir->i_sb, prev); - if (!IS_ERR(dirty)) { - mark_inode_dirty(dirty); - iput(dirty); - } - } - - err = 0; -out_free_bh: - brelse(bh); -out: - return err; -} - -static int omfs_dir_is_empty(struct inode *inode) -{ - int nbuckets = (inode->i_size - OMFS_DIR_START) / 8; - struct buffer_head *bh; - u64 *ptr; - int i; - - bh = omfs_bread(inode->i_sb, inode->i_ino); - - if (!bh) - return 0; - - ptr = (u64 *) &bh->b_data[OMFS_DIR_START]; - - for (i = 0; i < nbuckets; i++, ptr++) - if (*ptr != ~0) - break; - - brelse(bh); - return *ptr != ~0; -} - -static int omfs_remove(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - int ret; - - - if (S_ISDIR(inode->i_mode) && - !omfs_dir_is_empty(inode)) - return -ENOTEMPTY; - - ret = omfs_delete_entry(dentry); - if (ret) - return ret; - - clear_nlink(inode); - mark_inode_dirty(inode); - mark_inode_dirty(dir); - return 0; -} - -static int omfs_add_node(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - int err; - struct inode *inode = omfs_new_inode(dir, mode); - - if (IS_ERR(inode)) - return PTR_ERR(inode); - - err = omfs_make_empty(inode, dir->i_sb); - if (err) - goto out_free_inode; - - err = omfs_add_link(dentry, inode); - if (err) - goto out_free_inode; - - d_instantiate(dentry, inode); - return 0; - -out_free_inode: - iput(inode); - return err; -} - -static int omfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - return omfs_add_node(dir, dentry, mode | S_IFDIR); -} - -static int omfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, - struct nameidata *nd) -{ - return omfs_add_node(dir, dentry, mode | S_IFREG); -} - -static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry, - struct nameidata *nd) -{ - struct buffer_head *bh; - struct inode *inode = NULL; - - if (dentry->d_name.len > OMFS_NAMELEN) - return ERR_PTR(-ENAMETOOLONG); - - bh = omfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); - if (!IS_ERR(bh)) { - struct omfs_inode *oi = (struct omfs_inode *)bh->b_data; - ino_t ino = be64_to_cpu(oi->i_head.h_self); - brelse(bh); - inode = omfs_iget(dir->i_sb, ino); - if (IS_ERR(inode)) - return ERR_CAST(inode); - } - d_add(dentry, inode); - return NULL; -} - -/* sanity check block's self pointer */ -int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header, - u64 fsblock) -{ - int is_bad; - u64 ino = be64_to_cpu(header->h_self); - is_bad = ((ino != fsblock) || (ino < sbi->s_root_ino) || - (ino > sbi->s_num_blocks)); - - if (is_bad) - printk(KERN_WARNING "omfs: bad hash chain detected\n"); - - return is_bad; -} - -static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir, - u64 fsblock, int hindex) -{ - struct inode *dir = filp->f_dentry->d_inode; - struct buffer_head *bh; - struct omfs_inode *oi; - u64 self; - int res = 0; - unsigned char d_type; - - /* follow chain in this bucket */ - while (fsblock != ~0) { - bh = omfs_bread(dir->i_sb, fsblock); - if (!bh) - goto out; - - oi = (struct omfs_inode *) bh->b_data; - if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) { - brelse(bh); - goto out; - } - - self = fsblock; - fsblock = be64_to_cpu(oi->i_sibling); - - /* skip visited nodes */ - if (hindex) { - hindex--; - brelse(bh); - continue; - } - - d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG; - - res = filldir(dirent, oi->i_name, strnlen(oi->i_name, - OMFS_NAMELEN), filp->f_pos, self, d_type); - brelse(bh); - if (res < 0) - break; - filp->f_pos++; - } -out: - return res; -} - -static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) -{ - struct inode *new_inode = new_dentry->d_inode; - struct inode *old_inode = old_dentry->d_inode; - int err; - - if (new_inode) { - /* overwriting existing file/dir */ - err = omfs_remove(new_dir, new_dentry); - if (err) - goto out; - } - - /* since omfs locates files by name, we need to unlink _before_ - * adding the new link or we won't find the old one */ - err = omfs_delete_entry(old_dentry); - if (err) - goto out; - - mark_inode_dirty(old_dir); - err = omfs_add_link(new_dentry, old_inode); - if (err) - goto out; - - old_inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(old_inode); -out: - return err; -} - -static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir) -{ - struct inode *dir = filp->f_dentry->d_inode; - struct buffer_head *bh; - loff_t offset, res; - unsigned int hchain, hindex; - int nbuckets; - u64 fsblock; - int ret = -EINVAL; - - if (filp->f_pos >> 32) - goto success; - - switch ((unsigned long) filp->f_pos) { - case 0: - if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0) - goto success; - filp->f_pos++; - /* fall through */ - case 1: - if (filldir(dirent, "..", 2, 1, - parent_ino(filp->f_dentry), DT_DIR) < 0) - goto success; - filp->f_pos = 1 << 20; - /* fall through */ - } - - nbuckets = (dir->i_size - OMFS_DIR_START) / 8; - - /* high 12 bits store bucket + 1 and low 20 bits store hash index */ - hchain = (filp->f_pos >> 20) - 1; - hindex = filp->f_pos & 0xfffff; - - bh = omfs_bread(dir->i_sb, dir->i_ino); - if (!bh) - goto out; - - offset = OMFS_DIR_START + hchain * 8; - - for (; hchain < nbuckets; hchain++, offset += 8) { - fsblock = be64_to_cpu(*((__be64 *) &bh->b_data[offset])); - - res = omfs_fill_chain(filp, dirent, filldir, fsblock, hindex); - hindex = 0; - if (res < 0) - break; - - filp->f_pos = (hchain+2) << 20; - } - brelse(bh); -success: - ret = 0; -out: - return ret; -} - -const struct inode_operations omfs_dir_inops = { - .lookup = omfs_lookup, - .mkdir = omfs_mkdir, - .rename = omfs_rename, - .create = omfs_create, - .unlink = omfs_remove, - .rmdir = omfs_remove, -}; - -const struct file_operations omfs_dir_operations = { - .read = generic_read_dir, - .readdir = omfs_readdir, - .llseek = generic_file_llseek, -}; |