ext4l: Update symlink to replace existing files

The ext4l_ln() function returned -EEXIST when creating a symlink where
a file already exists. This differs from the old ext4 implementation
which deletes any existing file before creating the symlink (like ln -sf
behaviour).

Update ext4l_ln() to match this behaviour by calling __ext4_unlink() to
remove any existing non-directory file before creating the symlink.
Directories cannot be replaced with symlinks and return -EISDIR.

This allows test_symlink3 to pass.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
This commit is contained in:
Simon Glass
2025-12-29 16:42:46 -07:00
parent 4a0adf41fd
commit 8eabf8fb91
3 changed files with 21 additions and 6 deletions

View File

@@ -1268,9 +1268,21 @@ int ext4l_ln(const char *filename, const char *linkname)
return ret;
if (dentry->d_inode) {
/* File already exists */
ret = -EEXIST;
goto out;
/* File already exists - delete it first (like ln -sf) */
if (S_ISDIR(dentry->d_inode->i_mode)) {
/* Cannot replace a directory with a symlink */
ret = -EISDIR;
goto out;
}
ret = __ext4_unlink(dir_dentry->d_inode, &dentry->d_name,
dentry->d_inode, dentry);
if (ret)
goto out;
/* Release inode to free data blocks */
iput(dentry->d_inode);
dentry->d_inode = NULL;
}
/* Create the symlink - filename is what the link points to */

View File

@@ -114,9 +114,12 @@ int ext4l_mkdir(const char *dirname);
/**
* ext4l_ln() - Create a symbolic link
*
* Creates the symlink, replacing any existing file (like ln -sf).
* Refuses to replace a directory.
*
* @filename: Path of symlink to create
* @target: Target path the symlink points to
* Return: 0 on success, -EEXIST if file already exists,
* Return: 0 on success, -EISDIR if target is a directory,
* -ENOTDIR if parent is not a directory, -EROFS if read-only,
* negative on other errors
*/

View File

@@ -576,8 +576,8 @@ static int fs_test_ext4l_ln_norun(struct unit_test_state *uts)
ut_asserteq(12, actread);
ut_asserteq_str("hello world\n", buf);
/* Verify creating duplicate returns -EEXIST */
ut_asserteq(-EEXIST, ext4l_ln(target, link_name));
/* Verify creating duplicate succeeds (like ln -sf) */
ut_assertok(ext4l_ln(target, link_name));
/* Verify creating symlink in non-existent parent returns -ENOENT */
ut_asserteq(-ENOENT, ext4l_ln(target, "/nonexistent/link"));