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; }
static int recursivecmd(char *nam, int opt_noerr, int opt_recurse, int opt_safe, char **args, RecurseFunc dirpre_func, RecurseFunc dirpost_func, RecurseFunc leaf_func, void *magic) { int err = 0, len; char *rp, *s; struct dirsav ds; struct recursivecmd reccmd; reccmd.nam = nam; reccmd.opt_noerr = opt_noerr; reccmd.opt_recurse = opt_recurse; reccmd.opt_safe = opt_safe; reccmd.dirpre_func = dirpre_func; reccmd.dirpost_func = dirpost_func; reccmd.leaf_func = leaf_func; reccmd.magic = magic; init_dirsav(&ds); if (opt_recurse || opt_safe) { if ((ds.dirfd = open(".", O_RDONLY|O_NOCTTY)) < 0 && zgetdir(&ds) && *ds.dirname != '/') ds.dirfd = open("..", O_RDONLY|O_NOCTTY); } for(; !errflag && !(err & 2) && *args; args++) { rp = ztrdup(*args); unmetafy(rp, &len); if (opt_safe) { s = strrchr(rp, '/'); if (s && !s[1]) { while (*s == '/' && s > rp) *s-- = '\0'; while (*s != '/' && s > rp) s--; } if (s && s[1]) { int e; *s = '\0'; e = lchdir(s > rp ? rp : "/", &ds, 1); err |= -e; if (!e) { struct dirsav d; d.ino = d.dev = 0; d.dirname = NULL; d.dirfd = d.level = -1; err |= recursivecmd_doone(&reccmd, *args, s + 1, &d, 0); zsfree(d.dirname); if (restoredir(&ds)) err |= 2; } else if(!opt_noerr) zwarnnam(nam, "%s: %e", *args, errno); } else err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 0); } else err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 1); zfree(rp, len + 1); } if ((err & 2) && ds.dirfd >= 0 && restoredir(&ds) && zchdir(pwd)) { zsfree(pwd); pwd = ztrdup("/"); if (chdir(pwd) < 0) zwarn("failed to chdir(%s): %e", pwd, errno); } if (ds.dirfd >= 0) close(ds.dirfd); zsfree(ds.dirname); return !!err; }