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>
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
2010-02-01 05:28:48 +03:00
static inline int udf_match ( int len1 , const unsigned char * name1 , int len2 ,
const unsigned 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 ;
}
2015-04-08 22:23:58 +03:00
/**
* udf_find_entry - find entry in given directory .
*
* @ dir : directory inode to search in
* @ child : qstr of the name
* @ fibh : buffer head / inode with file identifier descriptor we found
* @ cfi : found file identifier descriptor with given name
*
* This function searches in the directory @ dir for a file name @ child . When
* found , @ fibh points to the buffer head ( s ) ( bh is NULL for in ICB
* directories ) containing the file identifier descriptor ( FID ) . In that case
* the function returns pointer to the FID in the buffer or inode - but note
* that FID may be split among two buffers ( blocks ) so accessing it via that
* pointer isn ' t easily possible . This pointer can be used only as an iterator
* for other directory manipulation functions . For inspection of the FID @ cfi
* can be used - the found FID is copied there .
*
* Returns pointer to FID , NULL when nothing found , or error code .
*/
2007-07-19 12:47:43 +04:00
static struct fileIdentDesc * udf_find_entry ( struct inode * dir ,
2010-02-01 05:28:48 +03:00
const 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 ;
2010-02-01 05:28:48 +03:00
unsigned char * fname = NULL ;
unsigned char * nameptr ;
2005-04-17 02:20:36 +04:00
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 ] = = ' . ' ;
2014-12-19 00:49:12 +03:00
struct super_block * sb = dir - > i_sb ;
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 ;
2014-12-19 00:49:12 +03:00
fibh - > soffset = fibh - > eoffset = f_pos & ( sb - > s_blocksize - 1 ) ;
2008-03-04 16:14:05 +03:00
if ( dinfo - > i_alloc_type ! = ICBTAG_FLAG_AD_IN_ICB ) {
2014-12-19 00:49:12 +03:00
if ( inode_bmap ( dir , f_pos > > sb - > s_blocksize_bits , & epos ,
2015-04-08 22:23:58 +03:00
& eloc , & elen , & offset ) ! = ( EXT_RECORDED_ALLOCATED > > 30 ) ) {
fi = ERR_PTR ( - EIO ) ;
2008-03-04 16:14:05 +03:00
goto out_err ;
2015-04-08 22:23:58 +03:00
}
2014-12-19 00:49:12 +03:00
block = udf_get_lb_pblock ( sb , & eloc , offset ) ;
if ( ( + + offset < < 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 ;
2014-12-19 00:49:12 +03:00
fibh - > sbh = fibh - > ebh = udf_tread ( sb , block ) ;
2015-04-08 22:23:58 +03:00
if ( ! fibh - > sbh ) {
fi = ERR_PTR ( - EIO ) ;
2008-03-04 16:14:05 +03:00
goto out_err ;
2015-04-08 22:23:58 +03:00
}
2005-04-17 02:20:36 +04:00
}
2008-03-04 16:14:05 +03:00
fname = kmalloc ( UDF_NAME_LEN , GFP_NOFS ) ;
2015-04-08 22:23:58 +03:00
if ( ! fname ) {
fi = ERR_PTR ( - ENOMEM ) ;
2008-03-04 16:14:05 +03:00
goto out_err ;
2015-04-08 22:23:58 +03:00
}
2008-03-04 16:14:05 +03: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 ) ;
2015-04-08 22:23:58 +03:00
if ( ! fi ) {
fi = ERR_PTR ( - EIO ) ;
2008-03-04 16:14:05 +03:00
goto out_err ;
2015-04-08 22:23:58 +03:00
}
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 ) {
2014-12-19 00:49:12 +03:00
if ( ! UDF_QUERY_FLAG ( 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 ) {
2014-12-19 00:49:12 +03:00
if ( ! UDF_QUERY_FLAG ( 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 ) & &
2010-12-13 01:18:15 +03:00
isdotdot )
goto out_ok ;
2008-04-30 19:22:06 +04:00
2005-04-17 02:20:36 +04:00
if ( ! lfi )
continue ;
2014-12-19 00:49:12 +03:00
flen = udf_get_filename ( sb , nameptr , lfi , fname , UDF_NAME_LEN ) ;
2015-04-08 22:23:58 +03:00
if ( flen < 0 ) {
fi = ERR_PTR ( flen ) ;
goto out_err ;
}
if ( 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
fi = NULL ;
2015-04-08 22:23:58 +03:00
out_err :
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 ,
2012-06-11 01:13:09 +04:00
unsigned int flags )
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 ;
2015-04-08 22:23:58 +03:00
struct fileIdentDesc * fi ;
2005-04-17 02:20:36 +04:00
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 ) ;
# 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 ) ;
2014-09-04 18:15:51 +04:00
if ( IS_ERR ( inode ) )
return inode ;
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
2015-04-08 22:23:58 +03:00
fi = udf_find_entry ( dir , & dentry - > d_name , & fibh , & cfi ) ;
if ( IS_ERR ( fi ) )
return ERR_CAST ( fi ) ;
if ( fi ) {
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 ) ;
2014-09-04 18:15:51 +04:00
if ( IS_ERR ( inode ) )
return ERR_CAST ( inode ) ;
2005-04-17 02:20:36 +04:00
}
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 ;
2010-02-01 05:28:48 +03:00
unsigned 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 ;
2010-11-25 05:56:24 +03:00
/* Extents could have been merged, invalidate our position */
brelse ( epos . bh ) ;
epos . bh = NULL ;
epos . block = dinfo - > i_location ;
epos . offset = udf_file_entry_alloc_offset ( dir ) ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
if ( ! fibh - > soffset ) {
2010-11-25 05:56:24 +03:00
/* Find the freshly allocated block */
while ( udf_next_aext ( dir , & epos , & eloc , & elen , 1 ) = =
( EXT_RECORDED_ALLOCATED > > 30 ) )
;
block = eloc . logicalBlockNum + ( ( elen - 1 ) > >
2007-07-21 15:37:18 +04:00
dir - > i_sb - > s_blocksize_bits ) ;
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 ) ;
}
2014-09-04 17:34:14 +04:00
static int udf_add_nondir ( struct dentry * dentry , struct inode * inode )
2005-04-17 02:20:36 +04:00
{
2014-09-04 17:34:14 +04:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2015-03-18 01:25:59 +03:00
struct inode * dir = d_inode ( dentry - > d_parent ) ;
2005-04-17 02:20:36 +04:00
struct udf_fileident_bh fibh ;
struct fileIdentDesc cfi , * fi ;
int err ;
2008-02-08 15:20:36 +03:00
fi = udf_add_entry ( dir , dentry , & fibh , & cfi , & err ) ;
2014-09-04 17:34:14 +04:00
if ( unlikely ( ! fi ) ) {
2011-10-28 16:13:28 +04:00
inode_dec_link_count ( inode ) ;
2014-09-04 17:38:11 +04:00
unlock_new_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
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 ) ;
2015-03-24 23:47:25 +03:00
dir - > i_ctime = dir - > i_mtime = current_fs_time ( dir - > i_sb ) ;
mark_inode_dirty ( 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 ) ;
2014-09-04 17:38:11 +04:00
unlock_new_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
d_instantiate ( dentry , inode ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2014-09-04 17:34:14 +04:00
static int udf_create ( struct inode * dir , struct dentry * dentry , umode_t mode ,
bool excl )
{
2014-09-04 17:47:41 +04:00
struct inode * inode = udf_new_inode ( dir , mode ) ;
2014-09-04 17:34:14 +04:00
2014-09-04 17:47:41 +04:00
if ( IS_ERR ( inode ) )
return PTR_ERR ( inode ) ;
2014-09-04 17:34:14 +04:00
if ( UDF_I ( inode ) - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
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 ;
mark_inode_dirty ( inode ) ;
return udf_add_nondir ( dentry , inode ) ;
}
2013-06-12 09:35:33 +04:00
static int udf_tmpfile ( struct inode * dir , struct dentry * dentry , umode_t mode )
{
2014-09-04 17:47:41 +04:00
struct inode * inode = udf_new_inode ( dir , mode ) ;
2013-06-12 09:35:33 +04:00
2014-09-04 17:47:41 +04:00
if ( IS_ERR ( inode ) )
return PTR_ERR ( inode ) ;
2013-06-12 09:35:33 +04:00
2014-09-04 17:47:41 +04:00
if ( UDF_I ( inode ) - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
2013-06-12 09:35:33 +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 ;
mark_inode_dirty ( inode ) ;
d_tmpfile ( dentry , inode ) ;
2014-09-04 17:38:11 +04:00
unlock_new_inode ( inode ) ;
2013-06-12 09:35:33 +04:00
return 0 ;
}
2011-07-26 09:52:52 +04:00
static int udf_mknod ( struct inode * dir , struct dentry * dentry , umode_t mode ,
2007-07-19 12:47:43 +04:00
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
if ( ! old_valid_dev ( rdev ) )
return - EINVAL ;
2014-09-04 17:47:41 +04:00
inode = udf_new_inode ( dir , mode ) ;
if ( IS_ERR ( inode ) )
return PTR_ERR ( inode ) ;
2007-07-21 15:37:18 +04:00
2014-09-04 17:34:14 +04:00
init_special_inode ( inode , mode , rdev ) ;
return udf_add_nondir ( dentry , inode ) ;
2005-04-17 02:20:36 +04:00
}
2011-07-26 09:41:39 +04:00
static int udf_mkdir ( struct inode * dir , struct dentry * dentry , umode_t 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
2014-09-04 17:47:41 +04:00
inode = udf_new_inode ( dir , S_IFDIR | mode ) ;
if ( IS_ERR ( inode ) )
return PTR_ERR ( inode ) ;
2005-04-17 02:20:36 +04:00
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 ) {
2011-10-28 16:13:28 +04:00
inode_dec_link_count ( inode ) ;
2014-09-04 17:38:11 +04:00
unlock_new_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
goto out ;
}
2011-10-28 16:13:29 +04:00
set_nlink ( inode , 2 ) ;
2005-04-17 02:20:36 +04:00
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
mark_inode_dirty ( inode ) ;
2008-02-08 15:20:36 +03:00
fi = udf_add_entry ( dir , dentry , & fibh , & cfi , & err ) ;
if ( ! fi ) {
2011-10-28 16:13:28 +04:00
clear_nlink ( inode ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
2014-09-04 17:38:11 +04:00
unlock_new_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
2015-03-24 23:47:25 +03:00
dir - > i_ctime = dir - > i_mtime = current_fs_time ( dir - > i_sb ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( dir ) ;
2014-09-04 17:38:11 +04:00
unlock_new_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
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
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 ;
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( dentry ) ;
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 ;
2008-10-12 08:15:17 +04:00
fi = udf_find_entry ( dir , & dentry - > d_name , & fibh , & cfi ) ;
2015-04-08 22:23:58 +03:00
if ( IS_ERR_OR_NULL ( fi ) ) {
if ( fi )
retval = PTR_ERR ( fi ) ;
2005-04-17 02:20:36 +04:00
goto out ;
2015-04-08 22:23:58 +03:00
}
2005-04-17 02:20:36 +04:00
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 )
2011-10-10 12:08:04 +04:00
udf_warn ( inode - > i_sb , " empty directory has nlink != 2 (%d) \n " ,
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
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 ;
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( dentry ) ;
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 ;
2008-10-12 08:15:17 +04:00
fi = udf_find_entry ( dir , & dentry - > d_name , & fibh , & cfi ) ;
2015-04-08 22:23:58 +03:00
if ( IS_ERR_OR_NULL ( fi ) ) {
if ( fi )
retval = PTR_ERR ( fi ) ;
2005-04-17 02:20:36 +04:00
goto out ;
2015-04-08 22:23:58 +03:00
}
2005-04-17 02:20:36 +04:00
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 ) ;
2011-10-28 16:13:29 +04:00
set_nlink ( inode , 1 ) ;
2005-04-17 02:20:36 +04:00
}
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
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
{
2014-09-04 17:47:41 +04:00
struct inode * inode = udf_new_inode ( dir , S_IFLNK | S_IRWXUGO ) ;
2005-04-17 02:20:36 +04:00
struct pathComponent * pc ;
2010-02-01 05:28:48 +03:00
const char * compstart ;
2007-07-21 15:37:18 +04:00
struct extent_position epos = { } ;
2005-04-17 02:20:36 +04:00
int eoffset , elen = 0 ;
2010-02-01 05:28:48 +03:00
uint8_t * ea ;
2005-04-17 02:20:36 +04:00
int err ;
int block ;
2010-02-01 05:28:48 +03:00
unsigned char * name = NULL ;
2005-04-17 02:20:36 +04:00
int namelen ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2010-10-20 20:28:46 +04:00
struct super_block * sb = dir - > i_sb ;
2005-04-17 02:20:36 +04:00
2014-09-04 17:47:41 +04:00
if ( IS_ERR ( inode ) )
return PTR_ERR ( inode ) ;
2005-04-17 02:20:36 +04:00
2010-11-16 20:40:47 +03:00
iinfo = UDF_I ( inode ) ;
down_write ( & iinfo - > i_data_sem ) ;
2008-03-04 16:14:05 +03:00
name = kmalloc ( UDF_NAME_LEN , GFP_NOFS ) ;
if ( ! name ) {
err = - ENOMEM ;
goto out_no_entry ;
}
2005-04-17 02:20:36 +04:00
inode - > i_data . a_ops = & udf_symlink_aops ;
2010-03-29 11:05:21 +04:00
inode - > i_op = & udf_symlink_inode_operations ;
2005-04-17 02:20:36 +04:00
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
2010-10-20 20:28:46 +04:00
block = udf_new_block ( 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 ;
2010-10-20 20:28:46 +04:00
bsize = sb - > s_blocksize ;
2008-04-28 13:16:19 +04:00
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
2010-10-20 20:28:46 +04:00
block = udf_get_pblock ( sb , block ,
2008-02-08 15:20:44 +03:00
iinfo - > i_location . partitionReferenceNum ,
2008-02-08 15:20:36 +03:00
0 ) ;
2010-10-20 20:28:46 +04:00
epos . bh = udf_tgetblk ( sb , block ) ;
2007-05-08 11:35:14 +04:00
lock_buffer ( epos . bh ) ;
2010-10-20 20:28:46 +04:00
memset ( epos . bh - > b_data , 0x00 , bsize ) ;
2007-05-08 11:35:14 +04:00
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
2010-10-20 20:28:46 +04:00
eoffset = sb - > s_blocksize - udf_ext0_offset ( inode ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
2010-02-01 05:28:48 +03:00
compstart = symname ;
2005-04-17 02:20:36 +04:00
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 ) {
2010-10-20 20:28:46 +04:00
namelen = udf_put_filename ( sb , compstart , name ,
2007-07-21 15:37:18 +04:00
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 ) ;
2013-12-24 01:02:16 +04:00
up_write ( & iinfo - > i_data_sem ) ;
2005-04-17 02:20:36 +04:00
2014-09-04 17:34:14 +04:00
err = udf_add_nondir ( dentry , inode ) ;
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
return err ;
2007-07-21 15:37:18 +04:00
out_no_entry :
2010-11-16 20:40:47 +03:00
up_write ( & iinfo - > i_data_sem ) ;
2006-10-01 10:29:03 +04:00
inode_dec_link_count ( inode ) ;
2014-09-04 17:38:11 +04:00
unlock_new_inode ( 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
{
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( old_dentry ) ;
2005-04-17 02:20:36 +04:00
struct udf_fileident_bh fibh ;
struct fileIdentDesc cfi , * fi ;
int err ;
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
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 ) ;
2010-10-20 20:28:46 +04:00
if ( UDF_SB ( inode - > i_sb ) - > s_lvid_bh ) {
2007-07-21 15:37:18 +04:00
* ( __le32 * ) ( ( struct allocDescImpUse * ) cfi . icb . impUse ) - > impUse =
2010-10-20 20:28:46 +04:00
cpu_to_le32 ( lvid_get_unique_id ( inode - > i_sb ) ) ;
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 ) ;
2015-03-24 23:47:25 +03:00
dir - > i_ctime = dir - > i_mtime = current_fs_time ( dir - > i_sb ) ;
mark_inode_dirty ( dir ) ;
2010-10-23 19:11:40 +04:00
ihold ( inode ) ;
2005-04-17 02:20:36 +04:00
d_instantiate ( dentry , inode ) ;
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
{
2015-03-18 01:25:59 +03:00
struct inode * old_inode = d_inode ( old_dentry ) ;
struct inode * new_inode = d_inode ( new_dentry ) ;
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
2008-10-12 08:15:17 +04:00
ofi = udf_find_entry ( old_dir , & old_dentry - > d_name , & ofibh , & ocfi ) ;
2015-04-08 22:23:58 +03:00
if ( IS_ERR ( ofi ) ) {
retval = PTR_ERR ( ofi ) ;
goto end_rename ;
2005-04-17 02:20:36 +04:00
}
2015-04-08 22:23:58 +03:00
if ( ofibh . sbh ! = ofibh . ebh )
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 ) ;
2015-04-08 22:23:58 +03:00
if ( IS_ERR ( nfi ) ) {
retval = PTR_ERR ( nfi ) ;
goto end_rename ;
}
if ( nfi & & ! new_inode ) {
if ( nfibh . sbh ! = nfibh . ebh )
brelse ( nfibh . ebh ) ;
brelse ( nfibh . sbh ) ;
nfi = NULL ;
2005-04-17 02:20:36 +04:00
}
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 ;
}
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 ) ;
2015-03-24 23:47:25 +03:00
new_dir - > i_ctime = new_dir - > i_mtime = current_fs_time ( new_dir - > i_sb ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( old_dir ) ;
2015-03-24 23:47:25 +03:00
mark_inode_dirty ( new_dir ) ;
2005-04-17 02:20:36 +04:00
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
}
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 ;
2012-05-11 00:14:12 +04:00
struct qstr dotdot = QSTR_INIT ( " .. " , 2 ) ;
2008-04-30 19:22:06 +04:00
struct fileIdentDesc cfi ;
struct udf_fileident_bh fibh ;
2015-03-18 01:25:59 +03:00
if ( ! udf_find_entry ( d_inode ( child ) , & dotdot , & fibh , & cfi ) )
2014-09-04 18:15:51 +04:00
return ERR_PTR ( - EACCES ) ;
2008-04-30 19:22:06 +04:00
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 ) ;
2015-03-18 01:25:59 +03:00
inode = udf_iget ( d_inode ( child ) - > i_sb , & tloc ) ;
2014-09-04 18:15:51 +04:00
if ( IS_ERR ( inode ) )
return ERR_CAST ( inode ) ;
2008-04-30 19:22:06 +04:00
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_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
2014-09-04 18:15:51 +04:00
if ( IS_ERR ( inode ) )
return ERR_CAST ( inode ) ;
2008-04-30 19:22:06 +04:00
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 )
{
2015-05-08 03:16:23 +03:00
if ( fh_len < 3 | |
2008-04-30 19:22:06 +04:00
( 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 )
{
2015-05-08 03:16:23 +03:00
if ( fh_len < 5 | | fh_type ! = FILEID_UDF_WITH_PARENT )
2008-04-30 19:22:06 +04:00
return NULL ;
return udf_nfs_get_inode ( sb , fid - > udf . parent_block ,
fid - > udf . parent_partref ,
fid - > udf . parent_generation ) ;
}
2012-04-02 22:34:06 +04:00
static int udf_encode_fh ( struct inode * inode , __u32 * fh , int * lenp ,
struct inode * parent )
2008-04-30 19:22:06 +04:00
{
int len = * lenp ;
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 ;
2012-04-02 22:34:06 +04:00
if ( parent & & ( len < 5 ) ) {
2011-01-29 16:13:25 +03:00
* lenp = 5 ;
2013-02-17 10:48:11 +04:00
return FILEID_INVALID ;
2011-01-29 16:13:25 +03:00
} else if ( len < 3 ) {
* lenp = 3 ;
2013-02-17 10:48:11 +04:00
return FILEID_INVALID ;
2011-01-29 16:13:25 +03:00
}
2008-04-30 19:22:06 +04:00
* lenp = 3 ;
fid - > udf . block = location . logicalBlockNum ;
fid - > udf . partref = location . partitionReferenceNum ;
2012-07-12 10:46:55 +04:00
fid - > udf . parent_partref = 0 ;
2008-04-30 19:22:06 +04:00
fid - > udf . generation = inode - > i_generation ;
2012-04-02 22:34:06 +04:00
if ( parent ) {
location = UDF_I ( parent ) - > i_location ;
2008-04-30 19:22:06 +04:00
fid - > udf . parent_block = location . logicalBlockNum ;
fid - > udf . parent_partref = location . partitionReferenceNum ;
fid - > udf . parent_generation = inode - > i_generation ;
* 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 ,
2013-06-12 09:35:33 +04:00
. tmpfile = udf_tmpfile ,
2005-04-17 02:20:36 +04:00
} ;
2010-03-29 11:05:21 +04:00
const struct inode_operations udf_symlink_inode_operations = {
. readlink = generic_readlink ,
. follow_link = page_follow_link_light ,
. put_link = page_put_link ,
} ;