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);
169 /* Check if FinderInfo equals default and empty FinderInfo*/
170 if (memcmp(FinderInfo, emptyFinderInfo, 32) != 0) {
171 /* FinderInfo contains some non 0 bytes -> include "com.apple.FinderInfo" */
172 strcpy(attrnamebuf, ea_finderinfo);
173 attrbuflen += strlen(ea_finderinfo) + 1;
174 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.FinderInfo", uname);
177 /* Now check for Ressource fork and add virtual EA "com.apple.ResourceFork" if size > 0 */
178 LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): Ressourcefork size: %llu", uname, adp->ad_rlen);
180 if (adp->ad_rlen > 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;
187 ret = vol->vfs->vfs_ea_list(vol, attrnamebuf, &attrbuflen, uname, oflag);
191 /* its a symlink and client requested O_NOFOLLOW */
192 LOG(log_debug, logtype_afpd, "afp_listextattr(%s): encountered symlink with kXAttrNoFollow", uname);
203 } /* if ((maxreply == 0) || (buf_valid == 0)) */
205 /* Start building reply packet */
206 bitmap = htons(bitmap);
207 memcpy( rbuf, &bitmap, sizeof(bitmap));
208 rbuf += sizeof(bitmap);
209 *rbuflen += sizeof(bitmap);
211 tmpattr = htonl(attrbuflen);
212 memcpy( rbuf, &tmpattr, sizeof(tmpattr));
213 rbuf += sizeof(tmpattr);
214 *rbuflen += sizeof(tmpattr);
216 /* Only copy buffer if the client asked for it (2nd request, maxreply>0)
217 and we didnt have an error (buf_valid) */
218 if (maxreply && buf_valid) {
219 memcpy( rbuf, attrnamebuf, attrbuflen);
220 *rbuflen += attrbuflen;
231 ad_close(adp, ADFLAGS_HF);
236 static char *to_stringz(char *ibuf, uint16_t len)
238 static char attrmname[256];
241 /* dont fool with us */
244 /* we must copy the name as its not 0-terminated and I DONT WANT TO WRITE to ibuf */
245 strlcpy(attrmname, ibuf, len + 1);
249 int afp_getextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
252 uint16_t vid, bitmap, attrnamelen;
253 uint32_t did, maxreply;
263 memcpy( &vid, ibuf, sizeof(vid));
265 if (NULL == ( vol = getvolbyvid( vid )) ) {
266 LOG(log_debug, logtype_afpd, "afp_getextattr: getvolbyvid error: %s", strerror(errno));
267 return AFPERR_ACCESS;
270 memcpy( &did, ibuf, sizeof(did));
272 if (NULL == ( dir = dirlookup( vol, did )) ) {
273 LOG(log_debug, logtype_afpd, "afp_getextattr: dirlookup error: %s", strerror(errno));
277 memcpy( &bitmap, ibuf, sizeof(bitmap));
278 bitmap = ntohs( bitmap );
279 ibuf += sizeof(bitmap);
281 if (bitmap & kXAttrNoFollow)
284 /* Skip Offset and ReqCount */
288 memcpy(&maxreply, ibuf, sizeof(maxreply));
289 maxreply = ntohl(maxreply);
290 ibuf += sizeof(maxreply);
293 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
294 LOG(log_debug, logtype_afpd, "afp_getextattr: cname error: %s", strerror(errno));
298 if ((unsigned long)ibuf & 1)
301 /* get length of EA name */
302 memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
303 attrnamelen = ntohs(attrnamelen);
304 ibuf += sizeof(attrnamelen);
306 LOG(log_debug, logtype_afpd, "afp_getextattr(%s): EA: %s", s_path->u_name, to_stringz(ibuf, attrnamelen));
308 /* Convert EA name in utf8 to unix charset */
309 if ( 0 >= convert_string(CH_UTF8_MAC, obj->options.unixcharset, ibuf, attrnamelen, attruname, 256) )
312 /* write bitmap now */
313 bitmap = htons(bitmap);
314 memcpy(rbuf, &bitmap, sizeof(bitmap));
315 rbuf += sizeof(bitmap);
316 *rbuflen += sizeof(bitmap);
320 if its 0 we must return the size of the requested attribute,
321 if its non 0 we must return the attribute.
324 ret = vol->vfs->vfs_ea_getsize(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname);
326 ret = vol->vfs->vfs_ea_getcontent(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, maxreply);
331 int afp_setextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
334 uint16_t vid, bitmap, attrnamelen;
335 uint32_t did, attrsize;
345 memcpy( &vid, ibuf, sizeof(vid));
347 if (NULL == ( vol = getvolbyvid( vid )) ) {
348 LOG(log_debug, logtype_afpd, "afp_setextattr: getvolbyvid error: %s", strerror(errno));
349 return AFPERR_ACCESS;
352 memcpy( &did, ibuf, sizeof(did));
354 if (NULL == ( dir = dirlookup( vol, did )) ) {
355 LOG(log_debug, logtype_afpd, "afp_setextattr: dirlookup error: %s", strerror(errno));
359 memcpy( &bitmap, ibuf, sizeof(bitmap));
360 bitmap = ntohs( bitmap );
361 ibuf += sizeof(bitmap);
363 if (bitmap & kXAttrNoFollow)
366 if (bitmap & kXAttrCreate)
368 else if (bitmap & kXAttrReplace)
375 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
376 LOG(log_debug, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
380 if ((unsigned long)ibuf & 1)
383 /* get length of EA name */
384 memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
385 attrnamelen = ntohs(attrnamelen);
386 ibuf += sizeof(attrnamelen);
387 if (attrnamelen > 255)
391 /* Convert EA name in utf8 to unix charset */
392 if ( 0 >= convert_string(CH_UTF8_MAC, obj->options.unixcharset, attrmname, attrnamelen, attruname, 256))
397 memcpy(&attrsize, ibuf, sizeof(attrsize));
398 attrsize = ntohl(attrsize);
399 ibuf += sizeof(attrsize);
400 if (attrsize > MAX_EA_SIZE)
401 /* we arbitrarily make this fatal */
404 LOG(log_debug, logtype_afpd, "afp_setextattr(%s): EA: %s, size: %u", s_path->u_name, to_stringz(attrmname, attrnamelen), attrsize);
406 ret = vol->vfs->vfs_ea_set(vol, s_path->u_name, attruname, ibuf, attrsize, oflag);
411 int afp_remextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
414 uint16_t vid, bitmap, attrnamelen;
424 memcpy( &vid, ibuf, sizeof(vid));
426 if (NULL == ( vol = getvolbyvid( vid )) ) {
427 LOG(log_debug, logtype_afpd, "afp_remextattr: getvolbyvid error: %s", strerror(errno));
428 return AFPERR_ACCESS;
431 memcpy( &did, ibuf, sizeof(did));
433 if (NULL == ( dir = dirlookup( vol, did )) ) {
434 LOG(log_debug, logtype_afpd, "afp_remextattr: dirlookup error: %s", strerror(errno));
438 memcpy( &bitmap, ibuf, sizeof(bitmap));
439 bitmap = ntohs( bitmap );
440 ibuf += sizeof(bitmap);
442 if (bitmap & kXAttrNoFollow)
446 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
447 LOG(log_debug, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
451 if ((unsigned long)ibuf & 1)
454 /* get length of EA name */
455 memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
456 attrnamelen = ntohs(attrnamelen);
457 ibuf += sizeof(attrnamelen);
458 if (attrnamelen > 255)
461 /* Convert EA name in utf8 to unix charset */
462 if ( 0 >= (convert_string(CH_UTF8_MAC, obj->options.unixcharset,ibuf, attrnamelen, attruname, 256)) )
465 LOG(log_debug, logtype_afpd, "afp_remextattr(%s): EA: %s", s_path->u_name, to_stringz(ibuf, attrnamelen));
467 ret = vol->vfs->vfs_ea_remove(vol, s_path->u_name, attruname, oflag);