2 $Id: extattrs.c,v 1.6 2009-10-15 10:43:13 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 */
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 count, ret, oflag = 0;
79 uint32_t did, maxreply, tmpattr;
83 struct adouble ad, *adp = NULL;
85 char *uname, *FinderInfo;
86 static int buf_valid = 0, attrbuflen = 0;
91 /* Get MaxReplySize first */
92 memcpy( &maxreply, ibuf + 14, 4);
93 maxreply = ntohl( maxreply );
96 If its the first request with maxreply=0 or if we didn't mark our buffers valid for
97 whatever reason (just a safety check, it should be valid), then scan for attributes
99 if ((maxreply == 0) || (buf_valid == 0)) {
103 memcpy( &vid, ibuf, 2);
105 if (NULL == ( vol = getvolbyvid( vid )) ) {
106 LOG(log_error, logtype_afpd, "afp_listextattr: getvolbyvid error: %s", strerror(errno));
107 return AFPERR_ACCESS;
110 memcpy( &did, ibuf, 4);
112 if (NULL == ( dir = dirlookup( vol, did )) ) {
113 LOG(log_error, logtype_afpd, "afp_listextattr: dirlookup error: %s", strerror(errno));
117 memcpy( &bitmap, ibuf, 2);
118 bitmap = ntohs( bitmap );
121 #ifdef HAVE_SOLARIS_EAS
122 if (bitmap & kXAttrNoFollow)
125 /* Skip ReqCount, StartIndex and maxreply*/
129 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
130 LOG(log_error, logtype_afpd, "afp_listextattr: cname error: %s", strerror(errno));
133 uname = s_path->u_name;
136 We have to check the FinderInfo for the file, because if they aren't all 0
137 we must return the synthetic attribute "com.apple.FinderInfo".
138 Note: the client will never (never seen in traces) request that attribute
141 if ((of = of_findname(s_path))) {
144 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
148 if ( ad_metadata( uname, 0, adp) < 0 ) {
151 LOG(log_error, logtype_afpd, "afp_listextattr(%s): %s: check resource fork permission?",
152 uname, strerror(errno));
153 return AFPERR_ACCESS;
155 LOG(log_error, logtype_afpd, "afp_listextattr(%s): error getting metadata: %s", uname, strerror(errno));
160 FinderInfo = ad_entry(adp, ADEID_FINDERI);
162 LOG(log_debug9, logtype_afpd, "afp_listextattr(%s): FinderInfo:", uname);
163 hexdump( FinderInfo, 32);
166 /* Now scan FinderInfo if its all 0 */
170 /* FinderInfo contains some non 0 bytes -> include "com.apple.FinderInfo" */
171 strcpy(attrnamebuf, ea_finderinfo);
172 attrbuflen += strlen(ea_finderinfo) + 1;
173 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.FinderInfo", uname);
178 /* Now check for Ressource fork and add virtual EA "com.apple.ResourceFork" if size > 0 */
179 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): Ressourcefork size: %u", uname, adp->ad_eid[ADEID_RFORK].ade_len);
180 if (adp->ad_eid[ADEID_RFORK].ade_len > 0) {
181 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.RessourceFork.", uname);
182 strcpy(attrnamebuf + attrbuflen, ea_resourcefork);
183 attrbuflen += strlen(ea_resourcefork) + 1;
186 ret = vol->vfs->vfs_ea_list(vol, attrnamebuf, &attrbuflen, uname, oflag);
190 /* its a symlink and client requested O_NOFOLLOW */
191 LOG(log_debug, logtype_afpd, "afp_listextattr(%s): encountered symlink with kXAttrNoFollow", uname);
204 /* Start building reply packet */
205 bitmap = htons(bitmap);
206 memcpy( rbuf, &bitmap, 2);
210 tmpattr = htonl(attrbuflen);
211 memcpy( rbuf, &tmpattr, 4);
215 /* Only copy buffer if the client asked for it (2nd request, maxreply>0)
216 and we didnt have an error (buf_valid) */
217 if (maxreply && buf_valid) {
218 memcpy( rbuf, attrnamebuf, attrbuflen);
219 *rbuflen += attrbuflen;
229 ad_close_metadata( adp);
234 int afp_getextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
237 uint16_t vid, bitmap;
238 uint32_t did, maxreply, attrnamelen;
239 char attrmname[256], attruname[256];
248 memcpy( &vid, ibuf, 2);
250 if (NULL == ( vol = getvolbyvid( vid )) ) {
251 LOG(log_error, logtype_afpd, "afp_getextattr: getvolbyvid error: %s", strerror(errno));
252 return AFPERR_ACCESS;
255 memcpy( &did, ibuf, 4);
257 if (NULL == ( dir = dirlookup( vol, did )) ) {
258 LOG(log_error, logtype_afpd, "afp_getextattr: dirlookup error: %s", strerror(errno));
262 memcpy( &bitmap, ibuf, 2);
263 bitmap = ntohs( bitmap );
266 #ifdef HAVE_SOLARIS_EAS
267 if (bitmap & kXAttrNoFollow)
271 /* Skip Offset and ReqCount */
275 memcpy(&maxreply, ibuf, 4);
276 maxreply = ntohl(maxreply);
280 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
281 LOG(log_error, logtype_afpd, "afp_getextattr: cname error: %s", strerror(errno));
285 if ((unsigned long)ibuf & 1)
288 /* get length of EA name */
289 memcpy(&attrnamelen, ibuf, 2);
290 attrnamelen = ntohs(attrnamelen);
292 if (attrnamelen > 255)
293 /* dont fool with us */
296 /* we must copy the name as its not 0-terminated and I DONT WANT TO WRITE to ibuf */
297 strncpy(attrmname, ibuf, attrnamelen);
298 attrmname[attrnamelen] = 0;
300 LOG(log_debug, logtype_afpd, "afp_getextattr(%s): EA: %s", s_path->u_name, attrmname);
302 /* Convert EA name in utf8 to unix charset */
303 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
306 if (attrnamelen == 255)
307 /* convert_string didn't 0-terminate */
310 /* write bitmap now */
311 bitmap = htons(bitmap);
312 memcpy(rbuf, &bitmap, 2);
318 if its 0 we must return the size of the requested attribute,
319 if its non 0 we must return the attribute.
322 ret = vol->vfs->vfs_ea_getsize(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname);
324 ret = vol->vfs->vfs_ea_getcontent(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, maxreply);
329 int afp_setextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
331 int oflag = O_CREAT | O_WRONLY, ret;
332 uint16_t vid, bitmap;
333 uint32_t did, attrnamelen, attrsize;
334 char attrmname[256], attruname[256];
342 memcpy( &vid, ibuf, 2);
344 if (NULL == ( vol = getvolbyvid( vid )) ) {
345 LOG(log_error, logtype_afpd, "afp_setextattr: getvolbyvid error: %s", strerror(errno));
346 return AFPERR_ACCESS;
349 memcpy( &did, ibuf, 4);
351 if (NULL == ( dir = dirlookup( vol, did )) ) {
352 LOG(log_error, logtype_afpd, "afp_setextattr: dirlookup error: %s", strerror(errno));
356 memcpy( &bitmap, ibuf, 2);
357 bitmap = ntohs( bitmap );
360 #ifdef HAVE_SOLARIS_EAS
361 if (bitmap & kXAttrNoFollow)
362 oflag |= AT_SYMLINK_NOFOLLOW;
365 if (bitmap & kXAttrCreate)
367 else if (bitmap & kXAttrReplace)
374 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
375 LOG(log_error, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
379 if ((unsigned long)ibuf & 1)
382 /* get length of EA name */
383 memcpy(&attrnamelen, ibuf, 2);
384 attrnamelen = ntohs(attrnamelen);
386 if (attrnamelen > 255)
389 /* we must copy the name as its not 0-terminated and we cant write to ibuf */
390 strncpy(attrmname, ibuf, attrnamelen);
391 attrmname[attrnamelen] = 0;
394 /* Convert EA name in utf8 to unix charset */
395 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
398 if (attrnamelen == 255)
399 /* convert_string didn't 0-terminate */
403 memcpy(&attrsize, ibuf, 4);
404 attrsize = ntohl(attrsize);
406 if (attrsize > MAX_EA_SIZE)
407 /* we arbitrarily make this fatal */
410 LOG(log_debug, logtype_afpd, "afp_setextattr(%s): EA: %s, size: %u", s_path->u_name, attrmname, attrsize);
412 ret = vol->vfs->vfs_ea_set(vol, s_path->u_name, attruname, ibuf, attrsize, oflag);
417 int afp_remextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
419 int oflag = O_RDONLY, ret;
420 uint16_t vid, bitmap;
421 uint32_t did, attrnamelen;
422 char attrmname[256], attruname[256];
430 memcpy( &vid, ibuf, 2);
432 if (NULL == ( vol = getvolbyvid( vid )) ) {
433 LOG(log_error, logtype_afpd, "afp_remextattr: getvolbyvid error: %s", strerror(errno));
434 return AFPERR_ACCESS;
437 memcpy( &did, ibuf, 4);
439 if (NULL == ( dir = dirlookup( vol, did )) ) {
440 LOG(log_error, logtype_afpd, "afp_remextattr: dirlookup error: %s", strerror(errno));
444 memcpy( &bitmap, ibuf, 2);
445 bitmap = ntohs( bitmap );
448 #ifdef HAVE_SOLARIS_EAS
449 if (bitmap & kXAttrNoFollow)
450 oflag |= AT_SYMLINK_NOFOLLOW;
454 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
455 LOG(log_error, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
459 if ((unsigned long)ibuf & 1)
462 /* get length of EA name */
463 memcpy(&attrnamelen, ibuf, 2);
464 attrnamelen = ntohs(attrnamelen);
466 if (attrnamelen > 255)
469 /* we must copy the name as its not 0-terminated and we cant write to ibuf */
470 strncpy(attrmname, ibuf, attrnamelen);
471 attrmname[attrnamelen] = 0;
474 /* Convert EA name in utf8 to unix charset */
475 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
478 if (attrnamelen == 255)
479 /* convert_string didn't 0-terminate */
482 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): EA: %s", s_path->u_name, attrmname);
484 ret = vol->vfs->vfs_ea_remove(vol, s_path->u_name, attruname, oflag);