Mailing List Archive

More fun with symlinks...
Roy and I just tracked down yet another problem with symlinks --- it seems
that on some systems, if you do an lstat() on "/path/to/some/symlink/", with
a trailing slash on the pathname, then it follows the symlink --- even in
lstat(). (Why his SunOS system exhibits this behavior, and mine doesn't, is
still a bit of a mystery, but his system does reliably exhibit this behavior.
Candidate explanations include SunOS 4.1.2 vs. 4.1.4, and direct-mounted vs.
NFS-mounted test directories). The easiest fix (albeit not a pretty one)
is to strip slashes off of pathnames in check_symlinks --- Roy has verified
that this works on his box...

Now also on hyperreal as patch10.symlinks-again...

*** http_request.c Sun Aug 20 19:58:00 1995
--- ../http_request.c Sun Aug 20 20:24:40 1995
***************
*** 96,109 ****
int check_symlinks (char *d, char opts)
{
struct stat lfi, fi;

if (opts & OPT_SYM_LINKS) return OK;

/* Note that we don't reject accesses to nonexistent files (multiviews
* or the like may cons up a way to run the transaction anyway)...
*/

! if (!(lstat (d, &lfi) >= 0) || !S_ISLNK(lfi.st_mode)) return OK;

/* OK, it's a symlink. May still be OK with OPT_SYM_OWNER */

--- 96,130 ----
int check_symlinks (char *d, char opts)
{
struct stat lfi, fi;
+ char *lastp;
+ int res;

if (opts & OPT_SYM_LINKS) return OK;

+ /* Strip trailing '/', if any, off what we're checking; trailing
+ * slashes make some systems follow symlinks to directories even in
+ * lstat(). After we've done the lstat, put it back. Also, don't
+ * bother checking '/' at all...
+ *
+ * Note that we don't have to worry about multiple slashes here
+ * because of no2slash() below...
+ */
+
+ lastp = d + strlen(d) - 1;
+ if (lastp == d) return OK; /* Root directory, '/' */
+
+ if (*lastp == '/') *lastp = '\0';
+ else lastp = NULL;
+
+ res = lstat (d, &lfi);
+
+ if (lastp) *lastp = '/';
+
/* Note that we don't reject accesses to nonexistent files (multiviews
* or the like may cons up a way to run the transaction anyway)...
*/

! if (!(res >= 0) || !S_ISLNK(lfi.st_mode)) return OK;

/* OK, it's a symlink. May still be OK with OPT_SYM_OWNER */