All of lore.kernel.org
 help / color / mirror / Atom feed
* [QUESTION] question about the errno of rename the parent dir to a subdir of a specified directory
@ 2019-12-25 13:16 zhangyi (F)
  2019-12-25 16:27 ` Al Viro
  0 siblings, 1 reply; 3+ messages in thread
From: zhangyi (F) @ 2019-12-25 13:16 UTC (permalink / raw)
  To: viro, linux-fsdevel; +Cc: linux-kernel, miaoxie, zhangtianci1

Hi,

If we rename the parent-dir to a sub-dir of a specified directory, the
rename() syscall return -EINVAL because lock_rename() in lock_rename()
checks the relations of the sorece and dest dirs. But if the 'parent'
dir is a mountpoint, the rename() syscall return -EXDEV instead because
it checks the parent dir's mountpoint of the sorece and dest dirs.

For example:
Case 1: rename() return -EINVAL
# mkdir -p parent/dir
# rename parent parent/dir/subdir parent
rename: parent: rename to parent/dir/subdir failed: Invalid argument

Case 2: rename() return -EXDEV
# mkdir parent
# mount -t tmpfs test parent
# mkdir parent/dir
# rename parent parent/dir/subdir parent
rename: parent: rename to parent/dir/subdir failed: Invalid cross-device link

In case 2, although 'parent' directory is a mountpoint, it acted as a root
dir of the "test tmpfs", so it should belongs to the same mounted fs of
'dir' directoty, so I think it shall return -EINVAL.

Is it a bug or just designed as this ?

Thanks,
Yi.


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [QUESTION] question about the errno of rename the parent dir to a subdir of a specified directory
  2019-12-25 13:16 [QUESTION] question about the errno of rename the parent dir to a subdir of a specified directory zhangyi (F)
@ 2019-12-25 16:27 ` Al Viro
  2019-12-27 12:47   ` zhangyi (F)
  0 siblings, 1 reply; 3+ messages in thread
From: Al Viro @ 2019-12-25 16:27 UTC (permalink / raw)
  To: zhangyi (F); +Cc: linux-fsdevel, linux-kernel, miaoxie, zhangtianci1

On Wed, Dec 25, 2019 at 09:16:09PM +0800, zhangyi (F) wrote:
> Hi,
> 
> If we rename the parent-dir to a sub-dir of a specified directory, the
> rename() syscall return -EINVAL because lock_rename() in lock_rename()
> checks the relations of the sorece and dest dirs. But if the 'parent'
> dir is a mountpoint, the rename() syscall return -EXDEV instead because
> it checks the parent dir's mountpoint of the sorece and dest dirs.
> 
> For example:
> Case 1: rename() return -EINVAL
> # mkdir -p parent/dir
> # rename parent parent/dir/subdir parent
> rename: parent: rename to parent/dir/subdir failed: Invalid argument

That was rename("parent", "parent/dir/subdir") being told to sod off and
not try to create loops.

> Case 2: rename() return -EXDEV
> # mkdir parent
> # mount -t tmpfs test parent
> # mkdir parent/dir
> # rename parent parent/dir/subdir parent
> rename: parent: rename to parent/dir/subdir failed: Invalid cross-device link
> 
> In case 2, although 'parent' directory is a mountpoint, it acted as a root
> dir of the "test tmpfs", so it should belongs to the same mounted fs of
> 'dir' directoty, so I think it shall return -EINVAL.
> 
> Is it a bug or just designed as this ?

rename() operates on directory entries.  Pathnames can refer to files (including
directories) or they can refer to directory entries (links).  rename() and other
directory-modifying syscalls operate on the latter.  In the second test two
error conditions apply: in addition to attempted loop creation, we are asked to
move the link 'parent' from whatever it's in (your current directory) to 'subdir'
in the directory parent/dir, the latter being on a different filesystem.

It's not "take the file old pathname refers to, move it to new place"; that's
particularly obvious when you consider

echo foo >a	# create a file
ln a b		# now 'a' and 'b' both refer to it
mv a c		# or rename a c a, if you really want to touch util-linux rename(1)

Desired result is, of course, 'a' disappearing, 'b' left as is and 'c' now refering
to the same file.  If you did mv b c as the last step, 'a' would be left as is,
'b' would disappear and 'c' added, refering to the same file.  But the only
difference between mv a c and mv b c is the first argument of rename(2) and
in both cases it resolves to the same file.  In other words, rename(2) can't
operate on that level; to be of any use it has to interpret the pathnames
as refering to directory entries.

That, BTW, is the source of "the last component must not be . or .." - they
do refer to directories just fine, but rename("dir1/.", "dir2/foo") is not just
'make the directory refered to by "dir1/." show up as "dir2/foo"' - it's
'rip the entry "." from the directory "dir1" and move it into directory "dir2"
under the name "foo"'.

So your second testcase is a genuine cross-filesystem move; you want a link
to disappear from a directory on one filesystem and reappear in a directory
on another.  It doesn't matter what's mounted on top of that - directory
entry refers to the mountpoint, not the thing mounted on it.

And in cases when more than one error condition applies, portable userland
should be ready to cope with the operating system returning any of those.
Different Unices might return different applicable errors.  In this particular
case I would expect EXDEV to take precedence on the majority of implementations,
but that's not guaranteed.  Note, BTW, that there might be other errors
applicable here and it's a sufficiently dark corner to expect differences
(e.g. there might be a blanket ban on renaming mountpoints in general,
POSIX being quiet on that topic be damned).  

That actually might be a good way to get into given Unix VFS - figuring out
what happens in this implementation will tell you a lot about its pathname
resolution, related kernel data structures and locking involved.  Might
send you away screaming, though - rename(2) is usually the worst part
as it is, and bringing the mountpoint crossing into the game is likely
to expose all kinds of interesting corner cases.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [QUESTION] question about the errno of rename the parent dir to a subdir of a specified directory
  2019-12-25 16:27 ` Al Viro
