@@ -3004,6 +3004,8 @@ struct ext4_renament {
30043004 struct inode * dir ;
30053005 struct dentry * dentry ;
30063006 struct inode * inode ;
3007+ bool is_dir ;
3008+ int dir_nlink_delta ;
30073009
30083010 /* entry for "dentry" */
30093011 struct buffer_head * bh ;
@@ -3135,6 +3137,17 @@ static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent)
31353137 }
31363138}
31373139
3140+ static void ext4_update_dir_count (handle_t * handle , struct ext4_renament * ent )
3141+ {
3142+ if (ent -> dir_nlink_delta ) {
3143+ if (ent -> dir_nlink_delta == -1 )
3144+ ext4_dec_count (handle , ent -> dir );
3145+ else
3146+ ext4_inc_count (handle , ent -> dir );
3147+ ext4_mark_inode_dirty (handle , ent -> dir );
3148+ }
3149+ }
3150+
31383151/*
31393152 * Anybody can rename anything with this: the permission checks are left to the
31403153 * higher-level routines.
@@ -3274,13 +3287,137 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
32743287 return retval ;
32753288}
32763289
3290+ static int ext4_cross_rename (struct inode * old_dir , struct dentry * old_dentry ,
3291+ struct inode * new_dir , struct dentry * new_dentry )
3292+ {
3293+ handle_t * handle = NULL ;
3294+ struct ext4_renament old = {
3295+ .dir = old_dir ,
3296+ .dentry = old_dentry ,
3297+ .inode = old_dentry -> d_inode ,
3298+ };
3299+ struct ext4_renament new = {
3300+ .dir = new_dir ,
3301+ .dentry = new_dentry ,
3302+ .inode = new_dentry -> d_inode ,
3303+ };
3304+ u8 new_file_type ;
3305+ int retval ;
3306+
3307+ dquot_initialize (old .dir );
3308+ dquot_initialize (new .dir );
3309+
3310+ old .bh = ext4_find_entry (old .dir , & old .dentry -> d_name ,
3311+ & old .de , & old .inlined );
3312+ /*
3313+ * Check for inode number is _not_ due to possible IO errors.
3314+ * We might rmdir the source, keep it as pwd of some process
3315+ * and merrily kill the link to whatever was created under the
3316+ * same name. Goodbye sticky bit ;-<
3317+ */
3318+ retval = - ENOENT ;
3319+ if (!old .bh || le32_to_cpu (old .de -> inode ) != old .inode -> i_ino )
3320+ goto end_rename ;
3321+
3322+ new .bh = ext4_find_entry (new .dir , & new .dentry -> d_name ,
3323+ & new .de , & new .inlined );
3324+
3325+ /* RENAME_EXCHANGE case: old *and* new must both exist */
3326+ if (!new .bh || le32_to_cpu (new .de -> inode ) != new .inode -> i_ino )
3327+ goto end_rename ;
3328+
3329+ handle = ext4_journal_start (old .dir , EXT4_HT_DIR ,
3330+ (2 * EXT4_DATA_TRANS_BLOCKS (old .dir -> i_sb ) +
3331+ 2 * EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2 ));
3332+ if (IS_ERR (handle ))
3333+ return PTR_ERR (handle );
3334+
3335+ if (IS_DIRSYNC (old .dir ) || IS_DIRSYNC (new .dir ))
3336+ ext4_handle_sync (handle );
3337+
3338+ if (S_ISDIR (old .inode -> i_mode )) {
3339+ old .is_dir = true;
3340+ retval = ext4_rename_dir_prepare (handle , & old );
3341+ if (retval )
3342+ goto end_rename ;
3343+ }
3344+ if (S_ISDIR (new .inode -> i_mode )) {
3345+ new .is_dir = true;
3346+ retval = ext4_rename_dir_prepare (handle , & new );
3347+ if (retval )
3348+ goto end_rename ;
3349+ }
3350+
3351+ /*
3352+ * Other than the special case of overwriting a directory, parents'
3353+ * nlink only needs to be modified if this is a cross directory rename.
3354+ */
3355+ if (old .dir != new .dir && old .is_dir != new .is_dir ) {
3356+ old .dir_nlink_delta = old .is_dir ? -1 : 1 ;
3357+ new .dir_nlink_delta = - old .dir_nlink_delta ;
3358+ retval = - EMLINK ;
3359+ if ((old .dir_nlink_delta > 0 && EXT4_DIR_LINK_MAX (old .dir )) ||
3360+ (new .dir_nlink_delta > 0 && EXT4_DIR_LINK_MAX (new .dir )))
3361+ goto end_rename ;
3362+ }
3363+
3364+ new_file_type = new .de -> file_type ;
3365+ retval = ext4_setent (handle , & new , old .inode -> i_ino , old .de -> file_type );
3366+ if (retval )
3367+ goto end_rename ;
3368+
3369+ retval = ext4_setent (handle , & old , new .inode -> i_ino , new_file_type );
3370+ if (retval )
3371+ goto end_rename ;
3372+
3373+ /*
3374+ * Like most other Unix systems, set the ctime for inodes on a
3375+ * rename.
3376+ */
3377+ old .inode -> i_ctime = ext4_current_time (old .inode );
3378+ new .inode -> i_ctime = ext4_current_time (new .inode );
3379+ ext4_mark_inode_dirty (handle , old .inode );
3380+ ext4_mark_inode_dirty (handle , new .inode );
3381+
3382+ if (old .dir_bh ) {
3383+ retval = ext4_rename_dir_finish (handle , & old , new .dir -> i_ino );
3384+ if (retval )
3385+ goto end_rename ;
3386+ }
3387+ if (new .dir_bh ) {
3388+ retval = ext4_rename_dir_finish (handle , & new , old .dir -> i_ino );
3389+ if (retval )
3390+ goto end_rename ;
3391+ }
3392+ ext4_update_dir_count (handle , & old );
3393+ ext4_update_dir_count (handle , & new );
3394+ retval = 0 ;
3395+
3396+ end_rename :
3397+ brelse (old .dir_bh );
3398+ brelse (new .dir_bh );
3399+ brelse (old .bh );
3400+ brelse (new .bh );
3401+ if (handle )
3402+ ext4_journal_stop (handle );
3403+ return retval ;
3404+ }
3405+
32773406static int ext4_rename2 (struct inode * old_dir , struct dentry * old_dentry ,
32783407 struct inode * new_dir , struct dentry * new_dentry ,
32793408 unsigned int flags )
32803409{
3281- if (flags & ~RENAME_NOREPLACE )
3410+ if (flags & ~( RENAME_NOREPLACE | RENAME_EXCHANGE ) )
32823411 return - EINVAL ;
32833412
3413+ if (flags & RENAME_EXCHANGE ) {
3414+ return ext4_cross_rename (old_dir , old_dentry ,
3415+ new_dir , new_dentry );
3416+ }
3417+ /*
3418+ * Existence checking was done by the VFS, otherwise "RENAME_NOREPLACE"
3419+ * is equivalent to regular rename.
3420+ */
32843421 return ext4_rename (old_dir , old_dentry , new_dir , new_dentry );
32853422}
32863423
0 commit comments