/* @(#)vfs_pathname.c 1.1 85/05/30 SMI */ #include "../h/param.h" #include "../h/dir.h" #include "../h/uio.h" #include "../h/errno.h" #include "../h/pathname.h" /* * Pathname utilities. * * In translating file names we copy each argument file * name into a pathname structure where we operate on it. * Each pathname structure can hold MAXPATHLEN characters * including a terminating null, and operations here support * allocating and freeing pathname structures, fetching * strings from user space, getting the next character from * a pathname, combining two pathnames (used in symbolic * link processing), and peeling off the first component * of a pathname. */ /* * Allocate contents of pathname structure. * Structure itself is typically automatic * variable in calling routine for convenience. */ pn_alloc(pnp) register struct pathname *pnp; { pnp->pn_buf = (char *)kmem_alloc(MAXPATHLEN); pnp->pn_path = (char *)pnp->pn_buf; pnp->pn_pathlen = 0; return (0); } /* * Pull a pathname from user user or kernel space */ int pn_get(str, seg, pnp) register struct pathname *pnp; int seg; register char *str; { register char *cp; extern char *strncpy(); pn_alloc(pnp); if (seg == UIOSEG_USER) { register int l; register int c; cp = pnp->pn_path; for (l = 0; l < MAXPATHLEN; l++) { c = fubyte(str++); if (c == -1) { pn_free(pnp); return(EFAULT); } if (c & 0x80) return(EPERM); *cp++ = c; if (c == 0) { pnp->pn_pathlen = l; return(0); } } } else { /* * cp will point to last null in pn_path */ cp = strncpy(pnp->pn_path, str, MAXPATHLEN); pnp->pn_pathlen = cp - pnp->pn_path; if (pnp->pn_pathlen < MAXPATHLEN) { return(0); } } pn_free(pnp); return (ENAMETOOLONG); } /* * Get next character from a path. * Return null at end forever. */ pn_getchar(pnp) register struct pathname *pnp; { if (pnp->pn_pathlen == 0) return (0); pnp->pn_pathlen--; return (*pnp->pn_path++); } /* * Set pathname to argument string. */ pn_set(pnp, path) register struct pathname *pnp; register char *path; { register char *cp; extern char *strncpy(); pnp->pn_path = pnp->pn_buf; cp = strncpy(pnp->pn_path, path, MAXPATHLEN); pnp->pn_pathlen = cp - pnp->pn_path; if (pnp->pn_pathlen >= MAXPATHLEN) return (ENAMETOOLONG); return (0); } /* * Combine two argument pathnames by putting * second argument before first in first's buffer, * and freeing second argument. * This isn't very general: it is designed specifically * for symbolic link processing. */ pn_combine(pnp, sympnp) register struct pathname *pnp; register struct pathname *sympnp; { if (pnp->pn_pathlen + sympnp->pn_pathlen >= MAXPATHLEN) return (ENAMETOOLONG); ovbcopy(pnp->pn_path, pnp->pn_buf + sympnp->pn_pathlen, pnp->pn_pathlen); bcopy(sympnp->pn_path, pnp->pn_buf, sympnp->pn_pathlen); pnp->pn_pathlen += sympnp->pn_pathlen; pnp->pn_path = pnp->pn_buf; return (0); } /* * Strip next component off a pathname and leave in * buffer comoponent which should have room for * MAXNAMLEN bytes and a null terminator character. */ pn_getcomponent(pnp, component) register struct pathname *pnp; register char *component; { register char *cp; register int l; register int n; cp = pnp->pn_path; l = pnp->pn_pathlen; n = MAXNAMLEN; while ((l > 0) && (*cp != '/')) { if (--n < 0) return(ENAMETOOLONG); *component++ = *cp++; --l; } pnp->pn_path = cp; pnp->pn_pathlen = l; *component = 0; return (0); } /* * skip over consecutive slashes in the pathname */ void pn_skipslash(pnp) register struct pathname *pnp; { while ((pnp->pn_pathlen > 0) && (*pnp->pn_path == '/')) { pnp->pn_path++; pnp->pn_pathlen--; } } /* * Free pathname resources. */ void pn_free(pnp) register struct pathname *pnp; { kmem_free(pnp->pn_buf, MAXPATHLEN); pnp->pn_buf = 0; }