diff options
author | Ian Dowse <iedowse@FreeBSD.org> | 2002-09-01 21:15:37 +0000 |
---|---|---|
committer | Ian Dowse <iedowse@FreeBSD.org> | 2002-09-01 21:15:37 +0000 |
commit | ff7663218920232f9a9f8cb5d69a4941bdf9d066 (patch) | |
tree | 34bd9f42149c266a29158d0370095f104a0b9600 /sys/compat/linux/linux_util.c | |
parent | ed7ada7c1086f538478775846edf6d0de6d88bc1 (diff) |
Add a new function linux_emul_convpath(), which is a version of
linux_emul_find() that does not use stack gap storage but instead
always returns the resulting path in a malloc'd kernel buffer.
Implement linux_emul_find() in terms of this function. Also add
LCONVPATH* macros that wrap linux_emul_convpath in the same way
that the CHECKALT* macros wrap linux_emul_find().
Notes
Notes:
svn path=/head/; revision=102803
Diffstat (limited to 'sys/compat/linux/linux_util.c')
-rw-r--r-- | sys/compat/linux/linux_util.c | 80 |
1 files changed, 48 insertions, 32 deletions
diff --git a/sys/compat/linux/linux_util.c b/sys/compat/linux/linux_util.c index 4949a451bee2..7b34586966e2 100644 --- a/sys/compat/linux/linux_util.c +++ b/sys/compat/linux/linux_util.c @@ -57,6 +57,39 @@ linux_emul_find(td, sgp, path, pbuf, cflag) char **pbuf; int cflag; { + char *newpath; + size_t sz; + int error; + + error = linux_emul_convpath(td, path, (sgp == NULL) ? UIO_SYSSPACE : + UIO_USERSPACE, &newpath, cflag); + if (newpath == NULL) + return (error); + + if (sgp == NULL) { + *pbuf = newpath; + return (error); + } + + sz = strlen(newpath); + *pbuf = stackgap_alloc(sgp, sz + 1); + if (*pbuf != NULL) + error = copyout(newpath, *pbuf, sz + 1); + else + error = ENAMETOOLONG; + free(newpath, M_TEMP); + + return (error); +} + +int +linux_emul_convpath(td, path, pathseg, pbuf, cflag) + struct thread *td; + char *path; + enum uio_seg pathseg; + char **pbuf; + int cflag; +{ struct nameidata nd; struct nameidata ndroot; struct vattr vat; @@ -64,32 +97,30 @@ linux_emul_find(td, sgp, path, pbuf, cflag) int error; const char *prefix; char *ptr, *buf, *cp; - size_t sz, len; + size_t len, sz; buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK); - *pbuf = path; + *pbuf = buf; prefix = linux_emul_path; for (ptr = buf; (*ptr = *prefix) != '\0'; ptr++, prefix++) continue; sz = MAXPATHLEN - (ptr - buf); - /* - * If sgp is not given then the path is already in kernel space - */ - if (sgp == NULL) + if (pathseg == UIO_SYSSPACE) error = copystr(path, ptr, sz, &len); else error = copyinstr(path, ptr, sz, &len); if (error) { + *pbuf = NULL; free(buf, M_TEMP); return error; } if (*ptr != '/') { - free(buf, M_TEMP); - return EINVAL; + error = EINVAL; + goto keeporig; } /* @@ -105,21 +136,16 @@ linux_emul_find(td, sgp, path, pbuf, cflag) *cp = '\0'; NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td); - - if ((error = namei(&nd)) != 0) { - free(buf, M_TEMP); - return error; - } - + error = namei(&nd); *cp = '/'; + if (error != 0) + goto keeporig; } else { NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td); - if ((error = namei(&nd)) != 0) { - free(buf, M_TEMP); - return error; - } + if ((error = namei(&nd)) != 0) + goto keeporig; /* * We now compare the vnode of the linux_root to the one @@ -134,10 +160,9 @@ linux_emul_find(td, sgp, path, pbuf, cflag) if ((error = namei(&ndroot)) != 0) { /* Cannot happen! */ - free(buf, M_TEMP); NDFREE(&nd, NDF_ONLY_PNBUF); vrele(nd.ni_vp); - return error; + goto keeporig; } if ((error = VOP_GETATTR(nd.ni_vp, &vat, td->td_ucred, td)) != 0) { @@ -156,17 +181,6 @@ linux_emul_find(td, sgp, path, pbuf, cflag) } } - if (sgp == NULL) - *pbuf = buf; - else { - sz = &ptr[len] - buf; - *pbuf = stackgap_alloc(sgp, sz + 1); - if (*pbuf != NULL) - error = copyout(buf, *pbuf, sz); - else - error = ENAMETOOLONG; - free(buf, M_TEMP); - } NDFREE(&nd, NDF_ONLY_PNBUF); vrele(nd.ni_vp); @@ -181,6 +195,8 @@ bad: vrele(ndroot.ni_vp); NDFREE(&nd, NDF_ONLY_PNBUF); vrele(nd.ni_vp); - free(buf, M_TEMP); +keeporig: + /* Keep the original path; copy it back to the start of the buffer. */ + bcopy(ptr, buf, len); return error; } |