2 $Id: extattrs.c,v 1.8 2009-10-20 09:53:42 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 static int buf_valid = 0, attrbuflen = 0;
88 char emptyFinderInfo[32] = { 0 };
93 /* Get MaxReplySize first */
94 memcpy( &maxreply, ibuf + 14, 4);
95 maxreply = ntohl( maxreply );
98 If its the first request with maxreply=0 or if we didn't mark our buffers valid for
99 whatever reason (just a safety check, it should be valid), then scan for attributes
101 if ((maxreply == 0) || (buf_valid == 0)) {
105 memcpy( &vid, ibuf, 2);
107 if (NULL == ( vol = getvolbyvid( vid )) ) {
108 LOG(log_error, logtype_afpd, "afp_listextattr: getvolbyvid error: %s", strerror(errno));
109 return AFPERR_ACCESS;
112 memcpy( &did, ibuf, 4);
114 if (NULL == ( dir = dirlookup( vol, did )) ) {
115 LOG(log_error, logtype_afpd, "afp_listextattr: dirlookup error: %s", strerror(errno));
119 memcpy( &bitmap, ibuf, 2);
120 bitmap = ntohs( bitmap );
123 #ifdef HAVE_SOLARIS_EAS
124 if (bitmap & kXAttrNoFollow)
127 /* Skip ReqCount, StartIndex and maxreply*/
131 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
132 LOG(log_error, logtype_afpd, "afp_listextattr: cname error: %s", strerror(errno));
135 uname = s_path->u_name;
138 We have to check the FinderInfo for the file, because if they aren't all 0
139 we must return the synthetic attribute "com.apple.FinderInfo".
140 Note: the client will never (never seen in traces) request that attribute
143 if ((of = of_findname(s_path))) {
146 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
151 if (S_ISDIR(st.st_mode))
152 adflags = ADFLAGS_DIR;
154 if ( ad_metadata( uname, adflags, adp) < 0 ) {
157 LOG(log_error, logtype_afpd, "afp_listextattr(%s): %s: check resource fork permission?",
158 uname, strerror(errno));
159 return AFPERR_ACCESS;
161 LOG(log_error, logtype_afpd, "afp_listextattr(%s): error getting metadata: %s", uname, strerror(errno));
166 FinderInfo = ad_entry(adp, ADEID_FINDERI);
169 LOG(log_maxdebug, logtype_afpd, "afp_listextattr(%s): FinderInfo:", uname);
170 hexdump( FinderInfo, 32);
173 if ((adflags & ADFLAGS_DIR)) {
174 /* set default view */
175 uint16 = htons(FINDERINFO_CLOSEDVIEW);
176 memcpy(emptyFinderInfo + FINDERINFO_FRVIEWOFF, &uint16, 2);
179 /* Check if FinderInfo equals default and empty FinderInfo*/
180 if ((memcmp(FinderInfo, emptyFinderInfo, 32)) != 0) {
181 /* FinderInfo contains some non 0 bytes -> include "com.apple.FinderInfo" */
182 strcpy(attrnamebuf, ea_finderinfo);
183 attrbuflen += strlen(ea_finderinfo) + 1;
184 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.FinderInfo", uname);
187 /* Now check for Ressource fork and add virtual EA "com.apple.ResourceFork" if size > 0 */
188 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): Ressourcefork size: %u", uname, adp->ad_eid[ADEID_RFORK].ade_len);
189 if (adp->ad_eid[ADEID_RFORK].ade_len > 0) {
190 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.RessourceFork.", uname);
191 strcpy(attrnamebuf + attrbuflen, ea_resourcefork);
192 attrbuflen += strlen(ea_resourcefork) + 1;
195 ret = vol->vfs->vfs_ea_list(vol, attrnamebuf, &attrbuflen, uname, oflag);
199 /* its a symlink and client requested O_NOFOLLOW */
200 LOG(log_debug, logtype_afpd, "afp_listextattr(%s): encountered symlink with kXAttrNoFollow", uname);
213 /* Start building reply packet */
214 bitmap = htons(bitmap);
215 memcpy( rbuf, &bitmap, 2);
219 tmpattr = htonl(attrbuflen);
220 memcpy( rbuf, &tmpattr, 4);
224 /* Only copy buffer if the client asked for it (2nd request, maxreply>0)
225 and we didnt have an error (buf_valid) */
226 if (maxreply && buf_valid) {
227 memcpy( rbuf, attrnamebuf, attrbuflen);
228 *rbuflen += attrbuflen;
238 ad_close_metadata( adp);
243 int afp_getextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
246 uint16_t vid, bitmap;
247 uint32_t did, maxreply, attrnamelen;
248 char attrmname[256], attruname[256];
257 memcpy( &vid, ibuf, 2);
259 if (NULL == ( vol = getvolbyvid( vid )) ) {
260 LOG(log_error, logtype_afpd, "afp_getextattr: getvolbyvid error: %s", strerror(errno));
261 return AFPERR_ACCESS;
264 memcpy( &did, ibuf, 4);
266 if (NULL == ( dir = dirlookup( vol, did )) ) {
267 LOG(log_error, logtype_afpd, "afp_getextattr: dirlookup error: %s", strerror(errno));
271 memcpy( &bitmap, ibuf, 2);
272 bitmap = ntohs( bitmap );
275 #ifdef HAVE_SOLARIS_EAS
276 if (bitmap & kXAttrNoFollow)
280 /* Skip Offset and ReqCount */
284 memcpy(&maxreply, ibuf, 4);
285 maxreply = ntohl(maxreply);
289 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
290 LOG(log_error, logtype_afpd, "afp_getextattr: cname error: %s", strerror(errno));
294 if ((unsigned long)ibuf & 1)
297 /* get length of EA name */
298 memcpy(&attrnamelen, ibuf, 2);
299 attrnamelen = ntohs(attrnamelen);
301 if (attrnamelen > 255)
302 /* dont fool with us */
305 /* we must copy the name as its not 0-terminated and I DONT WANT TO WRITE to ibuf */
306 strncpy(attrmname, ibuf, attrnamelen);
307 attrmname[attrnamelen] = 0;
309 LOG(log_debug, logtype_afpd, "afp_getextattr(%s): EA: %s", s_path->u_name, attrmname);
311 /* Convert EA name in utf8 to unix charset */
312 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
315 if (attrnamelen == 255)
316 /* convert_string didn't 0-terminate */
319 /* write bitmap now */
320 bitmap = htons(bitmap);
321 memcpy(rbuf, &bitmap, 2);
327 if its 0 we must return the size of the requested attribute,
328 if its non 0 we must return the attribute.
331 ret = vol->vfs->vfs_ea_getsize(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname);
333 ret = vol->vfs->vfs_ea_getcontent(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, maxreply);
338 int afp_setextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
340 int oflag = O_CREAT | O_WRONLY, ret;
341 uint16_t vid, bitmap;
342 uint32_t did, attrnamelen, attrsize;
343 char attrmname[256], attruname[256];
351 memcpy( &vid, ibuf, 2);
353 if (NULL == ( vol = getvolbyvid( vid )) ) {
354 LOG(log_error, logtype_afpd, "afp_setextattr: getvolbyvid error: %s", strerror(errno));
355 return AFPERR_ACCESS;
358 memcpy( &did, ibuf, 4);
360 if (NULL == ( dir = dirlookup( vol, did )) ) {
361 LOG(log_error, logtype_afpd, "afp_setextattr: dirlookup error: %s", strerror(errno));
365 memcpy( &bitmap, ibuf, 2);
366 bitmap = ntohs( bitmap );
369 #ifdef HAVE_SOLARIS_EAS
370 if (bitmap & kXAttrNoFollow)
371 oflag |= AT_SYMLINK_NOFOLLOW;
374 if (bitmap & kXAttrCreate)
376 else if (bitmap & kXAttrReplace)
383 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
384 LOG(log_error, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
388 if ((unsigned long)ibuf & 1)
391 /* get length of EA name */
392 memcpy(&attrnamelen, ibuf, 2);
393 attrnamelen = ntohs(attrnamelen);
395 if (attrnamelen > 255)
398 /* we must copy the name as its not 0-terminated and we cant write to ibuf */
399 strncpy(attrmname, ibuf, attrnamelen);
400 attrmname[attrnamelen] = 0;
403 /* Convert EA name in utf8 to unix charset */
404 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
407 if (attrnamelen == 255)
408 /* convert_string didn't 0-terminate */
412 memcpy(&attrsize, ibuf, 4);
413 attrsize = ntohl(attrsize);
415 if (attrsize > MAX_EA_SIZE)
416 /* we arbitrarily make this fatal */
419 LOG(log_debug, logtype_afpd, "afp_setextattr(%s): EA: %s, size: %u", s_path->u_name, attrmname, attrsize);
421 ret = vol->vfs->vfs_ea_set(vol, s_path->u_name, attruname, ibuf, attrsize, oflag);
426 int afp_remextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
428 int oflag = O_RDONLY, ret;
429 uint16_t vid, bitmap;
430 uint32_t did, attrnamelen;
431 char attrmname[256], attruname[256];
439 memcpy( &vid, ibuf, 2);
441 if (NULL == ( vol = getvolbyvid( vid )) ) {
442 LOG(log_error, logtype_afpd, "afp_remextattr: getvolbyvid error: %s", strerror(errno));
443 return AFPERR_ACCESS;
446 memcpy( &did, ibuf, 4);
448 if (NULL == ( dir = dirlookup( vol, did )) ) {
449 LOG(log_error, logtype_afpd, "afp_remextattr: dirlookup error: %s", strerror(errno));
453 memcpy( &bitmap, ibuf, 2);
454 bitmap = ntohs( bitmap );
457 #ifdef HAVE_SOLARIS_EAS
458 if (bitmap & kXAttrNoFollow)
459 oflag |= AT_SYMLINK_NOFOLLOW;
463 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
464 LOG(log_error, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
468 if ((unsigned long)ibuf & 1)
471 /* get length of EA name */
472 memcpy(&attrnamelen, ibuf, 2);
473 attrnamelen = ntohs(attrnamelen);
475 if (attrnamelen > 255)
478 /* we must copy the name as its not 0-terminated and we cant write to ibuf */
479 strncpy(attrmname, ibuf, attrnamelen);
480 attrmname[attrnamelen] = 0;
483 /* Convert EA name in utf8 to unix charset */
484 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
487 if (attrnamelen == 255)
488 /* convert_string didn't 0-terminate */
491 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): EA: %s", s_path->u_name, attrmname);
493 ret = vol->vfs->vfs_ea_remove(vol, s_path->u_name, attruname, oflag);