From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, UNPARSEABLE_RELAY autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 4769 invoked from network); 13 Jan 2021 03:04:43 -0000 Received: from zero.zsh.org (2a02:898:31:0:48:4558:7a:7368) by inbox.vuxu.org with ESMTPUTF8; 13 Jan 2021 03:04:43 -0000 ARC-Seal: i=1; cv=none; a=rsa-sha256; d=zsh.org; s=rsa-20200801; t=1610507083; b=ivpblN/9yLlBGuIJwVR5r5ndei1ULmOvWGHUYZKUMGoJ8RKk7rGTj9iZ/o4/9uU/1vfpjsT1BE xi8DIYywRVC/oF7CAvK5KzKE7oFQSbQFzsQOGtMvt54HRPg2+TvAd1rb6bJ2LJxADneP9ycCn9 In6hxPW1AcgdRxbB0bZIoH4dYweH83UccCy9QtG4pk+/IxqFfYmIp90eb0r6xs26Jt01Fs9/s3 DwqyoccPs8+9LZO+FC23t/LIvdE3PX7B+DHV5p2F2ljEyZ29UoLmeJq7bZMVp7GRJ9mJ1NAgOb qxXHdOFSRi41XYwZhDeQTcbNurqzinmwkomdLog9HLPxBA==; ARC-Authentication-Results: i=1; zsh.org; iprev=pass (mail-vk1-f171.google.com) smtp.remote-ip=209.85.221.171; dkim=pass header.d=gmail.com header.s=20161025 header.a=rsa-sha256; dmarc=pass header.from=gmail.com; arc=none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed; d=zsh.org; s=rsa-20200801; t=1610507083; bh=2t8hayJZPNAh0tgYhAhck+Hpcqk44KQZ9kde9Fohrx8=; h=List-Archive:List-Owner:List-Post:List-Unsubscribe:List-Subscribe:List-Help: List-Id:Sender:Content-Type:To:Subject:Message-ID:Date:From:MIME-Version: DKIM-Signature:DKIM-Signature; b=TauGqqo7lW09fgijc0w8t62ZDqDnpRGSczCDFlCcIARK88119zNM4Jm/mac+5e9KLvPgCsfcTe xAJ1K4ER30DczfEK2eaz+vbJug9UnPLcco/HJZ1tynDMz6p3R/U1U82nKNqUZAQKczk4Qycqz1 mZRwiLCSdBNdieZjatYl1kAmJoKvmj5JV1MxIF5FobwJI/ALrCGjQf9+h+PUVyccRaHck/dzDU PGd2GWSH1p5dbv1Voopa7DQUgZm08xAhVFN//8DuMGk7bQUk+vDi0W6vrcrqKLH26QA3m6nnSq 07nHStIDj9Mn8gs1VjTsP0XVsA9GOWeal1RqbOfjB7rDog==; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=zsh.org; s=rsa-20200801; h=List-Archive:List-Owner:List-Post:List-Unsubscribe: List-Subscribe:List-Help:List-Id:Sender:Content-Type:To:Subject:Message-ID: Date:From:MIME-Version:Reply-To:Cc:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References; bh=D45cTYvPz8X+dcwjpr6gsetal6K+7glZaKafIBq4ofI=; b=OZwCRg/SNZ+rl4Q6x3KtHzqn4l gKZb6iHPLfpd8N01tuD8a0PU1lhp5lYWHK+O+G441fFYNkKNg+TLF/OzUoNCu9z1SCDYTT85poElg oPRhLtN5Ykx3p0fIs2LY4zh5Ze5M1VpvDqrzI/OUx3/G8W/AiPX1OCWZ9XUWnjwW2oNVEIiY9nYF+ sfNfgbH1LkYd3DbnKrGUh6Rw1S+9mdBjD3vZisR2vQyrav2t4XDpMI6segg65rMTuorvsRtfZ4/20 X69s5HlkyLKwWOgw3aCFgRt9VAuePtPkPM2Np15r5HiKONdDl/XEPRDa7qcQVuuZOWY3rJRmh8ihu ELRgel7g==; Received: from authenticated user by zero.zsh.org with local id 1kzWSg-000CaC-5r; Wed, 13 Jan 2021 03:04:42 +0000 Authentication-Results: zsh.org; iprev=pass (mail-vk1-f171.google.com) smtp.remote-ip=209.85.221.171; dkim=pass header.d=gmail.com header.s=20161025 header.a=rsa-sha256; dmarc=pass header.from=gmail.com; arc=none Received: from mail-vk1-f171.google.com ([209.85.221.171]:38351) by zero.zsh.org with esmtps (TLS1.3:TLS_AES_128_GCM_SHA256:128) id 1kzWSQ-000CQm-63; Wed, 13 Jan 2021 03:04:26 +0000 Received: by mail-vk1-f171.google.com with SMTP id u67so202593vkb.5 for ; Tue, 12 Jan 2021 19:04:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=D45cTYvPz8X+dcwjpr6gsetal6K+7glZaKafIBq4ofI=; b=KdYh2nKC7U3pw4lxiDQny3xintmgPqIs3dUXE+WNicMlAB3XGlR3CEkb+za0EHfaHm qc5ktAAtIPeKrEJKY4CHw7zIaw4WkA2ywl+Tjdqwwm74GgLXnncl9xT0+WmJ3U6GXPpK XfTygamf9Bi2/FNq1IPyMXroWu4YubqLoliGsWbUvk/BwljVZ35GwP0DapCobylMHFch vtjm04WezA7si2vh5rZL1GBBaO2v13v/eM0IZyo4uDITdOfknpfXkJZ645Wb/WLt8E3X cG94sCzLYfFkzo9piz//4Wz0BbuF7cgnczYnHOEqFBY3xoewa5Ld4XEeqJgZ/dNTt+Wn Xmbw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=D45cTYvPz8X+dcwjpr6gsetal6K+7glZaKafIBq4ofI=; b=HlsyHe33/iLR/JLTDwnXKszabNPnab6Llnntdtddg8TGhnebDUVUkQDhajDhezuOcD h5ja2j9ZmfGeNzd65fveuwgTsR6JqOD+E5UWQ/CVGRwD3Ypu3kOtftfPy6ES9nIXQUVQ Fy5Q8WRCzFWV3DNpxTau1JdnyM+gllMDApqpc7Ai6icJsWscSY20ytO1Z/xFnQ/Jr9ao KlxTKdO86ZFbcd+tRBXSbwGaFMf8/1AaZRBjU+h9hGG1ZTPHM5l+XFbMGbNt8xPpWrE+ HNyVjywkt/ctc2NwB6UcUV+/PTtd1Gf5gUQhTbexZXeDllbos6V9673f58ZCi6plNvSK k7pg== X-Gm-Message-State: AOAM530On2fmkoz48kAioD0NWsUHgUgShZbX0G/FN+q5+k9MZWDLNksO sG65lm1V6cPb0SBfcHpflQCweUEda8Ibr4F3ZxVFTDiH X-Google-Smtp-Source: ABdhPJxqtj34zcWsmt8RVh3On/wZrLdxJYyvADH966gcN/fi+r4xQo5UIGoGx6EeNZ9nLDb1HrhCKoYYxaJCH0nTIcU= X-Received: by 2002:a1f:1f96:: with SMTP id f144mr192772vkf.16.1610507064617; Tue, 12 Jan 2021 19:04:24 -0800 (PST) MIME-Version: 1.0 Received: by 2002:ab0:2306:0:0:0:0:0 with HTTP; Tue, 12 Jan 2021 19:04:23 -0800 (PST) From: Devin Hussey Date: Tue, 12 Jan 2021 22:04:23 -0500 Message-ID: Subject: [PATCH] Allow globbing with unreadable parent directories To: zsh-workers@zsh.org Content-Type: text/plain; charset="UTF-8" X-Seq: 47822 Archived-At: X-Loop: zsh-workers@zsh.org Errors-To: zsh-workers-owner@zsh.org Precedence: list Precedence: bulk Sender: zsh-workers-request@zsh.org X-no-archive: yes List-Id: List-Help: List-Subscribe: List-Unsubscribe: List-Post: List-Owner: List-Archive: Archived-At: POSIX specifies that when globbing, parent directories only have to be searchable, not readable. Previously, globbing using NO_CASE_GLOB would fail if any of the parent directories in the path were not readable. This was a major issue primarily affecting Termux, a Linux environment for Android. Termux's $HOME is "/data/data/com.termux/files/home", and the issue is that "/data" and sometimes even "/" are not readable without system/root permission. This made every full path glob with NO_CASE_GLOB fail, breaking many scripts such as the Prezto prompt. Now, zsh will correctly glob even if the parent directory is not readable, while respecting the searchable bit. See: - https://github.com/sorin-ionescu/prezto/issues/1560 - https://github.com/termux/termux-packages/issues/1894 Signed-off-by: Devin Hussey --- Src/glob.c | 169 ++++++++++++++++++++++++++++------------------------- 1 file changed, 89 insertions(+), 80 deletions(-) diff --git a/Src/glob.c b/Src/glob.c index bee890caf..4f5c2cf8b 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -580,100 +580,109 @@ scanner(Complist q, int shortcircuit) } else { /* Do pattern matching on current path section. */ char *fn = pathbuf[pathbufcwd] ? unmeta(pathbuf + pathbufcwd) : "."; - int dirs = !!q->next; - DIR *lock = opendir(fn); char *subdirs = NULL; int subdirlen = 0; - if (lock == NULL) + /* First check for search permission. */ + if (access(fn, X_OK) != 0) return; - while ((fn = zreaddir(lock, 1)) && !errflag) { - /* prefix and suffix are zle trickery */ - if (!dirs && !colonmod && - ((glob_pre && !strpfx(glob_pre, fn)) - || (glob_suf && !strsfx(glob_suf, fn)))) - continue; - errsfound = errssofar; - if (pattry(p, fn)) { - /* if this name matches the pattern... */ - if (pbcwdsav == pathbufcwd && - strlen(fn) + pathpos - pathbufcwd >= PATH_MAX) { - int err; - - DPUTS(pathpos == pathbufcwd, - "BUG: filename longer than PATH_MAX"); - err = lchdir(unmeta(pathbuf + pathbufcwd), &ds, 0); - if (err == -1) - break; - if (err) { - zerr("current directory lost during glob"); - break; + + /* Then, if we have read permission, try to open the directory. */ + if (access(fn, R_OK) == 0) { + int dirs = !!q->next; + DIR *lock = opendir(fn); + + if (lock == NULL) + return; + + while ((fn = zreaddir(lock, 1)) && !errflag) { + /* prefix and suffix are zle trickery */ + if (!dirs && !colonmod && + ((glob_pre && !strpfx(glob_pre, fn)) + || (glob_suf && !strsfx(glob_suf, fn)))) + continue; + errsfound = errssofar; + if (pattry(p, fn)) { + /* if this name matches the pattern... */ + if (pbcwdsav == pathbufcwd && + strlen(fn) + pathpos - pathbufcwd >= PATH_MAX) { + int err; + + DPUTS(pathpos == pathbufcwd, + "BUG: filename longer than PATH_MAX"); + err = lchdir(unmeta(pathbuf + pathbufcwd), &ds, 0); + if (err == -1) + break; + if (err) { + zerr("current directory lost during glob"); + break; + } + pathbufcwd = pathpos; } - pathbufcwd = pathpos; - } - if (dirs) { - int l; + if (dirs) { + int l; - /* - * If not the last component in the path: - * - * If we made an approximation in the new path segment, - * then it is possible we made too many errors. For - * example, (ab)#(cb)# will match the directory abcb - * with one error if allowed to, even though it can - * match with none. This will stop later parts of the - * path matching, so we need to check by reducing the - * maximum number of errors and seeing if the directory - * still matches. Luckily, this is not a terribly - * common case, since complex patterns typically occur - * in the last part of the path which is not affected - * by this problem. - */ - if (errsfound > errssofar) { - forceerrs = errsfound - 1; - while (forceerrs >= errssofar) { - errsfound = errssofar; - if (!pattry(p, fn)) - break; + /* + * If not the last component in the path: + * + * If we made an approximation in the new path segment, + * then it is possible we made too many errors. For + * example, (ab)#(cb)# will match the directory abcb + * with one error if allowed to, even though it can + * match with none. This will stop later parts of the + * path matching, so we need to check by reducing the + * maximum number of errors and seeing if the directory + * still matches. Luckily, this is not a terribly + * common case, since complex patterns typically occur + * in the last part of the path which is not affected + * by this problem. + */ + if (errsfound > errssofar) { forceerrs = errsfound - 1; + while (forceerrs >= errssofar) { + errsfound = errssofar; + if (!pattry(p, fn)) + break; + forceerrs = errsfound - 1; + } + errsfound = forceerrs + 1; + forceerrs = -1; } - errsfound = forceerrs + 1; - forceerrs = -1; - } - if (closure) { - /* if matching multiple directories */ - struct stat buf; - - if (statfullpath(fn, &buf, !q->follow)) { - if (errno != ENOENT && errno != EINTR && - errno != ENOTDIR && !errflag) { - zwarn("%e: %s", errno, fn); + if (closure) { + /* if matching multiple directories */ + struct stat buf; + + if (statfullpath(fn, &buf, !q->follow)) { + if (errno != ENOENT && errno != EINTR && + errno != ENOTDIR && !errflag) { + zwarn("%e: %s", errno, fn); + } + continue; } - continue; + if (!S_ISDIR(buf.st_mode)) + continue; + } + l = strlen(fn) + 1; + subdirs = hrealloc(subdirs, subdirlen, subdirlen + l + + sizeof(int)); + strcpy(subdirs + subdirlen, fn); + subdirlen += l; + /* store the count of errors made so far, too */ + memcpy(subdirs + subdirlen, (char *)&errsfound, + sizeof(int)); + subdirlen += sizeof(int); + } else { + /* if the last filename component, just add it */ + insert(fn, 1); + if (shortcircuit && shortcircuit == matchct) { + closedir(lock); + return; } - if (!S_ISDIR(buf.st_mode)) - continue; - } - l = strlen(fn) + 1; - subdirs = hrealloc(subdirs, subdirlen, subdirlen + l - + sizeof(int)); - strcpy(subdirs + subdirlen, fn); - subdirlen += l; - /* store the count of errors made so far, too */ - memcpy(subdirs + subdirlen, (char *)&errsfound, - sizeof(int)); - subdirlen += sizeof(int); - } else { - /* if the last filename component, just add it */ - insert(fn, 1); - if (shortcircuit && shortcircuit == matchct) { - closedir(lock); - return; } } } + closedir(lock); } - closedir(lock); if (subdirs) { int oppos = pathpos; -- 2.30.0