2005-04-17 02:20:36 +04:00
/*
* namei . c
*
* PURPOSE
* Inode name handling routines for the OSTA - UDF ( tm ) filesystem .
*
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License ( GPL ) . Copies of the GPL can be obtained from :
* ftp : //prep.ai.mit.edu/pub/gnu/GPL
* Each contributing author retains all rights to their own work .
*
* ( C ) 1998 - 2004 Ben Fennema
* ( C ) 1999 - 2000 Stelias Computing Inc
*
* HISTORY
*
* 12 / 12 / 98 blf Created . Split out the lookup code from dir . c
* 04 / 19 / 99 blf link , mknod , symlink support
*/
# include "udfdecl.h"
# include "udf_i.h"
# include "udf_sb.h"
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/quotaops.h>
# include <linux/smp_lock.h>
# include <linux/buffer_head.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>
2008-04-17 11:47:48 +04:00
# include <linux/crc-itu-t.h>
2008-04-30 19:22:06 +04:00
# include <linux/exportfs.h>
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
static inline int udf_match ( int len1 , const char * name1 , int len2 ,
const char * name2 )
2005-04-17 02:20:36 +04:00
{
if ( len1 ! = len2 )
return 0 ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return ! memcmp ( name1 , name2 , len1 ) ;
}
int udf_write_fi ( struct inode * inode , struct fileIdentDesc * cfi ,
2007-07-19 12:47:43 +04:00
struct fileIdentDesc * sfi , struct udf_fileident_bh * fibh ,
2008-02-08 15:20:36 +03:00
uint8_t * impuse , uint8_t * fileident )
2005-04-17 02:20:36 +04:00
{
2008-10-15 14:28:03 +04:00
uint16_t crclen = fibh - > eoffset - fibh - > soffset - sizeof ( struct tag ) ;
2005-04-17 02:20:36 +04:00
uint16_t crc ;
int offset ;
uint16_t liu = le16_to_cpu ( cfi - > lengthOfImpUse ) ;
uint8_t lfi = cfi - > lengthFileIdent ;
int padlen = fibh - > eoffset - fibh - > soffset - liu - lfi -
2007-07-21 15:37:18 +04:00
sizeof ( struct fileIdentDesc ) ;
2005-04-17 02:20:36 +04:00
int adinicb = 0 ;
2008-02-08 15:20:42 +03:00
if ( UDF_I ( inode ) - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
2005-04-17 02:20:36 +04:00
adinicb = 1 ;
offset = fibh - > soffset + sizeof ( struct fileIdentDesc ) ;
2007-07-19 12:47:43 +04:00
if ( impuse ) {
2007-07-21 15:37:18 +04:00
if ( adinicb | | ( offset + liu < 0 ) ) {
memcpy ( ( uint8_t * ) sfi - > impUse , impuse , liu ) ;
} else if ( offset > = 0 ) {
2005-04-17 02:20:36 +04:00
memcpy ( fibh - > ebh - > b_data + offset , impuse , liu ) ;
2007-07-21 15:37:18 +04:00
} else {
memcpy ( ( uint8_t * ) sfi - > impUse , impuse , - offset ) ;
2008-02-08 15:20:36 +03:00
memcpy ( fibh - > ebh - > b_data , impuse - offset ,
liu + offset ) ;
2005-04-17 02:20:36 +04:00
}
}
offset + = liu ;
2007-07-19 12:47:43 +04:00
if ( fileident ) {
2007-07-21 15:37:18 +04:00
if ( adinicb | | ( offset + lfi < 0 ) ) {
memcpy ( ( uint8_t * ) sfi - > fileIdent + liu , fileident , lfi ) ;
} else if ( offset > = 0 ) {
2005-04-17 02:20:36 +04:00
memcpy ( fibh - > ebh - > b_data + offset , fileident , lfi ) ;
2007-07-21 15:37:18 +04:00
} else {
2008-02-08 15:20:36 +03:00
memcpy ( ( uint8_t * ) sfi - > fileIdent + liu , fileident ,
- offset ) ;
memcpy ( fibh - > ebh - > b_data , fileident - offset ,
lfi + offset ) ;
2005-04-17 02:20:36 +04:00
}
}
offset + = lfi ;
2007-07-21 15:37:18 +04:00
if ( adinicb | | ( offset + padlen < 0 ) ) {
memset ( ( uint8_t * ) sfi - > padding + liu + lfi , 0x00 , padlen ) ;
} else if ( offset > = 0 ) {
2005-04-17 02:20:36 +04:00
memset ( fibh - > ebh - > b_data + offset , 0x00 , padlen ) ;
2007-07-21 15:37:18 +04:00
} else {
memset ( ( uint8_t * ) sfi - > padding + liu + lfi , 0x00 , - offset ) ;
2005-04-17 02:20:36 +04:00
memset ( fibh - > ebh - > b_data , 0x00 , padlen + offset ) ;
}
2008-10-15 14:28:03 +04:00
crc = crc_itu_t ( 0 , ( uint8_t * ) cfi + sizeof ( struct tag ) ,
sizeof ( struct fileIdentDesc ) - sizeof ( struct tag ) ) ;
2007-07-21 15:37:18 +04:00
if ( fibh - > sbh = = fibh - > ebh ) {
2008-04-17 11:47:48 +04:00
crc = crc_itu_t ( crc , ( uint8_t * ) sfi - > impUse ,
2008-10-15 14:28:03 +04:00
crclen + sizeof ( struct tag ) -
2008-04-17 11:47:48 +04:00
sizeof ( struct fileIdentDesc ) ) ;
2007-07-21 15:37:18 +04:00
} else if ( sizeof ( struct fileIdentDesc ) > = - fibh - > soffset ) {
2008-04-17 11:47:48 +04:00
crc = crc_itu_t ( crc , fibh - > ebh - > b_data +
2008-02-08 15:20:36 +03:00
sizeof ( struct fileIdentDesc ) +
fibh - > soffset ,
2008-10-15 14:28:03 +04:00
crclen + sizeof ( struct tag ) -
2008-04-17 11:47:48 +04:00
sizeof ( struct fileIdentDesc ) ) ;
2007-07-21 15:37:18 +04:00
} else {
2008-04-17 11:47:48 +04:00
crc = crc_itu_t ( crc , ( uint8_t * ) sfi - > impUse ,
- fibh - > soffset - sizeof ( struct fileIdentDesc ) ) ;
crc = crc_itu_t ( crc , fibh - > ebh - > b_data , fibh - > eoffset ) ;
2005-04-17 02:20:36 +04:00
}
cfi - > descTag . descCRC = cpu_to_le16 ( crc ) ;
cfi - > descTag . descCRCLength = cpu_to_le16 ( crclen ) ;
2008-02-08 15:20:39 +03:00
cfi - > descTag . tagChecksum = udf_tag_checksum ( & cfi - > descTag ) ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
if ( adinicb | | ( sizeof ( struct fileIdentDesc ) < = - fibh - > soffset ) ) {
2008-02-08 15:20:36 +03:00
memcpy ( ( uint8_t * ) sfi , ( uint8_t * ) cfi ,
sizeof ( struct fileIdentDesc ) ) ;
2007-07-21 15:37:18 +04:00
} else {
memcpy ( ( uint8_t * ) sfi , ( uint8_t * ) cfi , - fibh - > soffset ) ;
memcpy ( fibh - > ebh - > b_data , ( uint8_t * ) cfi - fibh - > soffset ,
2007-07-19 12:47:43 +04:00
sizeof ( struct fileIdentDesc ) + fibh - > soffset ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
if ( adinicb ) {
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
2007-07-21 15:37:18 +04:00
} else {
2005-04-17 02:20:36 +04:00
if ( fibh - > sbh ! = fibh - > ebh )
mark_buffer_dirty_inode ( fibh - > ebh , inode ) ;
mark_buffer_dirty_inode ( fibh - > sbh , inode ) ;
}
return 0 ;
}
2007-07-19 12:47:43 +04:00
static struct fileIdentDesc * udf_find_entry ( struct inode * dir ,
2008-10-12 08:15:17 +04:00
struct qstr * child ,
2007-07-19 12:47:43 +04:00
struct udf_fileident_bh * fibh ,
struct fileIdentDesc * cfi )
2005-04-17 02:20:36 +04:00
{
2007-07-19 12:47:43 +04:00
struct fileIdentDesc * fi = NULL ;
2005-04-17 02:20:36 +04:00
loff_t f_pos ;
int block , flen ;
2008-03-04 16:14:05 +03:00
char * fname = NULL ;
2005-04-17 02:20:36 +04:00
char * nameptr ;
uint8_t lfi ;
uint16_t liu ;
2005-06-29 07:45:10 +04:00
loff_t size ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr eloc ;
2007-05-08 11:35:14 +04:00
uint32_t elen ;
2007-05-08 11:35:13 +04:00
sector_t offset ;
2007-07-21 15:37:18 +04:00
struct extent_position epos = { } ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * dinfo = UDF_I ( dir ) ;
2008-10-12 08:15:17 +04:00
int isdotdot = child - > len = = 2 & &
child - > name [ 0 ] = = ' . ' & & child - > name [ 1 ] = = ' . ' ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:50 +03:00
size = udf_ext0_offset ( dir ) + dir - > i_size ;
f_pos = udf_ext0_offset ( dir ) ;
2005-04-17 02:20:36 +04:00
2008-03-04 16:14:05 +03:00
fibh - > sbh = fibh - > ebh = NULL ;
2008-02-08 15:20:50 +03:00
fibh - > soffset = fibh - > eoffset = f_pos & ( dir - > i_sb - > s_blocksize - 1 ) ;
2008-03-04 16:14:05 +03:00
if ( dinfo - > i_alloc_type ! = ICBTAG_FLAG_AD_IN_ICB ) {
if ( inode_bmap ( dir , f_pos > > dir - > i_sb - > s_blocksize_bits , & epos ,
& eloc , & elen , & offset ) ! = ( EXT_RECORDED_ALLOCATED > > 30 ) )
goto out_err ;
2008-10-15 14:29:03 +04:00
block = udf_get_lb_pblock ( dir - > i_sb , & eloc , offset ) ;
2007-07-19 12:47:43 +04:00
if ( ( + + offset < < dir - > i_sb - > s_blocksize_bits ) < elen ) {
2008-02-08 15:20:44 +03:00
if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
2008-10-15 14:28:03 +04:00
epos . offset - = sizeof ( struct short_ad ) ;
2008-02-08 15:20:44 +03:00
else if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2008-10-15 14:28:03 +04:00
epos . offset - = sizeof ( struct long_ad ) ;
2008-02-08 15:20:36 +03:00
} else
2005-04-17 02:20:36 +04:00
offset = 0 ;
2008-02-08 15:20:36 +03:00
fibh - > sbh = fibh - > ebh = udf_tread ( dir - > i_sb , block ) ;
2008-03-04 16:14:05 +03:00
if ( ! fibh - > sbh )
goto out_err ;
2005-04-17 02:20:36 +04:00
}
2008-03-04 16:14:05 +03:00
fname = kmalloc ( UDF_NAME_LEN , GFP_NOFS ) ;
if ( ! fname )
goto out_err ;
2008-02-08 15:20:50 +03:00
while ( f_pos < size ) {
2007-07-19 12:47:43 +04:00
fi = udf_fileident_read ( dir , & f_pos , fibh , cfi , & epos , & eloc ,
& elen , & offset ) ;
2008-03-04 16:14:05 +03:00
if ( ! fi )
goto out_err ;
2005-04-17 02:20:36 +04:00
liu = le16_to_cpu ( cfi - > lengthOfImpUse ) ;
lfi = cfi - > lengthFileIdent ;
2007-07-19 12:47:43 +04:00
if ( fibh - > sbh = = fibh - > ebh ) {
2005-04-17 02:20:36 +04:00
nameptr = fi - > fileIdent + liu ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
int poffset ; /* Unpaded ending offset */
2008-02-08 15:20:36 +03:00
poffset = fibh - > soffset + sizeof ( struct fileIdentDesc ) +
liu + lfi ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
if ( poffset > = lfi )
nameptr = ( uint8_t * ) ( fibh - > ebh - > b_data +
poffset - lfi ) ;
else {
2005-04-17 02:20:36 +04:00
nameptr = fname ;
2008-02-08 15:20:36 +03:00
memcpy ( nameptr , fi - > fileIdent + liu ,
lfi - poffset ) ;
memcpy ( nameptr + lfi - poffset ,
fibh - > ebh - > b_data , poffset ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-07-19 12:47:43 +04:00
if ( ( cfi - > fileCharacteristics & FID_FILE_CHAR_DELETED ) ! = 0 ) {
if ( ! UDF_QUERY_FLAG ( dir - > i_sb , UDF_FLAG_UNDELETE ) )
2005-04-17 02:20:36 +04:00
continue ;
}
2007-07-19 12:47:43 +04:00
if ( ( cfi - > fileCharacteristics & FID_FILE_CHAR_HIDDEN ) ! = 0 ) {
if ( ! UDF_QUERY_FLAG ( dir - > i_sb , UDF_FLAG_UNHIDE ) )
2005-04-17 02:20:36 +04:00
continue ;
}
2008-04-30 19:22:06 +04:00
if ( ( cfi - > fileCharacteristics & FID_FILE_CHAR_PARENT ) & &
isdotdot ) {
brelse ( epos . bh ) ;
return fi ;
}
2005-04-17 02:20:36 +04:00
if ( ! lfi )
continue ;
2008-02-08 15:20:36 +03:00
flen = udf_get_filename ( dir - > i_sb , nameptr , fname , lfi ) ;
2008-10-12 08:15:17 +04:00
if ( flen & & udf_match ( flen , fname , child - > len , child - > name ) )
2008-03-04 16:14:05 +03:00
goto out_ok ;
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
2008-03-04 16:14:05 +03:00
out_err :
fi = NULL ;
2005-04-17 02:20:36 +04:00
if ( fibh - > sbh ! = fibh - > ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh - > ebh ) ;
brelse ( fibh - > sbh ) ;
2008-03-04 16:14:05 +03:00
out_ok :
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2008-03-04 16:14:05 +03:00
kfree ( fname ) ;
2007-07-21 15:37:18 +04:00
2008-03-04 16:14:05 +03:00
return fi ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
static struct dentry * udf_lookup ( struct inode * dir , struct dentry * dentry ,
struct nameidata * nd )
2005-04-17 02:20:36 +04:00
{
struct inode * inode = NULL ;
2006-02-03 14:04:50 +03:00
struct fileIdentDesc cfi ;
2005-04-17 02:20:36 +04:00
struct udf_fileident_bh fibh ;
2007-07-19 12:47:43 +04:00
if ( dentry - > d_name . len > UDF_NAME_LEN - 2 )
2005-04-17 02:20:36 +04:00
return ERR_PTR ( - ENAMETOOLONG ) ;
lock_kernel ( ) ;
# ifdef UDF_RECOVERY
/* temporary shorthand for specifying files by inode number */
2007-07-19 12:47:43 +04:00
if ( ! strncmp ( dentry - > d_name . name , " .B= " , 3 ) ) {
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr lb = {
2007-07-21 15:37:18 +04:00
. logicalBlockNum = 0 ,
2008-02-08 15:20:36 +03:00
. partitionReferenceNum =
simple_strtoul ( dentry - > d_name . name + 3 ,
NULL , 0 ) ,
2007-07-21 15:37:18 +04:00
} ;
2005-04-17 02:20:36 +04:00
inode = udf_iget ( dir - > i_sb , lb ) ;
2007-07-19 12:47:43 +04:00
if ( ! inode ) {
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return ERR_PTR ( - EACCES ) ;
}
2008-02-08 15:20:36 +03:00
} else
2007-07-21 15:37:18 +04:00
# endif /* UDF_RECOVERY */
2005-04-17 02:20:36 +04:00
2008-10-12 08:15:17 +04:00
if ( udf_find_entry ( dir , & dentry - > d_name , & fibh , & cfi ) ) {
2008-10-15 14:29:03 +04:00
struct kernel_lb_addr loc ;
2005-04-17 02:20:36 +04:00
if ( fibh . sbh ! = fibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
2005-04-17 02:20:36 +04:00
2008-10-15 14:29:03 +04:00
loc = lelb_to_cpu ( cfi . icb . extLocation ) ;
inode = udf_iget ( dir - > i_sb , & loc ) ;
2007-07-19 12:47:43 +04:00
if ( ! inode ) {
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return ERR_PTR ( - EACCES ) ;
}
}
unlock_kernel ( ) ;
2007-07-21 15:37:18 +04:00
2008-04-30 19:22:06 +04:00
return d_splice_alias ( inode , dentry ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
static struct fileIdentDesc * udf_add_entry ( struct inode * dir ,
struct dentry * dentry ,
struct udf_fileident_bh * fibh ,
struct fileIdentDesc * cfi , int * err )
2005-04-17 02:20:36 +04:00
{
2008-02-08 15:20:30 +03:00
struct super_block * sb = dir - > i_sb ;
2007-07-19 12:47:43 +04:00
struct fileIdentDesc * fi = NULL ;
2008-03-04 16:14:05 +03:00
char * name = NULL ;
2005-04-17 02:20:36 +04:00
int namelen ;
loff_t f_pos ;
2008-02-08 15:20:50 +03:00
loff_t size = udf_ext0_offset ( dir ) + dir - > i_size ;
2005-04-17 02:20:36 +04:00
int nfidlen ;
uint8_t lfi ;
uint16_t liu ;
int block ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr eloc ;
2008-05-06 20:26:17 +04:00
uint32_t elen = 0 ;
2007-05-08 11:35:13 +04:00
sector_t offset ;
2007-07-21 15:37:18 +04:00
struct extent_position epos = { } ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * dinfo ;
2005-04-17 02:20:36 +04:00
2008-03-04 16:14:05 +03:00
fibh - > sbh = fibh - > ebh = NULL ;
name = kmalloc ( UDF_NAME_LEN , GFP_NOFS ) ;
if ( ! name ) {
* err = - ENOMEM ;
goto out_err ;
}
2007-07-19 12:47:43 +04:00
if ( dentry ) {
if ( ! dentry - > d_name . len ) {
2005-04-17 02:20:36 +04:00
* err = - EINVAL ;
2008-03-04 16:14:05 +03:00
goto out_err ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:36 +03:00
namelen = udf_put_filename ( sb , dentry - > d_name . name , name ,
dentry - > d_name . len ) ;
if ( ! namelen ) {
2005-04-17 02:20:36 +04:00
* err = - ENAMETOOLONG ;
2008-03-04 16:14:05 +03:00
goto out_err ;
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
} else {
2005-04-17 02:20:36 +04:00
namelen = 0 ;
2007-07-21 15:37:18 +04:00
}
2005-04-17 02:20:36 +04:00
nfidlen = ( sizeof ( struct fileIdentDesc ) + namelen + 3 ) & ~ 3 ;
2008-02-08 15:20:50 +03:00
f_pos = udf_ext0_offset ( dir ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:50 +03:00
fibh - > soffset = fibh - > eoffset = f_pos & ( dir - > i_sb - > s_blocksize - 1 ) ;
2008-02-08 15:20:44 +03:00
dinfo = UDF_I ( dir ) ;
2008-03-04 16:14:05 +03:00
if ( dinfo - > i_alloc_type ! = ICBTAG_FLAG_AD_IN_ICB ) {
if ( inode_bmap ( dir , f_pos > > dir - > i_sb - > s_blocksize_bits , & epos ,
& eloc , & elen , & offset ) ! = ( EXT_RECORDED_ALLOCATED > > 30 ) ) {
block = udf_get_lb_pblock ( dir - > i_sb ,
2008-10-15 14:29:03 +04:00
& dinfo - > i_location , 0 ) ;
2008-03-04 16:14:05 +03:00
fibh - > soffset = fibh - > eoffset = sb - > s_blocksize ;
goto add ;
}
2008-10-15 14:29:03 +04:00
block = udf_get_lb_pblock ( dir - > i_sb , & eloc , offset ) ;
2007-07-19 12:47:43 +04:00
if ( ( + + offset < < dir - > i_sb - > s_blocksize_bits ) < elen ) {
2008-02-08 15:20:44 +03:00
if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
2008-10-15 14:28:03 +04:00
epos . offset - = sizeof ( struct short_ad ) ;
2008-02-08 15:20:44 +03:00
else if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2008-10-15 14:28:03 +04:00
epos . offset - = sizeof ( struct long_ad ) ;
2008-02-08 15:20:36 +03:00
} else
2005-04-17 02:20:36 +04:00
offset = 0 ;
2008-02-08 15:20:36 +03:00
fibh - > sbh = fibh - > ebh = udf_tread ( dir - > i_sb , block ) ;
if ( ! fibh - > sbh ) {
2005-04-17 02:20:36 +04:00
* err = - EIO ;
2008-03-04 16:14:05 +03:00
goto out_err ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:44 +03:00
block = dinfo - > i_location . logicalBlockNum ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:50 +03:00
while ( f_pos < size ) {
2007-07-19 12:47:43 +04:00
fi = udf_fileident_read ( dir , & f_pos , fibh , cfi , & epos , & eloc ,
& elen , & offset ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( ! fi ) {
2005-04-17 02:20:36 +04:00
* err = - EIO ;
2008-03-04 16:14:05 +03:00
goto out_err ;
2005-04-17 02:20:36 +04:00
}
liu = le16_to_cpu ( cfi - > lengthOfImpUse ) ;
lfi = cfi - > lengthFileIdent ;
2007-07-19 12:47:43 +04:00
if ( ( cfi - > fileCharacteristics & FID_FILE_CHAR_DELETED ) ! = 0 ) {
2008-02-08 15:20:36 +03:00
if ( ( ( sizeof ( struct fileIdentDesc ) +
liu + lfi + 3 ) & ~ 3 ) = = nfidlen ) {
2005-04-17 02:20:36 +04:00
cfi - > descTag . tagSerialNum = cpu_to_le16 ( 1 ) ;
cfi - > fileVersionNum = cpu_to_le16 ( 1 ) ;
cfi - > fileCharacteristics = 0 ;
cfi - > lengthFileIdent = namelen ;
cfi - > lengthOfImpUse = cpu_to_le16 ( 0 ) ;
2008-02-08 15:20:36 +03:00
if ( ! udf_write_fi ( dir , cfi , fi , fibh , NULL ,
name ) )
2008-03-04 16:14:05 +03:00
goto out_ok ;
2008-02-08 15:20:36 +03:00
else {
2005-04-17 02:20:36 +04:00
* err = - EIO ;
2008-03-04 16:14:05 +03:00
goto out_err ;
2005-04-17 02:20:36 +04:00
}
}
}
}
2007-07-21 15:37:18 +04:00
add :
2005-04-17 02:20:36 +04:00
f_pos + = nfidlen ;
2008-02-08 15:20:44 +03:00
if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB & &
2007-07-19 12:47:43 +04:00
sb - > s_blocksize - fibh - > eoffset < nfidlen ) {
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2007-05-08 11:35:14 +04:00
epos . bh = NULL ;
2005-04-17 02:20:36 +04:00
fibh - > soffset - = udf_ext0_offset ( dir ) ;
fibh - > eoffset - = udf_ext0_offset ( dir ) ;
2008-02-08 15:20:50 +03:00
f_pos - = udf_ext0_offset ( dir ) ;
2005-04-17 02:20:36 +04:00
if ( fibh - > sbh ! = fibh - > ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh - > ebh ) ;
brelse ( fibh - > sbh ) ;
2008-02-08 15:20:36 +03:00
fibh - > sbh = fibh - > ebh =
udf_expand_dir_adinicb ( dir , & block , err ) ;
if ( ! fibh - > sbh )
2008-03-04 16:14:05 +03:00
goto out_err ;
2008-02-08 15:20:44 +03:00
epos . block = dinfo - > i_location ;
2007-05-08 11:35:14 +04:00
epos . offset = udf_file_entry_alloc_offset ( dir ) ;
2008-02-08 15:20:51 +03:00
/* Load extent udf_expand_dir_adinicb() has created */
udf_current_aext ( dir , & epos , & eloc , & elen , 1 ) ;
2005-04-17 02:20:36 +04:00
}
2009-12-03 15:39:28 +03:00
/* Entry fits into current block? */
2007-07-19 12:47:43 +04:00
if ( sb - > s_blocksize - fibh - > eoffset > = nfidlen ) {
2005-04-17 02:20:36 +04:00
fibh - > soffset = fibh - > eoffset ;
fibh - > eoffset + = nfidlen ;
2007-07-19 12:47:43 +04:00
if ( fibh - > sbh ! = fibh - > ebh ) {
2007-05-08 11:35:16 +04:00
brelse ( fibh - > sbh ) ;
2005-04-17 02:20:36 +04:00
fibh - > sbh = fibh - > ebh ;
}
2008-02-08 15:20:44 +03:00
if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB ) {
block = dinfo - > i_location . logicalBlockNum ;
2008-02-08 15:20:36 +03:00
fi = ( struct fileIdentDesc * )
2008-02-08 15:20:44 +03:00
( dinfo - > i_ext . i_data +
2008-02-08 15:20:42 +03:00
fibh - > soffset -
2008-02-08 15:20:36 +03:00
udf_ext0_offset ( dir ) +
2008-02-08 15:20:44 +03:00
dinfo - > i_lenEAttr ) ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:36 +03:00
block = eloc . logicalBlockNum +
( ( elen - 1 ) > >
dir - > i_sb - > s_blocksize_bits ) ;
fi = ( struct fileIdentDesc * )
( fibh - > sbh - > b_data + fibh - > soffset ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
} else {
2009-12-03 15:39:28 +03:00
/* Round up last extent in the file */
elen = ( elen + sb - > s_blocksize - 1 ) & ~ ( sb - > s_blocksize - 1 ) ;
if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
epos . offset - = sizeof ( struct short_ad ) ;
else if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
epos . offset - = sizeof ( struct long_ad ) ;
udf_write_aext ( dir , & epos , & eloc , elen , 1 ) ;
dinfo - > i_lenExtents = ( dinfo - > i_lenExtents + sb - > s_blocksize
- 1 ) & ~ ( sb - > s_blocksize - 1 ) ;
2005-04-17 02:20:36 +04:00
fibh - > soffset = fibh - > eoffset - sb - > s_blocksize ;
fibh - > eoffset + = nfidlen - sb - > s_blocksize ;
2007-07-19 12:47:43 +04:00
if ( fibh - > sbh ! = fibh - > ebh ) {
2007-05-08 11:35:16 +04:00
brelse ( fibh - > sbh ) ;
2005-04-17 02:20:36 +04:00
fibh - > sbh = fibh - > ebh ;
}
block = eloc . logicalBlockNum + ( ( elen - 1 ) > >
2007-07-19 12:47:43 +04:00
dir - > i_sb - > s_blocksize_bits ) ;
2008-02-08 15:20:36 +03:00
fibh - > ebh = udf_bread ( dir ,
2008-02-08 15:20:50 +03:00
f_pos > > dir - > i_sb - > s_blocksize_bits , 1 , err ) ;
2008-03-04 16:14:05 +03:00
if ( ! fibh - > ebh )
goto out_err ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
if ( ! fibh - > soffset ) {
2007-05-08 11:35:14 +04:00
if ( udf_next_aext ( dir , & epos , & eloc , & elen , 1 ) = =
2007-07-19 12:47:43 +04:00
( EXT_RECORDED_ALLOCATED > > 30 ) ) {
2005-04-17 02:20:36 +04:00
block = eloc . logicalBlockNum + ( ( elen - 1 ) > >
2007-07-21 15:37:18 +04:00
dir - > i_sb - > s_blocksize_bits ) ;
2008-02-08 15:20:36 +03:00
} else
2007-07-19 12:47:43 +04:00
block + + ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:16 +04:00
brelse ( fibh - > sbh ) ;
2005-04-17 02:20:36 +04:00
fibh - > sbh = fibh - > ebh ;
fi = ( struct fileIdentDesc * ) ( fibh - > sbh - > b_data ) ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
fi = ( struct fileIdentDesc * )
2008-02-08 15:20:36 +03:00
( fibh - > sbh - > b_data + sb - > s_blocksize +
fibh - > soffset ) ;
2005-04-17 02:20:36 +04:00
}
}
memset ( cfi , 0 , sizeof ( struct fileIdentDesc ) ) ;
2008-02-08 15:20:30 +03:00
if ( UDF_SB ( sb ) - > s_udfrev > = 0x0200 )
2008-02-08 15:20:36 +03:00
udf_new_tag ( ( char * ) cfi , TAG_IDENT_FID , 3 , 1 , block ,
2008-10-15 14:28:03 +04:00
sizeof ( struct tag ) ) ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:36 +03:00
udf_new_tag ( ( char * ) cfi , TAG_IDENT_FID , 2 , 1 , block ,
2008-10-15 14:28:03 +04:00
sizeof ( struct tag ) ) ;
2005-04-17 02:20:36 +04:00
cfi - > fileVersionNum = cpu_to_le16 ( 1 ) ;
cfi - > lengthFileIdent = namelen ;
cfi - > lengthOfImpUse = cpu_to_le16 ( 0 ) ;
2007-07-19 12:47:43 +04:00
if ( ! udf_write_fi ( dir , cfi , fi , fibh , NULL , name ) ) {
2005-04-17 02:20:36 +04:00
dir - > i_size + = nfidlen ;
2008-02-08 15:20:44 +03:00
if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
dinfo - > i_lenAlloc + = nfidlen ;
2009-12-03 15:39:28 +03:00
else {
/* Find the last extent and truncate it to proper size */
while ( udf_next_aext ( dir , & epos , & eloc , & elen , 1 ) = =
( EXT_RECORDED_ALLOCATED > > 30 ) )
;
elen - = dinfo - > i_lenExtents - dir - > i_size ;
if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
epos . offset - = sizeof ( struct short_ad ) ;
else if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
epos . offset - = sizeof ( struct long_ad ) ;
udf_write_aext ( dir , & epos , & eloc , elen , 1 ) ;
dinfo - > i_lenExtents = dir - > i_size ;
}
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( dir ) ;
2008-03-04 16:14:05 +03:00
goto out_ok ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
* err = - EIO ;
2008-03-04 16:14:05 +03:00
goto out_err ;
2005-04-17 02:20:36 +04:00
}
2008-03-04 16:14:05 +03:00
out_err :
fi = NULL ;
if ( fibh - > sbh ! = fibh - > ebh )
brelse ( fibh - > ebh ) ;
brelse ( fibh - > sbh ) ;
out_ok :
brelse ( epos . bh ) ;
kfree ( name ) ;
return fi ;
2005-04-17 02:20:36 +04:00
}
static int udf_delete_entry ( struct inode * inode , struct fileIdentDesc * fi ,
2007-07-19 12:47:43 +04:00
struct udf_fileident_bh * fibh ,
struct fileIdentDesc * cfi )
2005-04-17 02:20:36 +04:00
{
cfi - > fileCharacteristics | = FID_FILE_CHAR_DELETED ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
if ( UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_STRICT ) )
2008-10-15 14:28:03 +04:00
memset ( & ( cfi - > icb ) , 0x00 , sizeof ( struct long_ad ) ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return udf_write_fi ( inode , cfi , fi , fibh , NULL , NULL ) ;
}
2007-07-19 12:47:43 +04:00
static int udf_create ( struct inode * dir , struct dentry * dentry , int mode ,
struct nameidata * nd )
2005-04-17 02:20:36 +04:00
{
struct udf_fileident_bh fibh ;
struct inode * inode ;
struct fileIdentDesc cfi , * fi ;
int err ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2005-04-17 02:20:36 +04:00
lock_kernel ( ) ;
inode = udf_new_inode ( dir , mode , & err ) ;
2007-07-19 12:47:43 +04:00
if ( ! inode ) {
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return err ;
}
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
2005-04-17 02:20:36 +04:00
inode - > i_data . a_ops = & udf_adinicb_aops ;
else
inode - > i_data . a_ops = & udf_aops ;
inode - > i_op = & udf_file_inode_operations ;
inode - > i_fop = & udf_file_operations ;
inode - > i_mode = mode ;
mark_inode_dirty ( inode ) ;
2008-02-08 15:20:36 +03:00
fi = udf_add_entry ( dir , dentry , & fibh , & cfi , & err ) ;
if ( ! fi ) {
2007-07-19 12:47:43 +04:00
inode - > i_nlink - - ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
iput ( inode ) ;
unlock_kernel ( ) ;
return err ;
}
cfi . icb . extLength = cpu_to_le32 ( inode - > i_sb - > s_blocksize ) ;
2008-02-08 15:20:44 +03:00
cfi . icb . extLocation = cpu_to_lelb ( iinfo - > i_location ) ;
2007-07-21 15:37:18 +04:00
* ( __le32 * ) ( ( struct allocDescImpUse * ) cfi . icb . impUse ) - > impUse =
2008-02-08 15:20:44 +03:00
cpu_to_le32 ( iinfo - > i_unique & 0x00000000FFFFFFFFUL ) ;
2005-04-17 02:20:36 +04:00
udf_write_fi ( dir , & cfi , fi , & fibh , NULL , NULL ) ;
2008-02-08 15:20:42 +03:00
if ( UDF_I ( dir ) - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( dir ) ;
if ( fibh . sbh ! = fibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
d_instantiate ( dentry , inode ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-19 12:47:43 +04:00
static int udf_mknod ( struct inode * dir , struct dentry * dentry , int mode ,
dev_t rdev )
2005-04-17 02:20:36 +04:00
{
2007-07-19 12:47:43 +04:00
struct inode * inode ;
2005-04-17 02:20:36 +04:00
struct udf_fileident_bh fibh ;
struct fileIdentDesc cfi , * fi ;
int err ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2005-04-17 02:20:36 +04:00
if ( ! old_valid_dev ( rdev ) )
return - EINVAL ;
lock_kernel ( ) ;
err = - EIO ;
inode = udf_new_inode ( dir , mode , & err ) ;
if ( ! inode )
goto out ;
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
2008-11-14 02:39:03 +03:00
inode - > i_uid = current_fsuid ( ) ;
2005-04-17 02:20:36 +04:00
init_special_inode ( inode , mode , rdev ) ;
2008-02-08 15:20:36 +03:00
fi = udf_add_entry ( dir , dentry , & fibh , & cfi , & err ) ;
if ( ! fi ) {
2007-07-19 12:47:43 +04:00
inode - > i_nlink - - ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
iput ( inode ) ;
unlock_kernel ( ) ;
return err ;
}
cfi . icb . extLength = cpu_to_le32 ( inode - > i_sb - > s_blocksize ) ;
2008-02-08 15:20:44 +03:00
cfi . icb . extLocation = cpu_to_lelb ( iinfo - > i_location ) ;
2007-07-21 15:37:18 +04:00
* ( __le32 * ) ( ( struct allocDescImpUse * ) cfi . icb . impUse ) - > impUse =
2008-02-08 15:20:44 +03:00
cpu_to_le32 ( iinfo - > i_unique & 0x00000000FFFFFFFFUL ) ;
2005-04-17 02:20:36 +04:00
udf_write_fi ( dir , & cfi , fi , & fibh , NULL , NULL ) ;
2008-02-08 15:20:42 +03:00
if ( UDF_I ( dir ) - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( dir ) ;
mark_inode_dirty ( inode ) ;
if ( fibh . sbh ! = fibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
2005-04-17 02:20:36 +04:00
d_instantiate ( dentry , inode ) ;
err = 0 ;
2007-07-21 15:37:18 +04:00
out :
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return err ;
}
2007-07-19 12:47:43 +04:00
static int udf_mkdir ( struct inode * dir , struct dentry * dentry , int mode )
2005-04-17 02:20:36 +04:00
{
2007-07-19 12:47:43 +04:00
struct inode * inode ;
2005-04-17 02:20:36 +04:00
struct udf_fileident_bh fibh ;
struct fileIdentDesc cfi , * fi ;
int err ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * dinfo = UDF_I ( dir ) ;
struct udf_inode_info * iinfo ;
2005-04-17 02:20:36 +04:00
lock_kernel ( ) ;
err = - EMLINK ;
2007-07-19 12:47:43 +04:00
if ( dir - > i_nlink > = ( 256 < < sizeof ( dir - > i_nlink ) ) - 1 )
2005-04-17 02:20:36 +04:00
goto out ;
err = - EIO ;
inode = udf_new_inode ( dir , S_IFDIR , & err ) ;
if ( ! inode )
goto out ;
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
inode - > i_op = & udf_dir_inode_operations ;
inode - > i_fop = & udf_dir_operations ;
2008-02-08 15:20:36 +03:00
fi = udf_add_entry ( inode , NULL , & fibh , & cfi , & err ) ;
if ( ! fi ) {
2005-04-17 02:20:36 +04:00
inode - > i_nlink - - ;
mark_inode_dirty ( inode ) ;
iput ( inode ) ;
goto out ;
}
inode - > i_nlink = 2 ;
cfi . icb . extLength = cpu_to_le32 ( inode - > i_sb - > s_blocksize ) ;
2008-02-08 15:20:44 +03:00
cfi . icb . extLocation = cpu_to_lelb ( dinfo - > i_location ) ;
2007-07-21 15:37:18 +04:00
* ( __le32 * ) ( ( struct allocDescImpUse * ) cfi . icb . impUse ) - > impUse =
2008-02-08 15:20:44 +03:00
cpu_to_le32 ( dinfo - > i_unique & 0x00000000FFFFFFFFUL ) ;
2008-02-08 15:20:36 +03:00
cfi . fileCharacteristics =
FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT ;
2005-04-17 02:20:36 +04:00
udf_write_fi ( inode , & cfi , fi , & fibh , NULL , NULL ) ;
2007-05-08 11:35:16 +04:00
brelse ( fibh . sbh ) ;
2005-04-17 02:20:36 +04:00
inode - > i_mode = S_IFDIR | mode ;
if ( dir - > i_mode & S_ISGID )
inode - > i_mode | = S_ISGID ;
mark_inode_dirty ( inode ) ;
2008-02-08 15:20:36 +03:00
fi = udf_add_entry ( dir , dentry , & fibh , & cfi , & err ) ;
if ( ! fi ) {
2005-04-17 02:20:36 +04:00
inode - > i_nlink = 0 ;
mark_inode_dirty ( inode ) ;
iput ( inode ) ;
goto out ;
}
cfi . icb . extLength = cpu_to_le32 ( inode - > i_sb - > s_blocksize ) ;
2008-02-08 15:20:44 +03:00
cfi . icb . extLocation = cpu_to_lelb ( iinfo - > i_location ) ;
2007-07-21 15:37:18 +04:00
* ( __le32 * ) ( ( struct allocDescImpUse * ) cfi . icb . impUse ) - > impUse =
2008-02-08 15:20:44 +03:00
cpu_to_le32 ( iinfo - > i_unique & 0x00000000FFFFFFFFUL ) ;
2005-04-17 02:20:36 +04:00
cfi . fileCharacteristics | = FID_FILE_CHAR_DIRECTORY ;
udf_write_fi ( dir , & cfi , fi , & fibh , NULL , NULL ) ;
2006-10-01 10:29:04 +04:00
inc_nlink ( dir ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( dir ) ;
d_instantiate ( dentry , inode ) ;
if ( fibh . sbh ! = fibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
2005-04-17 02:20:36 +04:00
err = 0 ;
2007-07-21 15:37:18 +04:00
out :
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return err ;
}
static int empty_dir ( struct inode * dir )
{
struct fileIdentDesc * fi , cfi ;
struct udf_fileident_bh fibh ;
loff_t f_pos ;
2008-02-08 15:20:50 +03:00
loff_t size = udf_ext0_offset ( dir ) + dir - > i_size ;
2005-04-17 02:20:36 +04:00
int block ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr eloc ;
2007-05-08 11:35:14 +04:00
uint32_t elen ;
2007-05-08 11:35:13 +04:00
sector_t offset ;
2007-07-21 15:37:18 +04:00
struct extent_position epos = { } ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * dinfo = UDF_I ( dir ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:50 +03:00
f_pos = udf_ext0_offset ( dir ) ;
fibh . soffset = fibh . eoffset = f_pos & ( dir - > i_sb - > s_blocksize - 1 ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:44 +03:00
if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
2005-04-17 02:20:36 +04:00
fibh . sbh = fibh . ebh = NULL ;
2008-02-08 15:20:50 +03:00
else if ( inode_bmap ( dir , f_pos > > dir - > i_sb - > s_blocksize_bits ,
2008-02-08 15:20:36 +03:00
& epos , & eloc , & elen , & offset ) = =
( EXT_RECORDED_ALLOCATED > > 30 ) ) {
2008-10-15 14:29:03 +04:00
block = udf_get_lb_pblock ( dir - > i_sb , & eloc , offset ) ;
2007-07-19 12:47:43 +04:00
if ( ( + + offset < < dir - > i_sb - > s_blocksize_bits ) < elen ) {
2008-02-08 15:20:44 +03:00
if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
2008-10-15 14:28:03 +04:00
epos . offset - = sizeof ( struct short_ad ) ;
2008-02-08 15:20:44 +03:00
else if ( dinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2008-10-15 14:28:03 +04:00
epos . offset - = sizeof ( struct long_ad ) ;
2008-02-08 15:20:36 +03:00
} else
2005-04-17 02:20:36 +04:00
offset = 0 ;
2008-02-08 15:20:36 +03:00
fibh . sbh = fibh . ebh = udf_tread ( dir - > i_sb , block ) ;
if ( ! fibh . sbh ) {
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-19 12:47:43 +04:00
} else {
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-02-08 15:20:50 +03:00
while ( f_pos < size ) {
2007-07-19 12:47:43 +04:00
fi = udf_fileident_read ( dir , & f_pos , & fibh , & cfi , & epos , & eloc ,
& elen , & offset ) ;
if ( ! fi ) {
2005-04-17 02:20:36 +04:00
if ( fibh . sbh ! = fibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
brelse ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-21 15:37:18 +04:00
if ( cfi . lengthFileIdent & &
( cfi . fileCharacteristics & FID_FILE_CHAR_DELETED ) = = 0 ) {
2005-04-17 02:20:36 +04:00
if ( fibh . sbh ! = fibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
brelse ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
}
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
if ( fibh . sbh ! = fibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
brelse ( epos . bh ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return 1 ;
}
2007-07-19 12:47:43 +04:00
static int udf_rmdir ( struct inode * dir , struct dentry * dentry )
2005-04-17 02:20:36 +04:00
{
int retval ;
2007-07-19 12:47:43 +04:00
struct inode * inode = dentry - > d_inode ;
2005-04-17 02:20:36 +04:00
struct udf_fileident_bh fibh ;
struct fileIdentDesc * fi , cfi ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr tloc ;
2005-04-17 02:20:36 +04:00
retval = - ENOENT ;
lock_kernel ( ) ;
2008-10-12 08:15:17 +04:00
fi = udf_find_entry ( dir , & dentry - > d_name , & fibh , & cfi ) ;
2005-04-17 02:20:36 +04:00
if ( ! fi )
goto out ;
retval = - EIO ;
tloc = lelb_to_cpu ( cfi . icb . extLocation ) ;
2008-10-15 14:29:03 +04:00
if ( udf_get_lb_pblock ( dir - > i_sb , & tloc , 0 ) ! = inode - > i_ino )
2005-04-17 02:20:36 +04:00
goto end_rmdir ;
retval = - ENOTEMPTY ;
if ( ! empty_dir ( inode ) )
goto end_rmdir ;
retval = udf_delete_entry ( dir , fi , & fibh , & cfi ) ;
if ( retval )
goto end_rmdir ;
if ( inode - > i_nlink ! = 2 )
udf_warning ( inode - > i_sb , " udf_rmdir " ,
2007-07-19 12:47:43 +04:00
" empty directory has nlink != 2 (%d) " ,
inode - > i_nlink ) ;
2006-10-01 10:29:06 +04:00
clear_nlink ( inode ) ;
2005-04-17 02:20:36 +04:00
inode - > i_size = 0 ;
2007-05-08 11:31:31 +04:00
inode_dec_link_count ( dir ) ;
2008-02-08 15:20:36 +03:00
inode - > i_ctime = dir - > i_ctime = dir - > i_mtime =
current_fs_time ( dir - > i_sb ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( dir ) ;
2007-07-21 15:37:18 +04:00
end_rmdir :
2005-04-17 02:20:36 +04:00
if ( fibh . sbh ! = fibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
2007-07-21 15:37:18 +04:00
out :
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return retval ;
}
2007-07-19 12:47:43 +04:00
static int udf_unlink ( struct inode * dir , struct dentry * dentry )
2005-04-17 02:20:36 +04:00
{
int retval ;
2007-07-19 12:47:43 +04:00
struct inode * inode = dentry - > d_inode ;
2005-04-17 02:20:36 +04:00
struct udf_fileident_bh fibh ;
struct fileIdentDesc * fi ;
struct fileIdentDesc cfi ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr tloc ;
2005-04-17 02:20:36 +04:00
retval = - ENOENT ;
lock_kernel ( ) ;
2008-10-12 08:15:17 +04:00
fi = udf_find_entry ( dir , & dentry - > d_name , & fibh , & cfi ) ;
2005-04-17 02:20:36 +04:00
if ( ! fi )
goto out ;
retval = - EIO ;
tloc = lelb_to_cpu ( cfi . icb . extLocation ) ;
2008-10-15 14:29:03 +04:00
if ( udf_get_lb_pblock ( dir - > i_sb , & tloc , 0 ) ! = inode - > i_ino )
2005-04-17 02:20:36 +04:00
goto end_unlink ;
2007-07-19 12:47:43 +04:00
if ( ! inode - > i_nlink ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " Deleting nonexistent file (%lu), %d \n " ,
2007-07-19 12:47:43 +04:00
inode - > i_ino , inode - > i_nlink ) ;
2005-04-17 02:20:36 +04:00
inode - > i_nlink = 1 ;
}
retval = udf_delete_entry ( dir , fi , & fibh , & cfi ) ;
if ( retval )
goto end_unlink ;
dir - > i_ctime = dir - > i_mtime = current_fs_time ( dir - > i_sb ) ;
mark_inode_dirty ( dir ) ;
2006-10-01 10:29:03 +04:00
inode_dec_link_count ( inode ) ;
2005-04-17 02:20:36 +04:00
inode - > i_ctime = dir - > i_ctime ;
retval = 0 ;
2007-07-21 15:37:18 +04:00
end_unlink :
2005-04-17 02:20:36 +04:00
if ( fibh . sbh ! = fibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
2007-07-21 15:37:18 +04:00
out :
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return retval ;
}
2007-07-19 12:47:43 +04:00
static int udf_symlink ( struct inode * dir , struct dentry * dentry ,
const char * symname )
2005-04-17 02:20:36 +04:00
{
2007-07-19 12:47:43 +04:00
struct inode * inode ;
2005-04-17 02:20:36 +04:00
struct pathComponent * pc ;
char * compstart ;
struct udf_fileident_bh fibh ;
2007-07-21 15:37:18 +04:00
struct extent_position epos = { } ;
2005-04-17 02:20:36 +04:00
int eoffset , elen = 0 ;
struct fileIdentDesc * fi ;
struct fileIdentDesc cfi ;
char * ea ;
int err ;
int block ;
2008-03-04 16:14:05 +03:00
char * name = NULL ;
2005-04-17 02:20:36 +04:00
int namelen ;
2008-02-08 15:20:30 +03:00
struct buffer_head * bh ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2005-04-17 02:20:36 +04:00
lock_kernel ( ) ;
2008-02-08 15:20:36 +03:00
inode = udf_new_inode ( dir , S_IFLNK , & err ) ;
if ( ! inode )
2005-04-17 02:20:36 +04:00
goto out ;
2008-03-04 16:14:05 +03:00
name = kmalloc ( UDF_NAME_LEN , GFP_NOFS ) ;
if ( ! name ) {
err = - ENOMEM ;
goto out_no_entry ;
}
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
inode - > i_mode = S_IFLNK | S_IRWXUGO ;
inode - > i_data . a_ops = & udf_symlink_aops ;
inode - > i_op = & page_symlink_inode_operations ;
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_alloc_type ! = ICBTAG_FLAG_AD_IN_ICB ) {
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr eloc ;
2008-04-28 13:16:19 +04:00
uint32_t bsize ;
2005-04-17 02:20:36 +04:00
block = udf_new_block ( inode - > i_sb , inode ,
2008-02-08 15:20:44 +03:00
iinfo - > i_location . partitionReferenceNum ,
iinfo - > i_location . logicalBlockNum , & err ) ;
2005-04-17 02:20:36 +04:00
if ( ! block )
goto out_no_entry ;
2008-02-08 15:20:44 +03:00
epos . block = iinfo - > i_location ;
2007-05-08 11:35:14 +04:00
epos . offset = udf_file_entry_alloc_offset ( inode ) ;
epos . bh = NULL ;
2005-04-17 02:20:36 +04:00
eloc . logicalBlockNum = block ;
2008-02-08 15:20:36 +03:00
eloc . partitionReferenceNum =
2008-02-08 15:20:44 +03:00
iinfo - > i_location . partitionReferenceNum ;
2008-04-28 13:16:19 +04:00
bsize = inode - > i_sb - > s_blocksize ;
iinfo - > i_lenExtents = bsize ;
2008-10-15 14:29:03 +04:00
udf_add_aext ( inode , & epos , & eloc , bsize , 0 ) ;
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
block = udf_get_pblock ( inode - > i_sb , block ,
2008-02-08 15:20:44 +03:00
iinfo - > i_location . partitionReferenceNum ,
2008-02-08 15:20:36 +03:00
0 ) ;
2009-12-03 15:39:28 +03:00
epos . bh = udf_tgetblk ( inode - > i_sb , block ) ;
2007-05-08 11:35:14 +04:00
lock_buffer ( epos . bh ) ;
memset ( epos . bh - > b_data , 0x00 , inode - > i_sb - > s_blocksize ) ;
set_buffer_uptodate ( epos . bh ) ;
unlock_buffer ( epos . bh ) ;
mark_buffer_dirty_inode ( epos . bh , inode ) ;
ea = epos . bh - > b_data + udf_ext0_offset ( inode ) ;
2008-02-08 15:20:44 +03:00
} else
ea = iinfo - > i_ext . i_data + iinfo - > i_lenEAttr ;
2005-04-17 02:20:36 +04:00
eoffset = inode - > i_sb - > s_blocksize - udf_ext0_offset ( inode ) ;
pc = ( struct pathComponent * ) ea ;
2007-07-19 12:47:43 +04:00
if ( * symname = = ' / ' ) {
do {
2005-04-17 02:20:36 +04:00
symname + + ;
} while ( * symname = = ' / ' ) ;
pc - > componentType = 1 ;
pc - > lengthComponentIdent = 0 ;
pc - > componentFileVersionNum = 0 ;
elen + = sizeof ( struct pathComponent ) ;
}
err = - ENAMETOOLONG ;
2007-07-19 12:47:43 +04:00
while ( * symname ) {
2005-04-17 02:20:36 +04:00
if ( elen + sizeof ( struct pathComponent ) > eoffset )
goto out_no_entry ;
pc = ( struct pathComponent * ) ( ea + elen ) ;
compstart = ( char * ) symname ;
2007-07-19 12:47:43 +04:00
do {
2005-04-17 02:20:36 +04:00
symname + + ;
} while ( * symname & & * symname ! = ' / ' ) ;
pc - > componentType = 5 ;
pc - > lengthComponentIdent = 0 ;
pc - > componentFileVersionNum = 0 ;
2007-07-19 12:47:43 +04:00
if ( compstart [ 0 ] = = ' . ' ) {
if ( ( symname - compstart ) = = 1 )
2005-04-17 02:20:36 +04:00
pc - > componentType = 4 ;
2008-02-08 15:20:36 +03:00
else if ( ( symname - compstart ) = = 2 & &
compstart [ 1 ] = = ' . ' )
2005-04-17 02:20:36 +04:00
pc - > componentType = 3 ;
}
2007-07-19 12:47:43 +04:00
if ( pc - > componentType = = 5 ) {
2007-07-21 15:37:18 +04:00
namelen = udf_put_filename ( inode - > i_sb , compstart , name ,
symname - compstart ) ;
if ( ! namelen )
2005-04-17 02:20:36 +04:00
goto out_no_entry ;
2008-02-08 15:20:36 +03:00
if ( elen + sizeof ( struct pathComponent ) + namelen >
eoffset )
2005-04-17 02:20:36 +04:00
goto out_no_entry ;
else
pc - > lengthComponentIdent = namelen ;
memcpy ( pc - > componentIdent , name , namelen ) ;
}
elen + = sizeof ( struct pathComponent ) + pc - > lengthComponentIdent ;
2007-07-19 12:47:43 +04:00
if ( * symname ) {
do {
2005-04-17 02:20:36 +04:00
symname + + ;
} while ( * symname = = ' / ' ) ;
}
}
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
inode - > i_size = elen ;
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
iinfo - > i_lenAlloc = inode - > i_size ;
2009-12-03 15:39:28 +03:00
else
udf_truncate_tail_extent ( inode ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
2008-02-08 15:20:36 +03:00
fi = udf_add_entry ( dir , dentry , & fibh , & cfi , & err ) ;
if ( ! fi )
2005-04-17 02:20:36 +04:00
goto out_no_entry ;
cfi . icb . extLength = cpu_to_le32 ( inode - > i_sb - > s_blocksize ) ;
2008-02-08 15:20:44 +03:00
cfi . icb . extLocation = cpu_to_lelb ( iinfo - > i_location ) ;
2008-02-08 15:20:30 +03:00
bh = UDF_SB ( inode - > i_sb ) - > s_lvid_bh ;
if ( bh ) {
2008-02-08 15:20:36 +03:00
struct logicalVolIntegrityDesc * lvid =
( struct logicalVolIntegrityDesc * ) bh - > b_data ;
2005-04-17 02:20:36 +04:00
struct logicalVolHeaderDesc * lvhd ;
uint64_t uniqueID ;
2008-02-08 15:20:36 +03:00
lvhd = ( struct logicalVolHeaderDesc * )
lvid - > logicalVolContentsUse ;
2005-04-17 02:20:36 +04:00
uniqueID = le64_to_cpu ( lvhd - > uniqueID ) ;
2007-07-21 15:37:18 +04:00
* ( __le32 * ) ( ( struct allocDescImpUse * ) cfi . icb . impUse ) - > impUse =
cpu_to_le32 ( uniqueID & 0x00000000FFFFFFFFUL ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( + + uniqueID & 0x00000000FFFFFFFFUL ) )
uniqueID + = 16 ;
lvhd - > uniqueID = cpu_to_le64 ( uniqueID ) ;
2008-02-08 15:20:30 +03:00
mark_buffer_dirty ( bh ) ;
2005-04-17 02:20:36 +04:00
}
udf_write_fi ( dir , & cfi , fi , & fibh , NULL , NULL ) ;
2008-02-08 15:20:42 +03:00
if ( UDF_I ( dir ) - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( dir ) ;
if ( fibh . sbh ! = fibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
2005-04-17 02:20:36 +04:00
d_instantiate ( dentry , inode ) ;
err = 0 ;
2007-07-21 15:37:18 +04:00
out :
2008-03-04 16:14:05 +03:00
kfree ( name ) ;
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return err ;
2007-07-21 15:37:18 +04:00
out_no_entry :
2006-10-01 10:29:03 +04:00
inode_dec_link_count ( inode ) ;
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
goto out ;
}
2007-07-19 12:47:43 +04:00
static int udf_link ( struct dentry * old_dentry , struct inode * dir ,
struct dentry * dentry )
2005-04-17 02:20:36 +04:00
{
struct inode * inode = old_dentry - > d_inode ;
struct udf_fileident_bh fibh ;
struct fileIdentDesc cfi , * fi ;
int err ;
2008-02-08 15:20:30 +03:00
struct buffer_head * bh ;
2005-04-17 02:20:36 +04:00
lock_kernel ( ) ;
2007-07-19 12:47:43 +04:00
if ( inode - > i_nlink > = ( 256 < < sizeof ( inode - > i_nlink ) ) - 1 ) {
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return - EMLINK ;
}
2008-02-08 15:20:36 +03:00
fi = udf_add_entry ( dir , dentry , & fibh , & cfi , & err ) ;
if ( ! fi ) {
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return err ;
}
cfi . icb . extLength = cpu_to_le32 ( inode - > i_sb - > s_blocksize ) ;
2008-02-08 15:20:42 +03:00
cfi . icb . extLocation = cpu_to_lelb ( UDF_I ( inode ) - > i_location ) ;
2008-02-08 15:20:30 +03:00
bh = UDF_SB ( inode - > i_sb ) - > s_lvid_bh ;
if ( bh ) {
2008-02-08 15:20:36 +03:00
struct logicalVolIntegrityDesc * lvid =
( struct logicalVolIntegrityDesc * ) bh - > b_data ;
2005-04-17 02:20:36 +04:00
struct logicalVolHeaderDesc * lvhd ;
uint64_t uniqueID ;
2008-02-08 15:20:36 +03:00
lvhd = ( struct logicalVolHeaderDesc * )
( lvid - > logicalVolContentsUse ) ;
2005-04-17 02:20:36 +04:00
uniqueID = le64_to_cpu ( lvhd - > uniqueID ) ;
2007-07-21 15:37:18 +04:00
* ( __le32 * ) ( ( struct allocDescImpUse * ) cfi . icb . impUse ) - > impUse =
cpu_to_le32 ( uniqueID & 0x00000000FFFFFFFFUL ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( + + uniqueID & 0x00000000FFFFFFFFUL ) )
uniqueID + = 16 ;
lvhd - > uniqueID = cpu_to_le64 ( uniqueID ) ;
2008-02-08 15:20:30 +03:00
mark_buffer_dirty ( bh ) ;
2005-04-17 02:20:36 +04:00
}
udf_write_fi ( dir , & cfi , fi , & fibh , NULL , NULL ) ;
2008-02-08 15:20:42 +03:00
if ( UDF_I ( dir ) - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( dir ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
if ( fibh . sbh ! = fibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
2006-10-01 10:29:04 +04:00
inc_nlink ( inode ) ;
2005-04-17 02:20:36 +04:00
inode - > i_ctime = current_fs_time ( inode - > i_sb ) ;
mark_inode_dirty ( inode ) ;
atomic_inc ( & inode - > i_count ) ;
d_instantiate ( dentry , inode ) ;
unlock_kernel ( ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* Anybody can rename anything with this: the permission checks are left to the
* higher - level routines .
*/
2007-07-19 12:47:43 +04:00
static int udf_rename ( struct inode * old_dir , struct dentry * old_dentry ,
struct inode * new_dir , struct dentry * new_dentry )
2005-04-17 02:20:36 +04:00
{
2007-07-19 12:47:43 +04:00
struct inode * old_inode = old_dentry - > d_inode ;
struct inode * new_inode = new_dentry - > d_inode ;
2005-04-17 02:20:36 +04:00
struct udf_fileident_bh ofibh , nfibh ;
2008-02-08 15:20:36 +03:00
struct fileIdentDesc * ofi = NULL , * nfi = NULL , * dir_fi = NULL ;
struct fileIdentDesc ocfi , ncfi ;
2005-04-17 02:20:36 +04:00
struct buffer_head * dir_bh = NULL ;
int retval = - ENOENT ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr tloc ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * old_iinfo = UDF_I ( old_inode ) ;
2005-04-17 02:20:36 +04:00
lock_kernel ( ) ;
2008-10-12 08:15:17 +04:00
ofi = udf_find_entry ( old_dir , & old_dentry - > d_name , & ofibh , & ocfi ) ;
2008-02-08 15:20:36 +03:00
if ( ofi ) {
2005-04-17 02:20:36 +04:00
if ( ofibh . sbh ! = ofibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( ofibh . ebh ) ;
brelse ( ofibh . sbh ) ;
2005-04-17 02:20:36 +04:00
}
tloc = lelb_to_cpu ( ocfi . icb . extLocation ) ;
2008-10-15 14:29:03 +04:00
if ( ! ofi | | udf_get_lb_pblock ( old_dir - > i_sb , & tloc , 0 )
2007-07-19 12:47:43 +04:00
! = old_inode - > i_ino )
2005-04-17 02:20:36 +04:00
goto end_rename ;
2008-10-12 08:15:17 +04:00
nfi = udf_find_entry ( new_dir , & new_dentry - > d_name , & nfibh , & ncfi ) ;
2007-07-19 12:47:43 +04:00
if ( nfi ) {
if ( ! new_inode ) {
2005-04-17 02:20:36 +04:00
if ( nfibh . sbh ! = nfibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( nfibh . ebh ) ;
brelse ( nfibh . sbh ) ;
2005-04-17 02:20:36 +04:00
nfi = NULL ;
}
}
2007-07-19 12:47:43 +04:00
if ( S_ISDIR ( old_inode - > i_mode ) ) {
2008-02-08 15:20:49 +03:00
int offset = udf_ext0_offset ( old_inode ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( new_inode ) {
2005-04-17 02:20:36 +04:00
retval = - ENOTEMPTY ;
if ( ! empty_dir ( new_inode ) )
goto end_rename ;
}
retval = - EIO ;
2008-02-08 15:20:44 +03:00
if ( old_iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB ) {
2008-02-08 15:20:36 +03:00
dir_fi = udf_get_fileident (
2008-02-08 15:20:44 +03:00
old_iinfo - > i_ext . i_data -
( old_iinfo - > i_efe ?
2008-02-08 15:20:36 +03:00
sizeof ( struct extendedFileEntry ) :
sizeof ( struct fileEntry ) ) ,
old_inode - > i_sb - > s_blocksize , & offset ) ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
dir_bh = udf_bread ( old_inode , 0 , 0 , & retval ) ;
if ( ! dir_bh )
goto end_rename ;
2008-02-08 15:20:36 +03:00
dir_fi = udf_get_fileident ( dir_bh - > b_data ,
old_inode - > i_sb - > s_blocksize , & offset ) ;
2005-04-17 02:20:36 +04:00
}
if ( ! dir_fi )
goto end_rename ;
tloc = lelb_to_cpu ( dir_fi - > icb . extLocation ) ;
2008-10-15 14:29:03 +04:00
if ( udf_get_lb_pblock ( old_inode - > i_sb , & tloc , 0 ) ! =
2008-02-08 15:20:36 +03:00
old_dir - > i_ino )
2005-04-17 02:20:36 +04:00
goto end_rename ;
retval = - EMLINK ;
2008-02-08 15:20:36 +03:00
if ( ! new_inode & &
new_dir - > i_nlink > =
( 256 < < sizeof ( new_dir - > i_nlink ) ) - 1 )
2005-04-17 02:20:36 +04:00
goto end_rename ;
}
2007-07-19 12:47:43 +04:00
if ( ! nfi ) {
2008-02-08 15:20:36 +03:00
nfi = udf_add_entry ( new_dir , new_dentry , & nfibh , & ncfi ,
& retval ) ;
2005-04-17 02:20:36 +04:00
if ( ! nfi )
goto end_rename ;
}
/*
* Like most other Unix systems , set the ctime for inodes on a
* rename .
*/
old_inode - > i_ctime = current_fs_time ( old_inode - > i_sb ) ;
mark_inode_dirty ( old_inode ) ;
/*
* ok , that ' s it
*/
ncfi . fileVersionNum = ocfi . fileVersionNum ;
ncfi . fileCharacteristics = ocfi . fileCharacteristics ;
2008-10-15 14:28:03 +04:00
memcpy ( & ( ncfi . icb ) , & ( ocfi . icb ) , sizeof ( struct long_ad ) ) ;
2005-04-17 02:20:36 +04:00
udf_write_fi ( new_dir , & ncfi , nfi , & nfibh , NULL , NULL ) ;
/* The old fid may have moved - find it again */
2008-10-12 08:15:17 +04:00
ofi = udf_find_entry ( old_dir , & old_dentry - > d_name , & ofibh , & ocfi ) ;
2005-04-17 02:20:36 +04:00
udf_delete_entry ( old_dir , ofi , & ofibh , & ocfi ) ;
2007-07-19 12:47:43 +04:00
if ( new_inode ) {
2005-04-17 02:20:36 +04:00
new_inode - > i_ctime = current_fs_time ( new_inode - > i_sb ) ;
2006-10-01 10:29:03 +04:00
inode_dec_link_count ( new_inode ) ;
2005-04-17 02:20:36 +04:00
}
old_dir - > i_ctime = old_dir - > i_mtime = current_fs_time ( old_dir - > i_sb ) ;
mark_inode_dirty ( old_dir ) ;
2007-07-19 12:47:43 +04:00
if ( dir_fi ) {
2008-02-08 15:20:42 +03:00
dir_fi - > icb . extLocation = cpu_to_lelb ( UDF_I ( new_dir ) - > i_location ) ;
2008-02-08 15:20:36 +03:00
udf_update_tag ( ( char * ) dir_fi ,
( sizeof ( struct fileIdentDesc ) +
le16_to_cpu ( dir_fi - > lengthOfImpUse ) + 3 ) & ~ 3 ) ;
2008-02-08 15:20:44 +03:00
if ( old_iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( old_inode ) ;
2008-02-08 15:20:36 +03:00
else
2005-04-17 02:20:36 +04:00
mark_buffer_dirty_inode ( dir_bh , old_inode ) ;
2008-02-08 15:20:36 +03:00
2006-10-01 10:29:03 +04:00
inode_dec_link_count ( old_dir ) ;
2008-02-08 15:20:36 +03:00
if ( new_inode )
2006-10-01 10:29:03 +04:00
inode_dec_link_count ( new_inode ) ;
2008-02-08 15:20:36 +03:00
else {
2006-10-01 10:29:04 +04:00
inc_nlink ( new_dir ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( new_dir ) ;
}
}
2007-07-19 12:47:43 +04:00
if ( ofi ) {
2005-04-17 02:20:36 +04:00
if ( ofibh . sbh ! = ofibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( ofibh . ebh ) ;
brelse ( ofibh . sbh ) ;
2005-04-17 02:20:36 +04:00
}
retval = 0 ;
2007-07-21 15:37:18 +04:00
end_rename :
2007-05-08 11:35:16 +04:00
brelse ( dir_bh ) ;
2007-07-19 12:47:43 +04:00
if ( nfi ) {
2005-04-17 02:20:36 +04:00
if ( nfibh . sbh ! = nfibh . ebh )
2007-05-08 11:35:16 +04:00
brelse ( nfibh . ebh ) ;
brelse ( nfibh . sbh ) ;
2005-04-17 02:20:36 +04:00
}
unlock_kernel ( ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return retval ;
}
2008-04-30 19:22:06 +04:00
static struct dentry * udf_get_parent ( struct dentry * child )
{
2008-10-15 14:29:03 +04:00
struct kernel_lb_addr tloc ;
2008-04-30 19:22:06 +04:00
struct inode * inode = NULL ;
2008-10-12 08:15:17 +04:00
struct qstr dotdot = { . name = " .. " , . len = 2 } ;
2008-04-30 19:22:06 +04:00
struct fileIdentDesc cfi ;
struct udf_fileident_bh fibh ;
lock_kernel ( ) ;
if ( ! udf_find_entry ( child - > d_inode , & dotdot , & fibh , & cfi ) )
goto out_unlock ;
if ( fibh . sbh ! = fibh . ebh )
brelse ( fibh . ebh ) ;
brelse ( fibh . sbh ) ;
2008-10-15 14:29:03 +04:00
tloc = lelb_to_cpu ( cfi . icb . extLocation ) ;
inode = udf_iget ( child - > d_inode - > i_sb , & tloc ) ;
2008-04-30 19:22:06 +04:00
if ( ! inode )
goto out_unlock ;
unlock_kernel ( ) ;
2008-08-11 17:49:04 +04:00
return d_obtain_alias ( inode ) ;
2008-04-30 19:22:06 +04:00
out_unlock :
unlock_kernel ( ) ;
return ERR_PTR ( - EACCES ) ;
}
static struct dentry * udf_nfs_get_inode ( struct super_block * sb , u32 block ,
u16 partref , __u32 generation )
{
struct inode * inode ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr loc ;
2008-04-30 19:22:06 +04:00
if ( block = = 0 )
return ERR_PTR ( - ESTALE ) ;
loc . logicalBlockNum = block ;
loc . partitionReferenceNum = partref ;
2008-10-15 14:29:03 +04:00
inode = udf_iget ( sb , & loc ) ;
2008-04-30 19:22:06 +04:00
if ( inode = = NULL )
return ERR_PTR ( - ENOMEM ) ;
if ( generation & & inode - > i_generation ! = generation ) {
iput ( inode ) ;
return ERR_PTR ( - ESTALE ) ;
}
2008-08-11 17:49:04 +04:00
return d_obtain_alias ( inode ) ;
2008-04-30 19:22:06 +04:00
}
static struct dentry * udf_fh_to_dentry ( struct super_block * sb ,
struct fid * fid , int fh_len , int fh_type )
{
if ( ( fh_len ! = 3 & & fh_len ! = 5 ) | |
( fh_type ! = FILEID_UDF_WITH_PARENT & &
fh_type ! = FILEID_UDF_WITHOUT_PARENT ) )
return NULL ;
return udf_nfs_get_inode ( sb , fid - > udf . block , fid - > udf . partref ,
fid - > udf . generation ) ;
}
static struct dentry * udf_fh_to_parent ( struct super_block * sb ,
struct fid * fid , int fh_len , int fh_type )
{
if ( fh_len ! = 5 | | fh_type ! = FILEID_UDF_WITH_PARENT )
return NULL ;
return udf_nfs_get_inode ( sb , fid - > udf . parent_block ,
fid - > udf . parent_partref ,
fid - > udf . parent_generation ) ;
}
static int udf_encode_fh ( struct dentry * de , __u32 * fh , int * lenp ,
int connectable )
{
int len = * lenp ;
struct inode * inode = de - > d_inode ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr location = UDF_I ( inode ) - > i_location ;
2008-04-30 19:22:06 +04:00
struct fid * fid = ( struct fid * ) fh ;
int type = FILEID_UDF_WITHOUT_PARENT ;
if ( len < 3 | | ( connectable & & len < 5 ) )
return 255 ;
* lenp = 3 ;
fid - > udf . block = location . logicalBlockNum ;
fid - > udf . partref = location . partitionReferenceNum ;
fid - > udf . generation = inode - > i_generation ;
if ( connectable & & ! S_ISDIR ( inode - > i_mode ) ) {
spin_lock ( & de - > d_lock ) ;
inode = de - > d_parent - > d_inode ;
location = UDF_I ( inode ) - > i_location ;
fid - > udf . parent_block = location . logicalBlockNum ;
fid - > udf . parent_partref = location . partitionReferenceNum ;
fid - > udf . parent_generation = inode - > i_generation ;
spin_unlock ( & de - > d_lock ) ;
* lenp = 5 ;
type = FILEID_UDF_WITH_PARENT ;
}
return type ;
}
const struct export_operations udf_export_ops = {
. encode_fh = udf_encode_fh ,
. fh_to_dentry = udf_fh_to_dentry ,
. fh_to_parent = udf_fh_to_parent ,
. get_parent = udf_get_parent ,
} ;
2007-02-12 11:55:40 +03:00
const struct inode_operations udf_dir_inode_operations = {
2007-07-21 15:37:18 +04:00
. lookup = udf_lookup ,
. create = udf_create ,
. link = udf_link ,
. unlink = udf_unlink ,
. symlink = udf_symlink ,
. mkdir = udf_mkdir ,
. rmdir = udf_rmdir ,
. mknod = udf_mknod ,
. rename = udf_rename ,
2005-04-17 02:20:36 +04:00
} ;