#include "extattr_os.h"
#ifdef EXTATTR_LINUX
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "flags.h"
static
void
*
memstr (
void
*buf,
const
char
*str,
const
size_t
buflen)
{
void
*p = buf;
size_t
len = buflen;
const
size_t
slen =
strlen
(str);
if
((slen == 0) || (buflen == 0))
p = NULL;
while
(p && (len >= slen))
{
p =
memchr
(p, str[0], len);
if
(!p)
break
;
if
(
memcmp
(p, str, slen) == 0)
break
;
++p;
--len;
}
return
p;
}
static
char
*
flags2namespace (
struct
hv *flags)
{
const
char
*NAMESPACE_DEFAULT = NAMESPACE_USER;
const
size_t
NAMESPACE_KEYLEN =
strlen
(NAMESPACE_KEY);
SV **psv_ns;
char
*ns = NULL;
if
(flags && (psv_ns = hv_fetch(flags, NAMESPACE_KEY, NAMESPACE_KEYLEN, 0)))
{
char
*s;
STRLEN len;
s = SvPV(*psv_ns, len);
ns =
malloc
(len + 1);
if
(ns)
{
strncpy
(ns, s, len);
ns[len] =
'\0'
;
}
}
else
{
ns = strdup(NAMESPACE_DEFAULT);
}
return
ns;
}
static
char
*
qualify_attrname (
const
char
*attrname,
struct
hv *flags)
{
char
*res = NULL;
char
*pNS;
size_t
reslen;
pNS = flags2namespace(flags);
if
(pNS)
{
reslen =
strlen
(pNS) +
strlen
(attrname) + 2;
res =
malloc
(reslen);
}
if
(res)
snprintf(res, reslen,
"%s.%s"
, pNS, attrname);
if
(pNS)
free
(pNS);
return
res;
}
int
linux_setxattr (
const
char
*path,
const
char
*attrname,
const
char
*attrvalue,
const
size_t
slen,
struct
hv *flags)
{
int
ret;
char
*q;
File_ExtAttr_setflags_t setflags;
int
xflags = 0;
setflags = File_ExtAttr_flags2setflags(flags);
switch
(setflags)
{
case
SET_CREATEIFNEEDED:
break
;
case
SET_CREATE: xflags |= XATTR_CREATE;
break
;
case
SET_REPLACE: xflags |= XATTR_REPLACE;
break
;
}
q = qualify_attrname(attrname, flags);
if
(q)
{
ret = setxattr(path, q, attrvalue, slen, xflags);
if
(ret == -1)
ret = -
errno
;
free
(q);
}
else
{
ret = -ENOMEM;
}
return
ret;
}
int
linux_fsetxattr (
const
int
fd,
const
char
*attrname,
const
char
*attrvalue,
const
size_t
slen,
struct
hv *flags)
{
int
ret;
char
*q;
File_ExtAttr_setflags_t setflags;
int
xflags = 0;
setflags = File_ExtAttr_flags2setflags(flags);
switch
(setflags)
{
case
SET_CREATEIFNEEDED:
break
;
case
SET_CREATE: xflags |= XATTR_CREATE;
break
;
case
SET_REPLACE: xflags |= XATTR_REPLACE;
break
;
}
q = qualify_attrname(attrname, flags);
if
(q)
{
ret = fsetxattr(fd, q, attrvalue, slen, xflags);
if
(ret == -1)
ret = -
errno
;
free
(q);
}
else
{
ret = -ENOMEM;
}
return
ret;
}
int
linux_getxattr (
const
char
*path,
const
char
*attrname,
void
*attrvalue,
const
size_t
slen,
struct
hv *flags)
{
int
ret;
char
*q;
q = qualify_attrname(attrname, flags);
if
(q)
{
ret = getxattr(path, q, attrvalue, slen);
if
(ret == -1)
ret = -
errno
;
free
(q);
}
else
{
ret = -ENOMEM;
}
return
ret;
}
int
linux_fgetxattr (
const
int
fd,
const
char
*attrname,
void
*attrvalue,
const
size_t
slen,
struct
hv *flags)
{
int
ret;
char
*q;
q = qualify_attrname(attrname, flags);
if
(q)
{
ret = fgetxattr(fd, q, attrvalue, slen);
if
(ret == -1)
ret = -
errno
;
free
(q);
}
else
{
ret = -ENOMEM;
}
return
ret;
}
int
linux_removexattr (
const
char
*path,
const
char
*attrname,
struct
hv *flags)
{
int
ret;
char
*q;
q = qualify_attrname(attrname, flags);
if
(q)
{
ret = removexattr(path, q);
if
(ret == -1)
ret = -
errno
;
free
(q);
}
else
{
ret = -ENOMEM;
}
return
ret;
}
int
linux_fremovexattr (
const
int
fd,
const
char
*attrname,
struct
hv *flags)
{
int
ret;
char
*q;
q = qualify_attrname(attrname, flags);
if
(q)
{
ret = fremovexattr(fd, q);
if
(ret == -1)
ret = -
errno
;
free
(q);
}
else
{
ret = -ENOMEM;
}
return
ret;
}
static
ssize_t
attrlist2list (
char
*sbuf,
const
size_t
slen,
char
*buf,
const
size_t
buflen,
const
int
iWantNames,
const
char
*pWantNS)
{
ssize_t sbuiltlen = 0;
ssize_t spos = 0;
int
ret = -1;
for
(spos = 0; (spos < slen); )
{
const
char
*psrc;
char
*pNS, *pname;
int
src_len;
pNS = &sbuf[spos];
pname =
strchr
(pNS,
'.'
);
if
(!pname)
break
;
spos +=
strlen
(pNS) + 1;
*pname =
'\0'
;
++pname;
if
(iWantNames)
{
psrc = pname;
if
(
strcmp
(pNS, pWantNS) != 0)
continue
;
}
else
{
psrc = pNS;
if
(memstr(sbuf, pNS, sbuiltlen) != NULL)
continue
;
}
src_len =
strlen
(psrc) + 1;
memmove
(&sbuf[sbuiltlen], psrc, src_len);
sbuiltlen += src_len;
}
if
(buflen == 0)
{
ret = sbuiltlen;
}
else
if
(sbuiltlen <= buflen)
{
memcpy
(buf, sbuf, sbuiltlen);
ret = sbuiltlen;
}
else
{
ret = -ERANGE;
}
return
ret;
}
ssize_t
linux_listxattr (
const
char
*path,
char
*buf,
const
size_t
buflen,
struct
hv *flags)
{
char
*pNS;
ssize_t ret = 0;
pNS = flags2namespace(flags);
if
(!pNS)
{
ret = -ENOMEM;
}
if
(ret == 0)
{
ssize_t slen;
slen = listxattr(path, buf, 0);
if
(slen == -1) {
ret = -
errno
;
}
else
if
(slen >= 0) {
char
*sbuf;
sbuf =
malloc
(slen);
if
(sbuf) {
slen = listxattr(path, sbuf, slen);
if
(slen >= 0) {
ret = attrlist2list(sbuf, slen, buf, buflen, 1, pNS);
}
else
{
ret = -
errno
;
}
}
else
{
ret = -
errno
;
slen = 0;
}
if
(sbuf)
free
(sbuf);
}
}
if
(pNS)
free
(pNS);
return
ret;
}
ssize_t
linux_flistxattr (
const
int
fd,
char
*buf,
const
size_t
buflen,
struct
hv *flags)
{
char
*pNS;
ssize_t ret = 0;
pNS = flags2namespace(flags);
if
(!pNS)
{
ret = -ENOMEM;
}
if
(ret == 0)
{
ssize_t slen;
slen = flistxattr(fd, buf, 0);
if
(slen == -1) {
ret = -
errno
;
}
else
if
(slen >= 0) {
char
*sbuf;
sbuf =
malloc
(slen);
if
(sbuf) {
slen = flistxattr(fd, sbuf, slen);
if
(slen >= 0) {
ret = attrlist2list(sbuf, slen, buf, buflen, 1, pNS);
}
else
{
ret = -
errno
;
}
}
else
{
ret = -
errno
;
}
if
(sbuf)
free
(sbuf);
}
}
if
(pNS)
free
(pNS);
return
ret;
}
ssize_t
linux_listxattrns (
const
char
*path,
char
*buf,
const
size_t
buflen,
struct
hv *flags)
{
ssize_t slen;
ssize_t ret;
slen = listxattr(path, buf, 0);
if
(slen >= 0)
{
char
*sbuf;
sbuf =
malloc
(slen);
if
(sbuf) {
slen = listxattr(path, sbuf, slen);
if
(slen >= 0) {
ret = attrlist2list(sbuf, slen, buf, buflen, 0, NULL);
}
else
{
ret = -
errno
;
}
}
else
{
ret = -
errno
;
}
if
(sbuf)
free
(sbuf);
}
else
{
ret = -
errno
;
}
return
ret;
}
ssize_t
linux_flistxattrns (
const
int
fd,
char
*buf,
const
size_t
buflen,
struct
hv *flags)
{
ssize_t slen;
ssize_t ret;
slen = flistxattr(fd, buf, 0);
if
(slen >= 0)
{
char
*sbuf;
sbuf =
malloc
(slen);
if
(sbuf) {
slen = flistxattr(fd, sbuf, slen);
if
(slen >= 0) {
ret = attrlist2list(sbuf, slen, buf, buflen, 0, NULL);
}
else
{
ret = -
errno
;
}
}
else
{
ret = -
errno
;
}
if
(sbuf)
free
(sbuf);
}
else
{
ret = -
errno
;
}
return
ret;
}
#endif /* EXTATTR_LINUX */