2 $Id: ea_sys.c,v 1.2 2009-11-18 11:14:59 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.
18 #endif /* HAVE_CONFIG_H */
25 #include <sys/types.h>
31 #include <attr/xattr.h>
32 #elif HAVE_SYS_XATTR_H
33 #include <sys/xattr.h>
40 #ifdef HAVE_SYS_EXTATTR_H
41 #include <sys/extattr.h>
44 #include <atalk/adouble.h>
46 #include <atalk/afp.h>
47 #include <atalk/logger.h>
48 #include <atalk/volume.h>
49 #include <atalk/vfs.h>
50 #include <atalk/util.h>
51 #include <atalk/unix.h>
54 /**********************************************************************************
55 * EA VFS funcs for storing EAs in nativa filesystem EAs
56 **********************************************************************************/
59 * Function: sys_get_easize
61 * Purpose: get size of a native EA
65 * vol (r) current volume
66 * rbuf (w) DSI reply buffer
67 * rbuflen (rw) current length of data in reply buffer
69 * oflag (r) link and create flag
70 * attruname (r) name of attribute
72 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
76 * Copies EA size into rbuf in network order. Increments *rbuflen +4.
78 int sys_get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
83 LOG(log_debug7, logtype_afpd, "sys_getextattr_size(%s): attribute: \"%s\"", uname, attruname);
85 if ((oflag & O_NOFOLLOW) ) {
86 ret = sys_lgetxattr(uname, attruname, rbuf +4, 0);
89 ret = sys_getxattr(uname, attruname, rbuf +4, 0);
95 /* its a symlink and client requested O_NOFOLLOW */
96 LOG(log_debug, logtype_afpd, "sys_getextattr_size(%s): encountered symlink with kXAttrNoFollow", uname);
103 LOG(log_error, logtype_afpd, "sys_getextattr_size: error: %s", strerror(errno));
108 if (ret > MAX_EA_SIZE)
111 /* Start building reply packet */
112 LOG(log_debug7, logtype_afpd, "sys_getextattr_size(%s): attribute: \"%s\", size: %u", uname, attruname, ret);
114 /* length of attribute data */
115 attrsize = htonl((uint32_t)ret);
116 memcpy(rbuf, &attrsize, 4);
124 * Function: sys_get_eacontent
126 * Purpose: copy native EA into rbuf
130 * vol (r) current volume
131 * rbuf (w) DSI reply buffer
132 * rbuflen (rw) current length of data in reply buffer
134 * oflag (r) link and create flag
135 * attruname (r) name of attribute
136 * maxreply (r) maximum EA size as of current specs/real-life
138 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
142 * Copies EA into rbuf. Increments *rbuflen accordingly.
144 int sys_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
149 /* Start building reply packet */
151 maxreply -= MAX_REPLY_EXTRA_BYTES;
153 if (maxreply > MAX_EA_SIZE)
154 maxreply = MAX_EA_SIZE;
156 LOG(log_debug7, logtype_afpd, "sys_getextattr_content(%s): attribute: \"%s\", size: %u", uname, attruname, maxreply);
158 if ((oflag & O_NOFOLLOW) ) {
159 ret = sys_lgetxattr(uname, attruname, rbuf +4, maxreply);
162 ret = sys_getxattr(uname, attruname, rbuf +4, maxreply);
165 if (ret == -1) switch(errno) {
167 /* its a symlink and client requested O_NOFOLLOW */
168 LOG(log_debug, logtype_afpd, "sys_getextattr_content(%s): encountered symlink with kXAttrNoFollow", uname);
175 LOG(log_error, logtype_afpd, "sys_getextattr_content(%s): error: %s", attruname, strerror(errno));
179 /* remember where we must store length of attribute data in rbuf */
182 attrsize = htonl((uint32_t)ret);
183 memcpy(rbuf, &attrsize, 4);
189 * Function: sys_list_eas
191 * Purpose: copy names of native EAs into attrnamebuf
195 * vol (r) current volume
196 * attrnamebuf (w) store names a consecutive C strings here
197 * buflen (rw) length of names in attrnamebuf
199 * oflag (r) link and create flag
201 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
205 * Copies names of all EAs of uname as consecutive C strings into rbuf.
206 * Increments *rbuflen accordingly.
208 int sys_list_eas(VFS_FUNC_ARGS_EA_LIST)
210 ssize_t attrbuflen = *buflen;
215 buf = malloc(ATTRNAMEBUFSIZ);
219 if ((oflag & O_NOFOLLOW)) {
220 ret = sys_llistxattr(uname, buf, ATTRNAMEBUFSIZ);
223 ret = sys_listxattr(uname, buf, ATTRNAMEBUFSIZ);
226 if (ret == -1) switch(errno) {
228 /* its a symlink and client requested O_NOFOLLOW */
229 ret = AFPERR_BADTYPE;
231 LOG(log_error, logtype_afpd, "sys_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno));
239 /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
240 if ( 0 >= ( nlen = convert_string(vol->v_volcharset, CH_UTF8_MAC, ptr, len, attrnamebuf + attrbuflen, 256)) ) {
245 LOG(log_debug7, logtype_afpd, "sys_list_extattr(%s): attribute: %s", uname, ptr);
247 attrbuflen += nlen + 1;
248 if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) {
249 /* Next EA name could overflow, so bail out with error.
250 FIXME: evantually malloc/memcpy/realloc whatever.
252 LOG(log_warning, logtype_afpd, "sys_list_extattr(%s): running out of buffer for EA names", uname);
264 *buflen = attrbuflen;
269 * Function: sys_set_ea
271 * Purpose: set a native EA
275 * vol (r) current volume
277 * attruname (r) EA name
278 * ibuf (r) buffer with EA content
279 * attrsize (r) length EA in ibuf
280 * oflag (r) link and create flag
282 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
287 int sys_set_ea(VFS_FUNC_ARGS_EA_SET)
293 if ((oflag & O_CREAT) )
294 attr_flag |= XATTR_CREATE;
296 else if ((oflag & O_TRUNC) )
297 attr_flag |= XATTR_REPLACE;
299 if ((oflag & O_NOFOLLOW) ) {
300 ret = sys_lsetxattr(uname, attruname, ibuf, attrsize,attr_flag);
303 ret = sys_setxattr(uname, attruname, ibuf, attrsize, attr_flag);
309 /* its a symlink and client requested O_NOFOLLOW */
310 LOG(log_debug, logtype_afpd, "sys_set_ea(%s/%s): encountered symlink with kXAttrNoFollow",
314 LOG(log_error, logtype_afpd, "sys_set_ea(%s/%s): error: %s", uname, attruname, strerror(errno));
323 * Function: sys_remove_ea
325 * Purpose: remove a native EA
329 * vol (r) current volume
331 * attruname (r) EA name
332 * oflag (r) link and create flag
334 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
338 * Removes EA attruname from file uname.
340 int sys_remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
344 if ((oflag & O_NOFOLLOW) ) {
345 ret = sys_lremovexattr(uname, attruname);
348 ret = sys_removexattr(uname, attruname);
354 /* its a symlink and client requested O_NOFOLLOW */
355 LOG(log_debug, logtype_afpd, "sys_remove_ea(%s/%s): encountered symlink with kXAttrNoFollow", uname);
358 LOG(log_debug, logtype_afpd, "sys_remove_ea(%s/%s): error: %s", uname, attruname, strerror(errno));
359 return AFPERR_ACCESS;
361 LOG(log_error, logtype_afpd, "sys_remove_ea(%s/%s): error: %s", uname, attruname, strerror(errno));
369 /* ---------------------
372 int sys_ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
375 ret = sys_copyxattr(src, dst);
382 LOG(log_debug, logtype_afpd, "sys_ea_copyfile(%s, %s): error: %s", src, dst, strerror(errno));
383 return AFPERR_ACCESS;
385 LOG(log_error, logtype_afpd, "sys_ea_copyfile(%s, %s): error: %s", src, dst, strerror(errno));