2 $Id: extattrs.c,v 1.11 2009-10-27 23:35:17 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>
28 #include <atalk/adouble.h>
29 #include <atalk/vfs.h>
30 #include <atalk/afp.h>
31 #include <atalk/logger.h>
37 #include "directory.h"
41 static char *ea_finderinfo = "com.apple.FinderInfo";
42 static char *ea_resourcefork = "com.apple.ResourceFork";
44 /* This should be big enough to consecutively store the names of all attributes */
45 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);
67 /***************************************
69 ****************************************/
72 Note: we're being called twice. Firstly the client only want the size of all
73 EA names, secondly it wants these names. In order to avoid scanning EAs twice
74 we cache them in a static buffer.
76 int afp_listextattr(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
78 int ret, oflag = 0, adflags = 0;
79 uint16_t vid, bitmap, uint16;
80 uint32_t did, maxreply, tmpattr;
85 struct adouble ad, *adp = NULL;
87 char *uname, *FinderInfo;
88 char emptyFinderInfo[32] = { 0 };
90 static int buf_valid = 0;
91 static size_t attrbuflen = 0;
96 /* Get MaxReplySize first */
97 memcpy( &maxreply, ibuf + 14, 4);
98 maxreply = ntohl( maxreply );
101 If its the first request with maxreply=0 or if we didn't mark our buffers valid for
102 whatever reason (just a safety check, it should be valid), then scan for attributes
104 if ((maxreply == 0) || (buf_valid == 0)) {
108 memcpy( &vid, ibuf, 2);
110 if (NULL == ( vol = getvolbyvid( vid )) ) {
111 LOG(log_error, logtype_afpd, "afp_listextattr: getvolbyvid error: %s", strerror(errno));
112 return AFPERR_ACCESS;
115 memcpy( &did, ibuf, 4);
117 if (NULL == ( dir = dirlookup( vol, did )) ) {
118 LOG(log_error, logtype_afpd, "afp_listextattr: dirlookup error: %s", strerror(errno));
122 memcpy( &bitmap, ibuf, 2);
123 bitmap = ntohs( bitmap );
126 #ifdef HAVE_SOLARIS_EAS
127 if (bitmap & kXAttrNoFollow)
130 /* Skip ReqCount, StartIndex and maxreply*/
134 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
135 LOG(log_error, logtype_afpd, "afp_listextattr: cname error: %s", strerror(errno));
138 uname = s_path->u_name;
141 We have to check the FinderInfo for the file, because if they aren't all 0
142 we must return the synthetic attribute "com.apple.FinderInfo".
143 Note: the client will never (never seen in traces) request that attribute
146 if ((of = of_findname(s_path))) {
149 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
154 if (S_ISDIR(st.st_mode))
155 adflags = ADFLAGS_DIR;
157 if ( ad_metadata( uname, adflags, adp) < 0 ) {
160 LOG(log_error, logtype_afpd, "afp_listextattr(%s): %s: check resource fork permission?",
161 uname, strerror(errno));
162 return AFPERR_ACCESS;
164 LOG(log_error, logtype_afpd, "afp_listextattr(%s): error getting metadata: %s", uname, strerror(errno));
169 FinderInfo = ad_entry(adp, ADEID_FINDERI);
172 LOG(log_maxdebug, logtype_afpd, "afp_listextattr(%s): FinderInfo:", uname);
173 hexdump( FinderInfo, 32);
176 if ((adflags & ADFLAGS_DIR)) {
177 /* set default view */
178 uint16 = htons(FINDERINFO_CLOSEDVIEW);
179 memcpy(emptyFinderInfo + FINDERINFO_FRVIEWOFF, &uint16, 2);
182 /* Check if FinderInfo equals default and empty FinderInfo*/
183 if ((memcmp(FinderInfo, emptyFinderInfo, 32)) != 0) {
184 /* FinderInfo contains some non 0 bytes -> include "com.apple.FinderInfo" */
185 strcpy(attrnamebuf, ea_finderinfo);
186 attrbuflen += strlen(ea_finderinfo) + 1;
187 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.FinderInfo", uname);
190 /* Now check for Ressource fork and add virtual EA "com.apple.ResourceFork" if size > 0 */
191 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): Ressourcefork size: %u", uname, adp->ad_eid[ADEID_RFORK].ade_len);
192 if (adp->ad_eid[ADEID_RFORK].ade_len > 0) {
193 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.RessourceFork.", uname);
194 strcpy(attrnamebuf + attrbuflen, ea_resourcefork);
195 attrbuflen += strlen(ea_resourcefork) + 1;
198 ret = vol->vfs->vfs_ea_list(vol, attrnamebuf, &attrbuflen, uname, oflag);
202 /* its a symlink and client requested O_NOFOLLOW */
203 LOG(log_debug, logtype_afpd, "afp_listextattr(%s): encountered symlink with kXAttrNoFollow", uname);
216 /* Start building reply packet */
217 bitmap = htons(bitmap);
218 memcpy( rbuf, &bitmap, 2);
222 tmpattr = htonl(attrbuflen);
223 memcpy( rbuf, &tmpattr, 4);
227 /* Only copy buffer if the client asked for it (2nd request, maxreply>0)
228 and we didnt have an error (buf_valid) */
229 if (maxreply && buf_valid) {
230 memcpy( rbuf, attrnamebuf, attrbuflen);
231 *rbuflen += attrbuflen;
241 ad_close_metadata( adp);
246 int afp_getextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
249 uint16_t vid, bitmap;
250 uint32_t did, maxreply, attrnamelen;
251 char attrmname[256], attruname[256];
260 memcpy( &vid, ibuf, 2);
262 if (NULL == ( vol = getvolbyvid( vid )) ) {
263 LOG(log_error, logtype_afpd, "afp_getextattr: getvolbyvid error: %s", strerror(errno));
264 return AFPERR_ACCESS;
267 memcpy( &did, ibuf, 4);
269 if (NULL == ( dir = dirlookup( vol, did )) ) {
270 LOG(log_error, logtype_afpd, "afp_getextattr: dirlookup error: %s", strerror(errno));
274 memcpy( &bitmap, ibuf, 2);
275 bitmap = ntohs( bitmap );
278 #ifdef HAVE_SOLARIS_EAS
279 if (bitmap & kXAttrNoFollow)
283 /* Skip Offset and ReqCount */
287 memcpy(&maxreply, ibuf, 4);
288 maxreply = ntohl(maxreply);
292 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
293 LOG(log_error, logtype_afpd, "afp_getextattr: cname error: %s", strerror(errno));
297 if ((unsigned long)ibuf & 1)
300 /* get length of EA name */
301 memcpy(&attrnamelen, ibuf, 2);
302 attrnamelen = ntohs(attrnamelen);
304 if (attrnamelen > 255)
305 /* dont fool with us */
308 /* we must copy the name as its not 0-terminated and I DONT WANT TO WRITE to ibuf */
309 strncpy(attrmname, ibuf, attrnamelen);
310 attrmname[attrnamelen] = 0;
312 LOG(log_debug, logtype_afpd, "afp_getextattr(%s): EA: %s", s_path->u_name, attrmname);
314 /* Convert EA name in utf8 to unix charset */
315 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
318 if (attrnamelen == 255)
319 /* convert_string didn't 0-terminate */
322 /* write bitmap now */
323 bitmap = htons(bitmap);
324 memcpy(rbuf, &bitmap, 2);
330 if its 0 we must return the size of the requested attribute,
331 if its non 0 we must return the attribute.
334 ret = vol->vfs->vfs_ea_getsize(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname);
336 ret = vol->vfs->vfs_ea_getcontent(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, maxreply);
341 int afp_setextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
343 int oflag = O_CREAT | O_WRONLY, ret;
344 uint16_t vid, bitmap;
345 uint32_t did, attrnamelen, attrsize;
346 char attrmname[256], attruname[256];
354 memcpy( &vid, ibuf, 2);
356 if (NULL == ( vol = getvolbyvid( vid )) ) {
357 LOG(log_error, logtype_afpd, "afp_setextattr: getvolbyvid error: %s", strerror(errno));
358 return AFPERR_ACCESS;
361 memcpy( &did, ibuf, 4);
363 if (NULL == ( dir = dirlookup( vol, did )) ) {
364 LOG(log_error, logtype_afpd, "afp_setextattr: dirlookup error: %s", strerror(errno));
368 memcpy( &bitmap, ibuf, 2);
369 bitmap = ntohs( bitmap );
372 #ifdef HAVE_SOLARIS_EAS
373 if (bitmap & kXAttrNoFollow)
374 oflag |= AT_SYMLINK_NOFOLLOW;
377 if (bitmap & kXAttrCreate)
379 else if (bitmap & kXAttrReplace)
386 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
387 LOG(log_error, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
391 if ((unsigned long)ibuf & 1)
394 /* get length of EA name */
395 memcpy(&attrnamelen, ibuf, 2);
396 attrnamelen = ntohs(attrnamelen);
398 if (attrnamelen > 255)
401 /* we must copy the name as its not 0-terminated and we cant write to ibuf */
402 strncpy(attrmname, ibuf, attrnamelen);
403 attrmname[attrnamelen] = 0;
406 /* Convert EA name in utf8 to unix charset */
407 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
410 if (attrnamelen == 255)
411 /* convert_string didn't 0-terminate */
415 memcpy(&attrsize, ibuf, 4);
416 attrsize = ntohl(attrsize);
418 if (attrsize > MAX_EA_SIZE)
419 /* we arbitrarily make this fatal */
422 LOG(log_debug, logtype_afpd, "afp_setextattr(%s): EA: %s, size: %u", s_path->u_name, attrmname, attrsize);
424 ret = vol->vfs->vfs_ea_set(vol, s_path->u_name, attruname, ibuf, attrsize, oflag);
429 int afp_remextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
431 int oflag = O_RDONLY, ret;
432 uint16_t vid, bitmap;
433 uint32_t did, attrnamelen;
434 char attrmname[256], attruname[256];
442 memcpy( &vid, ibuf, 2);
444 if (NULL == ( vol = getvolbyvid( vid )) ) {
445 LOG(log_error, logtype_afpd, "afp_remextattr: getvolbyvid error: %s", strerror(errno));
446 return AFPERR_ACCESS;
449 memcpy( &did, ibuf, 4);
451 if (NULL == ( dir = dirlookup( vol, did )) ) {
452 LOG(log_error, logtype_afpd, "afp_remextattr: dirlookup error: %s", strerror(errno));
456 memcpy( &bitmap, ibuf, 2);
457 bitmap = ntohs( bitmap );
460 #ifdef HAVE_SOLARIS_EAS
461 if (bitmap & kXAttrNoFollow)
462 oflag |= AT_SYMLINK_NOFOLLOW;
466 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
467 LOG(log_error, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
471 if ((unsigned long)ibuf & 1)
474 /* get length of EA name */
475 memcpy(&attrnamelen, ibuf, 2);
476 attrnamelen = ntohs(attrnamelen);
478 if (attrnamelen > 255)
481 /* we must copy the name as its not 0-terminated and we cant write to ibuf */
482 strncpy(attrmname, ibuf, attrnamelen);
483 attrmname[attrnamelen] = 0;
486 /* Convert EA name in utf8 to unix charset */
487 if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
490 if (attrnamelen == 255)
491 /* convert_string didn't 0-terminate */
494 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): EA: %s", s_path->u_name, attrmname);
496 ret = vol->vfs->vfs_ea_remove(vol, s_path->u_name, attruname, oflag);