Hello,

Thank you for the explanation and for the patch!  My bad, I
wrongly assumed that S_ISLNK implies (f)stat and vice versa
which, apparently, does not hold.

Regard,
Lukas

> On 3. 11. 2026, at 14:45, Bruno Haible <[email protected]> wrote:
> 
> Hi,
> 
> Lukáš Zaoral wrote:
>> file_has_aclinfo always calls lgetxattr unless ACL_SYMLINK_FOLLOW is
>> set.
> 
> ... and the documentation of file_has_acl states that SB was
> "obtained through stat() or lstat()".
> 
> But file_has_acl does not receive the information whether to call getxattr
> or lgetxattr. That is the main problem, and your patch does not fix it:
> it makes a guess. And that guess is correct in one case but wrong in
> the other case.
> 
> Instead, the correct fix would be to add to file_has_acl a flags
> argument, that would be either 0 (in the case lstat() was used)
> or ACL_SYMLINK_FOLLOW (in the case stat() or fstat() was used).
> 
> But this is a backwards-incompatible change, and it would cause
> compilation errors in GNU emacs and GNU tar. Therefore I don't
> want to do it. Instead, I'm merely applying the attached documentation
> change that adds a restriction to file_has_acl. I have verified that
>  - The only packages that use or used file_has_acl are
>    GNU coreutils, GNU emacs, GNU tar.
>  - GNU coreutils does not use file_has_acl any more, it now uses
>    file_has_aclinfo.
>  - GNU emacs and GNU tar satisfy the restriction.
> 
> So, the only package that does not satisfy the restriction is the
> GNU coreutils from two years ago, which is exactly your case.
> 
> For this case I would recommend that you apply a patch like this,
> locally for the coreutils package only.
> 
> diff --git a/lib/acl.h b/lib/acl.h
> index 4ac25fe226..74ccb09306 100644
> --- a/lib/acl.h
> +++ b/lib/acl.h
> @@ -77,7 +77,7 @@ struct aclinfo
> };
> 
> bool acl_errno_valid (int) _GL_ATTRIBUTE_CONST;
> -int file_has_acl (char const *, struct stat const *);
> +int file_has_acl (char const *, struct stat const *, int);
> int file_has_aclinfo (char const *restrict, struct aclinfo *restrict, int);
> int fdfile_has_aclinfo (int, char const *restrict,
>                         struct aclinfo *restrict, int);
> diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c
> index 4a70d4cf0f..f9d8efed3d 100644
> --- a/lib/file-has-acl.c
> +++ b/lib/file-has-acl.c
> @@ -973,14 +973,12 @@ fdfile_has_aclinfo (MAYBE_UNUSED int fd,
>    if ACLs are not supported as errno is set in that case also.
>    SB must be set to the stat buffer of NAME,
>    obtained through stat(), fstat(), or lstat().
> -   In the case that SB was obtained through lstat(), the caller must 
> guarantee
> -   that !S_ISLNK (SB->st_mode).  (In order to support S_ISLNK (SB->st_mode),
> -   this function would need a flags parameter, where the caller would need
> -   to pass either 0 or ACL_SYMLINK_FOLLOW.)  */
> +   FLAGS must be ACL_SYMLINK_FOLLOW in the stat(), fstat() cases, or
> +   0 in the lstat() case.  */
> int
> -file_has_acl (char const *name, struct stat const *sb)
> +file_has_acl (char const *name, struct stat const *sb, int flags)
> {
> -  int flags = IFTODT (sb->st_mode);
> +  flags |= IFTODT (sb->st_mode);
>   if (!S_ISDIR (sb->st_mode))
>     flags |= _GL_DT_NOTDIR;
>   struct aclinfo ai;
> 
> 
> Bruno
> 
> <0001-file-has-acl-Document-restriction.patch>


Reply via email to