1 /*
2  * attr.c - extended attributes (xattr) manipulation
3  *
4  * This file is part of zsh, the Z shell.
5  *
6  * Copyright (c) 2009 Mikael Magnusson
7  * All rights reserved.
8  *
9  * Permission is hereby granted, without written agreement and without
10  * license or royalty fees, to use, copy, modify, and distribute this
11  * software and to distribute modified versions of this software for any
12  * purpose, provided that the above copyright notice and the following
13  * two paragraphs appear in all copies of this software.
14  *
15  * In no event shall Mikael Magnusson or the Zsh Development Group be liable
16  * to any party for direct, indirect, special, incidental, or consequential
17  * damages arising out of the use of this software and its documentation,
18  * even if Andrew Main and the Zsh Development Group have been advised of
19  * the possibility of such damage.
20  *
21  * Mikael Magnusson and the Zsh Development Group specifically disclaim any
22  * warranties, including, but not limited to, the implied warranties of
23  * merchantability and fitness for a particular purpose.  The software
24  * provided hereunder is on an "as is" basis, and Mikael Magnusson and the
25  * Zsh Development Group have no obligation to provide maintenance,
26  * support, updates, enhancements, or modifications.
27  *
28  */
29 
30 #include <sys/types.h>
31 #include <sys/xattr.h>
32 
33 #include "attr.mdh"
34 #include "attr.pro"
35 
36 static ssize_t
xgetxattr(const char * path,const char * name,void * value,size_t size,int symlink)37 xgetxattr(const char *path, const char *name, void *value, size_t size, int symlink)
38 {
39 #ifdef XATTR_EXTRA_ARGS
40     return getxattr(path, name, value, size, 0, symlink ? XATTR_NOFOLLOW: 0);
41 #else
42     switch (symlink) {
43     case 0:
44         return getxattr(path, name, value, size);
45     default:
46         return lgetxattr(path, name, value, size);
47     }
48 #endif
49 }
50 
51 static ssize_t
xlistxattr(const char * path,char * list,size_t size,int symlink)52 xlistxattr(const char *path, char *list, size_t size, int symlink)
53 {
54 #ifdef XATTR_EXTRA_ARGS
55     return listxattr(path, list, size, symlink ? XATTR_NOFOLLOW : 0);
56 #else
57     switch (symlink) {
58     case 0:
59         return listxattr(path, list, size);
60     default:
61         return llistxattr(path, list, size);
62     }
63 #endif
64 }
65 
66 static int
xsetxattr(const char * path,const char * name,const void * value,size_t size,int flags,int symlink)67 xsetxattr(const char *path, const char *name, const void *value,
68           size_t size, int flags, int symlink)
69 {
70 #ifdef XATTR_EXTRA_ARGS
71     return setxattr(path, name, value, size, 0, flags | symlink ? XATTR_NOFOLLOW : 0);
72 #else
73     switch (symlink) {
74     case 0:
75         return setxattr(path, name, value, size, flags);
76     default:
77         return lsetxattr(path, name, value, size, flags);
78     }
79 #endif
80 }
81 
82 static int
xremovexattr(const char * path,const char * name,int symlink)83 xremovexattr(const char *path, const char *name, int symlink)
84 {
85 #ifdef XATTR_EXTRA_ARGS
86     return removexattr(path, name, symlink ? XATTR_NOFOLLOW : 0);
87 #else
88     switch (symlink) {
89     case 0:
90         return removexattr(path, name);
91     default:
92         return lremovexattr(path, name);
93     }
94 #endif
95 }
96 
97 static int
bin_getattr(char * nam,char ** argv,Options ops,UNUSED (int func))98 bin_getattr(char *nam, char **argv, Options ops, UNUSED(int func))
99 {
100     int ret = 0;
101     int val_len = 0, attr_len = 0, slen;
102     char *value, *file = argv[0], *attr = argv[1], *param = argv[2];
103     int symlink = OPT_ISSET(ops, 'h');
104 
105     unmetafy(file, &slen);
106     unmetafy(attr, NULL);
107     val_len = xgetxattr(file, attr, NULL, 0, symlink);
108     if (val_len == 0) {
109         if (param)
110             unsetparam(param);
111         return 0;
112     }
113     if (val_len > 0) {
114         value = (char *)zalloc(val_len+1);
115         attr_len = xgetxattr(file, attr, value, val_len, symlink);
116         if (attr_len > 0 && attr_len <= val_len) {
117             value[attr_len] = '\0';
118             if (param)
119                 setsparam(param, metafy(value, attr_len, META_DUP));
120             else
121                 printf("%s\n", value);
122         }
123         zfree(value, val_len+1);
124     }
125     if (val_len < 0 || attr_len < 0 || attr_len > val_len)  {
126         zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno);
127         ret = 1 + ((val_len > 0 && attr_len > val_len) || attr_len < 0);
128     }
129     return ret;
130 }
131 
132 static int
bin_setattr(char * nam,char ** argv,Options ops,UNUSED (int func))133 bin_setattr(char *nam, char **argv, Options ops, UNUSED(int func))
134 {
135     int ret = 0, slen, vlen;
136     int symlink = OPT_ISSET(ops, 'h');
137     char *file = argv[0], *attr = argv[1], *value = argv[2];
138 
139     unmetafy(file, &slen);
140     unmetafy(attr, NULL);
141     unmetafy(value, &vlen);
142     if (xsetxattr(file, attr, value, vlen, 0, symlink)) {
143         zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno);
144         ret = 1;
145     }
146     return ret;
147 }
148 
149 static int
bin_delattr(char * nam,char ** argv,Options ops,UNUSED (int func))150 bin_delattr(char *nam, char **argv, Options ops, UNUSED(int func))
151 {
152     int ret = 0, slen;
153     int symlink = OPT_ISSET(ops, 'h');
154     char *file = argv[0], **attr = argv;
155 
156     unmetafy(file, &slen);
157     while (*++attr) {
158         unmetafy(*attr, NULL);
159         if (xremovexattr(file, *attr, symlink)) {
160             zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno);
161             ret = 1;
162             break;
163         }
164     }
165     return ret;
166 }
167 
168 static int
bin_listattr(char * nam,char ** argv,Options ops,UNUSED (int func))169 bin_listattr(char *nam, char **argv, Options ops, UNUSED(int func))
170 {
171     int ret = 0;
172     int val_len, list_len = 0, slen;
173     char *value, *file = argv[0], *param = argv[1];
174     int symlink = OPT_ISSET(ops, 'h');
175 
176     unmetafy(file, &slen);
177     val_len = xlistxattr(file, NULL, 0, symlink);
178     if (val_len == 0) {
179         if (param)
180             unsetparam(param);
181         return 0;
182     }
183     if (val_len > 0) {
184         value = (char *)zalloc(val_len+1);
185         list_len = xlistxattr(file, value, val_len, symlink);
186         if (list_len > 0 && list_len <= val_len) {
187             char *p = value;
188             if (param) {
189                 int arrlen = 0;
190                 char **array = NULL, **arrptr = NULL;
191 
192                 while (p < &value[list_len]) {
193                     arrlen++;
194                     p += strlen(p) + 1;
195                 }
196                 arrptr = array = (char **)zshcalloc((arrlen+1) * sizeof(char *));
197                 p = value;
198                 while (p < &value[list_len]) {
199                     *arrptr++ = metafy(p, -1, META_DUP);
200                     p += strlen(p) + 1;
201                 }
202                 setaparam(param, array);
203             } else while (p < &value[list_len]) {
204                 printf("%s\n", p);
205                 p += strlen(p) + 1;
206             }
207         }
208         zfree(value, val_len+1);
209     }
210     if (val_len < 0 || list_len < 0 || list_len > val_len) {
211         zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno);
212         ret = 1 + (list_len > val_len || list_len < 0);
213     }
214     return ret;
215 }
216 
217 /* module paraphernalia */
218 
219 static struct builtin bintab[] = {
220     BUILTIN("zgetattr", 0, bin_getattr, 2, 3, 0, "h", NULL),
221     BUILTIN("zsetattr", 0, bin_setattr, 3, 3, 0, "h", NULL),
222     BUILTIN("zdelattr", 0, bin_delattr, 2, -1, 0, "h", NULL),
223     BUILTIN("zlistattr", 0, bin_listattr, 1, 2, 0, "h", NULL),
224 };
225 
226 static struct features module_features = {
227     bintab, sizeof(bintab)/sizeof(*bintab),
228     NULL, 0,
229     NULL, 0,
230     NULL, 0,
231     0
232 };
233 
234 /**/
235 int
setup_(UNUSED (Module m))236 setup_(UNUSED(Module m))
237 {
238     return 0;
239 }
240 
241 /**/
242 int
features_(Module m,char *** features)243 features_(Module m, char ***features)
244 {
245     *features = featuresarray(m, &module_features);
246     return 0;
247 }
248 
249 /**/
250 int
enables_(Module m,int ** enables)251 enables_(Module m, int **enables)
252 {
253     return handlefeatures(m, &module_features, enables);
254 }
255 
256 /**/
257 int
boot_(UNUSED (Module m))258 boot_(UNUSED(Module m))
259 {
260     return 0;
261 }
262 
263 /**/
264 int
cleanup_(Module m)265 cleanup_(Module m)
266 {
267     return setfeatureenables(m, &module_features, NULL);
268 }
269 
270 /**/
271 int
finish_(UNUSED (Module m))272 finish_(UNUSED(Module m))
273 {
274     return 0;
275 }
276