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 <atalk/adouble.h>
25 #include <atalk/util.h>
26 #include <atalk/vfs.h>
27 #include <atalk/afp.h>
28 #include <atalk/logger.h>
30 #include <atalk/globals.h>
31 #include <atalk/netatalk_conf.h>
35 #include "directory.h"
39 static const char *ea_finderinfo = "com.apple.FinderInfo";
40 static const char *ea_resourcefork = "com.apple.ResourceFork";
42 /* This should be big enough to consecutively store the names of all attributes */
43 static char attrnamebuf[ATTRNAMEBUFSIZ];
46 static void hexdump(void *m, size_t l) {
53 len = sprintf(bufp, "%02x ", *p++);
57 if ((count % 16) == 0) {
58 LOG(log_debug9, logtype_afpd, "%s", buf);
65 /***************************************
67 ****************************************/
70 Note: we're being called twice. Firstly the client only want the size of all
71 EA names, secondly it wants these names. In order to avoid scanning EAs twice
72 we cache them in a static buffer.
74 int afp_listextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
76 int ret, oflag = 0, adflags = 0;
77 uint16_t vid, bitmap, uint16;
78 uint32_t did, maxreply, tmpattr;
83 struct adouble ad, *adp = NULL;
84 char *uname, *FinderInfo;
85 char emptyFinderInfo[32] = { 0 };
87 static int buf_valid = 0;
88 static size_t attrbuflen = 0;
93 /* Get Bitmap and MaxReplySize first */
94 memcpy( &bitmap, ibuf +6, sizeof(bitmap));
95 bitmap = ntohs( bitmap );
97 memcpy( &maxreply, ibuf + 14, sizeof (maxreply));
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, sizeof(vid));
110 if (NULL == ( vol = getvolbyvid( vid )) ) {
111 LOG(log_debug, logtype_afpd, "afp_listextattr: getvolbyvid error: %s", strerror(errno));
112 return AFPERR_ACCESS;
115 memcpy( &did, ibuf, sizeof(did));
117 if (NULL == ( dir = dirlookup( vol, did )) ) {
118 LOG(log_debug, logtype_afpd, "afp_listextattr: dirlookup error: %s", strerror(errno));
122 if (bitmap & kXAttrNoFollow)
124 /* Skip Bitmap, ReqCount, StartIndex and maxreply*/
128 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
129 LOG(log_debug, logtype_afpd, "afp_listextattr: cname error: %s", strerror(errno));
134 if (!s_path->st_valid) {
135 /* it's a dir in our cache, we didn't stat it, do it now */
136 of_statdir(vol, s_path);
138 if ( s_path->st_errno != 0 ) {
139 return( AFPERR_NOOBJ );
142 uname = s_path->u_name;
144 We have to check the FinderInfo for the file, because if they aren't all 0
145 we must return the synthetic attribute "com.apple.FinderInfo".
146 Note: the client will never (never seen in traces) request that attribute
150 if (S_ISDIR(st->st_mode))
151 adflags = ADFLAGS_DIR;
155 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));
168 FinderInfo = ad_entry(adp, ADEID_FINDERI);
170 if ((adflags & ADFLAGS_DIR)) {
171 /* set default view */
172 uint16 = htons(FINDERINFO_CLOSEDVIEW);
173 memcpy(emptyFinderInfo + FINDERINFO_FRVIEWOFF, &uint16, 2);
176 /* Check if FinderInfo equals default and empty FinderInfo*/
177 if (memcmp(FinderInfo, emptyFinderInfo, 32) != 0) {
178 /* FinderInfo contains some non 0 bytes -> include "com.apple.FinderInfo" */
179 strcpy(attrnamebuf, ea_finderinfo);
180 attrbuflen += strlen(ea_finderinfo) + 1;
181 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.FinderInfo", uname);
184 /* Now check for Ressource fork and add virtual EA "com.apple.ResourceFork" if size > 0 */
185 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): Ressourcefork size: %llu", uname, adp->ad_rlen);
187 if (adp->ad_rlen > 0) {
188 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.RessourceFork.", uname);
189 strcpy(attrnamebuf + attrbuflen, ea_resourcefork);
190 attrbuflen += strlen(ea_resourcefork) + 1;
194 ret = vol->vfs->vfs_ea_list(vol, attrnamebuf, &attrbuflen, uname, oflag);
198 /* its a symlink and client requested O_NOFOLLOW */
199 LOG(log_debug, logtype_afpd, "afp_listextattr(%s): encountered symlink with kXAttrNoFollow", uname);
210 } /* if ((maxreply == 0) || (buf_valid == 0)) */
212 /* Start building reply packet */
213 bitmap = htons(bitmap);
214 memcpy( rbuf, &bitmap, sizeof(bitmap));
215 rbuf += sizeof(bitmap);
216 *rbuflen += sizeof(bitmap);
218 tmpattr = htonl(attrbuflen);
219 memcpy( rbuf, &tmpattr, sizeof(tmpattr));
220 rbuf += sizeof(tmpattr);
221 *rbuflen += sizeof(tmpattr);
223 /* Only copy buffer if the client asked for it (2nd request, maxreply>0)
224 and we didnt have an error (buf_valid) */
225 if (maxreply && buf_valid) {
226 memcpy( rbuf, attrnamebuf, attrbuflen);
227 *rbuflen += attrbuflen;
238 ad_close(adp, ADFLAGS_HF);
243 static char *to_stringz(char *ibuf, uint16_t len)
245 static char attrmname[256];
248 /* dont fool with us */
251 /* we must copy the name as its not 0-terminated and I DONT WANT TO WRITE to ibuf */
252 strlcpy(attrmname, ibuf, len + 1);
256 int afp_getextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
259 uint16_t vid, bitmap, attrnamelen;
260 uint32_t did, maxreply;
270 memcpy( &vid, ibuf, sizeof(vid));
272 if (NULL == ( vol = getvolbyvid( vid )) ) {
273 LOG(log_debug, logtype_afpd, "afp_getextattr: getvolbyvid error: %s", strerror(errno));
274 return AFPERR_ACCESS;
277 memcpy( &did, ibuf, sizeof(did));
279 if (NULL == ( dir = dirlookup( vol, did )) ) {
280 LOG(log_debug, logtype_afpd, "afp_getextattr: dirlookup error: %s", strerror(errno));
284 memcpy( &bitmap, ibuf, sizeof(bitmap));
285 bitmap = ntohs( bitmap );
286 ibuf += sizeof(bitmap);
288 if (bitmap & kXAttrNoFollow)
291 /* Skip Offset and ReqCount */
295 memcpy(&maxreply, ibuf, sizeof(maxreply));
296 maxreply = ntohl(maxreply);
297 ibuf += sizeof(maxreply);
300 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
301 LOG(log_debug, logtype_afpd, "afp_getextattr: cname error: %s", strerror(errno));
305 if ((unsigned long)ibuf & 1)
308 /* get length of EA name */
309 memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
310 attrnamelen = ntohs(attrnamelen);
311 ibuf += sizeof(attrnamelen);
313 LOG(log_debug, logtype_afpd, "afp_getextattr(%s): EA: %s", s_path->u_name, to_stringz(ibuf, attrnamelen));
315 /* Convert EA name in utf8 to unix charset */
316 if ( 0 >= convert_string(CH_UTF8_MAC, obj->options.unixcharset, ibuf, attrnamelen, attruname, 256) )
319 /* write bitmap now */
320 bitmap = htons(bitmap);
321 memcpy(rbuf, &bitmap, sizeof(bitmap));
322 rbuf += sizeof(bitmap);
323 *rbuflen += sizeof(bitmap);
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 _U_, size_t *rbuflen)
341 uint16_t vid, bitmap, attrnamelen;
342 uint32_t did, attrsize;
352 memcpy( &vid, ibuf, sizeof(vid));
354 if (NULL == ( vol = getvolbyvid( vid )) ) {
355 LOG(log_debug, logtype_afpd, "afp_setextattr: getvolbyvid error: %s", strerror(errno));
356 return AFPERR_ACCESS;
359 memcpy( &did, ibuf, sizeof(did));
361 if (NULL == ( dir = dirlookup( vol, did )) ) {
362 LOG(log_debug, logtype_afpd, "afp_setextattr: dirlookup error: %s", strerror(errno));
366 memcpy( &bitmap, ibuf, sizeof(bitmap));
367 bitmap = ntohs( bitmap );
368 ibuf += sizeof(bitmap);
370 if (bitmap & kXAttrNoFollow)
373 if (bitmap & kXAttrCreate)
375 else if (bitmap & kXAttrReplace)
382 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
383 LOG(log_debug, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
387 if ((unsigned long)ibuf & 1)
390 /* get length of EA name */
391 memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
392 attrnamelen = ntohs(attrnamelen);
393 ibuf += sizeof(attrnamelen);
394 if (attrnamelen > 255)
398 /* Convert EA name in utf8 to unix charset */
399 if ( 0 >= convert_string(CH_UTF8_MAC, obj->options.unixcharset, attrmname, attrnamelen, attruname, 256))
404 memcpy(&attrsize, ibuf, sizeof(attrsize));
405 attrsize = ntohl(attrsize);
406 ibuf += sizeof(attrsize);
407 if (attrsize > MAX_EA_SIZE)
408 /* we arbitrarily make this fatal */
411 LOG(log_debug, logtype_afpd, "afp_setextattr(%s): EA: %s, size: %u", s_path->u_name, to_stringz(attrmname, attrnamelen), attrsize);
413 ret = vol->vfs->vfs_ea_set(vol, s_path->u_name, attruname, ibuf, attrsize, oflag);
418 int afp_remextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
421 uint16_t vid, bitmap, attrnamelen;
431 memcpy( &vid, ibuf, sizeof(vid));
433 if (NULL == ( vol = getvolbyvid( vid )) ) {
434 LOG(log_debug, logtype_afpd, "afp_remextattr: getvolbyvid error: %s", strerror(errno));
435 return AFPERR_ACCESS;
438 memcpy( &did, ibuf, sizeof(did));
440 if (NULL == ( dir = dirlookup( vol, did )) ) {
441 LOG(log_debug, logtype_afpd, "afp_remextattr: dirlookup error: %s", strerror(errno));
445 memcpy( &bitmap, ibuf, sizeof(bitmap));
446 bitmap = ntohs( bitmap );
447 ibuf += sizeof(bitmap);
449 if (bitmap & kXAttrNoFollow)
453 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
454 LOG(log_debug, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
458 if ((unsigned long)ibuf & 1)
461 /* get length of EA name */
462 memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
463 attrnamelen = ntohs(attrnamelen);
464 ibuf += sizeof(attrnamelen);
465 if (attrnamelen > 255)
468 /* Convert EA name in utf8 to unix charset */
469 if ( 0 >= (convert_string(CH_UTF8_MAC, obj->options.unixcharset,ibuf, attrnamelen, attruname, 256)) )
472 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): EA: %s", s_path->u_name, to_stringz(ibuf, attrnamelen));
474 ret = vol->vfs->vfs_ea_remove(vol, s_path->u_name, attruname, oflag);