2005-04-17 02:20:36 +04:00
/*
* linux / fs / minix / namei . c
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
*/
# include "minix.h"
static int add_nondir ( struct dentry * dentry , struct inode * inode )
{
int err = minix_add_link ( dentry , inode ) ;
if ( ! err ) {
d_instantiate ( dentry , inode ) ;
return 0 ;
}
2006-03-23 14:00:51 +03:00
inode_dec_link_count ( inode ) ;
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
return err ;
}
2012-06-11 01:13:09 +04:00
static struct dentry * minix_lookup ( struct inode * dir , struct dentry * dentry , unsigned int flags )
2005-04-17 02:20:36 +04:00
{
struct inode * inode = NULL ;
ino_t ino ;
if ( dentry - > d_name . len > minix_sb ( dir - > i_sb ) - > s_namelen )
return ERR_PTR ( - ENAMETOOLONG ) ;
ino = minix_inode_by_name ( dentry ) ;
if ( ino ) {
2008-02-07 11:15:44 +03:00
inode = minix_iget ( dir - > i_sb , ino ) ;
if ( IS_ERR ( inode ) )
return ERR_CAST ( inode ) ;
2005-04-17 02:20:36 +04:00
}
d_add ( dentry , inode ) ;
return NULL ;
}
2011-07-26 09:52:52 +04:00
static int minix_mknod ( struct inode * dir , struct dentry * dentry , umode_t mode , dev_t rdev )
2005-04-17 02:20:36 +04:00
{
int error ;
struct inode * inode ;
if ( ! old_valid_dev ( rdev ) )
return - EINVAL ;
2010-03-04 17:32:14 +03:00
inode = minix_new_inode ( dir , mode , & error ) ;
2005-04-17 02:20:36 +04:00
if ( inode ) {
minix_set_inode ( inode , rdev ) ;
mark_inode_dirty ( inode ) ;
error = add_nondir ( dentry , inode ) ;
}
return error ;
}
2011-07-26 09:42:34 +04:00
static int minix_create ( struct inode * dir , struct dentry * dentry , umode_t mode ,
2005-04-17 02:20:36 +04:00
struct nameidata * nd )
{
return minix_mknod ( dir , dentry , mode , 0 ) ;
}
static int minix_symlink ( struct inode * dir , struct dentry * dentry ,
const char * symname )
{
int err = - ENAMETOOLONG ;
int i = strlen ( symname ) + 1 ;
struct inode * inode ;
if ( i > dir - > i_sb - > s_blocksize )
goto out ;
2010-03-04 17:32:14 +03:00
inode = minix_new_inode ( dir , S_IFLNK | 0777 , & err ) ;
2005-04-17 02:20:36 +04:00
if ( ! inode )
goto out ;
minix_set_inode ( inode , 0 ) ;
err = page_symlink ( inode , symname , i ) ;
if ( err )
goto out_fail ;
err = add_nondir ( dentry , inode ) ;
out :
return err ;
out_fail :
2006-03-23 14:00:51 +03:00
inode_dec_link_count ( inode ) ;
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
goto out ;
}
static int minix_link ( struct dentry * old_dentry , struct inode * dir ,
struct dentry * dentry )
{
struct inode * inode = old_dentry - > d_inode ;
inode - > i_ctime = CURRENT_TIME_SEC ;
2006-03-23 14:00:51 +03:00
inode_inc_link_count ( inode ) ;
2010-10-23 19:11:40 +04:00
ihold ( inode ) ;
2005-04-17 02:20:36 +04:00
return add_nondir ( dentry , inode ) ;
}
2011-07-26 09:41:39 +04:00
static int minix_mkdir ( struct inode * dir , struct dentry * dentry , umode_t mode )
2005-04-17 02:20:36 +04:00
{
struct inode * inode ;
2012-02-06 21:45:27 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:51 +03:00
inode_inc_link_count ( dir ) ;
2005-04-17 02:20:36 +04:00
2010-09-10 03:38:19 +04:00
inode = minix_new_inode ( dir , S_IFDIR | mode , & err ) ;
2005-04-17 02:20:36 +04:00
if ( ! inode )
goto out_dir ;
minix_set_inode ( inode , 0 ) ;
2006-03-23 14:00:51 +03:00
inode_inc_link_count ( inode ) ;
2005-04-17 02:20:36 +04:00
err = minix_make_empty ( inode , dir ) ;
if ( err )
goto out_fail ;
err = minix_add_link ( dentry , inode ) ;
if ( err )
goto out_fail ;
d_instantiate ( dentry , inode ) ;
out :
return err ;
out_fail :
2006-03-23 14:00:51 +03:00
inode_dec_link_count ( inode ) ;
inode_dec_link_count ( inode ) ;
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
out_dir :
2006-03-23 14:00:51 +03:00
inode_dec_link_count ( dir ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
static int minix_unlink ( struct inode * dir , struct dentry * dentry )
{
int err = - ENOENT ;
struct inode * inode = dentry - > d_inode ;
struct page * page ;
struct minix_dir_entry * de ;
de = minix_find_entry ( dentry , & page ) ;
if ( ! de )
goto end_unlink ;
err = minix_delete_entry ( de , page ) ;
if ( err )
goto end_unlink ;
inode - > i_ctime = dir - > i_ctime ;
2006-03-23 14:00:51 +03:00
inode_dec_link_count ( inode ) ;
2005-04-17 02:20:36 +04:00
end_unlink :
return err ;
}
static int minix_rmdir ( struct inode * dir , struct dentry * dentry )
{
struct inode * inode = dentry - > d_inode ;
int err = - ENOTEMPTY ;
if ( minix_empty_dir ( inode ) ) {
err = minix_unlink ( dir , dentry ) ;
if ( ! err ) {
2006-03-23 14:00:51 +03:00
inode_dec_link_count ( dir ) ;
inode_dec_link_count ( inode ) ;
2005-04-17 02:20:36 +04:00
}
}
return err ;
}
static int minix_rename ( struct inode * old_dir , struct dentry * old_dentry ,
struct inode * new_dir , struct dentry * new_dentry )
{
struct inode * old_inode = old_dentry - > d_inode ;
struct inode * new_inode = new_dentry - > d_inode ;
struct page * dir_page = NULL ;
struct minix_dir_entry * dir_de = NULL ;
struct page * old_page ;
struct minix_dir_entry * old_de ;
int err = - ENOENT ;
old_de = minix_find_entry ( old_dentry , & old_page ) ;
if ( ! old_de )
goto out ;
if ( S_ISDIR ( old_inode - > i_mode ) ) {
err = - EIO ;
dir_de = minix_dotdot ( old_inode , & dir_page ) ;
if ( ! dir_de )
goto out_old ;
}
if ( new_inode ) {
struct page * new_page ;
struct minix_dir_entry * new_de ;
err = - ENOTEMPTY ;
if ( dir_de & & ! minix_empty_dir ( new_inode ) )
goto out_dir ;
err = - ENOENT ;
new_de = minix_find_entry ( new_dentry , & new_page ) ;
if ( ! new_de )
goto out_dir ;
minix_set_link ( new_de , new_page , old_inode ) ;
new_inode - > i_ctime = CURRENT_TIME_SEC ;
if ( dir_de )
2006-10-01 10:29:03 +04:00
drop_nlink ( new_inode ) ;
2006-03-23 14:00:51 +03:00
inode_dec_link_count ( new_inode ) ;
2005-04-17 02:20:36 +04:00
} else {
err = minix_add_link ( new_dentry , old_inode ) ;
2011-03-02 17:41:38 +03:00
if ( err )
2005-04-17 02:20:36 +04:00
goto out_dir ;
if ( dir_de )
2006-03-23 14:00:51 +03:00
inode_inc_link_count ( new_dir ) ;
2005-04-17 02:20:36 +04:00
}
minix_delete_entry ( old_de , old_page ) ;
2011-03-02 17:41:38 +03:00
mark_inode_dirty ( old_inode ) ;
2005-04-17 02:20:36 +04:00
if ( dir_de ) {
minix_set_link ( dir_de , dir_page , new_dir ) ;
2006-03-23 14:00:51 +03:00
inode_dec_link_count ( old_dir ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
out_dir :
if ( dir_de ) {
kunmap ( dir_page ) ;
page_cache_release ( dir_page ) ;
}
out_old :
kunmap ( old_page ) ;
page_cache_release ( old_page ) ;
out :
return err ;
}
/*
* directories can handle most operations . . .
*/
2007-02-12 11:55:39 +03:00
const struct inode_operations minix_dir_inode_operations = {
2005-04-17 02:20:36 +04:00
. create = minix_create ,
. lookup = minix_lookup ,
. link = minix_link ,
. unlink = minix_unlink ,
. symlink = minix_symlink ,
. mkdir = minix_mkdir ,
. rmdir = minix_rmdir ,
. mknod = minix_mknod ,
. rename = minix_rename ,
. getattr = minix_getattr ,
} ;