michael@0: /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: /* michael@0: ** Pathname subroutines. michael@0: ** michael@0: ** Brendan Eich, 8/29/95 michael@0: */ michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include "pathsub.h" michael@0: michael@0: #ifdef USE_REENTRANT_LIBC michael@0: #include michael@0: #endif michael@0: michael@0: #ifdef SUNOS4 michael@0: #include "sunos4.h" michael@0: #endif michael@0: michael@0: #ifndef D_INO michael@0: #define D_INO d_ino michael@0: #endif michael@0: michael@0: char *program; michael@0: michael@0: void michael@0: fail(char *format, ...) michael@0: { michael@0: int error; michael@0: va_list ap; michael@0: michael@0: #ifdef USE_REENTRANT_LIBC michael@0: R_STRERROR_INIT_R(); michael@0: #endif michael@0: michael@0: error = errno; michael@0: fprintf(stderr, "%s: ", program); michael@0: va_start(ap, format); michael@0: vfprintf(stderr, format, ap); michael@0: va_end(ap); michael@0: if (error) { michael@0: michael@0: #ifdef USE_REENTRANT_LIBC michael@0: R_STRERROR_R(errno); michael@0: fprintf(stderr, ": %s", r_strerror_r); michael@0: #else michael@0: fprintf(stderr, ": %s", strerror(errno)); michael@0: #endif michael@0: } michael@0: michael@0: putc('\n', stderr); michael@0: exit(1); michael@0: } michael@0: michael@0: char * michael@0: getcomponent(char *path, char *name) michael@0: { michael@0: if (*path == '\0') michael@0: return 0; michael@0: if (*path == '/') { michael@0: *name++ = '/'; michael@0: } else { michael@0: do { michael@0: *name++ = *path++; michael@0: } while (*path != '/' && *path != '\0'); michael@0: } michael@0: *name = '\0'; michael@0: while (*path == '/') michael@0: path++; michael@0: return path; michael@0: } michael@0: michael@0: #ifdef LAME_READDIR michael@0: #include michael@0: /* michael@0: ** The static buffer in Unixware's readdir is too small. michael@0: */ michael@0: struct dirent *readdir(DIR *d) michael@0: { michael@0: static struct dirent *buf = NULL; michael@0: michael@0: if(buf == NULL) michael@0: buf = (struct dirent *) malloc(sizeof(struct dirent) + MAXPATHLEN); michael@0: return(readdir_r(d, buf)); michael@0: } michael@0: #endif michael@0: michael@0: char * michael@0: ino2name(ino_t ino) michael@0: { michael@0: DIR *dp; michael@0: struct dirent *ep; michael@0: char *name; michael@0: michael@0: dp = opendir(".."); michael@0: if (!dp) michael@0: fail("cannot read parent directory"); michael@0: for (;;) { michael@0: if (!(ep = readdir(dp))) michael@0: fail("cannot find current directory"); michael@0: if (ep->D_INO == ino) michael@0: break; michael@0: } michael@0: name = xstrdup(ep->d_name); michael@0: closedir(dp); michael@0: return name; michael@0: } michael@0: michael@0: void * michael@0: xmalloc(size_t size) michael@0: { michael@0: void *p = malloc(size); michael@0: if (!p) michael@0: fail("cannot allocate %u bytes", size); michael@0: return p; michael@0: } michael@0: michael@0: char * michael@0: xstrdup(char *s) michael@0: { michael@0: return strcpy(xmalloc(strlen(s) + 1), s); michael@0: } michael@0: michael@0: char * michael@0: xbasename(char *path) michael@0: { michael@0: char *cp; michael@0: michael@0: while ((cp = strrchr(path, '/')) && cp[1] == '\0') michael@0: *cp = '\0'; michael@0: if (!cp) return path; michael@0: return cp + 1; michael@0: } michael@0: michael@0: void michael@0: xchdir(char *dir) michael@0: { michael@0: if (chdir(dir) < 0) michael@0: fail("cannot change directory to %s", dir); michael@0: } michael@0: michael@0: int michael@0: relatepaths(char *from, char *to, char *outpath) michael@0: { michael@0: char *cp, *cp2; michael@0: int len; michael@0: char buf[NAME_MAX]; michael@0: michael@0: assert(*from == '/' && *to == '/'); michael@0: for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++) michael@0: if (*cp == '\0') michael@0: break; michael@0: while (cp[-1] != '/') michael@0: cp--, cp2--; michael@0: if (cp - 1 == to) { michael@0: /* closest common ancestor is /, so use full pathname */ michael@0: len = strlen(strcpy(outpath, to)); michael@0: if (outpath[len] != '/') { michael@0: outpath[len++] = '/'; michael@0: outpath[len] = '\0'; michael@0: } michael@0: } else { michael@0: len = 0; michael@0: while ((cp2 = getcomponent(cp2, buf)) != 0) { michael@0: strcpy(outpath + len, "../"); michael@0: len += 3; michael@0: } michael@0: while ((cp = getcomponent(cp, buf)) != 0) { michael@0: sprintf(outpath + len, "%s/", buf); michael@0: len += strlen(outpath + len); michael@0: } michael@0: } michael@0: return len; michael@0: } michael@0: michael@0: void michael@0: reversepath(char *inpath, char *name, int len, char *outpath) michael@0: { michael@0: char *cp, *cp2; michael@0: char buf[NAME_MAX]; michael@0: struct stat sb; michael@0: michael@0: cp = strcpy(outpath + PATH_MAX - (len + 1), name); michael@0: cp2 = inpath; michael@0: while ((cp2 = getcomponent(cp2, buf)) != 0) { michael@0: if (strcmp(buf, ".") == 0) michael@0: continue; michael@0: if (strcmp(buf, "..") == 0) { michael@0: if (stat(".", &sb) < 0) michael@0: fail("cannot stat current directory"); michael@0: name = ino2name(sb.st_ino); michael@0: len = strlen(name); michael@0: cp -= len + 1; michael@0: strcpy(cp, name); michael@0: cp[len] = '/'; michael@0: free(name); michael@0: xchdir(".."); michael@0: } else { michael@0: cp -= 3; michael@0: strncpy(cp, "../", 3); michael@0: xchdir(buf); michael@0: } michael@0: } michael@0: strcpy(outpath, cp); michael@0: }