mod_export char * zgetdir(struct dirsav *d) { char nbuf[PATH_MAX+3]; char *buf; int bufsiz, pos; struct stat sbuf; ino_t pino; dev_t pdev; #if !defined(__CYGWIN__) && !defined(USE_GETCWD) struct dirent *de; DIR *dir; dev_t dev; ino_t ino; int len; #endif buf = zhalloc(bufsiz = PATH_MAX); pos = bufsiz - 1; buf[pos] = '\0'; strcpy(nbuf, "../"); if (stat(".", &sbuf) < 0) { return NULL; } /* Record the initial inode and device */ pino = sbuf.st_ino; pdev = sbuf.st_dev; if (d) d->ino = pino, d->dev = pdev; #if !defined(__CYGWIN__) && !defined(USE_GETCWD) #ifdef HAVE_FCHDIR else #endif holdintr(); for (;;) { /* Examine the parent of the current directory. */ if (stat("..", &sbuf) < 0) break; /* Inode and device of curtent directory */ ino = pino; dev = pdev; /* Inode and device of current directory's parent */ pino = sbuf.st_ino; pdev = sbuf.st_dev; /* If they're the same, we've reached the root directory. */ if (ino == pino && dev == pdev) { if (!buf[pos]) buf[--pos] = '/'; if (d) { #ifndef HAVE_FCHDIR zchdir(buf + pos); noholdintr(); #endif return d->dirname = ztrdup(buf + pos); } zchdir(buf + pos); noholdintr(); return buf + pos; } /* Search the parent for the current directory. */ if (!(dir = opendir(".."))) break; while ((de = readdir(dir))) { char *fn = de->d_name; /* Ignore `.' and `..'. */ if (fn[0] == '.' && (fn[1] == '\0' || (fn[1] == '.' && fn[2] == '\0'))) continue; #ifdef HAVE_STRUCT_DIRENT_D_STAT if(de->d_stat.st_dev == dev && de->d_stat.st_ino == ino) { /* Found the directory we're currently in */ strncpy(nbuf + 3, fn, PATH_MAX); break; } #else /* !HAVE_STRUCT_DIRENT_D_STAT */ # ifdef HAVE_STRUCT_DIRENT_D_INO if (dev != pdev || (ino_t) de->d_ino == ino) # endif /* HAVE_STRUCT_DIRENT_D_INO */ { /* Maybe found directory, need to check device & inode */ strncpy(nbuf + 3, fn, PATH_MAX); lstat(nbuf, &sbuf); if (sbuf.st_dev == dev && sbuf.st_ino == ino) break; } #endif /* !HAVE_STRUCT_DIRENT_D_STAT */ } closedir(dir); if (!de) break; /* Not found */ /* * We get the "/" free just by copying from nbuf+2 instead * of nbuf+3, which is where we copied the path component. * This means buf[pos] is always a "/". */ len = strlen(nbuf + 2); pos -= len; while (pos <= 1) { char *newbuf = zhalloc(2*bufsiz); memcpy(newbuf + bufsiz, buf, bufsiz); buf = newbuf; pos += bufsiz; bufsiz *= 2; } memcpy(buf + pos, nbuf + 2, len); #ifdef HAVE_FCHDIR if (d) return d->dirname = ztrdup(buf + pos + 1); #endif if (chdir("..")) break; } /* * Fix up the directory, if necessary. * We're changing back down the hierarchy, ignore the * "/" at buf[pos]. */ if (d) { #ifndef HAVE_FCHDIR if (buf[pos]) zchdir(buf + pos + 1); noholdintr(); #endif return NULL; } if (buf[pos]) zchdir(buf + pos + 1); noholdintr(); #else /* __CYGWIN__, USE_GETCWD cases */ if (!getcwd(buf, bufsiz)) { if (d) { return NULL; } } else { if (d) { return d->dirname = ztrdup(buf); } return buf; } #endif /* * Something bad happened. * This has been seen when inside a special directory, * such as the Netapp .snapshot directory, that doesn't * appear as a directory entry in the parent directory. * We'll just need our best guess. * * We only get here from zgetcwd(); let that fall back to pwd. */ return NULL; }
char * zgetcwd(void) { static char buf0[PATH_MAX]; #if defined(_WIN32) getcwd(buf0, PATH_MAX); return ztrdup(buf0); #else char *buf2 = buf0 + 1; char buf3[PATH_MAX]; struct stat sbuf; struct dirent *de; DIR *dir; ino_t ino, pino, rootino = (ino_t) ~ 0; dev_t dev, pdev, rootdev = (dev_t) ~ 0; holdintr(); buf2[0] = '\0'; buf0[0] = '/'; if (stat(buf0, &sbuf) >= 0) { rootino = sbuf.st_ino; rootdev = sbuf.st_dev; } if (stat(".", &sbuf) < 0) { noholdintr(); return ztrdup("."); } pino = sbuf.st_ino; pdev = sbuf.st_dev; for (;;) { if (stat("..", &sbuf) < 0) { chdir(buf0); noholdintr(); return ztrdup("."); } ino = pino; dev = pdev; pino = sbuf.st_ino; pdev = sbuf.st_dev; if ((ino == pino && dev == pdev) || (ino == rootino && dev == rootdev)) { chdir(buf0); noholdintr(); return ztrdup(buf0); } dir = opendir(".."); if (!dir) { chdir(buf0); noholdintr(); return ztrdup("."); } chdir(".."); while ((de = readdir(dir))) { char *fn = de->d_name; /* Ignore `.' and `..'. */ if (fn[0] == '.' && (fn[1] == '\0' || (fn[1] == '.' && fn[2] == '\0'))) continue; if (dev != pdev || (ino_t) de->d_ino == ino) { lstat(fn, &sbuf); if (sbuf.st_dev == dev && sbuf.st_ino == ino) { strcpy(buf3, de->d_name); break; } } } closedir(dir); if (!de) { noholdintr(); return ztrdup("."); } if (*buf2) strcat(buf3, "/"); strcat(buf3, buf2); strcpy(buf2, buf3); } #endif }