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 "attr.mdh" 31#include "attr.pro" 32 33#include <sys/types.h> 34#include <sys/xattr.h> 35 36static ssize_t 37xgetxattr(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 51static ssize_t 52xlistxattr(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 66static int 67xsetxattr(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 82static int 83xremovexattr(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 97static int 98bin_getattr(char *nam, char **argv, Options ops, UNUSED(int func)) 99{ 100 int ret = 0; 101 int list_len, 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 list_len = xlistxattr(file, NULL, 0, symlink); 108 if (list_len > 0) { 109 val_len = xgetxattr(file, attr, NULL, 0, symlink); 110 if (val_len == 0) { 111 if (param) 112 unsetparam(param); 113 return 0; 114 } 115 if (val_len > 0) { 116 value = (char *)zalloc(val_len+1); 117 attr_len = xgetxattr(file, attr, value, val_len, symlink); 118 if (attr_len > 0 && attr_len <= val_len) { 119 value[attr_len] = '\0'; 120 if (param) 121 setsparam(param, metafy(value, attr_len, META_DUP)); 122 else 123 printf("%s\n", value); 124 } 125 zfree(value, val_len+1); 126 } 127 } 128 if (list_len < 0 || val_len < 0 || attr_len < 0 || attr_len > val_len) { 129 zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno); 130 ret = 1 + (attr_len > val_len || attr_len < 0); 131 } 132 return ret; 133} 134 135static int 136bin_setattr(char *nam, char **argv, Options ops, UNUSED(int func)) 137{ 138 int ret = 0, slen, vlen; 139 int symlink = OPT_ISSET(ops, 'h'); 140 char *file = argv[0], *attr = argv[1], *value = argv[2]; 141 142 unmetafy(file, &slen); 143 unmetafy(attr, NULL); 144 unmetafy(value, &vlen); 145 if (xsetxattr(file, attr, value, vlen, 0, symlink)) { 146 zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno); 147 ret = 1; 148 } 149 return ret; 150} 151 152static int 153bin_delattr(char *nam, char **argv, Options ops, UNUSED(int func)) 154{ 155 int ret = 0, slen; 156 int symlink = OPT_ISSET(ops, 'h'); 157 char *file = argv[0], **attr = argv; 158 159 unmetafy(file, &slen); 160 while (*++attr) { 161 unmetafy(*attr, NULL); 162 if (xremovexattr(file, *attr, symlink)) { 163 zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno); 164 ret = 1; 165 break; 166 } 167 } 168 return ret; 169} 170 171static int 172bin_listattr(char *nam, char **argv, Options ops, UNUSED(int func)) 173{ 174 int ret = 0; 175 int val_len, list_len = 0, slen; 176 char *value, *file = argv[0], *param = argv[1]; 177 int symlink = OPT_ISSET(ops, 'h'); 178 179 unmetafy(file, &slen); 180 val_len = xlistxattr(file, NULL, 0, symlink); 181 if (val_len == 0) { 182 if (param) 183 unsetparam(param); 184 return 0; 185 } 186 if (val_len > 0) { 187 value = (char *)zalloc(val_len+1); 188 list_len = xlistxattr(file, value, val_len, symlink); 189 if (list_len > 0 && list_len <= val_len) { 190 char *p = value; 191 if (param) { 192 if (strlen(value) + 1 == list_len) 193 setsparam(param, metafy(value, list_len-1, META_DUP)); 194 else { 195 int arrlen = 0; 196 char **array = NULL, **arrptr = NULL; 197 198 while (p < &value[list_len]) { 199 arrlen++; 200 p += strlen(p) + 1; 201 } 202 arrptr = array = (char **)zshcalloc((arrlen+1) * sizeof(char *)); 203 p = value; 204 while (p < &value[list_len]) { 205 *arrptr++ = metafy(p, -1, META_DUP); 206 p += strlen(p) + 1; 207 } 208 setaparam(param, array); 209 } 210 } else while (p < &value[list_len]) { 211 printf("%s\n", p); 212 p += strlen(p) + 1; 213 } 214 } 215 zfree(value, val_len+1); 216 } 217 if (val_len < 0 || list_len < 0 || list_len > val_len) { 218 zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno); 219 ret = 1 + (list_len > val_len || list_len < 0); 220 } 221 return ret; 222} 223 224/* module paraphernalia */ 225 226static struct builtin bintab[] = { 227 BUILTIN("zgetattr", 0, bin_getattr, 2, 3, 0, "h", NULL), 228 BUILTIN("zsetattr", 0, bin_setattr, 3, 3, 0, "h", NULL), 229 BUILTIN("zdelattr", 0, bin_delattr, 2, -1, 0, "h", NULL), 230 BUILTIN("zlistattr", 0, bin_listattr, 1, 2, 0, "h", NULL), 231}; 232 233static struct features module_features = { 234 bintab, sizeof(bintab)/sizeof(*bintab), 235 NULL, 0, 236 NULL, 0, 237 NULL, 0, 238 0 239}; 240 241/**/ 242int 243setup_(UNUSED(Module m)) 244{ 245 return 0; 246} 247 248/**/ 249int 250features_(Module m, char ***features) 251{ 252 *features = featuresarray(m, &module_features); 253 return 0; 254} 255 256/**/ 257int 258enables_(Module m, int **enables) 259{ 260 return handlefeatures(m, &module_features, enables); 261} 262 263/**/ 264int 265boot_(UNUSED(Module m)) 266{ 267 return 0; 268} 269 270/**/ 271int 272cleanup_(Module m) 273{ 274 return setfeatureenables(m, &module_features, NULL); 275} 276 277/**/ 278int 279finish_(UNUSED(Module m)) 280{ 281 return 0; 282} 283