Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
PATCH: misc glob fixes
- X-seq: zsh-workers 3960
- From: Zoltan Hidvegi <hzoli@xxxxxxxxxx>
- To: zsh-workers@xxxxxxxxxxxxxxx (Zsh hacking and development)
- Subject: PATCH: misc glob fixes
- Date: Sat, 9 May 1998 17:17:07 -0500 (CDT)
This patch fixes several glob problems.
First, many systems ignore trailing slashes on filenames. As a result */
will match all files instead of just directories as required by common
sense and the POSIX standard. The solution is to stat/lstat/access
`filename/.' instead of `filename/'.
The next problem was introduced by patch 3285 which fixes the (-T) and
(-M) qualifier behavior. The problem is the these will give no maches
found on a dangling symlink.
A somewhat related promlem occurs when the T or M qualifier is applied
together with some other mode qualifier. For example *(T-/) will not
match symbolic links to directories. That's because T will add the @ to
the ent of the symlink to mark it and the stat will be done on this
modified name.
The patch combines exists and getfullpatch into
statfullpath(const char *s, struct stat *st, int l).
This combines the current glob directory with the filename s. l is a
flag to follow symlinks. If st is NULL access is used instead of stat.
That's the same as before: exists used access. access is faster on
certain filesystems. Also some filesystems do not allow stat on a file,
although access returns success on the file. If I remember correctly
this is true for AFS when the file is in a directory which is listable
but not readable. * will work in such directories, but *(T) will give no
match, since if the lstat fails, it assumes that the file does not
exists. This may be considered a bug, but it is really because AFS does
not follow the usual Unix semantics, so I do not think it should be
fixed.
All of these are already in 3.0.5
Zoli
*** Src/glob.c.orig Sat May 9 15:06:05 1998
--- Src/glob.c Sat May 9 16:32:32 1998
*************** static char *pptr; /* current place in
*** 128,142 ****
static Comp tail;
static int first; /* are leading dots special? */
- /**/
- static int
- exists(char *s)
- {
- char *us = unmeta(s);
-
- return access(us, F_OK) == 0 || readlink(us,NULL,0) == 0;
- }
-
/* Add a component to pathbuf: This keeps track of how *
* far we are into a file name, since each path component *
* must be matched separately. */
--- 128,133 ----
*************** addpath(char *s)
*** 153,172 ****
pathbuf[pathpos] = '\0';
}
! /* return full path for s, which has path as *
! * already added to pathbuf */
/**/
! static char *
! getfullpath(char *s)
{
! static char buf[PATH_MAX];
! DPUTS(strlen(s) + pathpos - pathbufcwd >= PATH_MAX,
! "BUG: getfullpath(): pathname too long");
strcpy(buf, pathbuf + pathbufcwd);
strcpy(buf + pathpos - pathbufcwd, s);
! return buf;
}
/* add a match to the list */
--- 144,174 ----
pathbuf[pathpos] = '\0';
}
! /* stat the filename s appended to pathbuf. l should be true for lstat, *
! * false for stat. If st is NULL, the file is only chechked for existance. *
! * s == "" is treated as s == ".". This is necessary since on most systems *
! * foo/ can be used to reference a non-directory foo. Returns nonzero if *
! * the file does not exists. */
/**/
! static int
! statfullpath(const char *s, struct stat *st, int l)
{
! char buf[PATH_MAX];
! DPUTS(strlen(s) + !*s + pathpos - pathbufcwd >= PATH_MAX,
! "BUG: statfullpath(): pathname too long");
strcpy(buf, pathbuf + pathbufcwd);
strcpy(buf + pathpos - pathbufcwd, s);
! if (!*s) {
! buf[pathpos - pathbufcwd] = '.';
! buf[pathpos - pathbufcwd + 1] = '\0';
! l = 0;
! }
! unmetafy(buf, NULL);
! if (!st)
! return access(buf, F_OK) && (!l || readlink(buf, NULL, 0));
! return l ? lstat(buf, st) : stat(buf, st);
}
/* add a match to the list */
*************** static void
*** 176,245 ****
insert(char *s, int checked)
{
struct stat buf, buf2, *bp;
int statted = 0;
if (gf_listtypes || gf_markdirs) {
/* Add the type marker to the end of the filename */
checked = statted = 1;
! if (gf_follow ? stat(unmetafy(getfullpath(s), NULL), &buf)
! : lstat(unmetafy(getfullpath(s), NULL), &buf))
return;
! if (gf_listtypes || S_ISDIR(buf.st_mode)) {
! char *t;
int ll = strlen(s);
! t = (char *)ncalloc(ll + 2);
! strcpy(t, s);
! t[ll] = file_type(buf.st_mode);
! t[ll + 1] = '\0';
! s = t;
}
}
if (qualct || qualorct) {
/* Go through the qualifiers, rejecting the file if appropriate */
struct qual *qo, *qn;
- int t = 0; /* reject file unless t is set */
! if (!statted && lstat(unmetafy(getfullpath(s), NULL), &buf))
return;
! statted = 0;
! for (qo = quals; qo && !t; qo = qo->or) {
! t = 1;
! for (qn = qo; t && qn && qn->func; qn = qn->next) {
! range = qn->range;
! amc = qn->amc;
! units = qn->units;
! if ((qn->sense & 2) && !statted) {
! /* If (sense & 2), we're following links */
! if (!S_ISLNK(buf.st_mode) ||
! stat(unmetafy(getfullpath(s), NULL), &buf2))
! memcpy(&buf2, &buf, sizeof(buf));
! statted = 1;
! }
! bp = (qn->sense & 2) ? &buf2 : &buf;
! /* Reject the file if the function returned zero *
! * and the sense was positive (sense == 0), or *
! * vice versa. */
! if (!(!!((qn->func) (bp, qn->data)) ^
! (qn->sense & 1))) {
! t = 0;
! break;
! }
}
}
! if (!t)
! return;
! } else if (!checked && !exists(getfullpath(s)))
return;
! s = dyncat(pathbuf, s);
if (colonmod) {
/* Handle the remainder of the qualifer: e.g. (:r:s/foo/bar/). */
! char *cm2 = colonmod;
!
! modify(&s, &cm2);
}
! *matchptr++ = s;
if (++matchct == matchsz) {
matchbuf = (char **)realloc((char *)matchbuf,
sizeof(char **) * (matchsz *= 2));
--- 178,248 ----
insert(char *s, int checked)
{
struct stat buf, buf2, *bp;
+ char *news = s;
int statted = 0;
if (gf_listtypes || gf_markdirs) {
/* Add the type marker to the end of the filename */
+ mode_t mode;
checked = statted = 1;
! if (statfullpath(s, &buf, 1))
return;
! mode = buf.st_mode;
! if (gf_follow) {
! if (!S_ISLNK(mode) || statfullpath(s, &buf2, 0))
! memcpy(&buf2, &buf, sizeof(buf));
! statted = 2;
! mode = buf2.st_mode;
! }
! if (gf_listtypes || S_ISDIR(mode)) {
int ll = strlen(s);
! news = (char *)ncalloc(ll + 2);
! strcpy(news, s);
! news[ll] = file_type(mode);
! news[ll + 1] = '\0';
}
}
if (qualct || qualorct) {
/* Go through the qualifiers, rejecting the file if appropriate */
struct qual *qo, *qn;
! if (!statted && statfullpath(s, &buf, 1))
return;
! qo = quals;
! for (qn = qo; qn && qn->func;) {
! range = qn->range;
! amc = qn->amc;
! units = qn->units;
! if ((qn->sense & 2) && statted != 2) {
! /* If (sense & 2), we're following links */
! if (!S_ISLNK(buf.st_mode) || statfullpath(s, &buf2, 0))
! memcpy(&buf2, &buf, sizeof(buf));
! statted = 2;
}
+ bp = (qn->sense & 2) ? &buf2 : &buf;
+ /* Reject the file if the function returned zero *
+ * and the sense was positive (sense&1 == 0), or *
+ * vice versa. */
+ if ((!((qn->func) (bp, qn->data)) ^ qn->sense) & 1) {
+ /* Try next alternative, or return if there are no more */
+ if (!(qo = qo->or))
+ return;
+ qn = qo;
+ continue;
+ }
+ qn = qn->next;
}
! } else if (!checked && statfullpath(s, NULL, 1))
return;
! news = dyncat(pathbuf, news);
if (colonmod) {
/* Handle the remainder of the qualifer: e.g. (:r:s/foo/bar/). */
! s = colonmod;
! modify(&news, &s);
}
! *matchptr++ = news;
if (++matchct == matchsz) {
matchbuf = (char **)realloc((char *)matchbuf,
sizeof(char **) * (matchsz *= 2));
*************** scanner(Complist q)
*** 315,321 ****
/* It's a straight string to the end of the path section. */
int l = strlen(c->str);
! if (l + pathpos - pathbufcwd >= PATH_MAX) {
int err;
if (l >= PATH_MAX)
--- 318,324 ----
/* It's a straight string to the end of the path section. */
int l = strlen(c->str);
! if (l + !l + pathpos - pathbufcwd >= PATH_MAX) {
int err;
if (l >= PATH_MAX)
*************** scanner(Complist q)
*** 335,341 ****
if (!errflag && !(q->closure && !strcmp(c->str, "."))) {
addpath(c->str);
! if (!closure || exists(pathbuf))
scanner((q->closure) ? q : q->next);
pathbuf[pathpos = oppos] = '\0';
}
--- 338,344 ----
if (!errflag && !(q->closure && !strcmp(c->str, "."))) {
addpath(c->str);
! if (!closure || statfullpath("", NULL, 1))
scanner((q->closure) ? q : q->next);
pathbuf[pathpos = oppos] = '\0';
}
*************** scanner(Complist q)
*** 391,399 ****
/* if matching multiple directories */
struct stat buf;
! if ((q->follow ?
! stat(unmeta(getfullpath(fn)), &buf) :
! lstat(unmeta(getfullpath(fn)), &buf)) == -1) {
if (errno != ENOENT && errno != EINTR &&
errno != ENOTDIR && !errflag) {
zerr("%e: %s", fn, errno);
--- 394,400 ----
/* if matching multiple directories */
struct stat buf;
! if (statfullpath(fn, &buf, !q->follow)) {
if (errno != ENOENT && errno != EINTR &&
errno != ENOTDIR && !errflag) {
zerr("%e: %s", fn, errno);
Messages sorted by:
Reverse Date,
Date,
Thread,
Author