Module Name: src Committed By: reinoud Date: Tue Jul 29 15:48:22 UTC 2014
Modified Files: src/sys/fs/udf: udf_vnops.c Log Message: Posix requires the va_size of a symlink to be pathlength for symbolic links. This fixes yet another atf case. To generate a diff of this commit: cvs rdiff -u -r1.93 -r1.94 src/sys/fs/udf/udf_vnops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/fs/udf/udf_vnops.c diff -u src/sys/fs/udf/udf_vnops.c:1.93 src/sys/fs/udf/udf_vnops.c:1.94 --- src/sys/fs/udf/udf_vnops.c:1.93 Tue Jul 29 11:10:12 2014 +++ src/sys/fs/udf/udf_vnops.c Tue Jul 29 15:48:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: udf_vnops.c,v 1.93 2014/07/29 11:10:12 reinoud Exp $ */ +/* $NetBSD: udf_vnops.c,v 1.94 2014/07/29 15:48:22 reinoud Exp $ */ /* * Copyright (c) 2006, 2008 Reinoud Zandijk @@ -32,7 +32,7 @@ #include <sys/cdefs.h> #ifndef lint -__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.93 2014/07/29 11:10:12 reinoud Exp $"); +__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.94 2014/07/29 15:48:22 reinoud Exp $"); #endif /* not lint */ @@ -67,6 +67,9 @@ __KERNEL_RCSID(0, "$NetBSD: udf_vnops.c, #define VTOI(vnode) ((struct udf_node *) (vnode)->v_data) +/* forward declarations */ +static int udf_do_readlink(struct udf_node *udf_node, uint64_t filesize, + uint8_t *targetbuf, int *length); /* externs */ extern int prtactive; @@ -865,10 +868,10 @@ udf_getattr(void *v) uint64_t filesize, blkssize; uint32_t nlink; uint32_t offset, a_l; - uint8_t *filedata; + uint8_t *filedata, *targetbuf; uid_t uid; gid_t gid; - int error; + int length, error; DPRINTF(CALL, ("udf_getattr called\n")); @@ -939,6 +942,22 @@ udf_getattr(void *v) if (vap->va_type == VDIR) vap->va_nlink++; + /* + * BUG-ALERT: Posix requires the va_size to be pathlength for symbolic + * links. + */ + if (vap->va_type == VLNK) { + /* claim temporary buffers for translation */ + targetbuf = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK); + error = udf_do_readlink(udf_node, filesize, targetbuf, &length); + if (!error) { + vap->va_size = length; + KASSERT(length == strlen(targetbuf)); + } + free(targetbuf, M_UDFTEMP); + /* XXX return error? */ + } + /* access times */ udf_timestamp_to_timespec(ump, atime, &vap->va_atime); udf_timestamp_to_timespec(ump, mtime, &vap->va_mtime); @@ -1730,49 +1749,30 @@ udf_symlink(void *v) /* --------------------------------------------------------------------- */ -int -udf_readlink(void *v) +static int +udf_do_readlink(struct udf_node *udf_node, uint64_t filesize, + uint8_t *targetbuf, int *length) { - struct vop_readlink_args /* { - struct vnode *a_vp; - struct uio *a_uio; - kauth_cred_t a_cred; - } */ *ap = v; - struct vnode *vp = ap->a_vp; - struct uio *uio = ap->a_uio; - kauth_cred_t cred = ap->a_cred; - struct udf_node *udf_node; struct pathcomp pathcomp; - struct vattr vattr; - uint8_t *pathbuf, *targetbuf, *tmpname; + uint8_t *pathbuf, *tmpname; uint8_t *pathpos, *targetpos; char *mntonname; int pathlen, targetlen, namelen, mntonnamelen, len, l_ci; int first, error; - DPRINTF(CALL, ("udf_readlink called\n")); - - udf_node = VTOI(vp); - error = VOP_GETATTR(vp, &vattr, cred); - if (error) - return error; - - /* claim temporary buffers for translation */ pathbuf = malloc(UDF_SYMLINKBUFLEN, M_UDFTEMP, M_WAITOK); - targetbuf = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK); tmpname = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK); memset(pathbuf, 0, UDF_SYMLINKBUFLEN); memset(targetbuf, 0, PATH_MAX); /* read contents of file in our temporary buffer */ error = vn_rdwr(UIO_READ, udf_node->vnode, - pathbuf, vattr.va_size, 0, + pathbuf, filesize, 0, UIO_SYSSPACE, IO_NODELOCKED | IO_ALTSEMANTICS, FSCRED, NULL, NULL); if (error) { /* failed to read in symlink contents */ free(pathbuf, M_UDFTEMP); - free(targetbuf, M_UDFTEMP); free(tmpname, M_UDFTEMP); return error; } @@ -1787,7 +1787,7 @@ udf_readlink(void *v) error = 0; first = 1; - while (vattr.va_size - pathlen >= UDF_PATH_COMP_SIZE) { + while (filesize - pathlen >= UDF_PATH_COMP_SIZE) { len = UDF_PATH_COMP_SIZE; memcpy(&pathcomp, pathpos, len); l_ci = pathcomp.l_ci; @@ -1808,7 +1808,7 @@ udf_readlink(void *v) } memcpy(targetpos, mntonname, mntonnamelen); targetpos += mntonnamelen; targetlen -= mntonnamelen; - if (vattr.va_size-pathlen > UDF_PATH_COMP_SIZE+l_ci) { + if (filesize-pathlen > UDF_PATH_COMP_SIZE+l_ci) { /* more follows, so must be directory */ *targetpos++ = '/'; targetlen--; } @@ -1849,7 +1849,7 @@ udf_readlink(void *v) } memcpy(targetpos, tmpname, namelen); targetpos += namelen; targetlen -= namelen; - if (vattr.va_size-pathlen > UDF_PATH_COMP_SIZE+l_ci) { + if (filesize-pathlen > UDF_PATH_COMP_SIZE+l_ci) { /* more follows, so must be directory */ *targetpos++ = '/'; targetlen--; } @@ -1866,17 +1866,54 @@ udf_readlink(void *v) } /* all processed? */ - if (vattr.va_size - pathlen > 0) + if (filesize - pathlen > 0) error = EINVAL; + free(pathbuf, M_UDFTEMP); + free(tmpname, M_UDFTEMP); + + *length = PATH_MAX - targetlen; + return error; +} + + +int +udf_readlink(void *v) +{ + struct vop_readlink_args /* { + struct vnode *a_vp; + struct uio *a_uio; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct udf_node *udf_node = VTOI(vp); + struct file_entry *fe = udf_node->fe; + struct extfile_entry *efe = udf_node->efe; + struct uio *uio = ap->a_uio; + uint64_t filesize; + uint8_t *targetbuf; + int length; + int error; + + DPRINTF(CALL, ("udf_readlink called\n")); + + if (fe) { + filesize = udf_rw64(fe->inf_len); + } else { + assert(udf_node->efe); + filesize = udf_rw64(efe->inf_len); + } + + /* claim temporary buffers for translation */ + targetbuf = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK); + + error = udf_do_readlink(udf_node, filesize, targetbuf, &length); + /* uiomove() to destination */ if (!error) - uiomove(targetbuf, PATH_MAX - targetlen, uio); + uiomove(targetbuf, length, uio); - free(pathbuf, M_UDFTEMP); free(targetbuf, M_UDFTEMP); - free(tmpname, M_UDFTEMP); - return error; }