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>
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.
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.
16 /* According to man fsattr.5 we must define _ATFILE_SOURCE */
17 #define _ATFILE_SOURCE
21 #endif /* HAVE_CONFIG_H */
28 #include <sys/types.h>
34 #include <attr/xattr.h>
35 #elif HAVE_SYS_XATTR_H
36 #include <sys/xattr.h>
43 #ifdef HAVE_SYS_EXTATTR_H
44 #include <sys/extattr.h>
47 #include <atalk/adouble.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>
57 /**********************************************************************************
58 * Solaris EA VFS funcs
59 **********************************************************************************/
62 * Function: sol_get_easize
64 * Purpose: get size of an EA on Solaris native EA
68 * vol (r) current volume
69 * rbuf (w) DSI reply buffer
70 * rbuflen (rw) current length of data in reply buffer
72 * oflag (r) link and create flag
73 * attruname (r) name of attribute
75 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
79 * Copies EA size into rbuf in network order. Increments *rbuflen +4.
81 int sol_get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
86 LOG(log_debug7, logtype_afpd, "sol_getextattr_size(%s): attribute: \"%s\"", uname, attruname);
88 if ((oflag & O_NOFOLLOW) ) {
89 ret = sys_lgetxattr(uname, attruname, rbuf +4, 0);
92 ret = sys_getxattr(uname, attruname, rbuf +4, 0);
95 if (ret == -1) switch(errno) {
97 /* its a symlink and client requested O_NOFOLLOW */
98 LOG(log_debug, logtype_afpd, "sol_getextattr_size(%s): encountered symlink with kXAttrNoFollow", uname);
105 LOG(log_error, logtype_afpd, "sol_getextattr_size: error: %s", strerror(errno));
109 if (ret > MAX_EA_SIZE)
112 /* Start building reply packet */
113 LOG(log_debug7, logtype_afpd, "sol_getextattr_size(%s): attribute: \"%s\", size: %u", uname, attruname, ret);
115 /* length of attribute data */
116 attrsize = htonl((uint32_t)ret);
117 memcpy(rbuf, &attrsize, 4);
125 * Function: sol_get_eacontent
127 * Purpose: copy Solaris native EA into rbuf
131 * vol (r) current volume
132 * rbuf (w) DSI reply buffer
133 * rbuflen (rw) current length of data in reply buffer
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
139 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
143 * Copies EA into rbuf. Increments *rbuflen accordingly.
145 int sol_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
150 /* Start building reply packet */
152 maxreply -= MAX_REPLY_EXTRA_BYTES;
154 if (maxreply > MAX_EA_SIZE)
155 maxreply = MAX_EA_SIZE;
157 LOG(log_debug7, logtype_afpd, "sol_getextattr_content(%s): attribute: \"%s\", size: %u", uname, attruname, maxreply);
159 if ((oflag & O_NOFOLLOW) ) {
160 ret = sys_lgetxattr(uname, attruname, rbuf +4, maxreply);
163 ret = sys_getxattr(uname, attruname, rbuf +4, maxreply);
166 if (ret == -1) switch(errno) {
168 /* its a symlink and client requested O_NOFOLLOW */
169 LOG(log_debug, logtype_afpd, "sol_getextattr_content(%s): encountered symlink with kXAttrNoFollow", uname);
176 LOG(log_error, logtype_afpd, "sol_getextattr_content(%s): error: %s", attruname, strerror(errno));
180 /* remember where we must store length of attribute data in rbuf */
183 attrsize = htonl((uint32_t)ret);
184 memcpy(rbuf, &attrsize, 4);
190 * Function: sol_list_eas
192 * Purpose: copy names of Solaris native EA into attrnamebuf
196 * vol (r) current volume
197 * attrnamebuf (w) store names a consecutive C strings here
198 * buflen (rw) length of names in attrnamebuf
200 * oflag (r) link and create flag
202 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
206 * Copies names of all EAs of uname as consecutive C strings into rbuf.
207 * Increments *rbuflen accordingly.
209 int sol_list_eas(VFS_FUNC_ARGS_EA_LIST)
211 ssize_t attrbuflen = *buflen;
216 buf = malloc(ATTRNAMEBUFSIZ);
220 if ((oflag & O_NOFOLLOW)) {
221 ret = sys_llistxattr(uname, buf, ATTRNAMEBUFSIZ);
224 ret = sys_listxattr(uname, buf, ATTRNAMEBUFSIZ);
227 if (ret == -1) switch(errno) {
229 /* its a symlink and client requested O_NOFOLLOW */
230 ret = AFPERR_BADTYPE;
232 LOG(log_error, logtype_afpd, "sol_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno));
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)) ) {
246 LOG(log_debug7, logtype_afpd, "sol_list_extattr(%s): attribute: %s", uname, ptr);
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.
253 LOG(log_warning, logtype_afpd, "sol_list_extattr(%s): running out of buffer for EA names", uname);
265 *buflen = attrbuflen;
270 * Function: sol_set_ea
272 * Purpose: set a native EA
276 * vol (r) current volume
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
283 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
288 int sol_set_ea(VFS_FUNC_ARGS_EA_SET)
294 if ((oflag & O_CREAT) )
295 attr_flag |= XATTR_CREATE;
297 else if ((oflag & O_TRUNC) )
298 attr_flag |= XATTR_REPLACE;
300 if ((oflag & O_NOFOLLOW) ) {
301 ret = sys_lsetxattr(uname, attruname, ibuf, attrsize,attr_flag);
304 ret = sys_setxattr(uname, attruname, ibuf, attrsize, attr_flag);
307 if (ret == -1) switch(errno) {
309 /* its a symlink and client requested O_NOFOLLOW */
310 LOG(log_debug, logtype_afpd, "afp_setextattr(%s): encountered symlink with kXAttrNoFollow", uname);
313 LOG(log_error, logtype_afpd, "afp_setextattr(%s): read error: %s", attruname, strerror(errno));
321 * Function: sol_remove_ea
323 * Purpose: remove a native EA
327 * vol (r) current volume
329 * attruname (r) EA name
330 * oflag (r) link and create flag
332 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
336 * Removes EA attruname from file uname.
338 int sol_remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
342 if ((oflag & O_NOFOLLOW) ) {
343 ret = sys_lremovexattr(uname, attruname);
346 ret = sys_removexattr(uname, attruname);
349 if (ret == -1) switch(errno) {
351 /* its a symlink and client requested O_NOFOLLOW */
352 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): encountered symlink with kXAttrNoFollow", uname);
355 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): unlinkat error: %s", uname, strerror(errno));
356 return AFPERR_ACCESS;
358 LOG(log_error, logtype_afpd, "afp_remextattr(%s): attropen error: %s", uname, strerror(errno));