summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2009-03-19 15:00:18 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2009-03-19 15:00:18 +0000
commitcb6856d115b26fbe6d78e3e730a57e9c0e05e8b9 (patch)
treea42e224d0ccbeda8af4b9220501fe42839b27b55 /Src
parent9e1a3e6d062522c77f17d8be947850ee824cee8e (diff)
downloadzsh-cb6856d115b26fbe6d78e3e730a57e9c0e05e8b9.tar.gz
zsh-cb6856d115b26fbe6d78e3e730a57e9c0e05e8b9.zip
26754: tweak zgetdir() and test for realpath()
Diffstat (limited to 'Src')
-rw-r--r--Src/compat.c32
-rw-r--r--Src/hist.c32
2 files changed, 59 insertions, 5 deletions
diff --git a/Src/compat.c b/Src/compat.c
index 38f24d7fe..ec3a8bc39 100644
--- a/Src/compat.c
+++ b/Src/compat.c
@@ -227,6 +227,26 @@ zopenmax(void)
}
#endif
+/*
+ * Rationalise the current directory, returning the string.
+ *
+ * If "d" is not NULL, it is used to store information about the
+ * directory. The returned name is also present in d->dirname and is in
+ * permanently allocated memory. The handling of this case depends on
+ * whether the fchdir() system call is available; if it is, it is assumed
+ * the caller is able to restore the current directory. On successfully
+ * identifying the directory the function returns immediately rather
+ * than ascending the hierarchy.
+ *
+ * If "d" is NULL, no assumption about the caller's behaviour is
+ * made. The returned string is in heap memory. This case is
+ * always handled by changing directory up the hierarchy.
+ *
+ * On Cygwin or other systems where USE_GETCWD is defined (at the
+ * time of writing only QNX), we skip all the above and use the
+ * getcwd() system call.
+ */
+
/**/
mod_export char *
zgetdir(struct dirsav *d)
@@ -257,25 +277,30 @@ zgetdir(struct dirsav *d)
return buf;
}
+ /* 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
-#if !defined(__CYGWIN__) && !defined(USE_GETCWD)
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] = '/';
@@ -291,6 +316,7 @@ zgetdir(struct dirsav *d)
return buf + pos;
}
+ /* Search the parent for the current directory. */
if (!(dir = opendir("..")))
break;
@@ -303,6 +329,7 @@ zgetdir(struct dirsav *d)
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;
}
@@ -311,6 +338,7 @@ zgetdir(struct dirsav *d)
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)
@@ -320,7 +348,7 @@ zgetdir(struct dirsav *d)
}
closedir(dir);
if (!de)
- break;
+ break; /* Not found */
len = strlen(nbuf + 2);
pos -= len;
while (pos <= 1) {
diff --git a/Src/hist.c b/Src/hist.c
index 4a2c12530..b843a2399 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -1522,7 +1522,7 @@ chabspath(char **junkptr)
current += 3;
}
#endif
-
+
for (;;) {
if (*current == '/') {
#ifdef __CYGWIN__
@@ -1579,7 +1579,14 @@ chabspath(char **junkptr)
int
chrealpath(char **junkptr)
{
+ char *str;
+#ifdef HAVE_CANONICALIZE_FILE_NAME
+ char *lastpos, *nonreal, *real;
+#else
+# ifdef HAVE_REAL_PATH
char *lastpos, *nonreal, real[PATH_MAX];
+# endif
+#endif
if (!**junkptr)
return 1;
@@ -1588,6 +1595,9 @@ chrealpath(char **junkptr)
if (!chabspath(junkptr))
return 0;
+#if !defined(HAVE_REALPATH) && !defined(HAVE_CANONICALIZE_FILE_NAME)
+ return 1;
+#else
/*
* Notice that this means you cannot pass relative paths into this
* function!
@@ -1600,7 +1610,19 @@ chrealpath(char **junkptr)
lastpos = strend(*junkptr);
nonreal = lastpos + 1;
- while (!realpath(*junkptr, real)) {
+ while (!
+#ifdef HAVE_CANONICALIZE_FILE_NAME
+ /*
+ * This is a GNU extension to realpath(); it's the
+ * same as calling realpath() with a NULL second argument
+ * which uses malloc() to get memory. The alternative
+ * interface is easier to test for, however.
+ */
+ (real = canonicalize_file_name(*junkptr))
+#else
+ realpath(*junkptr, real)
+#endif
+ ) {
if (errno == EINVAL || errno == ELOOP ||
errno == ENAMETOOLONG || errno == ENOMEM)
return 0;
@@ -1615,7 +1637,7 @@ chrealpath(char **junkptr)
*nonreal = '\0';
}
- char *str = nonreal;
+ str = nonreal;
while (str <= lastpos) {
if (*str == '\0')
*str = '/';
@@ -1623,6 +1645,10 @@ chrealpath(char **junkptr)
}
*junkptr = metafy(bicat(real, nonreal), -1, META_HEAPDUP);
+#ifdef HAVE_CANONICALIZE_FILE_NAME
+ free(real);
+#endif
+#endif
return 1;
}