diff options
author | jhb <jhb@FreeBSD.org> | 2009-02-06 22:24:03 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2009-02-06 22:24:03 +0000 |
commit | fd7651dce022eb1cff7f7bdbf2f7289d3c7f4acf (patch) | |
tree | fd8b25280a974acccae27b9ccd42c2c58e603194 /sys | |
parent | c9a51b47827cb4aa2e2ba3db872e58d5d267ead1 (diff) | |
download | FreeBSD-src-fd7651dce022eb1cff7f7bdbf2f7289d3c7f4acf.zip FreeBSD-src-fd7651dce022eb1cff7f7bdbf2f7289d3c7f4acf.tar.gz |
Add rudimentary support for symbolic links on UDF. Links are stored as a
sequence of pathname components. We walk the list building a string in
the caller's passed in buffer. Currently this only handles path names
in CS8 (character set 8) as that is what mkisofs generates for UDF images.
MFC after: 1 month
Diffstat (limited to 'sys')
-rw-r--r-- | sys/fs/udf/ecma167-udf.h | 12 | ||||
-rw-r--r-- | sys/fs/udf/udf_vnops.c | 115 |
2 files changed, 124 insertions, 3 deletions
diff --git a/sys/fs/udf/ecma167-udf.h b/sys/fs/udf/ecma167-udf.h index 2d78758..30f8c8e 100644 --- a/sys/fs/udf/ecma167-udf.h +++ b/sys/fs/udf/ecma167-udf.h @@ -354,6 +354,18 @@ struct file_entry { #define UDF_FENTRY_PERM_GRP_MASK 0xE0 #define UDF_FENTRY_PERM_OWNER_MASK 0x1C00 +/* Path Component [4/14.16.1] */ +struct path_component { + uint8_t type; + uint8_t length; + uint16_t version; + uint8_t identifier[0]; +} __packed; +#define UDF_PATH_ROOT 2 +#define UDF_PATH_DOTDOT 3 +#define UDF_PATH_DOT 4 +#define UDF_PATH_PATH 5 + union dscrptr { struct desc_tag tag; struct anchor_vdp avdp; diff --git a/sys/fs/udf/udf_vnops.c b/sys/fs/udf/udf_vnops.c index 4b03b9d..a80c3ce 100644 --- a/sys/fs/udf/udf_vnops.c +++ b/sys/fs/udf/udf_vnops.c @@ -859,12 +859,121 @@ udf_readdir(struct vop_readdir_args *a) return (error); } -/* Are there any implementations out there that do soft-links? */ static int udf_readlink(struct vop_readlink_args *ap) { - printf("%s called\n", __func__); - return (EOPNOTSUPP); + struct path_component *pc, *end; + struct vnode *vp; + struct uio uio; + struct iovec iov[1]; + struct udf_node *node; + void *buf; + char *cp; + int error, len, root; + + /* + * A symbolic link in UDF is a list of variable-length path + * component structures. We build a pathname in the caller's + * uio by traversing this list. + */ + vp = ap->a_vp; + node = VTON(vp); + len = le64toh(node->fentry->inf_len); + buf = malloc(iov[0].iov_len, M_DEVBUF, M_WAITOK); + iov[0].iov_base = buf; + iov[0].iov_len = len; + uio.uio_iov = iov; + uio.uio_iovcnt = 1; + uio.uio_offset = 0; + uio.uio_resid = iov[0].iov_len; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_READ; + uio.uio_td = curthread; + error = VOP_READ(vp, &uio, 0, ap->a_cred); + if (error) + goto error; + + pc = buf; + end = (void *)((char *)buf + len); + root = 0; + while (pc < end) { + switch (pc->type) { + case UDF_PATH_ROOT: + /* Only allow this at the beginning of a path. */ + if ((void *)pc != buf) { + error = EINVAL; + goto error; + } + cp = "/"; + len = 1; + root = 1; + break; + case UDF_PATH_DOT: + cp = "."; + len = 1; + break; + case UDF_PATH_DOTDOT: + cp = ".."; + len = 2; + break; + case UDF_PATH_PATH: + if (pc->length == 0) { + error = EINVAL; + goto error; + } + /* + * XXX: We only support CS8 which appears to map + * to ASCII directly. + */ + switch (pc->identifier[0]) { + case 8: + cp = pc->identifier + 1; + len = pc->length - 1; + break; + default: + error = EOPNOTSUPP; + goto error; + } + break; + default: + error = EINVAL; + goto error; + } + + /* + * If this is not the first component, insert a path + * separator. + */ + if (pc != buf) { + /* If we started with root we already have a "/". */ + if (root) + goto skipslash; + root = 0; + if (ap->a_uio->uio_resid < 1) { + error = ENAMETOOLONG; + goto error; + } + error = uiomove("/", 1, ap->a_uio); + if (error) + break; + } + skipslash: + + /* Append string at 'cp' of length 'len' to our path. */ + if (len > ap->a_uio->uio_resid) { + error = ENAMETOOLONG; + goto error; + } + error = uiomove(cp, len, ap->a_uio); + if (error) + break; + + /* Advance to next component. */ + pc = (void *)((char *)pc + 4 + pc->length); + } +error: + free(buf, M_DEVBUF); + return (error); } static int |