#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include "portable.h"
#define MAX_INITIAL_VALUELEN_VARNAME "File::ExtAttr::MAX_INITIAL_VALUELEN"
/* Richard, fixme! */
MODULE = File::ExtAttr PACKAGE = File::ExtAttr
PROTOTYPES: ENABLE
int
_setfattr (path, attrname, attrvalueSV, flags = 0)
const char *path
const char *attrname
SV * attrvalueSV
HV * flags
PREINIT:
STRLEN slen;
char * attrvalue;
int rc;
CODE:
attrvalue = SvPV(attrvalueSV, slen);
rc = portable_setxattr(path, attrname, attrvalue, slen, flags);
if (rc < 0)
errno = -rc;
RETVAL = (rc == 0);
OUTPUT:
RETVAL
int
_fsetfattr (fd, attrname, attrvalueSV, flags = 0)
int fd
const char *attrname
SV * attrvalueSV
HV * flags
PREINIT:
STRLEN slen;
char * attrvalue;
int rc;
CODE:
attrvalue = SvPV(attrvalueSV, slen);
rc = portable_fsetxattr(fd, attrname, attrvalue, slen, flags);
if (rc < 0)
errno = -rc;
RETVAL = (rc == 0);
OUTPUT:
RETVAL
SV *
_getfattr(path, attrname, flags = 0)
const char *path
const char *attrname
HV * flags
PREINIT:
char * attrvalue;
int attrlen;
ssize_t buflen;
CODE:
buflen = portable_lenxattr(path, attrname, flags);
if (buflen <= 0)
buflen = SvIV(get_sv(MAX_INITIAL_VALUELEN_VARNAME, FALSE));
attrvalue = NULL;
Newz(1, attrvalue, buflen, char);
attrlen = portable_getxattr(path, attrname, attrvalue, buflen, flags);
if (attrlen < 0){
//key not found, just return undef
if(errno == ENOATTR){
Safefree(attrvalue);
errno = -attrlen;
XSRETURN_UNDEF;
//return undef
}else{
Safefree(attrvalue);
errno = -attrlen;
XSRETURN_UNDEF;
}
}
RETVAL = newSVpv(attrvalue, attrlen);
Safefree(attrvalue);
OUTPUT:
RETVAL
SV *
_fgetfattr(fd, attrname, flags = 0)
int fd
const char *attrname
HV * flags
PREINIT:
char * attrvalue;
int attrlen;
ssize_t buflen;
CODE:
buflen = portable_flenxattr(fd, attrname, flags);
if (buflen <= 0)
buflen = SvIV(get_sv(MAX_INITIAL_VALUELEN_VARNAME, FALSE));
attrvalue = NULL;
Newz(1, attrvalue, buflen, char);
attrlen = portable_fgetxattr(fd, attrname, attrvalue, buflen, flags);
if (attrlen < 0){
//key not found, just return undef
if(errno == ENOATTR){
Safefree(attrvalue);
errno = -attrlen;
XSRETURN_UNDEF;
//return undef
}else{
Safefree(attrvalue);
errno = -attrlen;
XSRETURN_UNDEF;
}
}
RETVAL = newSVpv(attrvalue, attrlen);
Safefree(attrvalue);
OUTPUT:
RETVAL
int
_delfattr (path, attrname, flags = 0)
const char *path
const char *attrname
HV * flags
PREINIT:
int rc;
CODE:
rc = portable_removexattr(path, attrname, flags);
if (rc < 0)
errno = -rc;
RETVAL = (rc == 0);
OUTPUT:
RETVAL
int
_fdelfattr (fd, attrname, flags = 0)
int fd
const char *attrname
HV * flags
PREINIT:
int rc;
CODE:
rc = portable_fremovexattr(fd, attrname, flags);
if (rc < 0)
errno = -rc;
RETVAL = (rc == 0);
OUTPUT:
RETVAL
void
_listfattr (path, fd, flags = 0)
const char *path
int fd
HV * flags
PREINIT:
ssize_t size, ret;
char *namebuf = NULL;
char *nameptr;
PPCODE:
if(fd == -1)
size = portable_listxattr(path, NULL, 0, flags);
else
size = portable_flistxattr(fd, NULL, 0, flags);
if (size < 0)
{
errno = -(int) size;
XSRETURN_UNDEF;
} else if (size == 0)
{
XSRETURN_EMPTY;
}
namebuf = malloc(size);
if (fd == -1)
ret = portable_listxattr(path, namebuf, size, flags);
else
ret = portable_flistxattr(fd, namebuf, size, flags);
// There could be a race condition here, if someone adds a new
// attribute between the two listxattr calls. However it just means we
// might return ERANGE.
if (ret < 0)
{
free(namebuf);
errno = -ret;
XSRETURN_UNDEF;
} else if (ret == 0)
{
free(namebuf);
XSRETURN_EMPTY;
}
nameptr = namebuf;
while(nameptr < namebuf + ret)
{
char *endptr = nameptr;
while(*endptr++ != '\0');
// endptr will now point one past the end..
XPUSHs(sv_2mortal(newSVpvn(nameptr, endptr - nameptr - 1)));
// nameptr could now point past the end of namebuf
nameptr = endptr;
}
free(namebuf);
void
_listfattrns (path, fd, flags = 0)
const char *path
int fd
HV * flags
PREINIT:
ssize_t size, ret;
char *namebuf = NULL;
char *nameptr;
PPCODE:
if(fd == -1)
size = portable_listxattrns(path, NULL, 0, flags);
else
size = portable_flistxattrns(fd, NULL, 0, flags);
if (size < 0)
{
errno = -(int) size;
XSRETURN_UNDEF;
} else if (size == 0)
{
XSRETURN_EMPTY;
}
namebuf = malloc(size);
if (fd == -1)
ret = portable_listxattrns(path, namebuf, size, flags);
else
ret = portable_flistxattrns(fd, namebuf, size, flags);
// There could be a race condition here, if someone adds a new
// attribute between the two listxattr calls. However it just means we
// might return ERANGE.
if (ret < 0)
{
free(namebuf);
errno = -ret;
XSRETURN_UNDEF;
} else if (ret == 0)
{
free(namebuf);
XSRETURN_EMPTY;
}
nameptr = namebuf;
while(nameptr < namebuf + ret)
{
char *endptr = nameptr;
while(*endptr++ != '\0');
// endptr will now point one past the end..
XPUSHs(sv_2mortal(newSVpvn(nameptr, endptr - nameptr - 1)));
// nameptr could now point past the end of namebuf
nameptr = endptr;
}
free(namebuf);