]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/bxattr_osx.c
Update ACL/XATTR code and define new ACL/XATTR API for Plugins.
[bacula/bacula] / bacula / src / filed / bxattr_osx.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2016 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18  */
19 /**
20  * Major refactoring of XATTR code written by:
21  *
22  *  RadosÅ‚aw Korzeniewski, MMXVI
23  *  radoslaw@korzeniewski.net, radekk@inteos.pl
24  *  Inteos Sp. z o.o. http://www.inteos.pl/
25  *
26  */
27
28 #include "bacula.h"
29 #include "filed.h"
30 #include "bxattr_osx.h"
31
32 #if defined(HAVE_DARWIN_OS)
33
34 /* check if XATTR support is enabled */
35 #if defined(HAVE_XATTR)
36
37 /*
38  * Define the supported XATTR streams for this OS
39  */
40 static const int os_xattr_streams[] = {
41    STREAM_XACL_DARWIN_XATTR,
42    0
43 };
44
45 static const char *os_xattr_skiplist[] = {
46    "com.apple.system.extendedsecurity",
47    "com.apple.ResourceFork",
48    NULL
49 };
50
51 static const char *os_xattr_acl_skiplist[] = {
52    "com.apple.system.Security",
53    NULL
54 };
55
56 /*
57  * OS specific constructor
58  */
59 BXATTR_OSX::BXATTR_OSX()
60 {
61    set_xattr_streams(os_xattr_streams);
62    set_xattr_skiplists(os_xattr_skiplist, os_xattr_acl_skiplist);
63 };
64
65 /*
66  * Perform OS specific extended attribute backup
67  *
68  * in/out - check API at bxattr.h
69  */
70 bRC_BXATTR BXATTR_OSX::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
71    return generic_backup_xattr(jcr, ff_pkt);
72 };
73
74 /*
75  * Perform OS specific XATTR restore. Runtime is called only when stream is supported by OS.
76  *
77  * in/out - check API at bxattr.h
78  */
79 bRC_BXATTR BXATTR_OSX::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){
80    return generic_restore_xattr(jcr, stream);
81 };
82
83 /*
84  * Return a list of xattr names in newly allocated pool memory and a length of the allocated buffer.
85  * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
86  * when not needed.
87  *
88  * in/out - check API at bxattr.h
89  */
90 bRC_BXATTR BXATTR_OSX::os_get_xattr_names (JCR *jcr, POOLMEM ** pxlist, uint32_t * xlen){
91
92    int len;
93    POOLMEM * list;
94
95    /* check input data */
96    if (jcr == NULL || xlen == NULL || pxlist == NULL){
97       return bRC_BXATTR_inval;
98    }
99    /* get the length of the extended attributes */
100    len = listxattr(jcr->last_fname, NULL, 0, XATTR_NOFOLLOW);
101    switch (len){
102       case -1: {
103          berrno be;
104
105          switch (errno){
106             case ENOENT:
107                /* no file available, skip it */
108                return bRC_BXATTR_skip;
109             case ENOTSUP:
110                /* no xattr supported on filesystem, clear a flag and skip it */
111                clear_flag(BXATTR_FLAG_NATIVE);
112                set_content(NULL);
113                return bRC_BXATTR_skip;
114             default:
115                Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
116                Dmsg2(100, "llistxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
117                return bRC_BXATTR_error;
118          }
119          break;
120       }
121       case 0:
122          /* xattr available but empty, skip it */
123          return bRC_BXATTR_skip;
124       default:
125          break;
126    }
127
128    /*
129     * allocate memory for the extented attribute list
130     * default size is a 4k for PM_BSOCK, which should be sufficient on almost all
131     * Linux system where xattrs a limited in size to single filesystem block ~4kB
132     * so we need to check required size
133     */
134    list = get_pool_memory(PM_BSOCK);
135    list = check_pool_memory_size(list, len + 1);
136    memset(list, 0, len + 1);
137
138    /* get the list of extended attributes names for a file */
139    len = listxattr(jcr->last_fname, list, len, XATTR_NOFOLLOW);
140    switch (len){
141    case -1: {
142       berrno be;
143
144       switch (errno){
145       case ENOENT:
146          /* no file available, skip it, first release allocated memory */
147          free_pool_memory(list);
148          return bRC_BXATTR_skip;
149       default:
150          Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
151          Dmsg2(100, "llistxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
152          free_pool_memory(list);
153          return bRC_BXATTR_error;
154       }
155       break;
156    }
157    default:
158       break;
159    }
160    /* ensure a list is nul terminated */
161    list[len] = '\0';
162    /* setup return data */
163    *pxlist = list;
164    *xlen = len;
165    return bRC_BXATTR_ok;
166 };
167
168 /*
169  * Return a value of the requested attribute name and a length of the allocated buffer.
170  * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
171  * when not needed.
172  *
173  * in/out - check API at bxattr.h
174  */
175 bRC_BXATTR BXATTR_OSX::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen){
176
177    int len;
178    POOLMEM * value;
179
180    /* check input data */
181    if (jcr == NULL || name == NULL || plen == NULL || pvalue == NULL){
182       return bRC_BXATTR_inval;
183    }
184
185    /* get the length of the value for extended attribute */
186    len = getxattr(jcr->last_fname, name, NULL, 0, 0, XATTR_NOFOLLOW);
187    switch (len){
188       case -1: {
189          berrno be;
190
191          switch (errno){
192             case ENOENT:
193                /* no file available, skip it */
194                return bRC_BXATTR_skip;
195             default:
196                /* XXX: what about ENOATTR error value? */
197                Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
198                Dmsg2(100, "lgetxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
199                return bRC_BXATTR_error;
200          }
201          break;
202       }
203       default:
204          break;
205    }
206
207    if (len > 0){
208       /*
209        * allocate memory for the extented attribute value
210        * default size is a 256B for PM_MESSAGE, so we need to check required size
211        */
212       value = get_pool_memory(PM_MESSAGE);
213       value = check_pool_memory_size(value, len + 1);
214       memset(value, 0, len + 1);
215       /* value is not empty, get a data */
216       len = getxattr(jcr->last_fname, name, value, len, 0, XATTR_NOFOLLOW);
217       switch (len){
218       case -1: {
219          berrno be;
220
221          switch (errno){
222          case ENOENT:
223             /* no file available, skip it, first release allocated memory */
224             free_pool_memory(value);
225             return bRC_BXATTR_skip;
226          default:
227             Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
228             Dmsg2(100, "lgetxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
229             free_pool_memory(value);
230             return bRC_BXATTR_error;
231          }
232          break;
233       }
234       default:
235          break;
236       }
237       /* ensure a value is nul terminated */
238       value[len] = '\0';
239    } else {
240       /* empty value */
241       value = NULL;
242       len = 0;
243    }
244    /* setup return data */
245    *pvalue = value;
246    *plen = len;
247    return bRC_BXATTR_ok;
248 };
249
250 /*
251  * Low level OS specific runtime to set extended attribute on file
252  *
253  * in/out - check API at bxattr.h
254  */
255 bRC_BXATTR BXATTR_OSX::os_set_xattr (JCR *jcr, BXATTR_xattr *xattr){
256
257    /* check input data */
258    if (jcr == NULL || xattr == NULL){
259       return bRC_BXATTR_inval;
260    }
261
262    /* set extattr on file */
263    if (setxattr(jcr->last_fname, xattr->name, xattr->value, xattr->value_len, 0, XATTR_NOFOLLOW) != 0){
264       berrno be;
265
266       switch (errno){
267       case ENOENT:
268          break;
269       case ENOTSUP:
270          /*
271           * If the filesystem reports it doesn't support XATTR we clear the
272           * BXATTR_FLAG_NATIVE flag so we skip XATTR restores on all other files
273           * on the same filesystem. The BXATTR_FLAG_NATIVE flag gets set again
274           * when we change from one filesystem to an other.
275           */
276          clear_flag(BXATTR_FLAG_NATIVE);
277          Mmsg1(jcr->errmsg, _("setxattr error on file \"%s\": filesystem doesn't support XATTR\n"), jcr->last_fname);
278          Dmsg3(100, "setxattr error name=%s value=%s file=%s filesystem doesn't support XATTR\n", xattr->name, xattr->value, jcr->last_fname);
279          break;
280       default:
281          Mmsg2(jcr->errmsg, _("setxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
282          Dmsg2(100, "setxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
283          return bRC_BXATTR_error;
284       }
285    }
286    return bRC_BXATTR_ok;
287 };
288
289 #endif /* HAVE_XATTR */
290
291 #endif /* HAVE_DARWIN_OS */