2 Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
17 #endif /* HAVE_CONFIG_H */
24 #include <sys/types.h>
29 #include <atalk/adouble.h>
31 #include <atalk/afp.h>
32 #include <atalk/logger.h>
33 #include <atalk/volume.h>
34 #include <atalk/vfs.h>
35 #include <atalk/util.h>
36 #include <atalk/unix.h>
37 #include <atalk/compat.h>
39 /**********************************************************************************
40 * EA VFS funcs for storing EAs in nativa filesystem EAs
41 **********************************************************************************/
44 * Function: sys_get_easize
46 * Purpose: get size of a native EA
50 * vol (r) current volume
51 * rbuf (w) DSI reply buffer
52 * rbuflen (rw) current length of data in reply buffer
54 * oflag (r) link and create flag
55 * attruname (r) name of attribute
57 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
61 * Copies EA size into rbuf in network order. Increments *rbuflen +4.
63 int sys_get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
68 LOG(log_debug7, logtype_afpd, "sys_getextattr_size(%s): attribute: \"%s\"", uname, attruname);
70 if ((oflag & O_NOFOLLOW) ) {
71 ret = sys_lgetxattr(uname, attruname, rbuf +4, 0);
74 ret = sys_getxattr(uname, attruname, rbuf +4, 0);
81 case OPEN_NOFOLLOW_ERRNO:
82 /* its a symlink and client requested O_NOFOLLOW */
83 LOG(log_debug, logtype_afpd, "sys_getextattr_size(%s): encountered symlink with kXAttrNoFollow", uname);
90 LOG(log_error, logtype_afpd, "sys_getextattr_size: error: %s", strerror(errno));
95 if (ret > MAX_EA_SIZE)
98 /* Start building reply packet */
99 LOG(log_debug7, logtype_afpd, "sys_getextattr_size(%s): attribute: \"%s\", size: %u", uname, attruname, ret);
101 /* length of attribute data */
102 attrsize = htonl((uint32_t)ret);
103 memcpy(rbuf, &attrsize, 4);
111 * Function: sys_get_eacontent
113 * Purpose: copy native EA into rbuf
117 * vol (r) current volume
118 * rbuf (w) DSI reply buffer
119 * rbuflen (rw) current length of data in reply buffer
121 * oflag (r) link and create flag
122 * attruname (r) name of attribute
123 * maxreply (r) maximum EA size as of current specs/real-life
125 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
129 * Copies EA into rbuf. Increments *rbuflen accordingly.
131 int sys_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
136 /* Start building reply packet */
138 maxreply -= MAX_REPLY_EXTRA_BYTES;
140 if (maxreply > MAX_EA_SIZE)
141 maxreply = MAX_EA_SIZE;
143 LOG(log_debug7, logtype_afpd, "sys_getextattr_content(%s): attribute: \"%s\", size: %u", uname, attruname, maxreply);
145 if ((oflag & O_NOFOLLOW) ) {
146 ret = sys_lgetxattr(uname, attruname, rbuf +4, maxreply);
149 ret = sys_getxattr(uname, attruname, rbuf +4, maxreply);
156 case OPEN_NOFOLLOW_ERRNO:
157 /* its a symlink and client requested O_NOFOLLOW */
158 LOG(log_debug, logtype_afpd, "sys_getextattr_content(%s): encountered symlink with kXAttrNoFollow", uname);
165 LOG(log_error, logtype_afpd, "sys_getextattr_content(%s): error: %s", attruname, strerror(errno));
170 /* remember where we must store length of attribute data in rbuf */
173 attrsize = htonl((uint32_t)ret);
174 memcpy(rbuf, &attrsize, 4);
180 * Function: sys_list_eas
182 * Purpose: copy names of native EAs into attrnamebuf
186 * vol (r) current volume
187 * attrnamebuf (w) store names a consecutive C strings here
188 * buflen (rw) length of names in attrnamebuf
190 * oflag (r) link and create flag
192 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
196 * Copies names of all EAs of uname as consecutive C strings into rbuf.
197 * Increments *rbuflen accordingly.
199 int sys_list_eas(VFS_FUNC_ARGS_EA_LIST)
201 ssize_t attrbuflen = *buflen;
206 buf = malloc(ATTRNAMEBUFSIZ);
210 if ((oflag & O_NOFOLLOW)) {
211 ret = sys_llistxattr(uname, buf, ATTRNAMEBUFSIZ);
214 ret = sys_listxattr(uname, buf, ATTRNAMEBUFSIZ);
217 if (ret == -1) switch(errno) {
218 case OPEN_NOFOLLOW_ERRNO:
219 /* its a symlink and client requested O_NOFOLLOW */
220 ret = AFPERR_BADTYPE;
222 #ifdef HAVE_ATTROPEN /* Solaris */
228 LOG(log_error, logtype_afpd, "sys_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno));
237 /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
238 if ( 0 >= ( nlen = convert_string(vol->v_volcharset, CH_UTF8_MAC, ptr, len, attrnamebuf + attrbuflen, 256)) ) {
243 LOG(log_debug7, logtype_afpd, "sys_list_extattr(%s): attribute: %s", uname, ptr);
245 attrbuflen += nlen + 1;
246 if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) {
247 /* Next EA name could overflow, so bail out with error.
248 FIXME: evantually malloc/memcpy/realloc whatever.
250 LOG(log_warning, logtype_afpd, "sys_list_extattr(%s): running out of buffer for EA names", uname);
262 *buflen = attrbuflen;
267 * Function: sys_set_ea
269 * Purpose: set a native EA
273 * vol (r) current volume
275 * attruname (r) EA name
276 * ibuf (r) buffer with EA content
277 * attrsize (r) length EA in ibuf
278 * oflag (r) link and create flag
280 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
285 int sys_set_ea(VFS_FUNC_ARGS_EA_SET)
291 if ((oflag & O_CREAT) )
292 attr_flag |= XATTR_CREATE;
294 else if ((oflag & O_TRUNC) )
295 attr_flag |= XATTR_REPLACE;
297 if ((oflag & O_NOFOLLOW) ) {
298 ret = sys_lsetxattr(uname, attruname, ibuf, attrsize,attr_flag);
301 ret = sys_setxattr(uname, attruname, ibuf, attrsize, attr_flag);
306 case OPEN_NOFOLLOW_ERRNO:
307 /* its a symlink and client requested O_NOFOLLOW */
308 LOG(log_debug, logtype_afpd, "sys_set_ea(%s/%s): encountered symlink with kXAttrNoFollow",
312 LOG(log_debug, logtype_afpd, "sys_set_ea(%s/%s): EA already exists",
316 LOG(log_error, logtype_afpd, "sys_set_ea(%s/%s): error: %s", uname, attruname, strerror(errno));
325 * Function: sys_remove_ea
327 * Purpose: remove a native EA
331 * vol (r) current volume
333 * attruname (r) EA name
334 * oflag (r) link and create flag
336 * Returns: AFP code: AFP_OK on success or appropiate AFP error code
340 * Removes EA attruname from file uname.
342 int sys_remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
346 if ((oflag & O_NOFOLLOW) ) {
347 ret = sys_lremovexattr(uname, attruname);
350 ret = sys_removexattr(uname, attruname);
355 case OPEN_NOFOLLOW_ERRNO:
356 /* its a symlink and client requested O_NOFOLLOW */
357 LOG(log_debug, logtype_afpd, "sys_remove_ea(%s/%s): encountered symlink with kXAttrNoFollow", uname);
360 LOG(log_debug, logtype_afpd, "sys_remove_ea(%s/%s): error: %s", uname, attruname, strerror(errno));
361 return AFPERR_ACCESS;
363 LOG(log_error, logtype_afpd, "sys_remove_ea(%s/%s): error: %s", uname, attruname, strerror(errno));
374 * @note Supports *at semantics, therfor switches back and forth between sfd and cwd
376 int sys_ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
381 char *names = NULL, *end_names, *name, *value = NULL;
382 unsigned int setxattr_ENOTSUP = 0;
385 if ((cwd = open(".", O_RDONLY)) == -1) {
386 LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant open cwd: %s",
394 if (fchdir(sfd) == -1) {
395 LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to sfd: %s",
402 size = sys_listxattr(src, NULL, 0);
404 if (errno != ENOSYS && errno != ENOTSUP) {
409 names = malloc(size+1);
414 size = sys_listxattr(src, names, size);
420 end_names = names + size;
424 if (fchdir(cwd) == -1) {
425 LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to cwd: %s",
432 for (name = names; name != end_names; name = strchr(name, '\0') + 1) {
435 /* check if this attribute shall be preserved */
440 if (fchdir(sfd) == -1) {
441 LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to sfd: %s",
448 size = sys_getxattr (src, name, NULL, 0);
453 value = realloc(old_value = value, size);
454 if (size != 0 && value == NULL) {
458 size = sys_getxattr(src, name, value, size);
465 if (fchdir(cwd) == -1) {
466 LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to cwd: %s",
473 if (sys_setxattr(dst, name, value, size, 0) != 0) {
474 if (errno == ENOTSUP)
477 if (errno == ENOSYS) {
479 /* no hope of getting any further */
487 if (setxattr_ENOTSUP) {
505 LOG(log_debug, logtype_afpd, "sys_ea_copyfile(%s, %s): error: %s", src, dst, strerror(errno));
506 return AFPERR_ACCESS;
508 LOG(log_error, logtype_afpd, "sys_ea_copyfile(%s, %s): error: %s", src, dst, strerror(errno));