#include <sys/fsevents.h>
#include <sys/kernel.h>
#include <sys/kauth.h>
-#include <sys/malloc.h>
+#include <kern/kalloc.h>
#include <sys/mount_internal.h>
#include <sys/namei.h>
#include <sys/proc_internal.h>
}
/* The offset can only be non-zero for resource forks. */
if (uio != NULL && uio_offset(uio) != 0 &&
- bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
+ strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
error = EINVAL;
goto out;
}
/* The offset can only be non-zero for resource forks. */
if (uio != NULL && uio_offset(uio) != 0 &&
- bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
+ strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
error = EINVAL;
goto out;
}
}
/* The offset can only be non-zero for resource forks. */
if (uio_offset(uio) != 0 &&
- bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
+ strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
error = EINVAL;
goto out;
}
int
xattr_validatename(const char *name)
{
- int namelen;
+ size_t namelen;
if (name == NULL || name[0] == '\0') {
return EINVAL;
}
namelen = strlen(name);
- if (name[namelen] != '\0') {
- return ENAMETOOLONG;
- }
if (utf8_validatestr((const unsigned char *)name, namelen) != 0) {
return EINVAL;
*/
vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_NAMEDSTREAM_PARENT);
+ if (vnode_isdyldsharedcache(vp)) {
+ vnode_lock_spin(svp);
+ svp->v_flag |= VSHARED_DYLD;
+ vnode_unlock(svp);
+ }
+
return;
}
cn.cn_pnbuf = tmpname;
cn.cn_pnlen = sizeof(tmpname);
cn.cn_nameptr = cn.cn_pnbuf;
- cn.cn_namelen = strlen(tmpname);
+ cn.cn_namelen = (int)strlen(tmpname);
/*
* Obtain the vnode for the shadow files directory. Make sure to
!VATTR_IS_SUPPORTED(&va, va_data_size)) {
return 0;
}
- datasize = va.va_data_size;
+ if (va.va_data_size > UINT32_MAX) {
+ return EINVAL;
+ }
+ datasize = (size_t)va.va_data_size;
if (datasize == 0) {
(void) default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
return 0;
cn.cn_pnbuf = tmpname;
cn.cn_pnlen = sizeof(tmpname);
cn.cn_nameptr = cn.cn_pnbuf;
- cn.cn_namelen = strlen(tmpname);
+ cn.cn_namelen = (int)strlen(tmpname);
if (VNOP_LOOKUP(shadow_dvp, &shadowfile, &cn, kernelctx) == 0) {
/* is the pointer the same? */
cn.cn_pnbuf = tmpname;
cn.cn_pnlen = sizeof(tmpname);
cn.cn_nameptr = cn.cn_pnbuf;
- cn.cn_namelen = strlen(tmpname);
+ cn.cn_namelen = (int)strlen(tmpname);
/* Pick up uid, gid, mode and date from original file. */
VATTR_INIT(&va);
/*
* Only the "com.apple.ResourceFork" stream is supported here.
*/
- if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
+ if (strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
*svpp = NULLVP;
return ENOATTR;
}
/*
* Only the "com.apple.ResourceFork" stream is supported here.
*/
- if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
+ if (strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
*svpp = NULLVP;
return ENOATTR;
}
/*
* Only the "com.apple.ResourceFork" stream is supported here.
*/
- if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
+ if (strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
return ENOATTR;
}
/*
cn.cn_pnbuf = tmpname;
cn.cn_pnlen = sizeof(tmpname);
cn.cn_nameptr = cn.cn_pnbuf;
- cn.cn_namelen = strlen(tmpname);
+ cn.cn_namelen = (int)strlen(tmpname);
/*
* owned by root, only readable by root, hidden
attr_header_t *header;
attr_entry_t *entry;
u_int8_t *attrdata;
- size_t datalen;
- int namelen;
+ u_int32_t datalen;
+ size_t namelen;
int isrsrcfork;
int fileflags;
int i;
int error;
fileflags = FREAD;
- if (strcmp(name, XATTR_RESOURCEFORK_NAME) == 0) {
+ if (strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) {
isrsrcfork = 1;
/*
* Open the file locked (shared) since the Carbon
}
/* Get the Finder Info. */
- if (strcmp(name, XATTR_FINDERINFO_NAME) == 0) {
+ if (strncmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
if (ainfo.finderinfo == NULL || ainfo.emptyfinderinfo) {
error = ENOATTR;
} else if (uio == NULL) {
*/
for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) {
if (strncmp((const char *)entry->name, name, namelen) == 0) {
- datalen = (size_t)entry->length;
+ datalen = entry->length;
if (uio == NULL) {
*size = datalen;
error = 0;
char finfo[FINDERINFOSIZE];
datalen = uio_resid(uio);
- namelen = strlen(name) + 1;
+ if (datalen > XATTR_MAXSIZE) {
+ return EINVAL;
+ }
+ namelen = (int)strlen(name) + 1;
+ if (namelen > UINT8_MAX) {
+ return EINVAL;
+ }
entrylen = ATTR_ENTRY_LENGTH(namelen);
/*
*
* NOTE: this copies the Finder Info data into the "finfo" local.
*/
- if (bcmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
+ if (strncmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
/*
* TODO: check the XATTR_CREATE and XATTR_REPLACE flags.
* That means we probably have to open_xattrfile and get_xattrinfo.
if (uio_offset(uio) != 0 || datalen != FINDERINFOSIZE) {
return EINVAL;
}
- error = uiomove(finfo, datalen, uio);
+ error = uiomove(finfo, (int)datalen, uio);
if (error) {
return error;
}
}
/* Set the Finder Info. */
- if (bcmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
+ if (strncmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
if (ainfo.finderinfo && !ainfo.emptyfinderinfo) {
/* attr exists and "create" was specified? */
if (options & XATTR_CREATE) {
}
/* Write the Resource Fork. */
- if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) {
- u_int32_t endoffset;
+ if (strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) {
+ off_t endoffset;
if (!vnode_isreg(vp)) {
error = EPERM;
}
endoffset = uio_resid(uio) + uio_offset(uio); /* new size */
+ if (endoffset > UINT32_MAX || endoffset < 0) {
+ error = EINVAL;
+ goto out;
+ }
uio_setoffset(uio, uio_offset(uio) + ainfo.rsrcfork->offset);
error = VNOP_WRITE(xvp, uio, 0, context);
if (error) {
}
uio_setoffset(uio, uio_offset(uio) - ainfo.rsrcfork->offset);
if (endoffset > ainfo.rsrcfork->length) {
- ainfo.rsrcfork->length = endoffset;
+ ainfo.rsrcfork->length = (u_int32_t)endoffset;
ainfo.iosize = sizeof(attr_header_t);
error = write_xattrinfo(&ainfo);
goto out;
}
} else {
attrdata = (u_int8_t *)header + entry->offset;
- error = uiomove((caddr_t)attrdata, datalen, uio);
+ error = uiomove((caddr_t)attrdata, (int)datalen, uio);
if (error) {
goto out;
}
} else {
attrdata = (u_int8_t *)header + header->data_start + header->data_length;
- error = uiomove((caddr_t)attrdata, datalen, uio);
+ error = uiomove((caddr_t)attrdata, (int)datalen, uio);
if (error) {
printf("setxattr: uiomove error %d\n", error);
goto out;
}
/* Create the attribute entry. */
- lastentry->length = datalen;
+ lastentry->length = (u_int32_t)datalen;
lastentry->offset = header->data_start + header->data_length;
- lastentry->namelen = namelen;
+ lastentry->namelen = (u_int8_t)namelen;
lastentry->flags = 0;
bcopy(name, &lastentry->name[0], namelen);
error = ENOATTR;
goto out;
}
- namelen = strlen(name) + 1;
+ namelen = (int)strlen(name) + 1;
header = ainfo.attrhdr;
entry = ainfo.attr_entry;
{
vnode_t xvp = NULLVP;
vnode_t dvp = NULLVP;
- struct vnode_attr va;
- struct nameidata nd;
+ struct vnode_attr *va = NULL;
+ struct nameidata *nd = NULL;
char smallname[64];
char *filename = NULL;
const char *basename = NULL;
len = snprintf(filename, sizeof(smallname), "%s%s", ATTR_FILE_PREFIX, basename);
if (len >= sizeof(smallname)) {
len++; /* snprintf result doesn't include '\0' */
- MALLOC(filename, char *, len, M_TEMP, M_WAITOK);
+ filename = kheap_alloc(KHEAP_TEMP, len, Z_WAITOK);
len = snprintf(filename, len, "%s%s", ATTR_FILE_PREFIX, basename);
}
/*
* file security from the EA must always get access
*/
lookup:
- NDINIT(&nd, LOOKUP, OP_OPEN, LOCKLEAF | NOFOLLOW | USEDVP | DONOTAUTH,
+ nd = kheap_alloc(KHEAP_TEMP, sizeof(struct nameidata), Z_WAITOK);
+ NDINIT(nd, LOOKUP, OP_OPEN, LOCKLEAF | NOFOLLOW | USEDVP | DONOTAUTH,
UIO_SYSSPACE, CAST_USER_ADDR_T(filename), context);
- nd.ni_dvp = dvp;
+ nd->ni_dvp = dvp;
+
+ va = kheap_alloc(KHEAP_TEMP, sizeof(struct vnode_attr), Z_WAITOK);
if (fileflags & O_CREAT) {
- nd.ni_cnd.cn_nameiop = CREATE;
+ nd->ni_cnd.cn_nameiop = CREATE;
#if CONFIG_TRIGGERS
- nd.ni_op = OP_LINK;
+ nd->ni_op = OP_LINK;
#endif
if (dvp != vp) {
- nd.ni_cnd.cn_flags |= LOCKPARENT;
+ nd->ni_cnd.cn_flags |= LOCKPARENT;
}
- if ((error = namei(&nd))) {
- nd.ni_dvp = NULLVP;
+ if ((error = namei(nd))) {
+ nd->ni_dvp = NULLVP;
error = ENOATTR;
goto out;
}
- if ((xvp = nd.ni_vp) == NULLVP) {
+ if ((xvp = nd->ni_vp) == NULLVP) {
uid_t uid;
gid_t gid;
mode_t umode;
/*
* Pick up uid/gid/mode from target file.
*/
- VATTR_INIT(&va);
- VATTR_WANTED(&va, va_uid);
- VATTR_WANTED(&va, va_gid);
- VATTR_WANTED(&va, va_mode);
- if (VNOP_GETATTR(vp, &va, context) == 0 &&
- VATTR_IS_SUPPORTED(&va, va_uid) &&
- VATTR_IS_SUPPORTED(&va, va_gid) &&
- VATTR_IS_SUPPORTED(&va, va_mode)) {
- uid = va.va_uid;
- gid = va.va_gid;
- umode = va.va_mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ VATTR_INIT(va);
+ VATTR_WANTED(va, va_uid);
+ VATTR_WANTED(va, va_gid);
+ VATTR_WANTED(va, va_mode);
+ if (VNOP_GETATTR(vp, va, context) == 0 &&
+ VATTR_IS_SUPPORTED(va, va_uid) &&
+ VATTR_IS_SUPPORTED(va, va_gid) &&
+ VATTR_IS_SUPPORTED(va, va_mode)) {
+ uid = va->va_uid;
+ gid = va->va_gid;
+ umode = va->va_mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
} else { /* fallback values */
uid = KAUTH_UID_NONE;
gid = KAUTH_GID_NONE;
umode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
}
- VATTR_INIT(&va);
- VATTR_SET(&va, va_type, VREG);
- VATTR_SET(&va, va_mode, umode);
+ VATTR_INIT(va);
+ VATTR_SET(va, va_type, VREG);
+ VATTR_SET(va, va_mode, umode);
if (uid != KAUTH_UID_NONE) {
- VATTR_SET(&va, va_uid, uid);
+ VATTR_SET(va, va_uid, uid);
}
if (gid != KAUTH_GID_NONE) {
- VATTR_SET(&va, va_gid, gid);
+ VATTR_SET(va, va_gid, gid);
}
- error = vn_create(dvp, &nd.ni_vp, &nd, &va,
+ error = vn_create(dvp, &nd->ni_vp, nd, va,
VN_CREATE_NOAUTH | VN_CREATE_NOINHERIT | VN_CREATE_NOLABEL,
0, NULL,
context);
if (error) {
error = ENOATTR;
} else {
- xvp = nd.ni_vp;
+ xvp = nd->ni_vp;
}
}
- nameidone(&nd);
+ nameidone(nd);
if (dvp != vp) {
vnode_put(dvp); /* drop iocount from LOCKPARENT request above */
}
goto out;
}
} else {
- if ((error = namei(&nd))) {
- nd.ni_dvp = NULLVP;
+ if ((error = namei(nd))) {
+ nd->ni_dvp = NULLVP;
error = ENOATTR;
goto out;
}
- xvp = nd.ni_vp;
- nameidone(&nd);
+ xvp = nd->ni_vp;
+ nameidone(nd);
}
- nd.ni_dvp = NULLVP;
+ nd->ni_dvp = NULLVP;
if (xvp->v_type != VREG) {
error = ENOATTR;
/*
* Owners must match.
*/
- VATTR_INIT(&va);
- VATTR_WANTED(&va, va_uid);
- if (VNOP_GETATTR(vp, &va, context) == 0 && VATTR_IS_SUPPORTED(&va, va_uid)) {
- uid_t owner = va.va_uid;
-
- VATTR_INIT(&va);
- VATTR_WANTED(&va, va_uid);
- if (VNOP_GETATTR(xvp, &va, context) == 0 && (owner != va.va_uid)) {
+ VATTR_INIT(va);
+ VATTR_WANTED(va, va_uid);
+ if (VNOP_GETATTR(vp, va, context) == 0 && VATTR_IS_SUPPORTED(va, va_uid)) {
+ uid_t owner = va->va_uid;
+
+ VATTR_INIT(va);
+ VATTR_WANTED(va, va_uid);
+ if (VNOP_GETATTR(xvp, va, context) == 0 && (owner != va->va_uid)) {
error = ENOATTR; /* don't use this "._" file */
goto out;
}
/* If create was requested, make sure file header exists. */
if (fileflags & O_CREAT) {
- VATTR_INIT(&va);
- VATTR_WANTED(&va, va_data_size);
- VATTR_WANTED(&va, va_fileid);
- VATTR_WANTED(&va, va_nlink);
- if ((error = vnode_getattr(xvp, &va, context)) != 0) {
+ VATTR_INIT(va);
+ VATTR_WANTED(va, va_data_size);
+ VATTR_WANTED(va, va_fileid);
+ VATTR_WANTED(va, va_nlink);
+ if ((error = vnode_getattr(xvp, va, context)) != 0) {
error = EPERM;
goto out;
}
/* If the file is empty then add a default header. */
- if (va.va_data_size == 0) {
+ if (va->va_data_size == 0) {
/* Don't adopt hard-linked "._" files. */
- if (VATTR_IS_SUPPORTED(&va, va_nlink) && va.va_nlink > 1) {
+ if (VATTR_IS_SUPPORTED(va, va_nlink) && va->va_nlink > 1) {
error = EPERM;
goto out;
}
- if ((error = create_xattrfile(xvp, (u_int32_t)va.va_fileid, context))) {
+ if ((error = create_xattrfile(xvp, (u_int32_t)va->va_fileid, context))) {
goto out;
}
}
}
}
/* Release resources after error-handling */
+ kheap_free(KHEAP_TEMP, nd, sizeof(struct nameidata));
+ kheap_free(KHEAP_TEMP, va, sizeof(struct vnode_attr));
if (dvp && (dvp != vp)) {
vnode_put(dvp);
}
vnode_putname(basename);
}
if (filename && filename != &smallname[0]) {
- FREE(filename, M_TEMP);
+ kheap_free(KHEAP_TEMP, filename, len);
}
*xvpp = xvp; /* return a referenced vnode */
int pathlen;
int error = 0;
- MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
- if (path == NULL) {
- return ENOMEM;
- }
-
+ path = zalloc(ZV_NAMEI);
pathlen = MAXPATHLEN;
error = vn_getpath(xvp, path, &pathlen);
if (error) {
- FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
+ zfree(ZV_NAMEI, path);
return error;
}
NDINIT(&nd, DELETE, OP_UNLINK, LOCKPARENT | NOFOLLOW | DONOTAUTH,
UIO_SYSSPACE, CAST_USER_ADDR_T(path), context);
error = namei(&nd);
- FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
+ zfree(ZV_NAMEI, path);
if (error) {
return error;
}
void * buffer = NULL;
apple_double_header_t *filehdr;
struct vnode_attr va;
- size_t iosize;
+ size_t iosize = 0;
int i;
int error;
goto bail;
}
ainfop->iosize = iosize;
- MALLOC(buffer, void *, iosize, M_TEMP, M_WAITOK);
+ buffer = kheap_alloc(KHEAP_DATA_BUFFERS, iosize, Z_WAITOK);
if (buffer == NULL) {
error = ENOMEM;
goto bail;
if (auio != NULL) {
uio_free(auio);
}
- if (buffer != NULL) {
- FREE(buffer, M_TEMP);
- }
+ kheap_free(KHEAP_DATA_BUFFERS, buffer, iosize);
return error;
}
int rsrcforksize;
int error;
- MALLOC(buffer, void *, ATTR_BUF_SIZE, M_TEMP, M_WAITOK);
+ buffer = kheap_alloc(KHEAP_TEMP, ATTR_BUF_SIZE, Z_WAITOK);
bzero(buffer, ATTR_BUF_SIZE);
xah = (attr_header_t *)buffer;
}
uio_free(auio);
- FREE(buffer, M_TEMP);
+ kheap_free(KHEAP_TEMP, buffer, ATTR_BUF_SIZE);
return error;
}
static void
rel_xattrinfo(attr_info_t *ainfop)
{
- FREE(ainfop->filehdr, M_TEMP);
+ kheap_free_addr(KHEAP_DATA_BUFFERS, ainfop->filehdr);
bzero(ainfop, sizeof(attr_info_t));
}
}
/* Make sure the variable-length name fits (+1 is for NUL terminator) */
- /* TODO: Make sure namelen matches strnlen(name,namelen+1)? */
if (&ae->name[ae->namelen + 1] > buf_end) {
return EINVAL;
}
+ /* Make sure that namelen is matching name's real length, namelen included NUL */
+ if (strnlen((const char *)ae->name, ae->namelen) != ae->namelen - 1) {
+ return EINVAL;
+ }
+
+
/* Swap the attribute entry fields */
ae->offset = SWAP32(ae->offset);
ae->length = SWAP32(ae->length);
ae->flags = SWAP16(ae->flags);
- /* Make sure the attribute content fits. */
+ /* Make sure the attribute content fits and points to the data part */
end = ae->offset + ae->length;
if (end < ae->offset || end > ah->total_size) {
return EINVAL;
}
+ /* Make sure entry points to data section and not header */
+ if (ae->offset < ah->data_start) {
+ return EINVAL;
+ }
+
ae = ATTR_NEXT(ae);
}
- /*
- * TODO: Make sure the contents of attributes don't overlap the header
- * and don't overlap each other. The hard part is that we don't know
- * what the actual header size is until we have looped over all of the
- * variable-sized attribute entries.
- *
- * XXX Is there any guarantee that attribute entries are stored in
- * XXX order sorted by the contents' file offset? If so, that would
- * XXX make the pairwise overlap check much easier.
- */
-
return 0;
}
}
for (pos = start + len - chunk; pos >= start; pos -= chunk) {
- ret = vn_rdwr(UIO_READ, xvp, buff, chunk, pos, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
+ ret = vn_rdwr(UIO_READ, xvp, buff, (int)chunk, pos, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
if (iolen != 0) {
printf("xattr:shift_data: error reading data @ %lld (read %d of %lu) (%d)\n",
pos, ret, chunk, ret);
break;
}
- ret = vn_rdwr(UIO_WRITE, xvp, buff, chunk, pos + delta, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
+ ret = vn_rdwr(UIO_WRITE, xvp, buff, (int)chunk, pos + delta, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
if (iolen != 0) {
printf("xattr:shift_data: error writing data @ %lld (wrote %d of %lu) (%d)\n",
pos + delta, ret, chunk, ret);
}
for (pos = start; pos < end; pos += chunk) {
- ret = vn_rdwr(UIO_READ, xvp, buff, chunk, pos, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
+ ret = vn_rdwr(UIO_READ, xvp, buff, (int)chunk, pos, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
if (iolen != 0) {
printf("xattr:shift_data: error reading data @ %lld (read %d of %lu) (%d)\n",
pos, ret, chunk, ret);
break;
}
- ret = vn_rdwr(UIO_WRITE, xvp, buff, chunk, pos - delta, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
+ ret = vn_rdwr(UIO_WRITE, xvp, buff, (int)chunk, pos - delta, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
if (iolen != 0) {
printf("xattr:shift_data: error writing data @ %lld (wrote %d of %lu) (%d)\n",
pos + delta, ret, chunk, ret);