#include "extattr_os.h"
#ifdef EXTATTR_BSD
#include <errno.h>
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "flags.h"
static
int
valid_namespace (
struct
hv *flags,
int
*pattrnamespace)
{
const
size_t
NAMESPACE_KEYLEN =
strlen
(NAMESPACE_KEY);
SV **psv_ns;
char
*ns = NULL;
int
ok = 1;
int
attrnamespace = EXTATTR_NAMESPACE_USER;
if
(flags && (psv_ns = hv_fetch(flags, NAMESPACE_KEY, NAMESPACE_KEYLEN, 0)))
{
if
(SvOK(*psv_ns))
{
char
*s;
STRLEN len = 0;
s = SvPV(*psv_ns, len);
if
(len)
{
if
(
memcmp
(NAMESPACE_USER, s, len) == 0)
attrnamespace = EXTATTR_NAMESPACE_USER;
else
if
(
memcmp
(NAMESPACE_SYSTEM, s, len) == 0)
attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
else
ok = 0;
}
else
{
ok = 0;
}
}
}
if
(ok)
*pattrnamespace = attrnamespace;
return
ok;
}
static
inline
int
bsd_extattr_set_succeeded (
const
int
expected,
const
int
actual)
{
int
ret = 0;
if
(actual == -1) {
ret = -
errno
;
}
else
if
(actual != expected) {
ret = -ENOBUFS;
}
return
ret;
}
int
bsd_setxattr (
const
char
*path,
const
char
*attrname,
const
char
*attrvalue,
const
size_t
slen,
struct
hv *flags)
{
int
attrnamespace = -1;
int
ret = 0;
if
(!valid_namespace(flags, &attrnamespace))
{
ret = -EOPNOTSUPP;
}
if
(ret == 0)
{
File_ExtAttr_setflags_t setflags = File_ExtAttr_flags2setflags(flags);
switch
(setflags)
{
case
SET_CREATEIFNEEDED:
case
SET_REPLACE:
break
;
case
SET_CREATE:
{
ssize_t sz = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
if
(sz >= 0)
{
ret = -EEXIST;
}
}
break
;
}
}
if
(ret == 0)
{
ret = extattr_set_file(path, attrnamespace, attrname, attrvalue, slen);
ret = bsd_extattr_set_succeeded(slen, ret);
}
return
ret;
}
int
bsd_fsetxattr (
const
int
fd,
const
char
*attrname,
const
char
*attrvalue,
const
size_t
slen,
struct
hv *flags)
{
int
attrnamespace = -1;
int
ret = 0;
if
(!valid_namespace(flags, &attrnamespace))
{
ret = -EOPNOTSUPP;
}
if
(ret == 0)
{
File_ExtAttr_setflags_t setflags = File_ExtAttr_flags2setflags(flags);
switch
(setflags)
{
case
SET_CREATEIFNEEDED:
case
SET_REPLACE:
break
;
case
SET_CREATE:
{
ssize_t sz = extattr_get_fd(fd, attrnamespace, attrname, NULL, 0);
if
(sz >= 0)
{
ret = -EEXIST;
}
}
break
;
}
}
if
(ret == 0)
{
ret = extattr_set_fd(fd, attrnamespace, attrname, attrvalue, slen);
ret = bsd_extattr_set_succeeded(slen, ret);
}
return
ret;
}
int
bsd_getxattr (
const
char
*path,
const
char
*attrname,
void
*attrvalue,
const
size_t
slen,
struct
hv *flags)
{
int
attrnamespace = -1;
int
ret = 0;
if
(!valid_namespace(flags, &attrnamespace))
{
ret = -EOPNOTSUPP;
}
if
(ret == 0) {
ret = extattr_get_file(path, attrnamespace, attrname, attrvalue, slen);
if
(ret < 0) {
ret = -
errno
;
}
}
return
ret;
}
int
bsd_fgetxattr (
const
int
fd,
const
char
*attrname,
void
*attrvalue,
const
size_t
slen,
struct
hv *flags)
{
int
attrnamespace = -1;
int
ret = 0;
if
(!valid_namespace(flags, &attrnamespace))
{
ret = -EOPNOTSUPP;
}
if
(ret == 0) {
ret = extattr_get_fd(fd, attrnamespace, attrname, attrvalue, slen);
if
(ret < 0) {
ret = -
errno
;
}
}
return
ret;
}
int
bsd_removexattr (
const
char
*path,
const
char
*attrname,
struct
hv *flags)
{
int
attrnamespace = -1;
int
ret = 0;
if
(!valid_namespace(flags, &attrnamespace))
{
ret = -EOPNOTSUPP;
}
if
(ret == 0) {
ret = extattr_delete_file(path, attrnamespace, attrname);
if
(ret < 0) {
ret = -
errno
;
}
}
return
ret;
}
int
bsd_fremovexattr (
const
int
fd,
const
char
*attrname,
struct
hv *flags)
{
int
attrnamespace = -1;
int
ret = 0;
if
(!valid_namespace(flags, &attrnamespace))
{
ret = -EOPNOTSUPP;
}
if
(ret == 0) {
ret = extattr_delete_fd(fd, attrnamespace, attrname);
if
(ret < 0) {
ret = -
errno
;
}
}
return
ret;
}
static
void
reformat_list (
char
*buf,
const
ssize_t len)
{
ssize_t pos = 0;
ssize_t attrlen;
while
(pos < len)
{
attrlen = (unsigned
char
) buf[pos];
memmove
(buf + pos, buf + pos + 1, attrlen);
buf[pos + attrlen] =
'\0'
;
pos += attrlen + 1;
}
}
ssize_t
bsd_listxattr (
const
char
*path,
char
*buf,
const
size_t
buflen,
struct
hv *flags)
{
int
attrnamespace = -1;
ssize_t ret = 0;
if
(!valid_namespace(flags, &attrnamespace))
{
ret = -EOPNOTSUPP;
}
if
(ret == 0)
{
ret = extattr_list_file(path,
attrnamespace,
buflen ? buf : NULL,
buflen);
if
(buflen && (ret > 0))
reformat_list(buf, ret);
if
(ret < 0) {
ret = -
errno
;
}
}
return
ret;
}
ssize_t
bsd_flistxattr (
const
int
fd,
char
*buf,
const
size_t
buflen,
struct
hv *flags)
{
int
attrnamespace = -1;
ssize_t ret = 0;
if
(!valid_namespace(flags, &attrnamespace))
{
ret = -EOPNOTSUPP;
}
if
(ret == 0)
{
ret = extattr_list_fd(fd,
attrnamespace,
buflen ? buf : NULL,
buflen);
if
(buflen && (ret > 0))
reformat_list(buf, ret);
if
(ret < 0) {
ret = -
errno
;
}
}
return
ret;
}
static
ssize_t
listxattrns (
char
*buf,
const
size_t
buflen,
const
int
iHasUser,
const
int
iHasSystem)
{
size_t
len = 0;
ssize_t ret = 0;
if
(iHasUser)
len +=
sizeof
(NAMESPACE_USER);
if
(iHasSystem)
len +=
sizeof
(NAMESPACE_SYSTEM);
if
(buflen >= len)
{
char
*p = buf;
if
(iHasUser)
{
memcpy
(p, NAMESPACE_USER,
sizeof
(NAMESPACE_USER));
p +=
sizeof
(NAMESPACE_USER);
}
if
(iHasSystem)
{
memcpy
(p, NAMESPACE_SYSTEM,
sizeof
(NAMESPACE_SYSTEM));
p +=
sizeof
(NAMESPACE_SYSTEM);
}
ret = len;
}
else
if
(buflen == 0)
{
ret = len;
}
else
{
ret = -ERANGE;
}
return
ret;
}
ssize_t
bsd_listxattrns (
const
char
*path,
char
*buf,
const
size_t
buflen,
struct
hv *flags)
{
int
iHasUser = 0;
int
iHasSystem = 0;
ssize_t ret = 0;
ret = extattr_list_file(path, EXTATTR_NAMESPACE_USER, NULL, 0);
if
(ret > 0)
iHasUser = 1;
if
(ret >= 0)
{
ret = extattr_list_file(path, EXTATTR_NAMESPACE_SYSTEM, NULL, 0);
if
(ret > 0)
iHasSystem = 1;
if
(ret == -1 &&
errno
== EPERM)
ret = 0;
}
if
(ret >= 0)
ret = listxattrns(buf, buflen, iHasUser, iHasSystem);
return
ret;
}
ssize_t
bsd_flistxattrns (
const
int
fd,
char
*buf,
const
size_t
buflen,
struct
hv *flags)
{
int
iHasUser = 0;
int
iHasSystem = 0;
ssize_t ret;
ret = extattr_list_fd(fd, EXTATTR_NAMESPACE_USER, NULL, 0);
if
(ret > 0)
iHasUser = 1;
if
(ret >= 0)
{
ret = extattr_list_fd(fd, EXTATTR_NAMESPACE_SYSTEM, NULL, 0);
if
(ret > 0)
iHasSystem = 1;
if
(ret == -1 &&
errno
== EPERM)
ret = 0;
}
if
(ret >= 0)
ret = listxattrns(buf, buflen, iHasUser, iHasSystem);
return
ret;
}
#endif /* EXTATTR_BSD */