2 $Id: ea_solaris.c,v 1.3 2009-10-29 13:06:19 franklahm 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>
33 #include <atalk/adouble.h>
35 #include <atalk/afp.h>
36 #include <atalk/logger.h>
37 #include <atalk/volume.h>
38 #include <atalk/vfs.h>
39 #include <atalk/util.h>
40 #include <atalk/unix.h>
43 /**********************************************************************************
44 * Solaris EA VFS funcs
45 **********************************************************************************/
48 * Function: sol_get_easize
50 * Purpose: get size of an EA on Solaris native EA
54 * vol (r) current volume
55 * rbuf (w) DSI reply buffer
56 * rbuflen (rw) current length of data in reply buffer
58 * oflag (r) link and create flag
59 * attruname (r) name of attribute
61 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
65 * Copies EA size into rbuf in network order. Increments *rbuflen +4.
67 int sol_get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
73 LOG(log_debug7, logtype_afpd, "sol_getextattr_size(%s): attribute: \"%s\"", uname, attruname);
75 if ( -1 == (attrdirfd = attropen(uname, ".", O_RDONLY | oflag))) {
77 /* its a symlink and client requested O_NOFOLLOW */
78 LOG(log_debug, logtype_afpd, "sol_getextattr_size(%s): encountered symlink with kXAttrNoFollow", uname);
85 LOG(log_error, logtype_afpd, "sol_getextattr_size: attropen error: %s", strerror(errno));
89 if ( -1 == (fstatat(attrdirfd, attruname, &st, 0))) {
90 LOG(log_error, logtype_afpd, "sol_getextattr_size: fstatat error: %s", strerror(errno));
94 attrsize = (st.st_size > MAX_EA_SIZE) ? MAX_EA_SIZE : st.st_size;
96 /* Start building reply packet */
98 LOG(log_debug7, logtype_afpd, "sol_getextattr_size(%s): attribute: \"%s\", size: %u", uname, attruname, attrsize);
100 /* length of attribute data */
101 attrsize = htonl(attrsize);
102 memcpy(rbuf, &attrsize, 4);
113 * Function: sol_get_eacontent
115 * Purpose: copy Solaris native EA into rbuf
119 * vol (r) current volume
120 * rbuf (w) DSI reply buffer
121 * rbuflen (rw) current length of data in reply buffer
123 * oflag (r) link and create flag
124 * attruname (r) name of attribute
125 * maxreply (r) maximum EA size as of current specs/real-life
127 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
131 * Copies EA into rbuf. Increments *rbuflen accordingly.
133 int sol_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
136 size_t toread, okread = 0, len;
140 if ( -1 == (attrdirfd = attropen(uname, attruname, O_RDONLY | oflag))) {
141 if (errno == ELOOP) {
142 /* its a symlink and client requested O_NOFOLLOW */
143 LOG(log_debug, logtype_afpd, "sol_getextattr_content(%s): encountered symlink with kXAttrNoFollow", uname);
150 LOG(log_error, logtype_afpd, "sol_getextattr_content(%s): attropen error: %s", attruname, strerror(errno));
154 if ( -1 == (fstat(attrdirfd, &st))) {
155 LOG(log_error, logtype_afpd, "sol_getextattr_content(%s): fstatat error: %s", attruname,strerror(errno));
160 /* Start building reply packet */
162 maxreply -= MAX_REPLY_EXTRA_BYTES;
163 if (maxreply > MAX_EA_SIZE)
164 maxreply = MAX_EA_SIZE;
166 /* But never send more than the client requested */
167 toread = (maxreply < st.st_size) ? maxreply : st.st_size;
169 LOG(log_debug7, logtype_afpd, "sol_getextattr_content(%s): attribute: \"%s\", size: %u", uname, attruname, maxreply);
171 /* remember where we must store length of attribute data in rbuf */
177 len = read(attrdirfd, rbuf, toread);
179 LOG(log_error, logtype_afpd, "sol_getextattr_content(%s): read error: %s", attruname, strerror(errno));
186 if ((len == 0) || (okread == toread))
190 okread = htonl((uint32_t)okread);
191 memcpy(datalength, &okread, 4);
201 * Function: sol_list_eas
203 * Purpose: copy names of Solaris native EA into attrnamebuf
207 * vol (r) current volume
208 * attrnamebuf (w) store names a consecutive C strings here
209 * buflen (rw) length of names in attrnamebuf
211 * oflag (r) link and create flag
213 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
217 * Copies names of all EAs of uname as consecutive C strings into rbuf.
218 * Increments *rbuflen accordingly.
220 int sol_list_eas(VFS_FUNC_ARGS_EA_LIST)
222 int ret, attrbuflen = *buflen, len, attrdirfd = 0;
226 /* Now list file attribute dir */
227 if ( -1 == (attrdirfd = attropen( uname, ".", O_RDONLY | oflag))) {
228 if (errno == ELOOP) {
229 /* its a symlink and client requested O_NOFOLLOW */
230 ret = AFPERR_BADTYPE;
233 LOG(log_error, logtype_afpd, "sol_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno));
238 if (NULL == (dirp = fdopendir(attrdirfd))) {
239 LOG(log_error, logtype_afpd, "sol_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno));
244 while ((dp = readdir(dirp))) {
245 /* check if its "." or ".." */
246 if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0) ||
247 (strcmp(dp->d_name, "SUNWattr_ro") == 0) || (strcmp(dp->d_name, "SUNWattr_rw") == 0))
250 len = strlen(dp->d_name);
252 /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
253 if ( 0 >= ( len = convert_string(vol->v_volcharset, CH_UTF8_MAC, dp->d_name, len, attrnamebuf + attrbuflen, 255)) ) {
258 /* convert_string didn't 0-terminate */
259 attrnamebuf[attrbuflen + 255] = 0;
261 LOG(log_debug7, logtype_afpd, "sol_list_extattr(%s): attribute: %s", uname, dp->d_name);
263 attrbuflen += len + 1;
264 if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) {
265 /* Next EA name could overflow, so bail out with error.
266 FIXME: evantually malloc/memcpy/realloc whatever.
268 LOG(log_warning, logtype_afpd, "sol_list_extattr(%s): running out of buffer for EA names", uname);
283 *buflen = attrbuflen;
288 * Function: sol_set_ea
290 * Purpose: set a Solaris native EA
294 * vol (r) current volume
296 * attruname (r) EA name
297 * ibuf (r) buffer with EA content
298 * attrsize (r) length EA in ibuf
299 * oflag (r) link and create flag
301 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
305 * Copies names of all EAs of uname as consecutive C strings into rbuf.
306 * Increments *rbuflen accordingly.
308 int sol_set_ea(VFS_FUNC_ARGS_EA_SET)
312 if ( -1 == (attrdirfd = attropen(uname, attruname, oflag, 0666))) {
313 if (errno == ELOOP) {
314 /* its a symlink and client requested O_NOFOLLOW */
315 LOG(log_debug, logtype_afpd, "afp_setextattr(%s): encountered symlink with kXAttrNoFollow", uname);
318 LOG(log_error, logtype_afpd, "afp_setextattr(%s): attropen error: %s", uname, strerror(errno));
322 if ((write(attrdirfd, ibuf, attrsize)) != attrsize) {
323 LOG(log_error, logtype_afpd, "afp_setextattr(%s): read error: %s", attruname, strerror(errno));
331 * Function: sol_remove_ea
333 * Purpose: remove a Solaris native EA
337 * vol (r) current volume
339 * attruname (r) EA name
340 * oflag (r) link and create flag
342 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
346 * Removes EA attruname from file uname.
348 int sol_remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
352 if ( -1 == (attrdirfd = attropen(uname, ".", oflag))) {
355 /* its a symlink and client requested O_NOFOLLOW */
356 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): encountered symlink with kXAttrNoFollow", uname);
359 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): unlinkat error: %s", uname, strerror(errno));
360 return AFPERR_ACCESS;
362 LOG(log_error, logtype_afpd, "afp_remextattr(%s): attropen error: %s", uname, strerror(errno));
367 if ( -1 == (unlinkat(attrdirfd, attruname, 0)) ) {
368 if (errno == EACCES) {
369 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): unlinkat error: %s", uname, strerror(errno));
370 return AFPERR_ACCESS;
372 LOG(log_error, logtype_afpd, "afp_remextattr(%s): unlinkat error: %s", uname, strerror(errno));