2 $Id: extattrs.c,v 1.9 2009-10-22 12:35:38 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.
18 #endif /* HAVE_CONFIG_H */
24 #include <sys/types.h>
29 #include <atalk/adouble.h>
30 #include <atalk/vfs.h>
31 #include <atalk/afp.h>
32 #include <atalk/logger.h>
38 #include "directory.h"
42 static char *ea_finderinfo = "com.apple.FinderInfo";
43 static char *ea_resourcefork = "com.apple.ResourceFork";
45 /* This should be big enough to consecutively store the names of all attributes */
46 static char attrnamebuf[ATTRNAMEBUFSIZ];
48 static void hexdump(void *m, size_t l) {
55 len = sprintf(bufp, "%02x ", *p++);
59 if ((count % 16) == 0) {
60 LOG(log_debug9, logtype_afpd, "%s", buf);
66 /***************************************
68 ****************************************/
71 Note: we're being called twice. Firstly the client only want the size of all
72 EA names, secondly it wants these names. In order to avoid scanning EAs twice
73 we cache them in a static buffer.
75 int afp_listextattr(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
77 int ret, oflag = 0, adflags = 0;
78 uint16_t vid, bitmap, uint16;
79 uint32_t did, maxreply, tmpattr;
84 struct adouble ad, *adp = NULL;
86 char *uname, *FinderInfo;
87 char emptyFinderInfo[32] = { 0 };
89 static int buf_valid = 0;
90 static size_t attrbuflen = 0;
95 /* Get MaxReplySize first */
96 memcpy( &maxreply, ibuf + 14, 4);
97 maxreply = ntohl( maxreply );
100 If its the first request with maxreply=0 or if we didn't mark our buffers valid for
101 whatever reason (just a safety check, it should be valid), then scan for attributes
103 if ((maxreply == 0) || (buf_valid == 0)) {
107 memcpy( &vid, ibuf, 2);
109 if (NULL == ( vol = getvolbyvid( vid )) ) {
110 LOG(log_error, logtype_afpd, "afp_listextattr: getvolbyvid error: %s", strerror(errno));
111 return AFPERR_ACCESS;
114 memcpy( &did, ibuf, 4);
116 if (NULL == ( dir = dirlookup( vol, did )) ) {
117 LOG(log_error, logtype_afpd, "afp_listextattr: dirlookup error: %s", strerror(errno));
121 memcpy( &bitmap, ibuf, 2);
122 bitmap = ntohs( bitmap );
125 #ifdef HAVE_SOLARIS_EAS
126 if (bitmap & kXAttrNoFollow)
129 /* Skip ReqCount, StartIndex and maxreply*/
133 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
134 LOG(log_error, logtype_afpd, "afp_listextattr: cname error: %s", strerror(errno));
137 uname = s_path->u_name;
140 We have to check the FinderInfo for the file, because if they aren't all 0
141 we must return the synthetic attribute "com.apple.FinderInfo".
142 Note: the client will never (never seen in traces) request that attribute
145 if ((of = of_findname(s_path))) {
148 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
153 if (S_ISDIR(st.st_mode))
154 adflags = ADFLAGS_DIR;
156 if ( ad_metadata( uname, adflags, adp) < 0 ) {
159 LOG(log_error, logtype_afpd, "afp_listextattr(%s): %s: check resource fork permission?",
160 uname, strerror(errno));
161 return AFPERR_ACCESS;
163 LOG(log_error, logtype_afpd, "afp_listextattr(%s): error getting metadata: %s", uname, strerror(errno));
168 FinderInfo = ad_entry(adp, ADEID_FINDERI);
171 LOG(log_maxdebug, logtype_afpd, "afp_listextattr(%s): FinderInfo:", uname);
172 hexdump( FinderInfo, 32);
175 if ((adflags & ADFLAGS_DIR)) {
176 /* set default view */
177 uint16 = htons(FINDERINFO_CLOSEDVIEW);
178 memcpy(emptyFinderInfo + FINDERINFO_FRVIEWOFF, &uint16, 2);
181 /* Check if FinderInfo equals default and empty FinderInfo*/
182 if ((memcmp(FinderInfo, emptyFinderInfo, 32)) != 0) {
183 /* FinderInfo contains some non 0 bytes -> include "com.apple.FinderInfo" */
184 strcpy(attrnamebuf, ea_finderinfo);
185 attrbuflen += strlen(ea_finderinfo) + 1;
186 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.FinderInfo", uname);
189 /* Now check for Ressource fork and add virtual EA "com.apple.ResourceFork" if size > 0 */
190 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): Ressourcefork size: %u", uname, adp->ad_eid[ADEID_RFORK].ade_len);
191 if (adp->ad_eid[ADEID_RFORK].ade_len > 0) {
192 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.RessourceFork.", uname);
193 strcpy(attrnamebuf + attrbuflen, ea_resourcefork);
194 attrbuflen += strlen(ea_resourcefork) + 1;
197 ret = vol->vfs->vfs_ea_list(vol, attrnamebuf, &attrbuflen, uname, oflag);
201 /* its a symlink and client requested O_NOFOLLOW */
202 LOG(log_debug, logtype_afpd, "afp_listextattr(%s): encountered symlink with kXAttrNoFollow", uname);
215 /* Start building reply packet */
216 bitmap = htons(bitmap);
217 memcpy( rbuf, &bitmap, 2);
221 tmpattr = htonl(attrbuflen);
222 memcpy( rbuf, &tmpattr, 4);
226 /* Only copy buffer if the client asked for it (2nd request, maxreply>0)
227 and we didnt have an error (buf_valid) */
228 if (maxreply && buf_valid) {
229 memcpy( rbuf, attrnamebuf, attrbuflen);
230 *rbuflen += attrbuflen;
240 ad_close_metadata( adp);
245 int afp_getextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
248 uint16_t vid, bitmap;
249 uint32_t did, maxreply, attrnamelen;
250 char attrmname[256], attruname[256];
259 memcpy( &vid, ibuf, 2);
261 if (NULL == ( vol = getvolbyvid( vid )) ) {
262 LOG(log_error, logtype_afpd, "afp_getextattr: getvolbyvid error: %s", strerror(errno));
263 return AFPERR_ACCESS;
266 memcpy( &did, ibuf, 4);
268 if (NULL == ( dir = dirlookup( vol, did )) ) {
269 LOG(log_error, logtype_afpd, "afp_getextattr: dirlookup error: %s", strerror(errno));
273 memcpy( &bitmap, ibuf, 2);
274 bitmap = ntohs( bitmap );
277 #ifdef HAVE_SOLARIS_EAS
278 if (bitmap & kXAttrNoFollow)
282 /* Skip Offset and ReqCount */
286 memcpy(&maxreply, ibuf, 4);
287 maxreply = ntohl(maxreply);
291 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
292 LOG(log_error, logtype_afpd, "afp_getextattr: cname error: %s", strerror(errno));
296 if ((unsigned long)ibuf & 1)
299 /* get length of EA name */
300 memcpy(&attrnamelen, ibuf, 2);
301 attrnamelen = ntohs(attrnamelen);
303 if (attrnamelen > 255)
304 /* dont fool with us */
307 /* we must copy the name as its not 0-terminated and I DONT WANT TO WRITE to ibuf */
308 strncpy(attrmname, ibuf, attrnamelen);
309 attrmname[attrnamelen] = 0;
311 LOG(log_debug, logtype_afpd, "afp_getextattr(%s): EA: %s", s_path->u_name, attrmname);
313 /* Convert EA name in utf8 to unix charset */
314 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
317 if (attrnamelen == 255)
318 /* convert_string didn't 0-terminate */
321 /* write bitmap now */
322 bitmap = htons(bitmap);
323 memcpy(rbuf, &bitmap, 2);
329 if its 0 we must return the size of the requested attribute,
330 if its non 0 we must return the attribute.
333 ret = vol->vfs->vfs_ea_getsize(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname);
335 ret = vol->vfs->vfs_ea_getcontent(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, maxreply);
340 int afp_setextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
342 int oflag = O_CREAT | O_WRONLY, ret;
343 uint16_t vid, bitmap;
344 uint32_t did, attrnamelen, attrsize;
345 char attrmname[256], attruname[256];
353 memcpy( &vid, ibuf, 2);
355 if (NULL == ( vol = getvolbyvid( vid )) ) {
356 LOG(log_error, logtype_afpd, "afp_setextattr: getvolbyvid error: %s", strerror(errno));
357 return AFPERR_ACCESS;
360 memcpy( &did, ibuf, 4);
362 if (NULL == ( dir = dirlookup( vol, did )) ) {
363 LOG(log_error, logtype_afpd, "afp_setextattr: dirlookup error: %s", strerror(errno));
367 memcpy( &bitmap, ibuf, 2);
368 bitmap = ntohs( bitmap );
371 #ifdef HAVE_SOLARIS_EAS
372 if (bitmap & kXAttrNoFollow)
373 oflag |= AT_SYMLINK_NOFOLLOW;
376 if (bitmap & kXAttrCreate)
378 else if (bitmap & kXAttrReplace)
385 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
386 LOG(log_error, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
390 if ((unsigned long)ibuf & 1)
393 /* get length of EA name */
394 memcpy(&attrnamelen, ibuf, 2);
395 attrnamelen = ntohs(attrnamelen);
397 if (attrnamelen > 255)
400 /* we must copy the name as its not 0-terminated and we cant write to ibuf */
401 strncpy(attrmname, ibuf, attrnamelen);
402 attrmname[attrnamelen] = 0;
405 /* Convert EA name in utf8 to unix charset */
406 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
409 if (attrnamelen == 255)
410 /* convert_string didn't 0-terminate */
414 memcpy(&attrsize, ibuf, 4);
415 attrsize = ntohl(attrsize);
417 if (attrsize > MAX_EA_SIZE)
418 /* we arbitrarily make this fatal */
421 LOG(log_debug, logtype_afpd, "afp_setextattr(%s): EA: %s, size: %u", s_path->u_name, attrmname, attrsize);
423 ret = vol->vfs->vfs_ea_set(vol, s_path->u_name, attruname, ibuf, attrsize, oflag);
428 int afp_remextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
430 int oflag = O_RDONLY, ret;
431 uint16_t vid, bitmap;
432 uint32_t did, attrnamelen;
433 char attrmname[256], attruname[256];
441 memcpy( &vid, ibuf, 2);
443 if (NULL == ( vol = getvolbyvid( vid )) ) {
444 LOG(log_error, logtype_afpd, "afp_remextattr: getvolbyvid error: %s", strerror(errno));
445 return AFPERR_ACCESS;
448 memcpy( &did, ibuf, 4);
450 if (NULL == ( dir = dirlookup( vol, did )) ) {
451 LOG(log_error, logtype_afpd, "afp_remextattr: dirlookup error: %s", strerror(errno));
455 memcpy( &bitmap, ibuf, 2);
456 bitmap = ntohs( bitmap );
459 #ifdef HAVE_SOLARIS_EAS
460 if (bitmap & kXAttrNoFollow)
461 oflag |= AT_SYMLINK_NOFOLLOW;
465 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
466 LOG(log_error, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
470 if ((unsigned long)ibuf & 1)
473 /* get length of EA name */
474 memcpy(&attrnamelen, ibuf, 2);
475 attrnamelen = ntohs(attrnamelen);
477 if (attrnamelen > 255)
480 /* we must copy the name as its not 0-terminated and we cant write to ibuf */
481 strncpy(attrmname, ibuf, attrnamelen);
482 attrmname[attrnamelen] = 0;
485 /* Convert EA name in utf8 to unix charset */
486 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
489 if (attrnamelen == 255)
490 /* convert_string didn't 0-terminate */
493 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): EA: %s", s_path->u_name, attrmname);
495 ret = vol->vfs->vfs_ea_remove(vol, s_path->u_name, attruname, oflag);