From: Peter Stephenson <pws@ibmth.df.unipi.it>
To: "ZSH workers mailing list" <zsh-workers@sunsite.auc.dk>
Subject: PATCH: 3.1.6-test-1: strange cd behaviour
Date: Wed, 14 Jul 1999 14:32:39 +0200 [thread overview]
Message-ID: <9907141232.AA36925@ibmth.df.unipi.it> (raw)
In-Reply-To: "Peter Stephenson"'s message of "Wed, 14 Jul 1999 11:15:49 DFT." <9907140915.AA13464@ibmth.df.unipi.it>
Peter Stephenson wrote:
> This is a story of horror.
>
> Without restoring the 3.0
> behaviour, the fix would be to do something clever when pwd is a prefix of
> the path --- i.e., $PWD/.. is automatically turned into $PWD:h, whether the
> directory exists or not, but $PWD/../dummy/.. becomes
> ${PWD:h}/dummy/.. which is weighed in the balance and found wanting. This
> would get all the advantages and none of the disadvantages of the 3.0
> method (I hope). The rule would be something like
>
> - If $PWD is a prefix, rationalize away any immediately following ..'s
> (and .'s, to be on the safe side) before doing any testing.
> - At that point, even if $PWD is a prefix, look at the path and see if it
> contains any /../ or finishes with /.. . If so, stat() it and check
> that it exists. If not, return and let the chdir code handle errors.
> - If everything's OK so far (i.e. no ..'s, or the directory exists)
> rationalize the rest of the path.
This does it: as you see it's a significant chunk of extra code with no
other aim than making sure cd foo/.. doesn't work if foo doesn't exist
without preventing you from changing back up to directories that still
exist if yours doesn't. But life is non-optimal. If anybody has any
better suggestions...?
Please test this, since people tend to get cross if they can't change
directories properly.
Note that this has the effect that `cd $PWD/<relative>' is tested in
exactly the same way as `cd <relative>', where <relative> is any relative
path. So `cd $PWD/..' will also always work if $PWD doesn't exist but its
parent does, regardless (obviously) of whether you use the variable $PWD or
the full directory name. That's the effect of the code change between 3.0
and 3.1. (Of course, if you're somewhere else in cdpath, none of this
matters.)
--- Src/builtin.c.cd Tue Jul 13 14:31:03 1999
+++ Src/builtin.c Wed Jul 14 14:26:38 1999
@@ -1045,11 +1045,41 @@
static void
fixdir(char *src)
{
- char *dest = src;
- char *d0 = dest;
-#ifdef __CYGWIN__
+ char *dest = src, *d0 = dest, *chks = src, *ptrp;
+#ifdef __CYGWIN
char *s0 = src;
#endif
+ int donecheck = 0, len;
+
+ /*
+ * Normally, we should not rationalize away path segments foo/.. if
+ * the directory foo does not exist. However, if foo was part of
+ * pwd then we should allow it, because we know the current
+ * directory was once valid, although may have been deleted, and `cd
+ * ..' should always work as long as the parent directory exists.
+ * Hence we find an initial portion of the path consisting of pwd
+ * followed by any number of .. or . segments, and don't check
+ * that the original path exists. After this point (given by
+ * chks), if there are any remaining ..'s in the path we
+ * check that the directory with the remaining portion
+ * unrationalized really exists, and return if it doesn't.
+ *
+ * Bug: this is ridiculously heavy handed.
+ */
+ len = strlen(pwd);
+ if (!strncmp(src, pwd, len) && src[len] == '/') {
+ chks = src + len;
+ while (*chks == '/')
+ chks++;
+ while (*chks == '.' &&
+ (!chks[1] || chks[1] == '/' ||
+ (chks[1] == '.' && (!chks[2] || chks[2] == '/')))) {
+ while (*chks == '.')
+ chks++;
+ while (*chks == '/')
+ chks++;
+ }
+ }
/*** if have RFS superroot directory ***/
#ifdef HAVE_SUPERROOT
@@ -1085,6 +1115,31 @@
}
if (src[0] == '.' && src[1] == '.' &&
(src[2] == '\0' || src[2] == '/')) {
+ if (!donecheck && src >= chks) {
+ /*
+ * We need to check the original path exists, to catch
+ * problems like 'cd nonexistent/..'. We use dest
+ * as far as we've got, plus the rest of src.
+ * We only need to do this once, as any later ..'s
+ * will automatically be tested here.
+ */
+ struct stat st;
+ char *testdir;
+ if (dest == src)
+ testdir = dupstring(d0);
+ else {
+ *dest = '\0';
+ testdir = dyncat(d0, src);
+ }
+ for (chks = src, ptrp = testdir + (dest - d0); *chks;
+ chks++, ptrp++)
+ *ptrp = (*chks == Meta) ? (*++chks ^ 32) : *chks;
+ if (stat(testdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
+ strcpy(d0, testdir);
+ return;
+ }
+ donecheck = 1;
+ }
if (dest > d0 + 1) {
/* remove a foo/.. combination */
for (dest--; dest > d0 + 1 && dest[-1] != '/'; dest--);
--
Peter Stephenson <pws@ibmth.df.unipi.it> Tel: +39 050 844536
WWW: http://www.ifh.de/~pws/
Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy
next prev parent reply other threads:[~1999-07-14 13:03 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
1999-07-13 15:29 Andrej Borsenkow
1999-07-14 8:06 ` Peter Stephenson
1999-07-14 8:47 ` Bart Schaefer
1999-07-14 9:15 ` Peter Stephenson
1999-07-14 12:32 ` Peter Stephenson [this message]
1999-07-15 11:57 ` PATCH: " Andrej Borsenkow
1999-07-15 12:23 ` Peter Stephenson
1999-07-15 15:56 ` Peter Stephenson
1999-07-15 17:27 ` Bart Schaefer
1999-07-16 10:14 ` PATCH: 3.1.6-test-1: remorselessly " Peter Stephenson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9907141232.AA36925@ibmth.df.unipi.it \
--to=pws@ibmth.df.unipi.it \
--cc=zsh-workers@sunsite.auc.dk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).