* hurd/hurd/xattr.h: New file.
[platform/upstream/glibc.git] / hurd / xattr.c
1 /* Support for *xattr interfaces on GNU/Hurd.
2    Copyright (C) 2006 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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <hurd.h>
21 #include <hurd/xattr.h>
22 #include <string.h>
23 #include <sys/mman.h>
24
25 /* Right now we support only a fixed set of xattr names for Hurd features.
26    There are no RPC interfaces for free-form xattr names and values.
27
28    Name                 Value encoding
29    ----                 ----- --------
30    gnu.author           empty if st_author==st_uid
31                         uid_t giving st_author value
32    gnu.translator       empty if no passive translator
33                         translator and arguments: "/hurd/foo\0arg1\0arg2\0"
34 */
35
36 error_t
37 _hurd_xattr_get (io_t port, const char *name, void *value, size_t *size)
38 {
39   if (strncmp (name, "gnu.", 4))
40     return EOPNOTSUPP;
41   name += 4;
42
43   if (!strcmp (name, "author"))
44     {
45       struct stat64 st;
46       error_t err = __io_stat (port, &st);
47       if (err)
48         return err;
49       if (st.st_author == st.st_uid)
50         *size = 0;
51       else if (value)
52         {
53           if (*size < sizeof st.st_author)
54             return ERANGE;
55           memcpy (value, &st.st_author, sizeof st.st_author);
56         }
57       *size = sizeof st.st_author;
58       return 0;
59     }
60
61   if (!strcmp (name, "translator"))
62     {
63       char *buf = value;
64       size_t bufsz = value ? *size : 0;
65       error_t err = __file_get_translator (port, &buf, &bufsz);
66       if (err)
67         return err;
68       if (value != NULL && *size < bufsz)
69         {
70           if (buf != value)
71             munmap (buf, bufsz);
72           return -ERANGE;
73         }
74       if (buf != value && bufsz > 0)
75         {
76           if (value != NULL)
77             memcpy (value, buf, bufsz);
78           munmap (buf, bufsz);
79         }
80       *size = bufsz;
81       return 0;
82     }
83
84   return EOPNOTSUPP;
85 }
86
87 error_t
88 _hurd_xattr_set (io_t port, const char *name, const void *value, size_t size,
89                  int flags)
90 {
91   if (strncmp (name, "gnu.", 4))
92     return EOPNOTSUPP;
93   name += 4;
94
95   if (!strcmp (name, "author"))
96     switch (size)
97       {
98       default:
99         return EINVAL;
100       case 0:                   /* "Clear" author by setting to st_uid. */
101         {
102           struct stat64 st;
103           error_t err = __io_stat (port, &st);
104           if (err)
105             return err;
106           if (st.st_author == st.st_uid)
107             {
108               /* Nothing to do.  */
109               if (flags & XATTR_REPLACE)
110                 return ENODATA;
111               return 0;
112             }
113           if (flags & XATTR_CREATE)
114             return EEXIST;
115           return __file_chauthor (port, st.st_uid);
116         }
117       case sizeof (uid_t):      /* Set the author.  */
118         {
119           uid_t id;
120           memcpy (&id, value, sizeof id);
121           if (flags & (XATTR_CREATE|XATTR_REPLACE))
122             {
123               struct stat64 st;
124               error_t err = __io_stat (port, &st);
125               if (err)
126                 return err;
127               if (st.st_author == st.st_uid)
128                 {
129                   if (flags & XATTR_REPLACE)
130                     return ENODATA;
131                 }
132               else if (flags & XATTR_CREATE)
133                 return EEXIST;
134               if (st.st_author == id)
135                 /* Nothing to do.  */
136                 return 0;
137             }
138           return __file_chauthor (port, id);
139         }
140       }
141
142   if (!strcmp (name, "translator"))
143     {
144       if (flags & XATTR_REPLACE)
145         {
146           /* Must make sure it's already there.  */
147           char *buf = NULL;
148           size_t bufsz = 0;
149           error_t err = __file_get_translator (port, &buf, &bufsz);
150           if (err)
151             return err;
152           if (bufsz > 0)
153             {
154               munmap (buf, bufsz);
155               return ENODATA;
156             }
157         }
158       return __file_set_translator (port,
159                                     FS_TRANS_SET | ((flags & XATTR_CREATE)
160                                                     ? FS_TRANS_EXCL : 0), 0, 0,
161                                     value, size,
162                                     MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
163     }
164
165   return EOPNOTSUPP;
166 }
167
168 error_t
169 _hurd_xattr_remove (io_t port, const char *name)
170 {
171   return _hurd_xattr_set (port, name, NULL, 0, XATTR_REPLACE);
172 }
173
174 error_t
175 _hurd_xattr_list (io_t port, void *buffer, size_t *size)
176 {
177   size_t total = 0;
178   char *bufp = buffer;
179   inline void add (const char *name, size_t len)
180     {
181       total += len;
182       if (bufp != NULL && total <= *size)
183         bufp = __mempcpy (bufp, name, len);
184     }
185 #define add(s) add (s, sizeof s)
186
187   struct stat64 st;
188   error_t err = __io_stat (port, &st);
189   if (err)
190     return err;
191
192   if (st.st_author != st.st_uid)
193     add ("gnu.author");
194   if (st.st_mode & S_IPTRANS)
195     add ("gnu.translator");
196
197   if (buffer != NULL && total > *size)
198     return ERANGE;
199   *size = total;
200   return 0;
201 }