(root)/
glibc-2.38/
hurd/
xattr.c
       1  /* Support for *xattr interfaces on GNU/Hurd.
       2     Copyright (C) 2006-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <hurd.h>
      20  #include <hurd/xattr.h>
      21  #include <string.h>
      22  #include <sys/mman.h>
      23  
      24  /* Right now we support only a fixed set of xattr names for Hurd features.
      25     There are no RPC interfaces for free-form xattr names and values.
      26  
      27     Name			Value encoding
      28     ----			----- --------
      29     gnu.author		empty if st_author==st_uid
      30  			uid_t giving st_author value
      31     gnu.translator	empty if no passive translator
      32  			translator and arguments: "/hurd/foo\0arg1\0arg2\0"
      33  */
      34  
      35  error_t
      36  _hurd_xattr_get (io_t port, const char *name, void *value, size_t *size)
      37  {
      38    if (strncmp (name, "gnu.", 4))
      39      return EOPNOTSUPP;
      40    name += 4;
      41  
      42    if (!strcmp (name, "author"))
      43      {
      44        struct stat64 st;
      45        error_t err = __io_stat (port, &st);
      46        if (err)
      47  	return err;
      48        if (st.st_author == st.st_uid)
      49  	*size = 0;
      50        else if (value)
      51  	{
      52  	  if (*size < sizeof st.st_author)
      53  	    return ERANGE;
      54  	  memcpy (value, &st.st_author, sizeof st.st_author);
      55  	}
      56        *size = sizeof st.st_author;
      57        return 0;
      58      }
      59  
      60    if (!strcmp (name, "translator"))
      61      {
      62        char *buf = value;
      63        mach_msg_type_number_t bufsz = value ? *size : 0;
      64        error_t err = __file_get_translator (port, &buf, &bufsz);
      65        if (err)
      66  	return err;
      67        if (value != NULL && *size < bufsz)
      68  	{
      69  	  if (buf != value)
      70  	    __munmap (buf, bufsz);
      71  	  return ERANGE;
      72  	}
      73        if (buf != value && bufsz > 0)
      74  	{
      75  	  if (value != NULL)
      76  	    memcpy (value, buf, bufsz);
      77  	  __munmap (buf, bufsz);
      78  	}
      79        *size = bufsz;
      80        return 0;
      81      }
      82  
      83    return EOPNOTSUPP;
      84  }
      85  
      86  error_t
      87  _hurd_xattr_set (io_t port, const char *name, const void *value, size_t size,
      88  		 int flags)
      89  {
      90    if (strncmp (name, "gnu.", 4))
      91      return EOPNOTSUPP;
      92    name += 4;
      93  
      94    if (!strcmp (name, "author"))
      95      switch (size)
      96        {
      97        default:
      98  	return EINVAL;
      99        case 0:			/* "Clear" author by setting to st_uid. */
     100  	{
     101  	  struct stat64 st;
     102  	  error_t err = __io_stat (port, &st);
     103  	  if (err)
     104  	    return err;
     105  	  if (st.st_author == st.st_uid)
     106  	    {
     107  	      /* Nothing to do.  */
     108  	      if (flags & XATTR_REPLACE)
     109  		return ENODATA;
     110  	      return 0;
     111  	    }
     112  	  if (flags & XATTR_CREATE)
     113  	    return EEXIST;
     114  	  return __file_chauthor (port, st.st_uid);
     115  	}
     116        case sizeof (uid_t):	/* Set the author.  */
     117  	{
     118  	  uid_t id;
     119  	  memcpy (&id, value, sizeof id);
     120  	  if (flags & (XATTR_CREATE|XATTR_REPLACE))
     121  	    {
     122  	      struct stat64 st;
     123  	      error_t err = __io_stat (port, &st);
     124  	      if (err)
     125  		return err;
     126  	      if (st.st_author == st.st_uid)
     127  		{
     128  		  if (flags & XATTR_REPLACE)
     129  		    return ENODATA;
     130  		}
     131  	      else if (flags & XATTR_CREATE)
     132  		return EEXIST;
     133  	      if (st.st_author == id)
     134  		/* Nothing to do.  */
     135  		return 0;
     136  	    }
     137  	  return __file_chauthor (port, id);
     138  	}
     139        }
     140  
     141    if (!strcmp (name, "translator"))
     142      {
     143        if (flags & XATTR_REPLACE)
     144  	{
     145  	  /* Must make sure it's already there.  */
     146  	  char *buf = NULL;
     147  	  mach_msg_type_number_t bufsz = 0;
     148  	  error_t err = __file_get_translator (port, &buf, &bufsz);
     149  	  if (err)
     150  	    return err;
     151  	  if (bufsz > 0)
     152  	    {
     153  	      __munmap (buf, bufsz);
     154  	      return ENODATA;
     155  	    }
     156  	}
     157        return __file_set_translator (port,
     158  				    FS_TRANS_SET | ((flags & XATTR_CREATE)
     159  						    ? FS_TRANS_EXCL : 0), 0, 0,
     160  				    value, size,
     161  				    MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
     162      }
     163  
     164    return EOPNOTSUPP;
     165  }
     166  
     167  error_t
     168  _hurd_xattr_remove (io_t port, const char *name)
     169  {
     170    return _hurd_xattr_set (port, name, NULL, 0, XATTR_REPLACE);
     171  }
     172  
     173  error_t
     174  _hurd_xattr_list (io_t port, void *buffer, size_t *size)
     175  {
     176    size_t total = 0;
     177    char *bufp = buffer;
     178    inline void add (const char *name, size_t len)
     179      {
     180        total += len;
     181        if (bufp != NULL && total <= *size)
     182  	bufp = __mempcpy (bufp, name, len);
     183      }
     184  #define add(s) add (s, sizeof s)
     185  
     186    struct stat64 st;
     187    error_t err = __io_stat (port, &st);
     188    if (err)
     189      return err;
     190  
     191    if (st.st_author != st.st_uid)
     192      add ("gnu.author");
     193    if (st.st_mode & S_IPTRANS)
     194      add ("gnu.translator");
     195  
     196    if (buffer != NULL && total > *size)
     197      return ERANGE;
     198    *size = total;
     199    return 0;
     200  }