]> arthur.barton.de Git - netatalk.git/blob - libatalk/vfs/ea_sys.c
Include config.h
[netatalk.git] / libatalk / vfs / ea_sys.c
1 /*
2   $Id: ea_sys.c,v 1.2 2009-11-18 11:14:59 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 <stdint.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <dirent.h>
29
30 #if HAVE_ATTR_XATTR_H
31 #include <attr/xattr.h>
32 #elif HAVE_SYS_XATTR_H
33 #include <sys/xattr.h>
34 #endif
35
36 #ifdef HAVE_SYS_EA_H
37 #include <sys/ea.h>
38 #endif
39
40 #ifdef HAVE_SYS_EXTATTR_H
41 #include <sys/extattr.h>
42 #endif
43
44 #include <atalk/adouble.h>
45 #include <atalk/ea.h>
46 #include <atalk/afp.h>
47 #include <atalk/logger.h>
48 #include <atalk/volume.h>
49 #include <atalk/vfs.h>
50 #include <atalk/util.h>
51 #include <atalk/unix.h>
52
53
54 /**********************************************************************************
55  * EA VFS funcs for storing EAs in nativa filesystem EAs
56  **********************************************************************************/
57
58 /*
59  * Function: sys_get_easize
60  *
61  * Purpose: get size of a native EA
62  *
63  * Arguments:
64  *
65  *    vol          (r) current volume
66  *    rbuf         (w) DSI reply buffer
67  *    rbuflen      (rw) current length of data in reply buffer
68  *    uname        (r) filename
69  *    oflag        (r) link and create flag
70  *    attruname    (r) name of attribute
71  *
72  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
73  *
74  * Effects:
75  *
76  * Copies EA size into rbuf in network order. Increments *rbuflen +4.
77  */
78 int sys_get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
79 {
80     ssize_t   ret;
81     uint32_t  attrsize;
82
83     LOG(log_debug7, logtype_afpd, "sys_getextattr_size(%s): attribute: \"%s\"", uname, attruname);
84
85     if ((oflag & O_NOFOLLOW) ) {
86         ret = sys_lgetxattr(uname, attruname, rbuf +4, 0);
87     }
88     else {
89         ret = sys_getxattr(uname, attruname,  rbuf +4, 0);
90     }
91     
92     if (ret == -1) {
93         switch(errno) {
94         case ELOOP:
95             /* its a symlink and client requested O_NOFOLLOW  */
96             LOG(log_debug, logtype_afpd, "sys_getextattr_size(%s): encountered symlink with kXAttrNoFollow", uname);
97
98             memset(rbuf, 0, 4);
99             *rbuflen += 4;
100
101             return AFP_OK;
102         default:
103             LOG(log_error, logtype_afpd, "sys_getextattr_size: error: %s", strerror(errno));
104             return AFPERR_MISC;
105         }
106     }
107
108     if (ret > MAX_EA_SIZE) 
109       ret = MAX_EA_SIZE;
110
111     /* Start building reply packet */
112     LOG(log_debug7, logtype_afpd, "sys_getextattr_size(%s): attribute: \"%s\", size: %u", uname, attruname, ret);
113
114     /* length of attribute data */
115     attrsize = htonl((uint32_t)ret);
116     memcpy(rbuf, &attrsize, 4);
117     *rbuflen += 4;
118
119     ret = AFP_OK;
120     return ret;
121 }
122
123 /*
124  * Function: sys_get_eacontent
125  *
126  * Purpose: copy native EA into rbuf
127  *
128  * Arguments:
129  *
130  *    vol          (r) current volume
131  *    rbuf         (w) DSI reply buffer
132  *    rbuflen      (rw) current length of data in reply buffer
133  *    uname        (r) filename
134  *    oflag        (r) link and create flag
135  *    attruname    (r) name of attribute
136  *    maxreply     (r) maximum EA size as of current specs/real-life
137  *
138  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
139  *
140  * Effects:
141  *
142  * Copies EA into rbuf. Increments *rbuflen accordingly.
143  */
144 int sys_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
145 {
146     ssize_t   ret;
147     uint32_t  attrsize;
148
149     /* Start building reply packet */
150
151     maxreply -= MAX_REPLY_EXTRA_BYTES;
152
153     if (maxreply > MAX_EA_SIZE)
154         maxreply = MAX_EA_SIZE;
155
156     LOG(log_debug7, logtype_afpd, "sys_getextattr_content(%s): attribute: \"%s\", size: %u", uname, attruname, maxreply);
157
158     if ((oflag & O_NOFOLLOW) ) {
159         ret = sys_lgetxattr(uname, attruname, rbuf +4, maxreply);
160     }
161     else {
162         ret = sys_getxattr(uname, attruname,  rbuf +4, maxreply);
163     }
164     
165     if (ret == -1) switch(errno) {
166     case ELOOP:
167         /* its a symlink and client requested O_NOFOLLOW  */
168         LOG(log_debug, logtype_afpd, "sys_getextattr_content(%s): encountered symlink with kXAttrNoFollow", uname);
169
170         memset(rbuf, 0, 4);
171         *rbuflen += 4;
172
173         return AFP_OK;
174     default:
175         LOG(log_error, logtype_afpd, "sys_getextattr_content(%s): error: %s", attruname, strerror(errno));
176         return AFPERR_MISC;
177     }
178
179     /* remember where we must store length of attribute data in rbuf */
180     *rbuflen += 4 +ret;
181
182     attrsize = htonl((uint32_t)ret);
183     memcpy(rbuf, &attrsize, 4);
184
185     return AFP_OK;
186 }
187
188 /*
189  * Function: sys_list_eas
190  *
191  * Purpose: copy names of native EAs into attrnamebuf
192  *
193  * Arguments:
194  *
195  *    vol          (r) current volume
196  *    attrnamebuf  (w) store names a consecutive C strings here
197  *    buflen       (rw) length of names in attrnamebuf
198  *    uname        (r) filename
199  *    oflag        (r) link and create flag
200  *
201  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
202  *
203  * Effects:
204  *
205  * Copies names of all EAs of uname as consecutive C strings into rbuf.
206  * Increments *rbuflen accordingly.
207  */
208 int sys_list_eas(VFS_FUNC_ARGS_EA_LIST)
209 {
210     ssize_t attrbuflen = *buflen;
211     int     ret, len, nlen;
212     char    *buf;
213     char    *ptr;
214         
215     buf = malloc(ATTRNAMEBUFSIZ);
216     if (!buf)
217         return AFPERR_MISC;
218
219     if ((oflag & O_NOFOLLOW)) {
220         ret = sys_llistxattr(uname, buf, ATTRNAMEBUFSIZ);
221     }
222     else {
223         ret = sys_listxattr(uname, buf, ATTRNAMEBUFSIZ);
224     }
225
226     if (ret == -1) switch(errno) {
227         case ELOOP:
228             /* its a symlink and client requested O_NOFOLLOW */
229             ret = AFPERR_BADTYPE;
230         default:
231             LOG(log_error, logtype_afpd, "sys_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno));
232             ret= AFPERR_MISC;
233     }
234     
235     ptr = buf;
236     while (ret > 0)  {
237         len = strlen(ptr);
238
239         /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
240         if ( 0 >= ( nlen = convert_string(vol->v_volcharset, CH_UTF8_MAC, ptr, len, attrnamebuf + attrbuflen, 256)) ) {
241             ret = AFPERR_MISC;
242             goto exit;
243         }
244
245         LOG(log_debug7, logtype_afpd, "sys_list_extattr(%s): attribute: %s", uname, ptr);
246
247         attrbuflen += nlen + 1;
248         if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) {
249             /* Next EA name could overflow, so bail out with error.
250                FIXME: evantually malloc/memcpy/realloc whatever.
251                Is it worth it ? */
252             LOG(log_warning, logtype_afpd, "sys_list_extattr(%s): running out of buffer for EA names", uname);
253             ret = AFPERR_MISC;
254             goto exit;
255         }
256         ret -= len +1;
257         ptr += len +1;
258     }
259
260     ret = AFP_OK;
261
262 exit:
263     free(buf);
264     *buflen = attrbuflen;
265     return ret;
266 }
267
268 /*
269  * Function: sys_set_ea
270  *
271  * Purpose: set a native EA
272  *
273  * Arguments:
274  *
275  *    vol          (r) current volume
276  *    uname        (r) filename
277  *    attruname    (r) EA name
278  *    ibuf         (r) buffer with EA content
279  *    attrsize     (r) length EA in ibuf
280  *    oflag        (r) link and create flag
281  *
282  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
283  *
284  * Effects:
285  *
286  */
287 int sys_set_ea(VFS_FUNC_ARGS_EA_SET)
288 {
289     int attr_flag;
290     int ret;
291
292     attr_flag = 0;
293     if ((oflag & O_CREAT) ) 
294         attr_flag |= XATTR_CREATE;
295
296     else if ((oflag & O_TRUNC) ) 
297         attr_flag |= XATTR_REPLACE;
298     
299     if ((oflag & O_NOFOLLOW) ) {
300         ret = sys_lsetxattr(uname, attruname,  ibuf, attrsize,attr_flag);
301     }
302     else {
303         ret = sys_setxattr(uname, attruname,  ibuf, attrsize, attr_flag);
304     }
305
306     if (ret == -1) {
307         switch(errno) {
308         case ELOOP:
309             /* its a symlink and client requested O_NOFOLLOW  */
310             LOG(log_debug, logtype_afpd, "sys_set_ea(%s/%s): encountered symlink with kXAttrNoFollow",
311                 uname, attruname);
312             return AFP_OK;
313         default:
314             LOG(log_error, logtype_afpd, "sys_set_ea(%s/%s): error: %s", uname, attruname, strerror(errno));
315             return AFPERR_MISC;
316         }
317     }
318
319     return AFP_OK;
320 }
321
322 /*
323  * Function: sys_remove_ea
324  *
325  * Purpose: remove a native EA
326  *
327  * Arguments:
328  *
329  *    vol          (r) current volume
330  *    uname        (r) filename
331  *    attruname    (r) EA name
332  *    oflag        (r) link and create flag
333  *
334  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
335  *
336  * Effects:
337  *
338  * Removes EA attruname from file uname.
339  */
340 int sys_remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
341 {
342     int ret;
343
344     if ((oflag & O_NOFOLLOW) ) {
345         ret = sys_lremovexattr(uname, attruname);
346     }
347     else {
348         ret = sys_removexattr(uname, attruname);
349     }
350
351     if (ret == -1) {
352         switch(errno) {
353         case ELOOP:
354             /* its a symlink and client requested O_NOFOLLOW  */
355             LOG(log_debug, logtype_afpd, "sys_remove_ea(%s/%s): encountered symlink with kXAttrNoFollow", uname);
356             return AFP_OK;
357         case EACCES:
358             LOG(log_debug, logtype_afpd, "sys_remove_ea(%s/%s): error: %s", uname, attruname, strerror(errno));
359             return AFPERR_ACCESS;
360         default:
361             LOG(log_error, logtype_afpd, "sys_remove_ea(%s/%s): error: %s", uname, attruname, strerror(errno));
362             return AFPERR_MISC;
363         }
364     }
365
366     return AFP_OK;
367 }
368
369 /* --------------------- 
370    copy EA 
371 */
372 int sys_ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
373 {
374     int ret;
375     ret = sys_copyxattr(src, dst);
376     if (ret == -1) {
377         switch(errno) {
378         case ENOENT:
379             /* no attribute */
380             break;
381         case EACCES:
382             LOG(log_debug, logtype_afpd, "sys_ea_copyfile(%s, %s): error: %s", src, dst, strerror(errno));
383             return AFPERR_ACCESS;
384         default:
385             LOG(log_error, logtype_afpd, "sys_ea_copyfile(%s, %s): error: %s", src, dst, strerror(errno));
386             return AFPERR_MISC;
387         }
388     }
389
390     return AFP_OK;
391 }