]> arthur.barton.de Git - netatalk.git/blob - libatalk/vfs/ea_solaris.c
6af89b8f90f6cf995666d41547fc7e8cdc9a3c50
[netatalk.git] / libatalk / vfs / ea_solaris.c
1 /*
2   $Id: ea_solaris.c,v 1.4 2009-11-13 13:03:29 didg Exp $
3   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program 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
13   GNU General Public License for more details.
14 */
15
16 /* According to man fsattr.5 we must define _ATFILE_SOURCE */
17 #define _ATFILE_SOURCE
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif /* HAVE_CONFIG_H */
22
23 #include <unistd.h>
24 #include <stdint.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <dirent.h>
32
33 #if HAVE_ATTR_XATTR_H
34 #include <attr/xattr.h>
35 #elif HAVE_SYS_XATTR_H
36 #include <sys/xattr.h>
37 #endif
38
39 #ifdef HAVE_SYS_EA_H
40 #include <sys/ea.h>
41 #endif
42
43 #ifdef HAVE_SYS_EXTATTR_H
44 #include <sys/extattr.h>
45 #endif
46
47 #include <atalk/adouble.h>
48 #include <atalk/ea.h>
49 #include <atalk/afp.h>
50 #include <atalk/logger.h>
51 #include <atalk/volume.h>
52 #include <atalk/vfs.h>
53 #include <atalk/util.h>
54 #include <atalk/unix.h>
55
56
57 /**********************************************************************************
58  * Solaris EA VFS funcs
59  **********************************************************************************/
60
61 /*
62  * Function: sol_get_easize
63  *
64  * Purpose: get size of an EA on Solaris native EA
65  *
66  * Arguments:
67  *
68  *    vol          (r) current volume
69  *    rbuf         (w) DSI reply buffer
70  *    rbuflen      (rw) current length of data in reply buffer
71  *    uname        (r) filename
72  *    oflag        (r) link and create flag
73  *    attruname    (r) name of attribute
74  *
75  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
76  *
77  * Effects:
78  *
79  * Copies EA size into rbuf in network order. Increments *rbuflen +4.
80  */
81 int sol_get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
82 {
83     ssize_t   ret;
84     uint32_t  attrsize;
85
86     LOG(log_debug7, logtype_afpd, "sol_getextattr_size(%s): attribute: \"%s\"", uname, attruname);
87
88     if ((oflag & O_NOFOLLOW) ) {
89         ret = sys_lgetxattr(uname, attruname, rbuf +4, 0);
90     }
91     else {
92         ret = sys_getxattr(uname, attruname,  rbuf +4, 0);
93     }
94     
95     if (ret == -1) switch(errno) {
96     case ELOOP:
97         /* its a symlink and client requested O_NOFOLLOW  */
98         LOG(log_debug, logtype_afpd, "sol_getextattr_size(%s): encountered symlink with kXAttrNoFollow", uname);
99
100         memset(rbuf, 0, 4);
101         *rbuflen += 4;
102
103         return AFP_OK;
104     default:
105         LOG(log_error, logtype_afpd, "sol_getextattr_size: error: %s", strerror(errno));
106         return AFPERR_MISC;
107     }
108
109     if (ret > MAX_EA_SIZE) 
110       ret = MAX_EA_SIZE;
111
112     /* Start building reply packet */
113     LOG(log_debug7, logtype_afpd, "sol_getextattr_size(%s): attribute: \"%s\", size: %u", uname, attruname, ret);
114
115     /* length of attribute data */
116     attrsize = htonl((uint32_t)ret);
117     memcpy(rbuf, &attrsize, 4);
118     *rbuflen += 4;
119
120     ret = AFP_OK;
121     return ret;
122 }
123
124 /*
125  * Function: sol_get_eacontent
126  *
127  * Purpose: copy Solaris native EA into rbuf
128  *
129  * Arguments:
130  *
131  *    vol          (r) current volume
132  *    rbuf         (w) DSI reply buffer
133  *    rbuflen      (rw) current length of data in reply buffer
134  *    uname        (r) filename
135  *    oflag        (r) link and create flag
136  *    attruname    (r) name of attribute
137  *    maxreply     (r) maximum EA size as of current specs/real-life
138  *
139  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
140  *
141  * Effects:
142  *
143  * Copies EA into rbuf. Increments *rbuflen accordingly.
144  */
145 int sol_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
146 {
147     ssize_t   ret;
148     uint32_t  attrsize;
149
150     /* Start building reply packet */
151
152     maxreply -= MAX_REPLY_EXTRA_BYTES;
153
154     if (maxreply > MAX_EA_SIZE)
155         maxreply = MAX_EA_SIZE;
156
157     LOG(log_debug7, logtype_afpd, "sol_getextattr_content(%s): attribute: \"%s\", size: %u", uname, attruname, maxreply);
158
159     if ((oflag & O_NOFOLLOW) ) {
160         ret = sys_lgetxattr(uname, attruname, rbuf +4, maxreply);
161     }
162     else {
163         ret = sys_getxattr(uname, attruname,  rbuf +4, maxreply);
164     }
165     
166     if (ret == -1) switch(errno) {
167     case ELOOP:
168         /* its a symlink and client requested O_NOFOLLOW  */
169         LOG(log_debug, logtype_afpd, "sol_getextattr_content(%s): encountered symlink with kXAttrNoFollow", uname);
170
171         memset(rbuf, 0, 4);
172         *rbuflen += 4;
173
174         return AFP_OK;
175     default:
176         LOG(log_error, logtype_afpd, "sol_getextattr_content(%s): error: %s", attruname, strerror(errno));
177         return AFPERR_MISC;
178     }
179
180     /* remember where we must store length of attribute data in rbuf */
181     *rbuflen += 4 +ret;
182
183     attrsize = htonl((uint32_t)ret);
184     memcpy(rbuf, &attrsize, 4);
185
186     return AFP_OK;
187 }
188
189 /*
190  * Function: sol_list_eas
191  *
192  * Purpose: copy names of Solaris native EA into attrnamebuf
193  *
194  * Arguments:
195  *
196  *    vol          (r) current volume
197  *    attrnamebuf  (w) store names a consecutive C strings here
198  *    buflen       (rw) length of names in attrnamebuf
199  *    uname        (r) filename
200  *    oflag        (r) link and create flag
201  *
202  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
203  *
204  * Effects:
205  *
206  * Copies names of all EAs of uname as consecutive C strings into rbuf.
207  * Increments *rbuflen accordingly.
208  */
209 int sol_list_eas(VFS_FUNC_ARGS_EA_LIST)
210 {
211     ssize_t attrbuflen = *buflen;
212     int     ret, len, nlen;
213     char    *buf;
214     char    *ptr;
215         
216     buf = malloc(ATTRNAMEBUFSIZ);
217     if (!buf)
218         return AFPERR_MISC;
219
220     if ((oflag & O_NOFOLLOW)) {
221         ret = sys_llistxattr(uname, buf, ATTRNAMEBUFSIZ);
222     }
223     else {
224         ret = sys_listxattr(uname, buf, ATTRNAMEBUFSIZ);
225     }
226
227     if (ret == -1) switch(errno) {
228         case ELOOP:
229             /* its a symlink and client requested O_NOFOLLOW */
230             ret = AFPERR_BADTYPE;
231         default:
232             LOG(log_error, logtype_afpd, "sol_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno));
233             ret= AFPERR_MISC;
234     }
235     
236     ptr = buf;
237     while (ret > 0)  {
238         len = strlen(ptr);
239
240         /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
241         if ( 0 >= ( nlen = convert_string(vol->v_volcharset, CH_UTF8_MAC, ptr, len, attrnamebuf + attrbuflen, 256)) ) {
242             ret = AFPERR_MISC;
243             goto exit;
244         }
245
246         LOG(log_debug7, logtype_afpd, "sol_list_extattr(%s): attribute: %s", uname, ptr);
247
248         attrbuflen += nlen + 1;
249         if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) {
250             /* Next EA name could overflow, so bail out with error.
251                FIXME: evantually malloc/memcpy/realloc whatever.
252                Is it worth it ? */
253             LOG(log_warning, logtype_afpd, "sol_list_extattr(%s): running out of buffer for EA names", uname);
254             ret = AFPERR_MISC;
255             goto exit;
256         }
257         ret -= len +1;
258         ptr += len +1;
259     }
260
261     ret = AFP_OK;
262
263 exit:
264     free(buf);
265     *buflen = attrbuflen;
266     return ret;
267 }
268
269 /*
270  * Function: sol_set_ea
271  *
272  * Purpose: set a native EA
273  *
274  * Arguments:
275  *
276  *    vol          (r) current volume
277  *    uname        (r) filename
278  *    attruname    (r) EA name
279  *    ibuf         (r) buffer with EA content
280  *    attrsize     (r) length EA in ibuf
281  *    oflag        (r) link and create flag
282  *
283  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
284  *
285  * Effects:
286  *
287  */
288 int sol_set_ea(VFS_FUNC_ARGS_EA_SET)
289 {
290     int attr_flag;
291     int ret;
292
293     attr_flag = 0;
294     if ((oflag & O_CREAT) ) 
295         attr_flag |= XATTR_CREATE;
296
297     else if ((oflag & O_TRUNC) ) 
298         attr_flag |= XATTR_REPLACE;
299     
300     if ((oflag & O_NOFOLLOW) ) {
301         ret = sys_lsetxattr(uname, attruname,  ibuf, attrsize,attr_flag);
302     }
303     else {
304         ret = sys_setxattr(uname, attruname,  ibuf, attrsize, attr_flag);
305     }
306
307     if (ret == -1) switch(errno) {
308     case ELOOP:
309         /* its a symlink and client requested O_NOFOLLOW  */
310         LOG(log_debug, logtype_afpd, "afp_setextattr(%s): encountered symlink with kXAttrNoFollow", uname);
311         return AFP_OK;
312     default:
313         LOG(log_error, logtype_afpd, "afp_setextattr(%s): read error: %s", attruname, strerror(errno));
314         return AFPERR_MISC;
315     }
316
317     return AFP_OK;
318 }
319
320 /*
321  * Function: sol_remove_ea
322  *
323  * Purpose: remove a native EA
324  *
325  * Arguments:
326  *
327  *    vol          (r) current volume
328  *    uname        (r) filename
329  *    attruname    (r) EA name
330  *    oflag        (r) link and create flag
331  *
332  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
333  *
334  * Effects:
335  *
336  * Removes EA attruname from file uname.
337  */
338 int sol_remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
339 {
340     int ret;
341
342     if ((oflag & O_NOFOLLOW) ) {
343         ret = sys_lremovexattr(uname, attruname);
344     }
345     else {
346         ret = sys_removexattr(uname, attruname);
347     }
348
349     if (ret == -1) switch(errno) {
350     case ELOOP:
351         /* its a symlink and client requested O_NOFOLLOW  */
352         LOG(log_debug, logtype_afpd, "afp_remextattr(%s): encountered symlink with kXAttrNoFollow", uname);
353         return AFP_OK;
354     case EACCES:
355         LOG(log_debug, logtype_afpd, "afp_remextattr(%s): unlinkat error: %s", uname, strerror(errno));
356         return AFPERR_ACCESS;
357     default:
358         LOG(log_error, logtype_afpd, "afp_remextattr(%s): attropen error: %s", uname, strerror(errno));
359         return AFPERR_MISC;
360     }
361     return AFP_OK;
362 }