Declare a `struct extattr' that defines the format of an extended
attribute. Also define some macros to manipulate one of these structures. Explain their use in the extattr.9 manual page. The next step will be to make a sweep through the kernel replacing the old pointer manipulation code. To get an idea of how they would be used, the ffs_findextattr() function in ufs/ffs/ffs_vnops.c is currently written as follows: /* * Vnode operating to retrieve a named extended attribute. * * Locate a particular EA (nspace:name) in the area (ptr:length), and return * the length of the EA, and possibly the pointer to the entry and to the data. */ static int ffs_findextattr(u_char *ptr, u_int length, int nspace, const char *name, u_char **eap, u_char **eac) { u_char *p, *pe, *pn, *p0; int eapad1, eapad2, ealength, ealen, nlen; uint32_t ul; pe = ptr + length; nlen = strlen(name); for (p = ptr; p < pe; p = pn) { p0 = p; bcopy(p, &ul, sizeof(ul)); pn = p + ul; /* make sure this entry is complete */ if (pn > pe) break; p += sizeof(uint32_t); if (*p != nspace) continue; p++; eapad2 = *p++; if (*p != nlen) continue; p++; if (bcmp(p, name, nlen)) continue; ealength = sizeof(uint32_t) + 3 + nlen; eapad1 = 8 - (ealength % 8); if (eapad1 == 8) eapad1 = 0; ealength += eapad1; ealen = ul - ealength - eapad2; p += nlen + eapad1; if (eap != NULL) *eap = p0; if (eac != NULL) *eac = p; return (ealen); } return(-1); } After applying the structure and macros, it would look like this: /* * Vnode operating to retrieve a named extended attribute. * * Locate a particular EA (nspace:name) in the area (ptr:length), and return * the length of the EA, and possibly the pointer to the entry and to the data. */ static int ffs_findextattr(u_char *ptr, u_int length, int nspace, const char *name, u_char **eapp, u_char **eac) { struct extattr *eap, *eaend; eaend = (struct extattr *)(ptr + length); for (eap = (struct extattr *)ptr; eap < eaend; eap = EXTATTR_NEXT(eap)){ /* make sure this entry is complete */ if (EXTATTR_NEXT(eap) > eaend) break; if (eap->ea_namespace != nspace || eap->ea_namelength != length || bcmp(eap->ea_name, name, length)) continue; if (eapp != NULL) *eapp = eap; if (eac != NULL) *eac = EXTATTR_CONTENT(eap); return (EXTATTR_CONTENT_SIZE(eap)); } return(-1); } Not only is it considerably shorter, but it hopefully more readable :-)
This commit is contained in:
parent
37471781c4
commit
22aa654f0b
@ -78,6 +78,61 @@ Appropriate vnode extended attribute calls are:
|
||||
.Xr VOP_LISTEXTATTR 9 ,
|
||||
and
|
||||
.Xr VOP_SETEXTATTR 9 .
|
||||
.Pp
|
||||
The format of an external attribute is defined by the extattr structure:
|
||||
.Bd -literal
|
||||
struct extattr {
|
||||
int32_t ea_length; /* length of this attribute */
|
||||
int8_t ea_namespace; /* name space of this attribute */
|
||||
int8_t ea_contentpadlen; /* padding at end of attribute */
|
||||
int8_t ea_namelength; /* length of attribute name */
|
||||
char ea_name[1]; /* null-terminated attribute name */
|
||||
/* extended attribute content follows */
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
Several macros are defined to manipulate these structures.
|
||||
Each macro takes a pointer to an extattr structure.
|
||||
.Bl -tag -width ".Dv EXTATTR_SET_LENGTHS(eap, size)"
|
||||
.It Dv EXTATTR_NEXT(eap)
|
||||
Returns a pointer to the next extended attribute following
|
||||
.Fa eap .
|
||||
.It Dv EXTATTR_CONTENT(eap)
|
||||
Returns a pointer to the extended attribute content referenced by
|
||||
.Fa eap .
|
||||
.It Dv EXTATTR_CONTENT_SIZE(eap)
|
||||
Returns the size of the extended attribute content referenced by
|
||||
.Fa eap .
|
||||
.It Dv EXTATTR_SET_LENGTHS(eap, size)
|
||||
Called with the size of the attribute content after initializing
|
||||
the attribute name to calculate and set the
|
||||
.Fa ea_length ,
|
||||
.Fa ea_namelength ,
|
||||
and
|
||||
.Fa ea_contentpadlen
|
||||
fields of the extended attribute structure.
|
||||
.El
|
||||
.Pp
|
||||
The following code identifies an ACL:
|
||||
.Bd -literal
|
||||
if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
|
||||
!strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME) {
|
||||
aclp = EXTATTR_CONTENT(eap);
|
||||
acllen = EXTATTR_CONTENT_SIZE(eap);
|
||||
...
|
||||
}
|
||||
.Ed
|
||||
.Pp
|
||||
The following code creates an extended attribute
|
||||
containing a copy of a structure
|
||||
.Fa mygif :
|
||||
.Bd -literal
|
||||
eap->ea_namespace = EXTATTR_NAMESPACE_USER;
|
||||
strcpy(eap->ea_name, "filepic.gif");
|
||||
EXTATTR_SET_LENGTHS(eap, sizeof(struct mygif));
|
||||
memcpy(EXTATTR_CONTENT(eap), &mygif, sizeof(struct mygif));
|
||||
.Ed
|
||||
.Pp
|
||||
.Sh SEE ALSO
|
||||
.Xr VFS 9 ,
|
||||
.Xr VFS_EXTATTRCTL 9 ,
|
||||
|
@ -39,11 +39,65 @@
|
||||
* Defined name spaces for extended attributes. Numeric constants are passed
|
||||
* via system calls, but a user-friendly string is also defined.
|
||||
*/
|
||||
#define EXTATTR_NAMESPACE_EMPTY 0x00000000
|
||||
#define EXTATTR_NAMESPACE_EMPTY_STRING "empty"
|
||||
#define EXTATTR_NAMESPACE_USER 0x00000001
|
||||
#define EXTATTR_NAMESPACE_USER_STRING "user"
|
||||
#define EXTATTR_NAMESPACE_SYSTEM 0x00000002
|
||||
#define EXTATTR_NAMESPACE_SYSTEM_STRING "system"
|
||||
|
||||
/*
|
||||
* The following macro is designed to initialize an array that maps
|
||||
* extended-attribute namespace values to their names, e.g.,
|
||||
* char *extattr_namespace_names[] = EXTATTR_NAMESPACE_NAMES;
|
||||
*/
|
||||
#define EXTATTR_NAMESPACE_NAMES { \
|
||||
EXTATTR_NAMESPACE_EMPTY_STRING, \
|
||||
EXTATTR_NAMESPACE_USER_STRING, \
|
||||
EXTATTR_NAMESPACE_SYSTEM_STRING }
|
||||
|
||||
/*
|
||||
* This structure defines the required fields of an extended-attribute header.
|
||||
*/
|
||||
struct extattr {
|
||||
int32_t ea_length; /* length of this attribute */
|
||||
int8_t ea_namespace; /* name space of this attribute */
|
||||
int8_t ea_contentpadlen; /* bytes of padding at end of attribute */
|
||||
int8_t ea_namelength; /* length of attribute name */
|
||||
char ea_name[1]; /* null-terminated attribute name */
|
||||
/* extended attribute content follows */
|
||||
};
|
||||
|
||||
/*
|
||||
* These macros are used to access and manipulate an extended attribute:
|
||||
*
|
||||
* EXTATTR_NEXT(eap) returns a pointer to the next extended attribute
|
||||
* following eap.
|
||||
* EXTATTR_CONTENT(eap) returns a pointer to the extended attribute
|
||||
* content referenced by eap.
|
||||
* EXTATTR_CONTENT_SIZE(eap) returns the size of the extended attribute
|
||||
* content referenced by eap.
|
||||
* EXTATTR_SET_LENGTHS(eap, contentsize) called after initializing the
|
||||
* attribute name to calculate and set the ea_length, ea_namelength,
|
||||
* and ea_contentpadlen fields of the extended attribute structure.
|
||||
*/
|
||||
#define EXTATTR_NEXT(eap) \
|
||||
((struct extattr *)(((void *)(eap)) + (eap)->ea_length))
|
||||
#define EXTATTR_CONTENT(eap) (((void *)(eap)) + EXTATTR_BASE_LENGTH(eap))
|
||||
#define EXTATTR_CONTENT_SIZE(eap) \
|
||||
((eap)->ea_length - EXTATTR_BASE_LENGTH(eap) - (eap)->ea_contentpadlen)
|
||||
#define EXTATTR_BASE_LENGTH(eap) \
|
||||
((sizeof(struct extattr) + (eap)->ea_namelength + 7) & ~7)
|
||||
#define EXTATTR_SET_LENGTHS(eap, contentsize) do { \
|
||||
KASSERT(((eap)->ea_name[0] != 0), \
|
||||
("Must initialize name before setting lengths")); \
|
||||
(eap)->ea_namelength = strlen((eap)->ea_name); \
|
||||
(eap)->ea_contentpadlen = ((contentsize) % 8) ? \
|
||||
8 - ((contentsize) % 8) : 0; \
|
||||
(eap)->ea_length = EXTATTR_BASE_LENGTH(eap) + \
|
||||
(contentsize) + (eap)->ea_contentpadlen; \
|
||||
} while (0)
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#define EXTATTR_MAXNAMELEN NAME_MAX
|
||||
@ -56,6 +110,11 @@ int extattr_check_cred(struct vnode *vp, int attrnamespace,
|
||||
#else
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
/* User-level definition of KASSERT for macros above */
|
||||
#define KASSERT(cond, str) do { \
|
||||
if (cond) { printf("panic: "); printf(str); printf("\n"); exit(1); } \
|
||||
} while (0)
|
||||
|
||||
struct iovec;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
Loading…
x
Reference in New Issue
Block a user