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, fd = -1;
77 uint16_t vid, bitmap, uint16;
78 uint32_t did, maxreply, tmpattr;
83 struct adouble ad, *adp = NULL;
84 struct ofork *opened = NULL;
85 char *uname, *FinderInfo;
86 char emptyFinderInfo[32] = { 0 };
88 static int buf_valid = 0;
89 static size_t attrbuflen = 0;
94 /* Get Bitmap and MaxReplySize first */
95 memcpy( &bitmap, ibuf +6, sizeof(bitmap));
96 bitmap = ntohs( bitmap );
98 memcpy( &maxreply, ibuf + 14, sizeof (maxreply));
99 maxreply = ntohl( maxreply );
102 If its the first request with maxreply=0 or if we didn't mark our buffers valid for
103 whatever reason (just a safety check, it should be valid), then scan for attributes
105 if ((maxreply == 0) || (buf_valid == 0)) {
109 memcpy( &vid, ibuf, sizeof(vid));
111 if (NULL == ( vol = getvolbyvid( vid )) ) {
112 LOG(log_debug, logtype_afpd, "afp_listextattr: getvolbyvid error: %s", strerror(errno));
113 return AFPERR_ACCESS;
116 memcpy( &did, ibuf, sizeof(did));
118 if (NULL == ( dir = dirlookup( vol, did )) ) {
119 LOG(log_debug, logtype_afpd, "afp_listextattr: dirlookup error: %s", strerror(errno));
123 if (bitmap & kXAttrNoFollow)
125 /* Skip Bitmap, ReqCount, StartIndex and maxreply*/
129 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
130 LOG(log_debug, logtype_afpd, "afp_listextattr: cname error: %s", strerror(errno));
135 if (!s_path->st_valid) {
136 /* it's a dir in our cache, we didn't stat it, do it now */
137 of_statdir(vol, s_path);
139 if ( s_path->st_errno != 0 ) {
140 return( AFPERR_NOOBJ );
143 uname = s_path->u_name;
145 We have to check the FinderInfo for the file, because if they aren't all 0
146 we must return the synthetic attribute "com.apple.FinderInfo".
147 Note: the client will never (never seen in traces) request that attribute
154 if (path_isadir(s_path)) {
155 LOG(log_debug, logtype_afpd, "afp_listextattr(%s): is a dir", uname);
156 adflags = ADFLAGS_DIR;
158 LOG(log_debug, logtype_afpd, "afp_listextattr(%s): is a file", uname);
159 opened = of_findname(vol, s_path);
162 fd = ad_meta_fileno(adp);
166 if (ad_metadata(uname, adflags, adp) != 0 ) {
171 LOG(log_error, logtype_afpd, "afp_listextattr(%s): %s: check resource fork permission?",
172 uname, strerror(errno));
173 return AFPERR_ACCESS;
175 LOG(log_error, logtype_afpd, "afp_listextattr(%s): error getting metadata: %s", uname, strerror(errno));
179 FinderInfo = ad_entry(adp, ADEID_FINDERI);
180 /* Check if FinderInfo equals default and empty FinderInfo*/
181 if (memcmp(FinderInfo, emptyFinderInfo, 32) != 0) {
182 /* FinderInfo contains some non 0 bytes -> include "com.apple.FinderInfo" */
183 strcpy(attrnamebuf, ea_finderinfo);
184 attrbuflen += strlen(ea_finderinfo) + 1;
185 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.FinderInfo", uname);
188 /* Now check for Ressource fork and add virtual EA "com.apple.ResourceFork" if size > 0 */
189 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): Ressourcefork size: %llu", uname, adp->ad_rlen);
191 if (adp->ad_rlen > 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;
198 ret = vol->vfs->vfs_ea_list(vol, attrnamebuf, &attrbuflen, uname, oflag, fd);
202 /* its a symlink and client requested O_NOFOLLOW */
203 LOG(log_debug, logtype_afpd, "afp_listextattr(%s): encountered symlink with kXAttrNoFollow", uname);
214 } /* if ((maxreply == 0) || (buf_valid == 0)) */
216 /* Start building reply packet */
217 bitmap = htons(bitmap);
218 memcpy( rbuf, &bitmap, sizeof(bitmap));
219 rbuf += sizeof(bitmap);
220 *rbuflen += sizeof(bitmap);
222 tmpattr = htonl(attrbuflen);
223 memcpy( rbuf, &tmpattr, sizeof(tmpattr));
224 rbuf += sizeof(tmpattr);
225 *rbuflen += sizeof(tmpattr);
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;
242 ad_close(adp, ADFLAGS_HF);
247 static char *to_stringz(char *ibuf, uint16_t len)
249 static char attrmname[256];
252 /* dont fool with us */
255 /* we must copy the name as its not 0-terminated and I DONT WANT TO WRITE to ibuf */
256 strlcpy(attrmname, ibuf, len + 1);
260 int afp_getextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
262 int ret, oflag = 0, fd = -1;
263 uint16_t vid, bitmap, attrnamelen;
264 uint32_t did, maxreply;
269 struct adouble ad, *adp = NULL;
270 struct ofork *opened = NULL;
276 memcpy( &vid, ibuf, sizeof(vid));
278 if (NULL == ( vol = getvolbyvid( vid )) ) {
279 LOG(log_debug, logtype_afpd, "afp_getextattr: getvolbyvid error: %s", strerror(errno));
280 return AFPERR_ACCESS;
283 memcpy( &did, ibuf, sizeof(did));
285 if (NULL == ( dir = dirlookup( vol, did )) ) {
286 LOG(log_debug, logtype_afpd, "afp_getextattr: dirlookup error: %s", strerror(errno));
290 memcpy( &bitmap, ibuf, sizeof(bitmap));
291 bitmap = ntohs( bitmap );
292 ibuf += sizeof(bitmap);
294 if (bitmap & kXAttrNoFollow)
297 /* Skip Offset and ReqCount */
301 memcpy(&maxreply, ibuf, sizeof(maxreply));
302 maxreply = ntohl(maxreply);
303 ibuf += sizeof(maxreply);
306 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
307 LOG(log_debug, logtype_afpd, "afp_getextattr: cname error: %s", strerror(errno));
311 if ((unsigned long)ibuf & 1)
314 /* get length of EA name */
315 memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
316 attrnamelen = ntohs(attrnamelen);
317 ibuf += sizeof(attrnamelen);
319 LOG(log_debug, logtype_afpd, "afp_getextattr(%s): EA: %s", s_path->u_name, to_stringz(ibuf, attrnamelen));
321 /* Convert EA name in utf8 to unix charset */
322 if ( 0 >= convert_string(CH_UTF8_MAC, obj->options.unixcharset, ibuf, attrnamelen, attruname, 256) )
325 /* write bitmap now */
326 bitmap = htons(bitmap);
327 memcpy(rbuf, &bitmap, sizeof(bitmap));
328 rbuf += sizeof(bitmap);
329 *rbuflen += sizeof(bitmap);
331 if (path_isadir(s_path)) {
332 LOG(log_debug, logtype_afpd, "afp_getextattr(%s): is a dir", s_path->u_name);
334 LOG(log_debug, logtype_afpd, "afp_getextattr(%s): is a file", s_path->u_name);
335 opened = of_findname(vol, s_path);
338 fd = ad_meta_fileno(adp);
344 if its 0 we must return the size of the requested attribute,
345 if its non 0 we must return the attribute.
348 ret = vol->vfs->vfs_ea_getsize(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, fd);
350 ret = vol->vfs->vfs_ea_getcontent(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, maxreply, fd);
355 int afp_setextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
357 int oflag = 0, ret, fd = -1;
358 uint16_t vid, bitmap, attrnamelen;
359 uint32_t did, attrsize;
365 struct adouble ad, *adp = NULL;
366 struct ofork *opened = NULL;
371 memcpy( &vid, ibuf, sizeof(vid));
373 if (NULL == ( vol = getvolbyvid( vid )) ) {
374 LOG(log_debug, logtype_afpd, "afp_setextattr: getvolbyvid error: %s", strerror(errno));
375 return AFPERR_ACCESS;
378 memcpy( &did, ibuf, sizeof(did));
380 if (NULL == ( dir = dirlookup( vol, did )) ) {
381 LOG(log_debug, logtype_afpd, "afp_setextattr: dirlookup error: %s", strerror(errno));
385 memcpy( &bitmap, ibuf, sizeof(bitmap));
386 bitmap = ntohs( bitmap );
387 ibuf += sizeof(bitmap);
389 if (bitmap & kXAttrNoFollow)
392 if (bitmap & kXAttrCreate)
394 else if (bitmap & kXAttrReplace)
401 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
402 LOG(log_debug, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
406 if (path_isadir(s_path)) {
407 LOG(log_debug, logtype_afpd, "afp_setextattr(%s): is a dir", s_path->u_name);
409 LOG(log_debug, logtype_afpd, "afp_setextattr(%s): is a file", s_path->u_name);
410 opened = of_findname(vol, s_path);
413 fd = ad_meta_fileno(adp);
418 if ((unsigned long)ibuf & 1)
421 /* get length of EA name */
422 memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
423 attrnamelen = ntohs(attrnamelen);
424 ibuf += sizeof(attrnamelen);
425 if (attrnamelen > 255)
429 /* Convert EA name in utf8 to unix charset */
430 if ( 0 >= convert_string(CH_UTF8_MAC, obj->options.unixcharset, attrmname, attrnamelen, attruname, 256))
435 memcpy(&attrsize, ibuf, sizeof(attrsize));
436 attrsize = ntohl(attrsize);
437 ibuf += sizeof(attrsize);
438 if (attrsize > MAX_EA_SIZE)
439 /* we arbitrarily make this fatal */
442 LOG(log_debug, logtype_afpd, "afp_setextattr(%s): EA: %s, size: %u", s_path->u_name, to_stringz(attrmname, attrnamelen), attrsize);
444 ret = vol->vfs->vfs_ea_set(vol, s_path->u_name, attruname, ibuf, attrsize, oflag, fd);
449 int afp_remextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
451 int oflag = 0, ret, fd = -1;
452 uint16_t vid, bitmap, attrnamelen;
458 struct adouble ad, *adp = NULL;
459 struct ofork *opened = NULL;
464 memcpy( &vid, ibuf, sizeof(vid));
466 if (NULL == ( vol = getvolbyvid( vid )) ) {
467 LOG(log_debug, logtype_afpd, "afp_remextattr: getvolbyvid error: %s", strerror(errno));
468 return AFPERR_ACCESS;
471 memcpy( &did, ibuf, sizeof(did));
473 if (NULL == ( dir = dirlookup( vol, did )) ) {
474 LOG(log_debug, logtype_afpd, "afp_remextattr: dirlookup error: %s", strerror(errno));
478 memcpy( &bitmap, ibuf, sizeof(bitmap));
479 bitmap = ntohs( bitmap );
480 ibuf += sizeof(bitmap);
482 if (bitmap & kXAttrNoFollow)
486 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
487 LOG(log_debug, logtype_afpd, "afp_remextattr: cname error: %s", strerror(errno));
491 if (path_isadir(s_path)) {
492 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): is a dir", s_path->u_name);
494 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): is a file", s_path->u_name);
495 opened = of_findname(vol, s_path);
498 fd = ad_meta_fileno(adp);
502 if ((unsigned long)ibuf & 1)
505 /* get length of EA name */
506 memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
507 attrnamelen = ntohs(attrnamelen);
508 ibuf += sizeof(attrnamelen);
509 if (attrnamelen > 255)
512 /* Convert EA name in utf8 to unix charset */
513 if ( 0 >= (convert_string(CH_UTF8_MAC, obj->options.unixcharset,ibuf, attrnamelen, attruname, 256)) )
516 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): EA: %s", s_path->u_name, to_stringz(ibuf, attrnamelen));
518 ret = vol->vfs->vfs_ea_remove(vol, s_path->u_name, attruname, oflag, fd);