mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-10-31 06:00:54 +01:00 
			
		
		
		
	Remove the listattr call in zgetattr, it only caused no error to be output when trying to retrieve an xattr from a file with no xattrs. When a file had xattrs, it would just add an extra syscall for no good reason. Always set an array parameter in zlistattr, this makes the returned value much easier to use; in fact the _zattr completer didn't account for this and zlistattr foo <tab> on a file with only one attribute did not work. Almost all of the patch is only reindent, the only modification that's not a pure deletions is: - ret = 1 + (attr_len > val_len || attr_len < 0); + ret = 1 + ((val_len > 0 && attr_len > val_len) || attr_len < 0); which makes sure we return the correct error in the new path due to the removed listattr call. (If val_len is -1 due to no attribute existing, it doesn't mean the user should retry the call because the attribute grew in size).
		
			
				
	
	
		
			275 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			275 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * attr.c - extended attributes (xattr) manipulation
 | |
|  *
 | |
|  * This file is part of zsh, the Z shell.
 | |
|  *
 | |
|  * Copyright (c) 2009 Mikael Magnusson
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Permission is hereby granted, without written agreement and without
 | |
|  * license or royalty fees, to use, copy, modify, and distribute this
 | |
|  * software and to distribute modified versions of this software for any
 | |
|  * purpose, provided that the above copyright notice and the following
 | |
|  * two paragraphs appear in all copies of this software.
 | |
|  *
 | |
|  * In no event shall Mikael Magnusson or the Zsh Development Group be liable
 | |
|  * to any party for direct, indirect, special, incidental, or consequential
 | |
|  * damages arising out of the use of this software and its documentation,
 | |
|  * even if Andrew Main and the Zsh Development Group have been advised of
 | |
|  * the possibility of such damage.
 | |
|  *
 | |
|  * Mikael Magnusson and the Zsh Development Group specifically disclaim any
 | |
|  * warranties, including, but not limited to, the implied warranties of
 | |
|  * merchantability and fitness for a particular purpose.  The software
 | |
|  * provided hereunder is on an "as is" basis, and Mikael Magnusson and the
 | |
|  * Zsh Development Group have no obligation to provide maintenance,
 | |
|  * support, updates, enhancements, or modifications.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include "attr.mdh"
 | |
| #include "attr.pro"
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/xattr.h>
 | |
| 
 | |
| static ssize_t
 | |
| xgetxattr(const char *path, const char *name, void *value, size_t size, int symlink)
 | |
| {
 | |
| #ifdef XATTR_EXTRA_ARGS
 | |
|     return getxattr(path, name, value, size, 0, symlink ? XATTR_NOFOLLOW: 0);
 | |
| #else
 | |
|     switch (symlink) {
 | |
|     case 0:
 | |
|         return getxattr(path, name, value, size);
 | |
|     default:
 | |
|         return lgetxattr(path, name, value, size);
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static ssize_t
 | |
| xlistxattr(const char *path, char *list, size_t size, int symlink)
 | |
| {
 | |
| #ifdef XATTR_EXTRA_ARGS
 | |
|     return listxattr(path, list, size, symlink ? XATTR_NOFOLLOW : 0);
 | |
| #else
 | |
|     switch (symlink) {
 | |
|     case 0:
 | |
|         return listxattr(path, list, size);
 | |
|     default:
 | |
|         return llistxattr(path, list, size);
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static int
 | |
| xsetxattr(const char *path, const char *name, const void *value,
 | |
|           size_t size, int flags, int symlink)
 | |
| {
 | |
| #ifdef XATTR_EXTRA_ARGS
 | |
|     return setxattr(path, name, value, size, 0, flags | symlink ? XATTR_NOFOLLOW : 0);
 | |
| #else
 | |
|     switch (symlink) {
 | |
|     case 0:
 | |
|         return setxattr(path, name, value, size, flags);
 | |
|     default:
 | |
|         return lsetxattr(path, name, value, size, flags);
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static int
 | |
| xremovexattr(const char *path, const char *name, int symlink)
 | |
| {
 | |
| #ifdef XATTR_EXTRA_ARGS
 | |
|     return removexattr(path, name, symlink ? XATTR_NOFOLLOW : 0);
 | |
| #else
 | |
|     switch (symlink) {
 | |
|     case 0:
 | |
|         return removexattr(path, name);
 | |
|     default:
 | |
|         return lremovexattr(path, name);
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static int
 | |
| bin_getattr(char *nam, char **argv, Options ops, UNUSED(int func))
 | |
| {
 | |
|     int ret = 0;
 | |
|     int val_len = 0, attr_len = 0, slen;
 | |
|     char *value, *file = argv[0], *attr = argv[1], *param = argv[2];
 | |
|     int symlink = OPT_ISSET(ops, 'h');
 | |
| 
 | |
|     unmetafy(file, &slen);
 | |
|     unmetafy(attr, NULL);
 | |
|     val_len = xgetxattr(file, attr, NULL, 0, symlink);
 | |
|     if (val_len == 0) {
 | |
|         if (param)
 | |
|             unsetparam(param);
 | |
|         return 0;
 | |
|     }
 | |
|     if (val_len > 0) {
 | |
|         value = (char *)zalloc(val_len+1);
 | |
|         attr_len = xgetxattr(file, attr, value, val_len, symlink);
 | |
|         if (attr_len > 0 && attr_len <= val_len) {
 | |
|             value[attr_len] = '\0';
 | |
|             if (param)
 | |
|                 setsparam(param, metafy(value, attr_len, META_DUP));
 | |
|             else
 | |
|                 printf("%s\n", value);
 | |
|         }
 | |
|         zfree(value, val_len+1);
 | |
|     }
 | |
|     if (val_len < 0 || attr_len < 0 || attr_len > val_len)  {
 | |
|         zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno);
 | |
|         ret = 1 + ((val_len > 0 && attr_len > val_len) || attr_len < 0);
 | |
|     }
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static int
 | |
| bin_setattr(char *nam, char **argv, Options ops, UNUSED(int func))
 | |
| {
 | |
|     int ret = 0, slen, vlen;
 | |
|     int symlink = OPT_ISSET(ops, 'h');
 | |
|     char *file = argv[0], *attr = argv[1], *value = argv[2];
 | |
| 
 | |
|     unmetafy(file, &slen);
 | |
|     unmetafy(attr, NULL);
 | |
|     unmetafy(value, &vlen);
 | |
|     if (xsetxattr(file, attr, value, vlen, 0, symlink)) {
 | |
|         zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno);
 | |
|         ret = 1;
 | |
|     }
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static int
 | |
| bin_delattr(char *nam, char **argv, Options ops, UNUSED(int func))
 | |
| {
 | |
|     int ret = 0, slen;
 | |
|     int symlink = OPT_ISSET(ops, 'h');
 | |
|     char *file = argv[0], **attr = argv;
 | |
| 
 | |
|     unmetafy(file, &slen);
 | |
|     while (*++attr) {
 | |
|         unmetafy(*attr, NULL);
 | |
|         if (xremovexattr(file, *attr, symlink)) {
 | |
|             zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno);
 | |
|             ret = 1;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static int
 | |
| bin_listattr(char *nam, char **argv, Options ops, UNUSED(int func))
 | |
| {
 | |
|     int ret = 0;
 | |
|     int val_len, list_len = 0, slen;
 | |
|     char *value, *file = argv[0], *param = argv[1];
 | |
|     int symlink = OPT_ISSET(ops, 'h');
 | |
| 
 | |
|     unmetafy(file, &slen);
 | |
|     val_len = xlistxattr(file, NULL, 0, symlink);
 | |
|     if (val_len == 0) {
 | |
|         if (param)
 | |
|             unsetparam(param);
 | |
|         return 0;
 | |
|     }
 | |
|     if (val_len > 0) {
 | |
|         value = (char *)zalloc(val_len+1);
 | |
|         list_len = xlistxattr(file, value, val_len, symlink);
 | |
|         if (list_len > 0 && list_len <= val_len) {
 | |
|             char *p = value;
 | |
|             if (param) {
 | |
|                 int arrlen = 0;
 | |
|                 char **array = NULL, **arrptr = NULL;
 | |
| 
 | |
|                 while (p < &value[list_len]) {
 | |
|                     arrlen++;
 | |
|                     p += strlen(p) + 1;
 | |
|                 }
 | |
|                 arrptr = array = (char **)zshcalloc((arrlen+1) * sizeof(char *));
 | |
|                 p = value;
 | |
|                 while (p < &value[list_len]) {
 | |
|                     *arrptr++ = metafy(p, -1, META_DUP);
 | |
|                     p += strlen(p) + 1;
 | |
|                 }
 | |
|                 setaparam(param, array);
 | |
|             } else while (p < &value[list_len]) {
 | |
|                 printf("%s\n", p);
 | |
|                 p += strlen(p) + 1;
 | |
|             }
 | |
|         }
 | |
|         zfree(value, val_len+1);
 | |
|     }
 | |
|     if (val_len < 0 || list_len < 0 || list_len > val_len) {
 | |
|         zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno);
 | |
|         ret = 1 + (list_len > val_len || list_len < 0);
 | |
|     }
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /* module paraphernalia */
 | |
| 
 | |
| static struct builtin bintab[] = {
 | |
|     BUILTIN("zgetattr", 0, bin_getattr, 2, 3, 0, "h", NULL),
 | |
|     BUILTIN("zsetattr", 0, bin_setattr, 3, 3, 0, "h", NULL),
 | |
|     BUILTIN("zdelattr", 0, bin_delattr, 2, -1, 0, "h", NULL),
 | |
|     BUILTIN("zlistattr", 0, bin_listattr, 1, 2, 0, "h", NULL),
 | |
| };
 | |
| 
 | |
| static struct features module_features = {
 | |
|     bintab, sizeof(bintab)/sizeof(*bintab),
 | |
|     NULL, 0,
 | |
|     NULL, 0,
 | |
|     NULL, 0,
 | |
|     0
 | |
| };
 | |
| 
 | |
| /**/
 | |
| int
 | |
| setup_(UNUSED(Module m))
 | |
| {
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| features_(Module m, char ***features)
 | |
| {
 | |
|     *features = featuresarray(m, &module_features);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| enables_(Module m, int **enables)
 | |
| {
 | |
|     return handlefeatures(m, &module_features, enables);
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| boot_(UNUSED(Module m))
 | |
| {
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| cleanup_(Module m)
 | |
| {
 | |
|     return setfeatureenables(m, &module_features, NULL);
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| finish_(UNUSED(Module m))
 | |
| {
 | |
|     return 0;
 | |
| }
 |