2005-04-17 02:20:36 +04:00
/*
* linux / fs / hfsplus / inode . c
*
* Copyright ( C ) 2001
* Brad Boyer ( flar @ allandria . com )
* ( C ) 2003 Ardis Technologies < roman @ ardistech . com >
*
* Inode handling routines
*/
2010-11-23 16:38:21 +03:00
# include <linux/blkdev.h>
2005-04-17 02:20:36 +04:00
# include <linux/mm.h>
# include <linux/fs.h>
# include <linux/pagemap.h>
# include <linux/mpage.h>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <linux/sched.h>
2005-04-17 02:20:36 +04:00
# include "hfsplus_fs.h"
# include "hfsplus_raw.h"
2013-02-28 05:03:04 +04:00
# include "xattr.h"
2005-04-17 02:20:36 +04:00
static int hfsplus_readpage ( struct file * file , struct page * page )
{
return block_read_full_page ( page , hfsplus_get_block ) ;
}
static int hfsplus_writepage ( struct page * page , struct writeback_control * wbc )
{
return block_write_full_page ( page , hfsplus_get_block , wbc ) ;
}
2012-12-15 14:55:07 +04:00
static void hfsplus_write_failed ( struct address_space * mapping , loff_t to )
{
struct inode * inode = mapping - > host ;
if ( to > inode - > i_size ) {
truncate_pagecache ( inode , to , inode - > i_size ) ;
hfsplus_file_truncate ( inode ) ;
}
}
2007-10-16 12:25:09 +04:00
static int hfsplus_write_begin ( struct file * file , struct address_space * mapping ,
loff_t pos , unsigned len , unsigned flags ,
struct page * * pagep , void * * fsdata )
2005-04-17 02:20:36 +04:00
{
2010-06-04 13:29:55 +04:00
int ret ;
2007-10-16 12:25:09 +04:00
* pagep = NULL ;
2010-06-04 13:29:55 +04:00
ret = cont_write_begin ( file , mapping , pos , len , flags , pagep , fsdata ,
2007-10-16 12:25:09 +04:00
hfsplus_get_block ,
2010-10-01 07:43:31 +04:00
& HFSPLUS_I ( mapping - > host ) - > phys_size ) ;
2012-12-15 14:55:07 +04:00
if ( unlikely ( ret ) )
hfsplus_write_failed ( mapping , pos + len ) ;
2010-06-04 13:29:55 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
static sector_t hfsplus_bmap ( struct address_space * mapping , sector_t block )
{
return generic_block_bmap ( mapping , block , hfsplus_get_block ) ;
}
2005-10-21 11:20:48 +04:00
static int hfsplus_releasepage ( struct page * page , gfp_t mask )
2005-04-17 02:20:36 +04:00
{
struct inode * inode = page - > mapping - > host ;
struct super_block * sb = inode - > i_sb ;
struct hfs_btree * tree ;
struct hfs_bnode * node ;
u32 nidx ;
int i , res = 1 ;
switch ( inode - > i_ino ) {
case HFSPLUS_EXT_CNID :
2010-10-01 07:42:59 +04:00
tree = HFSPLUS_SB ( sb ) - > ext_tree ;
2005-04-17 02:20:36 +04:00
break ;
case HFSPLUS_CAT_CNID :
2010-10-01 07:42:59 +04:00
tree = HFSPLUS_SB ( sb ) - > cat_tree ;
2005-04-17 02:20:36 +04:00
break ;
case HFSPLUS_ATTR_CNID :
2010-10-01 07:42:59 +04:00
tree = HFSPLUS_SB ( sb ) - > attr_tree ;
2005-04-17 02:20:36 +04:00
break ;
default :
BUG ( ) ;
return 0 ;
}
2008-05-13 01:02:21 +04:00
if ( ! tree )
return 0 ;
2005-04-17 02:20:36 +04:00
if ( tree - > node_size > = PAGE_CACHE_SIZE ) {
2010-12-16 19:08:38 +03:00
nidx = page - > index > >
( tree - > node_size_shift - PAGE_CACHE_SHIFT ) ;
2005-04-17 02:20:36 +04:00
spin_lock ( & tree - > hash_lock ) ;
node = hfs_bnode_findhash ( tree , nidx ) ;
if ( ! node )
;
else if ( atomic_read ( & node - > refcnt ) )
res = 0 ;
if ( res & & node ) {
hfs_bnode_unhash ( node ) ;
hfs_bnode_free ( node ) ;
}
spin_unlock ( & tree - > hash_lock ) ;
} else {
2010-12-16 19:08:38 +03:00
nidx = page - > index < <
( PAGE_CACHE_SHIFT - tree - > node_size_shift ) ;
2005-04-17 02:20:36 +04:00
i = 1 < < ( PAGE_CACHE_SHIFT - tree - > node_size_shift ) ;
spin_lock ( & tree - > hash_lock ) ;
do {
node = hfs_bnode_findhash ( tree , nidx + + ) ;
if ( ! node )
continue ;
if ( atomic_read ( & node - > refcnt ) ) {
res = 0 ;
break ;
}
hfs_bnode_unhash ( node ) ;
hfs_bnode_free ( node ) ;
} while ( - - i & & nidx < tree - > node_count ) ;
spin_unlock ( & tree - > hash_lock ) ;
}
return res ? try_to_free_buffers ( page ) : 0 ;
}
static ssize_t hfsplus_direct_IO ( int rw , struct kiocb * iocb ,
const struct iovec * iov , loff_t offset , unsigned long nr_segs )
{
struct file * file = iocb - > ki_filp ;
2012-12-15 14:55:07 +04:00
struct address_space * mapping = file - > f_mapping ;
2013-01-24 02:07:38 +04:00
struct inode * inode = file_inode ( file ) - > i_mapping - > host ;
2010-06-04 13:29:53 +04:00
ssize_t ret ;
2005-04-17 02:20:36 +04:00
2011-06-24 22:29:47 +04:00
ret = blockdev_direct_IO ( rw , iocb , inode , iov , offset , nr_segs ,
hfsplus_get_block ) ;
2010-06-04 13:29:53 +04:00
/*
* In case of error extending write may have instantiated a few
* blocks outside i_size . Trim these off again .
*/
if ( unlikely ( ( rw & WRITE ) & & ret < 0 ) ) {
loff_t isize = i_size_read ( inode ) ;
loff_t end = offset + iov_length ( iov , nr_segs ) ;
if ( end > isize )
2012-12-15 14:55:07 +04:00
hfsplus_write_failed ( mapping , end ) ;
2010-06-04 13:29:53 +04:00
}
return ret ;
2005-04-17 02:20:36 +04:00
}
static int hfsplus_writepages ( struct address_space * mapping ,
struct writeback_control * wbc )
{
return mpage_writepages ( mapping , wbc , hfsplus_get_block ) ;
}
2006-06-28 15:26:44 +04:00
const struct address_space_operations hfsplus_btree_aops = {
2005-04-17 02:20:36 +04:00
. readpage = hfsplus_readpage ,
. writepage = hfsplus_writepage ,
2007-10-16 12:25:09 +04:00
. write_begin = hfsplus_write_begin ,
. write_end = generic_write_end ,
2005-04-17 02:20:36 +04:00
. bmap = hfsplus_bmap ,
. releasepage = hfsplus_releasepage ,
} ;
2006-06-28 15:26:44 +04:00
const struct address_space_operations hfsplus_aops = {
2005-04-17 02:20:36 +04:00
. readpage = hfsplus_readpage ,
. writepage = hfsplus_writepage ,
2007-10-16 12:25:09 +04:00
. write_begin = hfsplus_write_begin ,
. write_end = generic_write_end ,
2005-04-17 02:20:36 +04:00
. bmap = hfsplus_bmap ,
. direct_IO = hfsplus_direct_IO ,
. writepages = hfsplus_writepages ,
} ;
2009-02-20 08:55:13 +03:00
const struct dentry_operations hfsplus_dentry_operations = {
2007-07-16 10:41:23 +04:00
. d_hash = hfsplus_hash_dentry ,
. d_compare = hfsplus_compare_dentry ,
} ;
2010-12-16 19:08:38 +03:00
static struct dentry * hfsplus_file_lookup ( struct inode * dir ,
2012-06-11 01:13:09 +04:00
struct dentry * dentry , unsigned int flags )
2005-04-17 02:20:36 +04:00
{
struct hfs_find_data fd ;
struct super_block * sb = dir - > i_sb ;
struct inode * inode = NULL ;
2010-10-01 07:43:31 +04:00
struct hfsplus_inode_info * hip ;
2005-04-17 02:20:36 +04:00
int err ;
if ( HFSPLUS_IS_RSRC ( dir ) | | strcmp ( dentry - > d_name . name , " rsrc " ) )
goto out ;
2010-10-01 07:43:31 +04:00
inode = HFSPLUS_I ( dir ) - > rsrc_inode ;
2005-04-17 02:20:36 +04:00
if ( inode )
goto out ;
inode = new_inode ( sb ) ;
if ( ! inode )
return ERR_PTR ( - ENOMEM ) ;
2010-10-01 07:43:31 +04:00
hip = HFSPLUS_I ( inode ) ;
2005-04-17 02:20:36 +04:00
inode - > i_ino = dir - > i_ino ;
2010-10-01 07:43:31 +04:00
INIT_LIST_HEAD ( & hip - > open_dir_list ) ;
mutex_init ( & hip - > extents_lock ) ;
2010-11-23 16:38:13 +03:00
hip - > extent_state = 0 ;
hip - > flags = 0 ;
2012-03-13 20:10:34 +04:00
hip - > userflags = 0 ;
2010-11-23 16:38:13 +03:00
set_bit ( HFSPLUS_I_RSRC , & hip - > flags ) ;
2005-04-17 02:20:36 +04:00
2011-07-06 02:29:59 +04:00
err = hfs_find_init ( HFSPLUS_SB ( sb ) - > cat_tree , & fd ) ;
if ( ! err ) {
err = hfsplus_find_cat ( sb , dir - > i_ino , & fd ) ;
if ( ! err )
err = hfsplus_cat_read_inode ( inode , & fd ) ;
hfs_find_exit ( & fd ) ;
}
2005-04-17 02:20:36 +04:00
if ( err ) {
iput ( inode ) ;
return ERR_PTR ( err ) ;
}
2010-10-01 07:43:31 +04:00
hip - > rsrc_inode = dir ;
HFSPLUS_I ( dir ) - > rsrc_inode = inode ;
2005-04-17 02:20:36 +04:00
igrab ( dir ) ;
2010-10-01 07:44:02 +04:00
/*
* __mark_inode_dirty expects inodes to be hashed . Since we don ' t
* want resource fork inodes in the regular inode space , we make them
* appear hashed , but do not put on any lists . hlist_del ( )
* will work fine and require no locking .
*/
2010-10-23 23:23:40 +04:00
hlist_add_fake ( & inode - > i_hash ) ;
2010-10-01 07:44:02 +04:00
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
out :
d_add ( dentry , inode ) ;
return NULL ;
}
2010-12-16 19:08:38 +03:00
static void hfsplus_get_perms ( struct inode * inode ,
struct hfsplus_perm * perms , int dir )
2005-04-17 02:20:36 +04:00
{
2010-10-01 07:42:59 +04:00
struct hfsplus_sb_info * sbi = HFSPLUS_SB ( inode - > i_sb ) ;
2005-04-17 02:20:36 +04:00
u16 mode ;
mode = be16_to_cpu ( perms - > mode ) ;
2012-02-08 04:27:17 +04:00
i_uid_write ( inode , be32_to_cpu ( perms - > owner ) ) ;
if ( ! i_uid_read ( inode ) & & ! mode )
2010-10-01 07:42:59 +04:00
inode - > i_uid = sbi - > uid ;
2005-04-17 02:20:36 +04:00
2012-02-08 04:27:17 +04:00
i_gid_write ( inode , be32_to_cpu ( perms - > group ) ) ;
if ( ! i_gid_read ( inode ) & & ! mode )
2010-10-01 07:42:59 +04:00
inode - > i_gid = sbi - > gid ;
2005-04-17 02:20:36 +04:00
if ( dir ) {
2010-10-01 07:42:59 +04:00
mode = mode ? ( mode & S_IALLUGO ) : ( S_IRWXUGO & ~ ( sbi - > umask ) ) ;
2005-04-17 02:20:36 +04:00
mode | = S_IFDIR ;
} else if ( ! mode )
2010-10-01 07:42:59 +04:00
mode = S_IFREG | ( ( S_IRUGO | S_IWUGO ) & ~ ( sbi - > umask ) ) ;
2005-04-17 02:20:36 +04:00
inode - > i_mode = mode ;
2010-10-01 07:43:31 +04:00
HFSPLUS_I ( inode ) - > userflags = perms - > userflags ;
2005-04-17 02:20:36 +04:00
if ( perms - > rootflags & HFSPLUS_FLG_IMMUTABLE )
inode - > i_flags | = S_IMMUTABLE ;
else
inode - > i_flags & = ~ S_IMMUTABLE ;
if ( perms - > rootflags & HFSPLUS_FLG_APPEND )
inode - > i_flags | = S_APPEND ;
else
inode - > i_flags & = ~ S_APPEND ;
}
static int hfsplus_file_open ( struct inode * inode , struct file * file )
{
if ( HFSPLUS_IS_RSRC ( inode ) )
2010-10-01 07:43:31 +04:00
inode = HFSPLUS_I ( inode ) - > rsrc_inode ;
2008-10-19 07:28:01 +04:00
if ( ! ( file - > f_flags & O_LARGEFILE ) & & i_size_read ( inode ) > MAX_NON_LFS )
return - EOVERFLOW ;
2010-10-01 07:43:31 +04:00
atomic_inc ( & HFSPLUS_I ( inode ) - > opencnt ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int hfsplus_file_release ( struct inode * inode , struct file * file )
{
struct super_block * sb = inode - > i_sb ;
if ( HFSPLUS_IS_RSRC ( inode ) )
2010-10-01 07:43:31 +04:00
inode = HFSPLUS_I ( inode ) - > rsrc_inode ;
if ( atomic_dec_and_test ( & HFSPLUS_I ( inode ) - > opencnt ) ) {
2006-01-10 02:59:24 +03:00
mutex_lock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
hfsplus_file_truncate ( inode ) ;
if ( inode - > i_flags & S_DEAD ) {
2010-10-01 07:42:59 +04:00
hfsplus_delete_cat ( inode - > i_ino ,
HFSPLUS_SB ( sb ) - > hidden_dir , NULL ) ;
2005-04-17 02:20:36 +04:00
hfsplus_delete_inode ( inode ) ;
}
2006-01-10 02:59:24 +03:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
2010-06-04 13:29:59 +04:00
static int hfsplus_setattr ( struct dentry * dentry , struct iattr * attr )
{
struct inode * inode = dentry - > d_inode ;
int error ;
error = inode_change_ok ( inode , attr ) ;
if ( error )
return error ;
2010-06-04 13:30:02 +04:00
if ( ( attr - > ia_valid & ATTR_SIZE ) & &
attr - > ia_size ! = i_size_read ( inode ) ) {
2011-06-24 22:29:45 +04:00
inode_dio_wait ( inode ) ;
2012-12-15 14:55:07 +04:00
truncate_setsize ( inode , attr - > ia_size ) ;
hfsplus_file_truncate ( inode ) ;
2010-06-04 13:30:02 +04:00
}
setattr_copy ( inode , attr ) ;
mark_inode_dirty ( inode ) ;
return 0 ;
2010-06-04 13:29:59 +04:00
}
2011-07-17 04:44:56 +04:00
int hfsplus_file_fsync ( struct file * file , loff_t start , loff_t end ,
int datasync )
2010-07-04 12:24:09 +04:00
{
2010-11-23 16:38:06 +03:00
struct inode * inode = file - > f_mapping - > host ;
2010-11-23 16:38:15 +03:00
struct hfsplus_inode_info * hip = HFSPLUS_I ( inode ) ;
2010-11-23 16:38:06 +03:00
struct hfsplus_sb_info * sbi = HFSPLUS_SB ( inode - > i_sb ) ;
2010-11-23 16:38:15 +03:00
int error = 0 , error2 ;
2010-07-04 12:24:09 +04:00
2011-07-17 04:44:56 +04:00
error = filemap_write_and_wait_range ( inode - > i_mapping , start , end ) ;
if ( error )
return error ;
mutex_lock ( & inode - > i_mutex ) ;
2010-11-23 16:38:06 +03:00
/*
* Sync inode metadata into the catalog and extent trees .
*/
sync_inode_metadata ( inode , 1 ) ;
/*
* And explicitly write out the btrees .
*/
2010-11-23 16:38:15 +03:00
if ( test_and_clear_bit ( HFSPLUS_I_CAT_DIRTY , & hip - > flags ) )
error = filemap_write_and_wait ( sbi - > cat_tree - > inode - > i_mapping ) ;
if ( test_and_clear_bit ( HFSPLUS_I_EXT_DIRTY , & hip - > flags ) ) {
2010-12-16 19:08:38 +03:00
error2 =
filemap_write_and_wait ( sbi - > ext_tree - > inode - > i_mapping ) ;
2010-11-23 16:38:15 +03:00
if ( ! error )
error = error2 ;
}
2013-02-28 05:03:04 +04:00
if ( test_and_clear_bit ( HFSPLUS_I_ATTR_DIRTY , & hip - > flags ) ) {
if ( sbi - > attr_tree ) {
error2 =
filemap_write_and_wait (
sbi - > attr_tree - > inode - > i_mapping ) ;
if ( ! error )
error = error2 ;
} else {
printk ( KERN_ERR " hfs: sync non-existent attributes tree \n " ) ;
}
}
2010-11-23 16:38:15 +03:00
if ( test_and_clear_bit ( HFSPLUS_I_ALLOC_DIRTY , & hip - > flags ) ) {
error2 = filemap_write_and_wait ( sbi - > alloc_file - > i_mapping ) ;
if ( ! error )
error = error2 ;
}
2010-11-23 16:38:21 +03:00
if ( ! test_bit ( HFSPLUS_SB_NOBARRIER , & sbi - > flags ) )
blkdev_issue_flush ( inode - > i_sb - > s_bdev , GFP_KERNEL , NULL ) ;
2011-07-17 04:44:56 +04:00
mutex_unlock ( & inode - > i_mutex ) ;
2010-11-23 16:38:06 +03:00
return error ;
2010-07-04 12:24:09 +04:00
}
2007-02-12 11:55:39 +03:00
static const struct inode_operations hfsplus_file_inode_operations = {
2005-04-17 02:20:36 +04:00
. lookup = hfsplus_file_lookup ,
2010-06-04 13:29:59 +04:00
. setattr = hfsplus_setattr ,
2013-02-28 05:03:04 +04:00
. setxattr = generic_setxattr ,
. getxattr = generic_getxattr ,
2005-04-17 02:20:36 +04:00
. listxattr = hfsplus_listxattr ,
2013-02-28 05:03:04 +04:00
. removexattr = hfsplus_removexattr ,
2005-04-17 02:20:36 +04:00
} ;
2006-03-28 13:56:42 +04:00
static const struct file_operations hfsplus_file_operations = {
2010-12-16 19:08:40 +03:00
. llseek = generic_file_llseek ,
2006-10-01 10:28:48 +04:00
. read = do_sync_read ,
. aio_read = generic_file_aio_read ,
. write = do_sync_write ,
. aio_write = generic_file_aio_write ,
2005-04-17 02:20:36 +04:00
. mmap = generic_file_mmap ,
2007-06-01 13:49:19 +04:00
. splice_read = generic_file_splice_read ,
2010-07-04 12:24:09 +04:00
. fsync = hfsplus_file_fsync ,
2005-04-17 02:20:36 +04:00
. open = hfsplus_file_open ,
. release = hfsplus_file_release ,
2010-04-27 18:24:20 +04:00
. unlocked_ioctl = hfsplus_ioctl ,
2005-04-17 02:20:36 +04:00
} ;
2011-07-26 11:26:51 +04:00
struct inode * hfsplus_new_inode ( struct super_block * sb , umode_t mode )
2005-04-17 02:20:36 +04:00
{
2010-10-01 07:42:59 +04:00
struct hfsplus_sb_info * sbi = HFSPLUS_SB ( sb ) ;
2005-04-17 02:20:36 +04:00
struct inode * inode = new_inode ( sb ) ;
2010-10-01 07:43:31 +04:00
struct hfsplus_inode_info * hip ;
2010-10-01 07:42:59 +04:00
2005-04-17 02:20:36 +04:00
if ( ! inode )
return NULL ;
2010-10-01 07:42:59 +04:00
inode - > i_ino = sbi - > next_cnid + + ;
2005-04-17 02:20:36 +04:00
inode - > i_mode = mode ;
2008-11-14 02:38:54 +03:00
inode - > i_uid = current_fsuid ( ) ;
inode - > i_gid = current_fsgid ( ) ;
2011-10-28 16:13:29 +04:00
set_nlink ( inode , 1 ) ;
2005-04-17 02:20:36 +04:00
inode - > i_mtime = inode - > i_atime = inode - > i_ctime = CURRENT_TIME_SEC ;
2010-10-01 07:43:31 +04:00
hip = HFSPLUS_I ( inode ) ;
INIT_LIST_HEAD ( & hip - > open_dir_list ) ;
mutex_init ( & hip - > extents_lock ) ;
atomic_set ( & hip - > opencnt , 0 ) ;
2010-11-23 16:38:13 +03:00
hip - > extent_state = 0 ;
2010-10-01 07:43:31 +04:00
hip - > flags = 0 ;
2012-03-13 20:10:34 +04:00
hip - > userflags = 0 ;
2010-10-01 07:43:31 +04:00
memset ( hip - > first_extents , 0 , sizeof ( hfsplus_extent_rec ) ) ;
memset ( hip - > cached_extents , 0 , sizeof ( hfsplus_extent_rec ) ) ;
hip - > alloc_blocks = 0 ;
hip - > first_blocks = 0 ;
hip - > cached_start = 0 ;
hip - > cached_blocks = 0 ;
hip - > phys_size = 0 ;
hip - > fs_blocks = 0 ;
hip - > rsrc_inode = NULL ;
2005-04-17 02:20:36 +04:00
if ( S_ISDIR ( inode - > i_mode ) ) {
inode - > i_size = 2 ;
2010-10-01 07:42:59 +04:00
sbi - > folder_count + + ;
2005-04-17 02:20:36 +04:00
inode - > i_op = & hfsplus_dir_inode_operations ;
inode - > i_fop = & hfsplus_dir_operations ;
} else if ( S_ISREG ( inode - > i_mode ) ) {
2010-10-01 07:42:59 +04:00
sbi - > file_count + + ;
2005-04-17 02:20:36 +04:00
inode - > i_op = & hfsplus_file_inode_operations ;
inode - > i_fop = & hfsplus_file_operations ;
inode - > i_mapping - > a_ops = & hfsplus_aops ;
2010-10-01 07:43:31 +04:00
hip - > clump_blocks = sbi - > data_clump_blocks ;
2005-04-17 02:20:36 +04:00
} else if ( S_ISLNK ( inode - > i_mode ) ) {
2010-10-01 07:42:59 +04:00
sbi - > file_count + + ;
2005-04-17 02:20:36 +04:00
inode - > i_op = & page_symlink_inode_operations ;
inode - > i_mapping - > a_ops = & hfsplus_aops ;
2010-10-01 07:43:31 +04:00
hip - > clump_blocks = 1 ;
2005-04-17 02:20:36 +04:00
} else
2010-10-01 07:42:59 +04:00
sbi - > file_count + + ;
2005-04-17 02:20:36 +04:00
insert_inode_hash ( inode ) ;
mark_inode_dirty ( inode ) ;
2012-07-12 18:26:31 +04:00
hfsplus_mark_mdb_dirty ( sb ) ;
2005-04-17 02:20:36 +04:00
return inode ;
}
void hfsplus_delete_inode ( struct inode * inode )
{
struct super_block * sb = inode - > i_sb ;
if ( S_ISDIR ( inode - > i_mode ) ) {
2010-10-01 07:42:59 +04:00
HFSPLUS_SB ( sb ) - > folder_count - - ;
2012-07-12 18:26:31 +04:00
hfsplus_mark_mdb_dirty ( sb ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2010-10-01 07:42:59 +04:00
HFSPLUS_SB ( sb ) - > file_count - - ;
2005-04-17 02:20:36 +04:00
if ( S_ISREG ( inode - > i_mode ) ) {
if ( ! inode - > i_nlink ) {
inode - > i_size = 0 ;
hfsplus_file_truncate ( inode ) ;
}
} else if ( S_ISLNK ( inode - > i_mode ) ) {
inode - > i_size = 0 ;
hfsplus_file_truncate ( inode ) ;
}
2012-07-12 18:26:31 +04:00
hfsplus_mark_mdb_dirty ( sb ) ;
2005-04-17 02:20:36 +04:00
}
void hfsplus_inode_read_fork ( struct inode * inode , struct hfsplus_fork_raw * fork )
{
struct super_block * sb = inode - > i_sb ;
2010-10-01 07:42:59 +04:00
struct hfsplus_sb_info * sbi = HFSPLUS_SB ( sb ) ;
2010-10-01 07:43:31 +04:00
struct hfsplus_inode_info * hip = HFSPLUS_I ( inode ) ;
2005-04-17 02:20:36 +04:00
u32 count ;
int i ;
2010-10-01 07:43:31 +04:00
memcpy ( & hip - > first_extents , & fork - > extents , sizeof ( hfsplus_extent_rec ) ) ;
2005-04-17 02:20:36 +04:00
for ( count = 0 , i = 0 ; i < 8 ; i + + )
count + = be32_to_cpu ( fork - > extents [ i ] . block_count ) ;
2010-10-01 07:43:31 +04:00
hip - > first_blocks = count ;
memset ( hip - > cached_extents , 0 , sizeof ( hfsplus_extent_rec ) ) ;
hip - > cached_start = 0 ;
hip - > cached_blocks = 0 ;
hip - > alloc_blocks = be32_to_cpu ( fork - > total_blocks ) ;
hip - > phys_size = inode - > i_size = be64_to_cpu ( fork - > total_size ) ;
hip - > fs_blocks =
( inode - > i_size + sb - > s_blocksize - 1 ) > > sb - > s_blocksize_bits ;
inode_set_bytes ( inode , hip - > fs_blocks < < sb - > s_blocksize_bits ) ;
hip - > clump_blocks =
2010-10-01 07:42:59 +04:00
be32_to_cpu ( fork - > clump_size ) > > sbi - > alloc_blksz_shift ;
2010-10-01 07:43:31 +04:00
if ( ! hip - > clump_blocks ) {
hip - > clump_blocks = HFSPLUS_IS_RSRC ( inode ) ?
2010-10-01 07:42:59 +04:00
sbi - > rsrc_clump_blocks :
sbi - > data_clump_blocks ;
}
2005-04-17 02:20:36 +04:00
}
2010-12-16 19:08:38 +03:00
void hfsplus_inode_write_fork ( struct inode * inode ,
struct hfsplus_fork_raw * fork )
2005-04-17 02:20:36 +04:00
{
2010-10-01 07:43:31 +04:00
memcpy ( & fork - > extents , & HFSPLUS_I ( inode ) - > first_extents ,
2005-04-17 02:20:36 +04:00
sizeof ( hfsplus_extent_rec ) ) ;
fork - > total_size = cpu_to_be64 ( inode - > i_size ) ;
2010-10-01 07:43:31 +04:00
fork - > total_blocks = cpu_to_be32 ( HFSPLUS_I ( inode ) - > alloc_blocks ) ;
2005-04-17 02:20:36 +04:00
}
int hfsplus_cat_read_inode ( struct inode * inode , struct hfs_find_data * fd )
{
hfsplus_cat_entry entry ;
int res = 0 ;
u16 type ;
type = hfs_bnode_read_u16 ( fd - > bnode , fd - > entryoffset ) ;
2010-10-14 17:54:28 +04:00
HFSPLUS_I ( inode ) - > linkid = 0 ;
2005-04-17 02:20:36 +04:00
if ( type = = HFSPLUS_FOLDER ) {
struct hfsplus_cat_folder * folder = & entry . folder ;
if ( fd - > entrylength < sizeof ( struct hfsplus_cat_folder ) )
/* panic? */ ;
hfs_bnode_read ( fd - > bnode , & entry , fd - > entryoffset ,
sizeof ( struct hfsplus_cat_folder ) ) ;
hfsplus_get_perms ( inode , & folder - > permissions , 1 ) ;
2011-10-28 16:13:29 +04:00
set_nlink ( inode , 1 ) ;
2005-04-17 02:20:36 +04:00
inode - > i_size = 2 + be32_to_cpu ( folder - > valence ) ;
inode - > i_atime = hfsp_mt2ut ( folder - > access_date ) ;
inode - > i_mtime = hfsp_mt2ut ( folder - > content_mod_date ) ;
2006-01-19 04:43:09 +03:00
inode - > i_ctime = hfsp_mt2ut ( folder - > attribute_mod_date ) ;
2010-10-01 07:43:31 +04:00
HFSPLUS_I ( inode ) - > create_date = folder - > create_date ;
HFSPLUS_I ( inode ) - > fs_blocks = 0 ;
2005-04-17 02:20:36 +04:00
inode - > i_op = & hfsplus_dir_inode_operations ;
inode - > i_fop = & hfsplus_dir_operations ;
} else if ( type = = HFSPLUS_FILE ) {
struct hfsplus_cat_file * file = & entry . file ;
if ( fd - > entrylength < sizeof ( struct hfsplus_cat_file ) )
/* panic? */ ;
hfs_bnode_read ( fd - > bnode , & entry , fd - > entryoffset ,
sizeof ( struct hfsplus_cat_file ) ) ;
2010-11-23 16:38:13 +03:00
hfsplus_inode_read_fork ( inode , HFSPLUS_IS_RSRC ( inode ) ?
& file - > rsrc_fork : & file - > data_fork ) ;
2005-04-17 02:20:36 +04:00
hfsplus_get_perms ( inode , & file - > permissions , 0 ) ;
2011-10-28 16:13:29 +04:00
set_nlink ( inode , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( S_ISREG ( inode - > i_mode ) ) {
if ( file - > permissions . dev )
2011-10-28 16:13:29 +04:00
set_nlink ( inode ,
be32_to_cpu ( file - > permissions . dev ) ) ;
2005-04-17 02:20:36 +04:00
inode - > i_op = & hfsplus_file_inode_operations ;
inode - > i_fop = & hfsplus_file_operations ;
inode - > i_mapping - > a_ops = & hfsplus_aops ;
} else if ( S_ISLNK ( inode - > i_mode ) ) {
inode - > i_op = & page_symlink_inode_operations ;
inode - > i_mapping - > a_ops = & hfsplus_aops ;
} else {
init_special_inode ( inode , inode - > i_mode ,
be32_to_cpu ( file - > permissions . dev ) ) ;
}
inode - > i_atime = hfsp_mt2ut ( file - > access_date ) ;
inode - > i_mtime = hfsp_mt2ut ( file - > content_mod_date ) ;
2006-01-19 04:43:09 +03:00
inode - > i_ctime = hfsp_mt2ut ( file - > attribute_mod_date ) ;
2010-10-01 07:43:31 +04:00
HFSPLUS_I ( inode ) - > create_date = file - > create_date ;
2005-04-17 02:20:36 +04:00
} else {
2006-01-19 04:43:05 +03:00
printk ( KERN_ERR " hfs: bad catalog entry used to create inode \n " ) ;
2005-04-17 02:20:36 +04:00
res = - EIO ;
}
return res ;
}
int hfsplus_cat_write_inode ( struct inode * inode )
{
struct inode * main_inode = inode ;
struct hfs_find_data fd ;
hfsplus_cat_entry entry ;
if ( HFSPLUS_IS_RSRC ( inode ) )
2010-10-01 07:43:31 +04:00
main_inode = HFSPLUS_I ( inode ) - > rsrc_inode ;
2005-04-17 02:20:36 +04:00
if ( ! main_inode - > i_nlink )
return 0 ;
2010-10-01 07:42:59 +04:00
if ( hfs_find_init ( HFSPLUS_SB ( main_inode - > i_sb ) - > cat_tree , & fd ) )
2005-04-17 02:20:36 +04:00
/* panic? */
return - EIO ;
if ( hfsplus_find_cat ( main_inode - > i_sb , main_inode - > i_ino , & fd ) )
/* panic? */
goto out ;
if ( S_ISDIR ( main_inode - > i_mode ) ) {
struct hfsplus_cat_folder * folder = & entry . folder ;
if ( fd . entrylength < sizeof ( struct hfsplus_cat_folder ) )
/* panic? */ ;
hfs_bnode_read ( fd . bnode , & entry , fd . entryoffset ,
sizeof ( struct hfsplus_cat_folder ) ) ;
/* simple node checks? */
2010-10-14 17:54:39 +04:00
hfsplus_cat_set_perms ( inode , & folder - > permissions ) ;
2005-04-17 02:20:36 +04:00
folder - > access_date = hfsp_ut2mt ( inode - > i_atime ) ;
folder - > content_mod_date = hfsp_ut2mt ( inode - > i_mtime ) ;
folder - > attribute_mod_date = hfsp_ut2mt ( inode - > i_ctime ) ;
folder - > valence = cpu_to_be32 ( inode - > i_size - 2 ) ;
hfs_bnode_write ( fd . bnode , & entry , fd . entryoffset ,
sizeof ( struct hfsplus_cat_folder ) ) ;
} else if ( HFSPLUS_IS_RSRC ( inode ) ) {
struct hfsplus_cat_file * file = & entry . file ;
hfs_bnode_read ( fd . bnode , & entry , fd . entryoffset ,
sizeof ( struct hfsplus_cat_file ) ) ;
hfsplus_inode_write_fork ( inode , & file - > rsrc_fork ) ;
hfs_bnode_write ( fd . bnode , & entry , fd . entryoffset ,
sizeof ( struct hfsplus_cat_file ) ) ;
} else {
struct hfsplus_cat_file * file = & entry . file ;
if ( fd . entrylength < sizeof ( struct hfsplus_cat_file ) )
/* panic? */ ;
hfs_bnode_read ( fd . bnode , & entry , fd . entryoffset ,
sizeof ( struct hfsplus_cat_file ) ) ;
hfsplus_inode_write_fork ( inode , & file - > data_fork ) ;
2010-10-14 17:54:39 +04:00
hfsplus_cat_set_perms ( inode , & file - > permissions ) ;
2010-12-16 19:08:38 +03:00
if ( HFSPLUS_FLG_IMMUTABLE &
( file - > permissions . rootflags |
file - > permissions . userflags ) )
2005-04-17 02:20:36 +04:00
file - > flags | = cpu_to_be16 ( HFSPLUS_FILE_LOCKED ) ;
else
file - > flags & = cpu_to_be16 ( ~ HFSPLUS_FILE_LOCKED ) ;
file - > access_date = hfsp_ut2mt ( inode - > i_atime ) ;
file - > content_mod_date = hfsp_ut2mt ( inode - > i_mtime ) ;
file - > attribute_mod_date = hfsp_ut2mt ( inode - > i_ctime ) ;
hfs_bnode_write ( fd . bnode , & entry , fd . entryoffset ,
sizeof ( struct hfsplus_cat_file ) ) ;
}
2010-11-23 16:38:15 +03:00
set_bit ( HFSPLUS_I_CAT_DIRTY , & HFSPLUS_I ( inode ) - > flags ) ;
2005-04-17 02:20:36 +04:00
out :
hfs_find_exit ( & fd ) ;
return 0 ;
}