@ 2019-12-27 12:47   ` zhangyi (F)
  0 siblings, 0 replies; 3+ messages in thread
From: zhangyi (F) @ 2019-12-27 12:47 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel, linux-kernel, miaoxie (A), zhangtianci

Hi,

Thanks for your detailed explanation, I will also check the freeBSD.

Thanks,
Yi.

On 2019/12/26 0:27, Al Viro wrote:
> On Wed, Dec 25, 2019 at 09:16:09PM +0800, zhangyi (F) wrote:
>> Hi,
>>
>> If we rename the parent-dir to a sub-dir of a specified directory, the
>> rename() syscall return -EINVAL because lock_rename() in lock_rename()
>> checks the relations of the sorece and dest dirs. But if the 'parent'
>> dir is a mountpoint, the rename() syscall return -EXDEV instead because
>> it checks the parent dir's mountpoint of the sorece and dest dirs.
>>
>> For example:
>> Case 1: rename() return -EINVAL
>> # mkdir -p parent/dir
>> # rename parent parent/dir/subdir parent
>> rename: parent: rename to parent/dir/subdir failed: Invalid argument
> 
> That was rename("parent", "parent/dir/subdir") being told to sod off and
> not try to create loops.
> 
>> Case 2: rename() return -EXDEV
>> # mkdir parent
>> # mount -t tmpfs test parent
>> # mkdir parent/dir
>> # rename parent parent/dir/subdir parent
>> rename: parent: rename to parent/dir/subdir failed: Invalid cross-device link
>>
>> In case 2, although 'parent' directory is a mountpoint, it acted as a root
>> dir of the "test tmpfs", so it should belongs to the same mounted fs of
>> 'dir' directoty, so I think it shall return -EINVAL.
>>
>> Is it a bug or just designed as this ?
> 
> rename() operates on directory entries.  Pathnames can refer to files (including
> directories) or they can refer to directory entries (links).  rename() and other
> directory-modifying syscalls operate on the latter.  In the second test two
> error conditions apply: in addition to attempted loop creation, we are asked to
> move the link 'parent' from whatever it's in (your current directory) to 'subdir'
> in the directory parent/dir, the latter being on a different filesystem.
> 
> It's not "take the file old pathname refers to, move it to new place"; that's
> particularly obvious when you consider
> 
> echo foo >a	# create a file
> ln a b		# now 'a' and 'b' both refer to it
> mv a c		# or rename a c a, if you really want to touch util-linux rename(1)
> 
> Desired result is, of course, 'a' disappearing, 'b' left as is and 'c' now refering
> to the same file.  If you did mv b c as the last step, 'a' would be left as is,
> 'b' would disappear and 'c' added, refering to the same file.  But the only
> difference between mv a c and mv b c is the first argument of rename(2) and
> in both cases it resolves to the same file.  In other words, rename(2) can't
> operate on that level; to be of any use it has to interpret the pathnames
> as refering to directory entries.
> 
> That, BTW, is the source of "the last component must not be . or .." - they
> do refer to directories just fine, but rename("dir1/.", "dir2/foo") is not just
> 'make the directory refered to by "dir1/." show up as "dir2/foo"' - it's
> 'rip the entry "." from the directory "dir1" and move it into directory "dir2"
> under the name "foo"'.
> 
> So your second testcase is a genuine cross-filesystem move; you want a link
> to disappear from a directory on one filesystem and reappear in a directory
> on another.  It doesn't matter what's mounted on top of that - directory
> entry refers to the mountpoint, not the thing mounted on it.
> 
> And in cases when more than one error condition applies, portable userland
> should be ready to cope with the operating system returning any of those.
> Different Unices might return different applicable errors.  In this particular
> case I would expect EXDEV to take precedence on the majority of implementations,
> but that's not guaranteed.  Note, BTW, that there might be other errors
> applicable here and it's a sufficiently dark corner to expect differences
> (e.g. there might be a blanket ban on renaming mountpoints in general,
> POSIX being quiet on that topic be damned).  
> 
> That actually might be a good way to get into given Unix VFS - figuring out
> what happens in this implementation will tell you a lot about its pathname
> resolution, related kernel data structures and locking involved.  Might
> send you away screaming, though - rename(2) is usually the worst part
> as it is, and bringing the mountpoint crossing into the game is likely
> to expose all kinds of interesting corner cases.
> 
> .
> 


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-12-27 12:48 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-25 13:16 [QUESTION] question about the errno of rename the parent dir to a subdir of a specified directory zhangyi (F)
2019-12-25 16:27 ` Al Viro
2019-12-27 12:47   ` zhangyi (F)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.