]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/extattrs.c
remove unused parameter warning
[netatalk.git] / etc / afpd / extattrs.c
1 /*
2   $Id: extattrs.c,v 1.18 2009-10-29 10:34:15 didg Exp $
3   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
4
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.
9
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.
14 */
15
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif /* HAVE_CONFIG_H */
19
20 #include <unistd.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <atalk/adouble.h>
26 #include <atalk/vfs.h>
27 #include <atalk/afp.h>
28 #include <atalk/logger.h>
29 #include <atalk/ea.h>
30
31 #include "globals.h"
32 #include "volume.h"
33 #include "desktop.h"
34 #include "directory.h"
35 #include "fork.h"
36 #include "extattrs.h"
37
38 static const char *ea_finderinfo = "com.apple.FinderInfo";
39 static const char *ea_resourcefork = "com.apple.ResourceFork";
40
41 /* This should be big enough to consecutively store the names of all attributes */
42 static char attrnamebuf[ATTRNAMEBUFSIZ];
43
44 #ifdef DEBUG
45 static void hexdump(void *m, size_t l) {
46     char *p = m;
47     int count = 0, len;
48     char buf[100];
49     char *bufp = buf;
50
51     while (l--) {
52         len = sprintf(bufp, "%02x ", *p++);
53         bufp += len;
54         count++;
55
56         if ((count % 16) == 0) {
57             LOG(log_debug9, logtype_afpd, "%s", buf);
58             bufp = buf;
59         }
60     }
61 }
62 #endif
63
64 /***************************************
65  * AFP funcs
66  ****************************************/
67
68 /*
69   Note: we're being called twice. Firstly the client only want the size of all
70   EA names, secondly it wants these names. In order to avoid scanning EAs twice
71   we cache them in a static buffer.
72 */
73 int afp_listextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
74 {
75     int                 ret, oflag = 0, adflags = 0;
76     uint16_t            vid, bitmap, uint16;
77     uint32_t            did, maxreply, tmpattr;
78     struct vol          *vol;
79     struct dir          *dir;
80     struct path         *s_path;
81     struct stat         *st;
82     struct adouble      ad, *adp = NULL;
83     struct ofork        *of;
84     char                *uname, *FinderInfo;
85     char                emptyFinderInfo[32] = { 0 };
86
87     static int          buf_valid = 0;
88     static size_t       attrbuflen = 0;
89
90     *rbuflen = 0;
91     ibuf += 2;
92
93     /* Get MaxReplySize first */
94     memcpy( &maxreply, ibuf + 14, sizeof (maxreply));
95     maxreply = ntohl( maxreply );
96
97     /*
98       If its the first request with maxreply=0 or if we didn't mark our buffers valid for
99       whatever reason (just a safety check, it should be valid), then scan for attributes
100     */
101     if ((maxreply == 0) || (buf_valid == 0)) {
102
103         attrbuflen = 0;
104
105         memcpy( &vid, ibuf, sizeof(vid));
106         ibuf += sizeof(vid);
107         if (NULL == ( vol = getvolbyvid( vid )) ) {
108             LOG(log_error, logtype_afpd, "afp_listextattr: getvolbyvid error: %s", strerror(errno));
109             return AFPERR_ACCESS;
110         }
111
112         memcpy( &did, ibuf, sizeof(did));
113         ibuf += sizeof(did);
114         if (NULL == ( dir = dirlookup( vol, did )) ) {
115             LOG(log_error, logtype_afpd, "afp_listextattr: dirlookup error: %s", strerror(errno));
116             return afp_errno;
117         }
118
119         memcpy( &bitmap, ibuf, sizeof(bitmap));
120         bitmap = ntohs( bitmap );
121         ibuf += sizeof(bitmap);
122
123 #ifdef HAVE_SOLARIS_EAS
124         if (bitmap & kXAttrNoFollow)
125             oflag = O_NOFOLLOW;
126 #endif
127         /* Skip ReqCount, StartIndex and maxreply*/
128         ibuf += 10;
129
130         /* get name */
131         if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
132             LOG(log_error, logtype_afpd, "afp_listextattr: cname error: %s", strerror(errno));
133             return AFPERR_NOOBJ;
134         }
135
136         st   = &s_path->st;
137         if (!s_path->st_valid) {
138             /* it's a dir in our cache, we didn't stat it, do it now */
139             of_statdir(vol, s_path);
140         }
141         if ( s_path->st_errno != 0 ) {
142             return( AFPERR_NOOBJ );
143         }
144
145         uname = s_path->u_name;        /*
146           We have to check the FinderInfo for the file, because if they aren't all 0
147           we must return the synthetic attribute "com.apple.FinderInfo".
148           Note: the client will never (never seen in traces) request that attribute
149           via FPGetExtAttr !
150         */
151         if ((of = of_findname(s_path))) {
152             adp = of->of_ad;
153         } else {
154             ad_init(&ad, vol->v_adouble, vol->v_ad_options);
155             adp = &ad;
156         }
157
158         if (S_ISDIR(st->st_mode))
159             adflags = ADFLAGS_DIR;
160
161         if ( ad_metadata( uname, adflags, adp) < 0 ) {
162             switch (errno) {
163             case EACCES:
164                 LOG(log_error, logtype_afpd, "afp_listextattr(%s): %s: check resource fork permission?",
165                     uname, strerror(errno));
166                 return AFPERR_ACCESS;
167             default:
168                 LOG(log_error, logtype_afpd, "afp_listextattr(%s): error getting metadata: %s", uname, strerror(errno));
169                 return AFPERR_MISC;
170             }
171         }
172
173         FinderInfo = ad_entry(adp, ADEID_FINDERI);
174
175 #ifdef DEBUG
176         LOG(log_maxdebug, logtype_afpd, "afp_listextattr(%s): FinderInfo:", uname);
177         hexdump( FinderInfo, 32);
178 #endif
179
180         if ((adflags & ADFLAGS_DIR)) {
181             /* set default view */
182             uint16 = htons(FINDERINFO_CLOSEDVIEW);
183             memcpy(emptyFinderInfo + FINDERINFO_FRVIEWOFF, &uint16, 2);
184         }
185
186         /* Check if FinderInfo equals default and empty FinderInfo*/
187         if ((memcmp(FinderInfo, emptyFinderInfo, 32)) != 0) {
188             /* FinderInfo contains some non 0 bytes -> include "com.apple.FinderInfo" */
189             strcpy(attrnamebuf, ea_finderinfo);
190             attrbuflen += strlen(ea_finderinfo) + 1;
191             LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.FinderInfo", uname);
192         }
193
194         /* Now check for Ressource fork and add virtual EA "com.apple.ResourceFork" if size > 0 */
195         LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): Ressourcefork size: %u", uname, adp->ad_eid[ADEID_RFORK].ade_len);
196         if (adp->ad_eid[ADEID_RFORK].ade_len > 0) {
197             LOG(log_debug7, logtype_afpd, "afp_listextattr(%s): sending com.apple.RessourceFork.", uname);
198             strcpy(attrnamebuf + attrbuflen, ea_resourcefork);
199             attrbuflen += strlen(ea_resourcefork) + 1;
200         }
201
202         ret = vol->vfs->vfs_ea_list(vol, attrnamebuf, &attrbuflen, uname, oflag);
203
204         switch (ret) {
205         case AFPERR_BADTYPE:
206             /* its a symlink and client requested O_NOFOLLOW */
207             LOG(log_debug, logtype_afpd, "afp_listextattr(%s): encountered symlink with kXAttrNoFollow", uname);
208             attrbuflen = 0;
209             buf_valid = 0;
210             ret = AFP_OK;
211             goto exit;
212         case AFPERR_MISC:
213             attrbuflen = 0;
214             goto exit;
215         default:
216             buf_valid = 1;
217         }
218     }
219
220     /* Start building reply packet */
221     bitmap = htons(bitmap);
222     memcpy( rbuf, &bitmap, sizeof(bitmap));
223     rbuf += sizeof(bitmap);
224     *rbuflen += sizeof(bitmap);
225
226     tmpattr = htonl(attrbuflen);
227     memcpy( rbuf, &tmpattr, sizeof(tmpattr));
228     rbuf += sizeof(tmpattr);
229     *rbuflen += sizeof(tmpattr);
230
231     /* Only copy buffer if the client asked for it (2nd request, maxreply>0)
232        and we didnt have an error (buf_valid) */
233     if (maxreply && buf_valid) {
234         memcpy( rbuf, attrnamebuf, attrbuflen);
235         *rbuflen += attrbuflen;
236         buf_valid = 0;
237     }
238
239     ret = AFP_OK;
240
241 exit:
242     if (ret != AFP_OK)
243         buf_valid = 0;
244     if (adp)
245         ad_close_metadata( adp);
246
247     return ret;
248 }
249
250 int afp_getextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
251 {
252     int                 ret, oflag = 0;
253     uint16_t            vid, bitmap, attrnamelen;
254     uint32_t            did, maxreply;
255     char                attrmname[256], attruname[256];
256     struct vol          *vol;
257     struct dir          *dir;
258     struct path         *s_path;
259
260
261     *rbuflen = 0;
262     ibuf += 2;
263
264     memcpy( &vid, ibuf, sizeof(vid));
265     ibuf += sizeof(vid);
266     if (NULL == ( vol = getvolbyvid( vid )) ) {
267         LOG(log_error, logtype_afpd, "afp_getextattr: getvolbyvid error: %s", strerror(errno));
268         return AFPERR_ACCESS;
269     }
270
271     memcpy( &did, ibuf, sizeof(did));
272     ibuf += sizeof(did);
273     if (NULL == ( dir = dirlookup( vol, did )) ) {
274         LOG(log_error, logtype_afpd, "afp_getextattr: dirlookup error: %s", strerror(errno));
275         return afp_errno;
276     }
277
278     memcpy( &bitmap, ibuf, sizeof(bitmap));
279     bitmap = ntohs( bitmap );
280     ibuf += sizeof(bitmap);
281
282 #ifdef HAVE_SOLARIS_EAS
283     if (bitmap & kXAttrNoFollow)
284         oflag = O_NOFOLLOW;
285 #endif
286
287     /* Skip Offset and ReqCount */
288     ibuf += 16;
289
290     /* Get MaxReply */
291     memcpy(&maxreply, ibuf, sizeof(maxreply));
292     maxreply = ntohl(maxreply);
293     ibuf += sizeof(maxreply);
294
295     /* get name */
296     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
297         LOG(log_error, logtype_afpd, "afp_getextattr: cname error: %s", strerror(errno));
298         return AFPERR_NOOBJ;
299     }
300
301     if ((unsigned long)ibuf & 1)
302         ibuf++;
303
304     /* get length of EA name */
305     memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
306     attrnamelen = ntohs(attrnamelen);
307     ibuf += sizeof(attrnamelen);
308     if (attrnamelen > 255)
309         /* dont fool with us */
310         attrnamelen = 255;
311
312     /* we must copy the name as its not 0-terminated and I DONT WANT TO WRITE to ibuf */
313     strncpy(attrmname, ibuf, attrnamelen);
314     attrmname[attrnamelen] = 0;
315
316     LOG(log_debug, logtype_afpd, "afp_getextattr(%s): EA: %s", s_path->u_name, attrmname);
317
318     /* Convert EA name in utf8 to unix charset */
319     if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
320         return AFPERR_MISC;
321
322     if (attrnamelen == 255)
323         /* convert_string didn't 0-terminate */
324         attruname[255] = 0;
325
326     /* write bitmap now */
327     bitmap = htons(bitmap);
328     memcpy(rbuf, &bitmap, sizeof(bitmap));
329     rbuf += sizeof(bitmap);
330     *rbuflen += sizeof(bitmap);
331
332     /*
333       Switch on maxreply:
334       if its 0 we must return the size of the requested attribute,
335       if its non 0 we must return the attribute.
336     */
337     if (maxreply == 0)
338         ret = vol->vfs->vfs_ea_getsize(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname);
339     else
340         ret = vol->vfs->vfs_ea_getcontent(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, maxreply);
341
342     return ret;
343 }
344
345 int afp_setextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
346 {
347     int                 oflag = O_CREAT | O_WRONLY, ret;
348     uint16_t            vid, bitmap, attrnamelen;
349     uint32_t            did, attrsize;
350     char                attrmname[256], attruname[256];
351     struct vol          *vol;
352     struct dir          *dir;
353     struct path         *s_path;
354
355     *rbuflen = 0;
356     ibuf += 2;
357
358     memcpy( &vid, ibuf, sizeof(vid));
359     ibuf += sizeof(vid);
360     if (NULL == ( vol = getvolbyvid( vid )) ) {
361         LOG(log_error, logtype_afpd, "afp_setextattr: getvolbyvid error: %s", strerror(errno));
362         return AFPERR_ACCESS;
363     }
364
365     memcpy( &did, ibuf, sizeof(did));
366     ibuf += sizeof(did);
367     if (NULL == ( dir = dirlookup( vol, did )) ) {
368         LOG(log_error, logtype_afpd, "afp_setextattr: dirlookup error: %s", strerror(errno));
369         return afp_errno;
370     }
371
372     memcpy( &bitmap, ibuf, sizeof(bitmap));
373     bitmap = ntohs( bitmap );
374     ibuf += sizeof(bitmap);
375
376 #ifdef HAVE_SOLARIS_EAS
377     if (bitmap & kXAttrNoFollow)
378         oflag |= AT_SYMLINK_NOFOLLOW;
379 #endif
380
381     if (bitmap & kXAttrCreate)
382         oflag |= O_EXCL;
383     else if (bitmap & kXAttrReplace)
384         oflag |= O_TRUNC;
385
386     /* Skip Offset */
387     ibuf += 8;
388
389     /* get name */
390     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
391         LOG(log_error, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
392         return AFPERR_NOOBJ;
393     }
394
395     if ((unsigned long)ibuf & 1)
396         ibuf++;
397
398     /* get length of EA name */
399     memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
400     attrnamelen = ntohs(attrnamelen);
401     ibuf += sizeof(attrnamelen);
402     if (attrnamelen > 255)
403         return AFPERR_PARAM;
404
405     /* we must copy the name as its not 0-terminated and we cant write to ibuf */
406     strncpy(attrmname, ibuf, attrnamelen);
407     attrmname[attrnamelen] = 0;
408     ibuf += attrnamelen;
409
410     /* Convert EA name in utf8 to unix charset */
411     if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
412         return AFPERR_MISC;
413
414     if (attrnamelen == 255)
415         /* convert_string didn't 0-terminate */
416         attruname[255] = 0;
417
418     /* get EA size */
419     memcpy(&attrsize, ibuf, sizeof(attrsize));
420     attrsize = ntohl(attrsize);
421     ibuf += sizeof(attrsize);
422     if (attrsize > MAX_EA_SIZE)
423         /* we arbitrarily make this fatal */
424         return AFPERR_PARAM;
425
426     LOG(log_debug, logtype_afpd, "afp_setextattr(%s): EA: %s, size: %u", s_path->u_name, attrmname, attrsize);
427
428     ret = vol->vfs->vfs_ea_set(vol, s_path->u_name, attruname, ibuf, attrsize, oflag);
429
430     return ret;
431 }
432
433 int afp_remextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
434 {
435     int                 oflag = O_RDONLY, ret;
436     uint16_t            vid, bitmap, attrnamelen;
437     uint32_t            did;
438     char                attrmname[256], attruname[256];
439     struct vol          *vol;
440     struct dir          *dir;
441     struct path         *s_path;
442
443     *rbuflen = 0;
444     ibuf += 2;
445
446     memcpy( &vid, ibuf, sizeof(vid));
447     ibuf += sizeof(vid);
448     if (NULL == ( vol = getvolbyvid( vid )) ) {
449         LOG(log_error, logtype_afpd, "afp_remextattr: getvolbyvid error: %s", strerror(errno));
450         return AFPERR_ACCESS;
451     }
452
453     memcpy( &did, ibuf, sizeof(did));
454     ibuf += sizeof(did);
455     if (NULL == ( dir = dirlookup( vol, did )) ) {
456         LOG(log_error, logtype_afpd, "afp_remextattr: dirlookup error: %s", strerror(errno));
457         return afp_errno;
458     }
459
460     memcpy( &bitmap, ibuf, sizeof(bitmap));
461     bitmap = ntohs( bitmap );
462     ibuf += sizeof(bitmap);
463
464 #ifdef HAVE_SOLARIS_EAS
465     if (bitmap & kXAttrNoFollow)
466         oflag |= AT_SYMLINK_NOFOLLOW;
467 #endif
468
469     /* get name */
470     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
471         LOG(log_error, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
472         return AFPERR_NOOBJ;
473     }
474
475     if ((unsigned long)ibuf & 1)
476         ibuf++;
477
478     /* get length of EA name */
479     memcpy(&attrnamelen, ibuf, sizeof(attrnamelen));
480     attrnamelen = ntohs(attrnamelen);
481     ibuf += sizeof(attrnamelen);
482     if (attrnamelen > 255)
483         return AFPERR_PARAM;
484
485     /* we must copy the name as its not 0-terminated and we cant write to ibuf */
486     strncpy(attrmname, ibuf, attrnamelen);
487     attrmname[attrnamelen] = 0;
488     ibuf += attrnamelen;
489
490     /* Convert EA name in utf8 to unix charset */
491     if ( 0 >= ( attrnamelen = convert_string(CH_UTF8_MAC, obj->options.unixcharset,attrmname, attrnamelen, attruname, 255)) )
492         return AFPERR_MISC;
493
494     if (attrnamelen == 255)
495         /* convert_string didn't 0-terminate */
496         attruname[255] = 0;
497
498     LOG(log_debug, logtype_afpd, "afp_remextattr(%s): EA: %s", s_path->u_name, attrmname);
499
500     ret = vol->vfs->vfs_ea_remove(vol, s_path->u_name, attruname, oflag);
501
502     return ret;
503 }
504