mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-28 12:05:47 +08:00
Cygwin: fstatat, fchownat: support the AT_EMPTY_PATH flag
Following Linux, allow the pathname argument to be an empty string if the AT_EMPTY_PATH flag is specified. In this case the dirfd argument can refer to any type of file, not just a directory, and the call operates on that file. In particular, dirfd can refer to a symlink that was opened with O_PATH | O_NOFOLLOW.
This commit is contained in:
parent
6cc05784e1
commit
352dbd304b
@ -4785,14 +4785,36 @@ fchownat (int dirfd, const char *pathname, uid_t uid, gid_t gid, int flags)
|
|||||||
tmp_pathbuf tp;
|
tmp_pathbuf tp;
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
if (flags & ~AT_SYMLINK_NOFOLLOW)
|
if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
|
||||||
{
|
{
|
||||||
set_errno (EINVAL);
|
set_errno (EINVAL);
|
||||||
__leave;
|
__leave;
|
||||||
}
|
}
|
||||||
char *path = tp.c_get ();
|
char *path = tp.c_get ();
|
||||||
if (gen_full_path_at (path, dirfd, pathname))
|
int res = gen_full_path_at (path, dirfd, pathname);
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
if (!(errno == ENOENT && (flags & AT_EMPTY_PATH)))
|
||||||
__leave;
|
__leave;
|
||||||
|
/* pathname is an empty string. Operate on dirfd. */
|
||||||
|
if (dirfd == AT_FDCWD)
|
||||||
|
{
|
||||||
|
cwdstuff::cwd_lock.acquire ();
|
||||||
|
strcpy (path, cygheap->cwd.get_posix ());
|
||||||
|
cwdstuff::cwd_lock.release ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cygheap_fdget cfd (dirfd);
|
||||||
|
if (cfd < 0)
|
||||||
|
__leave;
|
||||||
|
strcpy (path, cfd->get_name ());
|
||||||
|
/* If dirfd refers to a symlink (which was necessarily
|
||||||
|
opened with O_PATH | O_NOFOLLOW), we must operate
|
||||||
|
directly on that symlink.. */
|
||||||
|
flags = AT_SYMLINK_NOFOLLOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
return chown_worker (path, (flags & AT_SYMLINK_NOFOLLOW)
|
return chown_worker (path, (flags & AT_SYMLINK_NOFOLLOW)
|
||||||
? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, uid, gid);
|
? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, uid, gid);
|
||||||
}
|
}
|
||||||
@ -4808,14 +4830,27 @@ fstatat (int dirfd, const char *__restrict pathname, struct stat *__restrict st,
|
|||||||
tmp_pathbuf tp;
|
tmp_pathbuf tp;
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
if (flags & ~AT_SYMLINK_NOFOLLOW)
|
if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
|
||||||
{
|
{
|
||||||
set_errno (EINVAL);
|
set_errno (EINVAL);
|
||||||
__leave;
|
__leave;
|
||||||
}
|
}
|
||||||
char *path = tp.c_get ();
|
char *path = tp.c_get ();
|
||||||
if (gen_full_path_at (path, dirfd, pathname))
|
int res = gen_full_path_at (path, dirfd, pathname);
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
if (!(errno == ENOENT && (flags & AT_EMPTY_PATH)))
|
||||||
__leave;
|
__leave;
|
||||||
|
/* pathname is an empty string. Operate on dirfd. */
|
||||||
|
if (dirfd == AT_FDCWD)
|
||||||
|
{
|
||||||
|
cwdstuff::cwd_lock.acquire ();
|
||||||
|
strcpy (path, cygheap->cwd.get_posix ());
|
||||||
|
cwdstuff::cwd_lock.release ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return fstat (dirfd, st);
|
||||||
|
}
|
||||||
path_conv pc (path, ((flags & AT_SYMLINK_NOFOLLOW)
|
path_conv pc (path, ((flags & AT_SYMLINK_NOFOLLOW)
|
||||||
? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW)
|
? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW)
|
||||||
| PC_POSIX | PC_KEEP_HANDLE, stat_suffixes);
|
| PC_POSIX | PC_KEEP_HANDLE, stat_suffixes);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user