pramfs: dir operations
PATCH 9/17 pramfs: dir operations
From: Marco Stornelli <[email protected]>
File operations for directories.
Signed-off-by Marco Stornelli <[email protected]>
---
fs/pramfs/dir.c new file +208 -0
@@ -0,0 +1,208 @@ +/* +* BRIEF DESCRIPTION +* +* File operations for directories. +* +* Copyright 2009-2010 Marco Stornelli <[email protected]> +* Copyright 2003 Sony Corporation +* Copyright 2003 Matsushita Electric Industrial Co., Ltd. +* 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam +* This file is licensed under the terms of the GNU General Public +* License version 2. This program is licensed "as is" without any +* warranty of any kind, whether express or implied. +*/ + +#include <linux/fs.h> +#include <linux/pagemap.h> +#include "pram.h" + +/* +* Parent is locked. +*/ +int pram_add_link (struct dentry *dentry,struct inode *inode) +{ +struct inode *dir = dentry->d_parent->d_inode; +struct pram_inode *pidir, *pi, *pitail =NULL ; +u64 tail_ino, prev_ino; + +const char *name = dentry->d_name.name; + + int namelen = min_t(unsigned int, dentry->d_name.len, PRAM_NAME_LEN); + + pidir =pram_get_inode (dir->i_sb, dir->i_ino); + pi =pram_get_inode (dir->i_sb, inode->i_ino); + + dir->i_mtime = dir->i_ctime =CURRENT_TIME ; + + tail_ino =be64_to_cpu (pidir->i_type.dir.tail); +if (tail_ino !=0 ) { + pitail =pram_get_inode (dir->i_sb, tail_ino); +pram_memunlock_inode (dir->i_sb, pitail); + pitail->i_d.d_next =cpu_to_be64 (inode->i_ino); +pram_memlock_inode (dir->i_sb, pitail); + + prev_ino = tail_ino; + +pram_memunlock_inode (dir->i_sb, pidir); + pidir->i_type.dir.tail =cpu_to_be64 (inode->i_ino); + pidir->i_mtime =cpu_to_be32 (dir->i_mtime.tv_sec); + pidir->i_ctime =cpu_to_be32 (dir->i_ctime.tv_sec); +pram_memlock_inode (dir->i_sb, pidir); + }else { +/* the directory is empty */ + prev_ino =0 ; + +pram_memunlock_inode (dir->i_sb, pidir); + pidir->i_type.dir.tail =cpu_to_be64 (inode->i_ino); + pidir->i_type.dir.head =cpu_to_be64 (inode->i_ino); + pidir->i_mtime =cpu_to_be32 (dir->i_mtime.tv_sec); + pidir->i_ctime =cpu_to_be32 (dir->i_ctime.tv_sec); +pram_memlock_inode (dir->i_sb, pidir); + } + + +pram_memunlock_inode (dir->i_sb, pi); + pi->i_d.d_prev =cpu_to_be64 (prev_ino); + pi->i_d.d_parent =cpu_to_be64 (dir->i_ino); +memcpy (pi->i_d.d_name, name, namelen); + pi->i_d.d_name[namelen] ='\0' ; +pram_memlock_inode (dir->i_sb, pi); +return 0 ; +} + +int pram_remove_link (struct inode *inode) +{ +struct super_block *sb = inode->i_sb; +struct pram_inode *prev =NULL ; +struct pram_inode *next =NULL ; +struct pram_inode *pidir, *pi; + + pi =pram_get_inode (sb, inode->i_ino); + pidir =pram_get_inode (sb,be64_to_cpu (pi->i_d.d_parent)); +if (!pidir) +return -EACCES ; + +if (inode->i_ino ==be64_to_cpu (pidir->i_type.dir.head)) { +/* first inode in directory */ + next =pram_get_inode (sb,be64_to_cpu (pi->i_d.d_next)); + +if (next) { +pram_memunlock_inode (sb, next); + next->i_d.d_prev =0 ; +pram_memlock_inode (sb, next); + +pram_memunlock_inode (sb, pidir); + pidir->i_type.dir.head = pi->i_d.d_next; + }else { +pram_memunlock_inode (sb, pidir); + pidir->i_type.dir.head =0 ; + pidir->i_type.dir.tail =0 ; + } +pram_memlock_inode (sb, pidir); + }else if (inode->i_ino ==be64_to_cpu (pidir->i_type.dir.tail)) { +/* last inode in directory */ + prev =pram_get_inode (sb,be64_to_cpu (pi->i_d.d_prev)); + +pram_memunlock_inode (sb, prev); + prev->i_d.d_next =0 ; +pram_memlock_inode (sb, prev); + +pram_memunlock_inode (sb, pidir); + pidir->i_type.dir.tail = pi->i_d.d_prev; +pram_memlock_inode (sb, pidir); + }else { +/* somewhere in the middle */ + prev =pram_get_inode (sb,be64_to_cpu (pi->i_d.d_prev)); + next =pram_get_inode (sb,be64_to_cpu (pi->i_d.d_next)); + +if (prev && next) { +pram_memunlock_inode (sb, prev); + prev->i_d.d_next = pi->i_d.d_next; +pram_memlock_inode (sb, prev); + +pram_memunlock_inode (sb, next); + next->i_d.d_prev = pi->i_d.d_prev; +pram_memlock_inode (sb, next); + } + } + +pram_memunlock_inode (sb, pi); + pi->i_d.d_next =0 ; + pi->i_d.d_prev =0 ; + pi->i_d.d_parent =0 ; +pram_memlock_inode (sb, pi); + +return 0 ; +} + +#define DT2IF (dt) (((dt) << 12) & S_IFMT) +#define IF2DT (sif) (((sif) & S_IFMT) >> 12) + +static int pram_readdir (struct file *filp,void *dirent,filldir_t filldir) +{ +struct inode *inode = filp->f_dentry->d_inode; +struct super_block *sb = inode->i_sb; +struct pram_inode *pi; +int namelen, ret =0 ; +char *name; +ino_t ino; + + pi =pram_get_inode (sb, inode->i_ino); + +switch ((unsigned long )filp->f_pos) { +case 0 : + ret =filldir (dirent,"." ,1 ,0 , inode->i_ino,DT_DIR ); + filp->f_pos++; +return ret; +case 1 : + ret =filldir (dirent,".." ,2 ,1 ,be64_to_cpu (pi->i_d.d_parent),DT_DIR ); + ino =be64_to_cpu (pi->i_type.dir.head); + filp->f_pos = ino ? ino :2 ; +return ret; +case 2 : + ino =be64_to_cpu (pi->i_type.dir.head); +if (ino) { + filp->f_pos = ino; + pi =pram_get_inode (sb, ino); +break ; + }else { +/* the directory is empty */ + filp->f_pos =2 ; +return 0 ; + } +case 3 : +return 0 ; +default : + ino = filp->f_pos; + pi =pram_get_inode (sb, ino); +break ; + } + +while (pi && !be16_to_cpu (pi->i_links_count)) { + ino = filp->f_pos =be64_to_cpu (pi->i_d.d_next); + pi =pram_get_inode (sb, ino); + } + +if (pi) { + name = pi->i_d.d_name; + namelen =strlen (name); + + ret =filldir (dirent, name, namelen, + filp->f_pos, ino, +IF2DT (be16_to_cpu (pi->i_mode))); + filp->f_pos = pi->i_d.d_next ?be64_to_cpu (pi->i_d.d_next) :3 ; + }else + filp->f_pos =3 ; + +return ret; +} + +struct file_operations pram_dir_operations = { + .read = generic_read_dir, + .readdir = pram_readdir, + .fsync = noop_fsync, + .unlocked_ioctl = pram_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = pram_compat_ioctl, +#endif +};