From patchwork Wed Dec 30 20:15:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 41605 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8EAC0388C031; Wed, 30 Dec 2020 20:15:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8EAC0388C031 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1609359322; bh=v/Y9eW8pNHEYQlbm/tUgVvO4QO1LHcrZFpPLsPXxgm8=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=eUr94yIcOr4p3M7VbXcV2W6L7/Q2WhSXjMmyAFfQd6yXL9m8bznvrZy20zLvIhx0r n2ryKenz57U8fi2Lj4ZFpGIVcZ9P/9jnctiXAHM644jRCI/74+AIn2oqfTiOgdNmFb dWLuKjS/b3Ni7iQV8nbPl2/6hK8HohkZyn0mo68k= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qt1-x82e.google.com (mail-qt1-x82e.google.com [IPv6:2607:f8b0:4864:20::82e]) by sourceware.org (Postfix) with ESMTPS id 44C66386103C for ; Wed, 30 Dec 2020 20:15:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 44C66386103C Received: by mail-qt1-x82e.google.com with SMTP id b9so11696646qtr.2 for ; Wed, 30 Dec 2020 12:15:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=v/Y9eW8pNHEYQlbm/tUgVvO4QO1LHcrZFpPLsPXxgm8=; b=qTGe+7qk14Dqke0D+fQE5J+ZyoWbJJnd6fLHcudzBCaOijC9fKPMuQFiN3Atdw/zYr nOFFQsfugi7GeYMrXkgudg9igiDdJg4ULna5wdKJFXJBNfFYP25BGctcGRz3x6MFqEev ZdmjCXsOVlQapE4SuxLbQeuRnqr7rfvn+Wln98cxO36cMq7nugOO13q6UcAfbceaXjRt vxsFmZtwUIAFXEcsA2Cy5lBKp0ZPfPjPOvOXYzNK5MvxWQAQyUi8Lyf59fyzmT4+XwOI rXHa+hIQCHwp//C9/8juwdvdkMWTeRwIptaIMIGlg/o8u6l6jnhqg4E/tDjKqw4lvbMU AAkg== X-Gm-Message-State: AOAM533aN1HhaSnhTYG0oAQk1KKWK1EluhgXE7FMPKFKBLajXIvwPhd+ XLdby30lV86/zcnbv3NO6v1sa894E4PLcg== X-Google-Smtp-Source: ABdhPJxNfbH0T8eRX1JUe3eIjjnPaBBuLLlHi82654EKs0k5yizJExTCK2eBal4X0T9QlpO/kdH4YA== X-Received: by 2002:ac8:57c4:: with SMTP id w4mr54218512qta.163.1609359314159; Wed, 30 Dec 2020 12:15:14 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id v145sm5949057qka.27.2020.12.30.12.15.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Dec 2020 12:15:13 -0800 (PST) To: libc-alpha@sourceware.org, Paul Eggert Subject: [PATCH 2/5] posix: Sync glob code with gnulib Date: Wed, 30 Dec 2020 17:15:04 -0300 Message-Id: <20201230201507.2755086-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201230201507.2755086-1-adhemerval.zanella@linaro.org> References: <20201230201507.2755086-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Netto Reply-To: Adhemerval Zanella Cc: bug-gnulib@gnu.org Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" It sync with gnulib commit 43ee1a6bf and fixes and use-after-free bug (gnulib commit 717766da8926e36). The main change over gnulib is: --- posix/glob.c +++ lib/glob.c @@ -59,6 +59,12 @@ # define readdir(str) __readdir64 (str) # define getpwnam_r(name, bufp, buf, len, res) \ __getpwnam_r (name, bufp, buf, len, res) +# ifndef __lstat64 +# define __lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf) +# endif +# ifndef __stat64 +# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) +# endif # define struct_stat64 struct stat64 # define FLEXIBLE_ARRAY_MEMBER # include Which is required since xstat symbols are not used internally anymore. Checked on x86_64-linux-gnu. --- posix/glob.c | 1748 ++++++++++++++++++++-------------------- posix/glob_pattern_p.c | 2 +- posix/globfree.c | 2 +- 3 files changed, 886 insertions(+), 866 deletions(-) diff --git a/posix/glob.c b/posix/glob.c index b4b34945e2..20239f780f 100644 --- a/posix/glob.c +++ b/posix/glob.c @@ -15,6 +15,16 @@ License along with the GNU C Library; if not, see . */ +#ifndef _LIBC + +/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc + optimizes away the pattern == NULL test below. */ +# define _GL_ARG_NONNULL(params) + +# include + +#endif + #include #include @@ -26,7 +36,7 @@ #include #include -#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +#if defined _WIN32 && ! defined __CYGWIN__ # define WINDOWS32 #endif @@ -49,14 +59,19 @@ # define readdir(str) __readdir64 (str) # define getpwnam_r(name, bufp, buf, len, res) \ __getpwnam_r (name, bufp, buf, len, res) -# define struct_stat64 struct stat64 +# define struct_stat64 struct stat64 # define FLEXIBLE_ARRAY_MEMBER # include #else /* !_LIBC */ # define __glob glob # define __getlogin_r(buf, len) getlogin_r (buf, len) # define __lstat64(fname, buf) lstat (fname, buf) +# if defined _WIN32 && !defined __CYGWIN__ + /* Avoid GCC or clang warning. The original __stat64 macro is unused. */ +# undef __stat64 +# endif # define __stat64(fname, buf) stat (fname, buf) +# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag) # define struct_stat64 struct stat # ifndef __MVS__ # define __alloca alloca @@ -73,7 +88,9 @@ static const char *next_brace_sub (const char *begin, int flags) __THROWNL; -typedef uint_fast8_t dirent_type; +/* The type of ((struct dirent *) 0)->d_type is 'unsigned char' on most + platforms, but 'unsigned int' in the mingw from mingw.org. */ +typedef uint_fast32_t dirent_type; #if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE /* Any distinct values will do here. @@ -112,9 +129,9 @@ readdir_result_type (struct readdir_result d) /* Construct an initializer for a struct readdir_result object from a struct dirent *. No copy of the name is made. */ #define READDIR_RESULT_INITIALIZER(source) \ - { \ - source->d_name, \ - D_TYPE_TO_RESULT (source) \ + { \ + source->d_name, \ + D_TYPE_TO_RESULT (source) \ } /* Call gl_readdir on STREAM. This macro can be overridden to reduce @@ -204,7 +221,7 @@ glob_lstat (glob_t *pglob, int flags, const char *fullname) static bool size_add_wrapv (size_t a, size_t b, size_t *r) { -#if 5 <= __GNUC__ && !defined __ICC +#if 7 <= __GNUC__ && !defined __ICC return __builtin_add_overflow (a, b, r); #else *r = a + b; @@ -221,8 +238,8 @@ glob_use_alloca (size_t alloca_used, size_t len) } static int glob_in_dir (const char *pattern, const char *directory, - int flags, int (*errfunc) (const char *, int), - glob_t *pglob, size_t alloca_used); + int flags, int (*errfunc) (const char *, int), + glob_t *pglob, size_t alloca_used); static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL; static int collated_compare (const void *, const void *) __THROWNL; @@ -247,17 +264,17 @@ next_brace_sub (const char *cp, int flags) while (*cp != '\0') if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\') { - if (*++cp == '\0') - break; - ++cp; + if (*++cp == '\0') + break; + ++cp; } else { - if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) - break; + if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) + break; - if (*cp++ == '{') - depth++; + if (*cp++ == '{') + depth++; } return *cp != '\0' ? cp : NULL; @@ -278,7 +295,7 @@ next_brace_sub (const char *cp, int flags) int GLOB_ATTRIBUTE __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), - glob_t *pglob) + glob_t *pglob) { const char *filename; char *dirname = NULL; @@ -312,22 +329,22 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { pglob->gl_pathc = 0; if (!(flags & GLOB_DOOFFS)) - pglob->gl_pathv = NULL; + pglob->gl_pathv = NULL; else - { - size_t i; + { + size_t i; - if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *)) - return GLOB_NOSPACE; + if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *)) + return GLOB_NOSPACE; - pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1) - * sizeof (char *)); - if (pglob->gl_pathv == NULL) - return GLOB_NOSPACE; + pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1) + * sizeof (char *)); + if (pglob->gl_pathv == NULL) + return GLOB_NOSPACE; - for (i = 0; i <= pglob->gl_offs; ++i) - pglob->gl_pathv[i] = NULL; - } + for (i = 0; i <= pglob->gl_offs; ++i) + pglob->gl_pathv[i] = NULL; + } } if (flags & GLOB_BRACE) @@ -335,129 +352,129 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), const char *begin; if (flags & GLOB_NOESCAPE) - begin = strchr (pattern, '{'); + begin = strchr (pattern, '{'); else - { - begin = pattern; - while (1) - { - if (*begin == '\0') - { - begin = NULL; - break; - } - - if (*begin == '\\' && begin[1] != '\0') - ++begin; - else if (*begin == '{') - break; - - ++begin; - } - } + { + begin = pattern; + while (1) + { + if (*begin == '\0') + { + begin = NULL; + break; + } + + if (*begin == '\\' && begin[1] != '\0') + ++begin; + else if (*begin == '{') + break; + + ++begin; + } + } if (begin != NULL) - { - /* Allocate working buffer large enough for our work. Note that - we have at least an opening and closing brace. */ - size_t firstc; - char *alt_start; - const char *p; - const char *next; - const char *rest; - size_t rest_len; - char *onealt; - size_t pattern_len = strlen (pattern) - 1; - int alloca_onealt = glob_use_alloca (alloca_used, pattern_len); - if (alloca_onealt) - onealt = alloca_account (pattern_len, alloca_used); - else - { - onealt = malloc (pattern_len); - if (onealt == NULL) - return GLOB_NOSPACE; - } - - /* We know the prefix for all sub-patterns. */ - alt_start = mempcpy (onealt, pattern, begin - pattern); - - /* Find the first sub-pattern and at the same time find the - rest after the closing brace. */ - next = next_brace_sub (begin + 1, flags); - if (next == NULL) - { - /* It is an invalid expression. */ - illegal_brace: - if (__glibc_unlikely (!alloca_onealt)) - free (onealt); - flags &= ~GLOB_BRACE; - goto no_brace; - } - - /* Now find the end of the whole brace expression. */ - rest = next; - while (*rest != '}') - { - rest = next_brace_sub (rest + 1, flags); - if (rest == NULL) - /* It is an illegal expression. */ - goto illegal_brace; - } - /* Please note that we now can be sure the brace expression - is well-formed. */ - rest_len = strlen (++rest) + 1; - - /* We have a brace expression. BEGIN points to the opening {, - NEXT points past the terminator of the first element, and END - points past the final }. We will accumulate result names from - recursive runs for each brace alternative in the buffer using - GLOB_APPEND. */ - firstc = pglob->gl_pathc; - - p = begin + 1; - while (1) - { - int result; - - /* Construct the new glob expression. */ - mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); - - result = __glob (onealt, - ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC)) - | GLOB_APPEND), - errfunc, pglob); - - /* If we got an error, return it. */ - if (result && result != GLOB_NOMATCH) - { - if (__glibc_unlikely (!alloca_onealt)) - free (onealt); - if (!(flags & GLOB_APPEND)) - { - globfree (pglob); - pglob->gl_pathc = 0; - } - return result; - } - - if (*next == '}') - /* We saw the last entry. */ - break; - - p = next + 1; - next = next_brace_sub (p, flags); - assert (next != NULL); - } - - if (__glibc_unlikely (!alloca_onealt)) - free (onealt); - - if (pglob->gl_pathc != firstc) - /* We found some entries. */ - return 0; - else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) - return GLOB_NOMATCH; - } + { + /* Allocate working buffer large enough for our work. Note that + we have at least an opening and closing brace. */ + size_t firstc; + char *alt_start; + const char *p; + const char *next; + const char *rest; + size_t rest_len; + char *onealt; + size_t pattern_len = strlen (pattern) - 1; + int alloca_onealt = glob_use_alloca (alloca_used, pattern_len); + if (alloca_onealt) + onealt = alloca_account (pattern_len, alloca_used); + else + { + onealt = malloc (pattern_len); + if (onealt == NULL) + return GLOB_NOSPACE; + } + + /* We know the prefix for all sub-patterns. */ + alt_start = mempcpy (onealt, pattern, begin - pattern); + + /* Find the first sub-pattern and at the same time find the + rest after the closing brace. */ + next = next_brace_sub (begin + 1, flags); + if (next == NULL) + { + /* It is an invalid expression. */ + illegal_brace: + if (__glibc_unlikely (!alloca_onealt)) + free (onealt); + flags &= ~GLOB_BRACE; + goto no_brace; + } + + /* Now find the end of the whole brace expression. */ + rest = next; + while (*rest != '}') + { + rest = next_brace_sub (rest + 1, flags); + if (rest == NULL) + /* It is an illegal expression. */ + goto illegal_brace; + } + /* Please note that we now can be sure the brace expression + is well-formed. */ + rest_len = strlen (++rest) + 1; + + /* We have a brace expression. BEGIN points to the opening {, + NEXT points past the terminator of the first element, and END + points past the final }. We will accumulate result names from + recursive runs for each brace alternative in the buffer using + GLOB_APPEND. */ + firstc = pglob->gl_pathc; + + p = begin + 1; + while (1) + { + int result; + + /* Construct the new glob expression. */ + mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); + + result = __glob (onealt, + ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC)) + | GLOB_APPEND), + errfunc, pglob); + + /* If we got an error, return it. */ + if (result && result != GLOB_NOMATCH) + { + if (__glibc_unlikely (!alloca_onealt)) + free (onealt); + if (!(flags & GLOB_APPEND)) + { + globfree (pglob); + pglob->gl_pathc = 0; + } + return result; + } + + if (*next == '}') + /* We saw the last entry. */ + break; + + p = next + 1; + next = next_brace_sub (p, flags); + assert (next != NULL); + } + + if (__glibc_unlikely (!alloca_onealt)) + free (onealt); + + if (pglob->gl_pathc != firstc) + /* We found some entries. */ + return 0; + else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) + return GLOB_NOMATCH; + } } no_brace: @@ -479,33 +496,33 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (filename == NULL) { /* This can mean two things: a simple name or "~name". The latter - case is nothing but a notation for a directory. */ + case is nothing but a notation for a directory. */ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~') - { - dirname = (char *) pattern; - dirlen = strlen (pattern); - - /* Set FILENAME to NULL as a special flag. This is ugly but - other solutions would require much more code. We test for - this special case below. */ - filename = NULL; - } + { + dirname = (char *) pattern; + dirlen = strlen (pattern); + + /* Set FILENAME to NULL as a special flag. This is ugly but + other solutions would require much more code. We test for + this special case below. */ + filename = NULL; + } else - { - if (__glibc_unlikely (pattern[0] == '\0')) - { - dirs.gl_pathv = NULL; - goto no_matches; - } - - filename = pattern; - dirname = (char *) "."; - dirlen = 0; - } + { + if (__glibc_unlikely (pattern[0] == '\0')) + { + dirs.gl_pathv = NULL; + goto no_matches; + } + + filename = pattern; + dirname = (char *) "."; + dirlen = 0; + } } else if (filename == pattern - || (filename == pattern + 1 && pattern[0] == '\\' - && (flags & GLOB_NOESCAPE) == 0)) + || (filename == pattern + 1 && pattern[0] == '\\' + && (flags & GLOB_NOESCAPE) == 0)) { /* "/pattern" or "\\/pattern". */ dirname = (char *) "/"; @@ -518,32 +535,32 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), dirlen = filename - pattern; #if defined __MSDOS__ || defined WINDOWS32 if (*filename == ':' - || (filename > pattern + 1 && filename[-1] == ':')) - { - char *drive_spec; - - ++dirlen; - drive_spec = __alloca (dirlen + 1); - *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; - /* For now, disallow wildcards in the drive spec, to - prevent infinite recursion in glob. */ - if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) - return GLOB_NOMATCH; - /* If this is "d:pattern", we need to copy ':' to DIRNAME - as well. If it's "d:/pattern", don't remove the slash - from "d:/", since "d:" and "d:/" are not the same.*/ - } + || (filename > pattern + 1 && filename[-1] == ':')) + { + char *drive_spec; + + ++dirlen; + drive_spec = __alloca (dirlen + 1); + *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; + /* For now, disallow wildcards in the drive spec, to + prevent infinite recursion in glob. */ + if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) + return GLOB_NOMATCH; + /* If this is "d:pattern", we need to copy ':' to DIRNAME + as well. If it's "d:/pattern", don't remove the slash + from "d:/", since "d:" and "d:/" are not the same.*/ + } #endif if (glob_use_alloca (alloca_used, dirlen + 1)) - newp = alloca_account (dirlen + 1, alloca_used); + newp = alloca_account (dirlen + 1, alloca_used); else - { - newp = malloc (dirlen + 1); - if (newp == NULL) - return GLOB_NOSPACE; - malloc_dirname = 1; - } + { + newp = malloc (dirlen + 1); + if (newp == NULL) + return GLOB_NOSPACE; + malloc_dirname = 1; + } *((char *) mempcpy (newp, pattern, dirlen)) = '\0'; dirname = newp; ++filename; @@ -559,363 +576,366 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (filename[0] == '\0' && dirlen > 1 && !drive_root) /* "pattern/". Expand "pattern", appending slashes. */ - { - int orig_flags = flags; - if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') - { - /* "pattern\\/". Remove the final backslash if it hasn't - been quoted. */ - char *p = (char *) &dirname[dirlen - 1]; - - while (p > dirname && p[-1] == '\\') --p; - if ((&dirname[dirlen] - p) & 1) - { - *(char *) &dirname[--dirlen] = '\0'; - flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); - } - } - int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob); - if (val == 0) - pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) - | (flags & GLOB_MARK)); - else if (val == GLOB_NOMATCH && flags != orig_flags) - { - /* Make sure globfree (&dirs); is a nop. */ - dirs.gl_pathv = NULL; - flags = orig_flags; - oldcount = pglob->gl_pathc + pglob->gl_offs; - goto no_matches; - } - retval = val; - goto out; - } + { + int orig_flags = flags; + if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') + { + /* "pattern\\/". Remove the final backslash if it hasn't + been quoted. */ + char *p = (char *) &dirname[dirlen - 1]; + + while (p > dirname && p[-1] == '\\') --p; + if ((&dirname[dirlen] - p) & 1) + { + *(char *) &dirname[--dirlen] = '\0'; + flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); + } + } + int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob); + if (val == 0) + pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) + | (flags & GLOB_MARK)); + else if (val == GLOB_NOMATCH && flags != orig_flags) + { + /* Make sure globfree (&dirs); is a nop. */ + dirs.gl_pathv = NULL; + flags = orig_flags; + oldcount = pglob->gl_pathc + pglob->gl_offs; + goto no_matches; + } + retval = val; + goto out; + } } if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') { if (dirname[1] == '\0' || dirname[1] == '/' - || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\' - && (dirname[2] == '\0' || dirname[2] == '/'))) - { - /* Look up home directory. */ - char *home_dir = getenv ("HOME"); - int malloc_home_dir = 0; - if (home_dir == NULL || home_dir[0] == '\0') - { + || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\' + && (dirname[2] == '\0' || dirname[2] == '/'))) + { + /* Look up home directory. */ + char *home_dir = getenv ("HOME"); + int malloc_home_dir = 0; + if (home_dir == NULL || home_dir[0] == '\0') + { #ifdef WINDOWS32 - /* Windows NT defines HOMEDRIVE and HOMEPATH. But give - preference to HOME, because the user can change HOME. */ - const char *home_drive = getenv ("HOMEDRIVE"); - const char *home_path = getenv ("HOMEPATH"); - - if (home_drive != NULL && home_path != NULL) - { - size_t home_drive_len = strlen (home_drive); - size_t home_path_len = strlen (home_path); - char *mem = alloca (home_drive_len + home_path_len + 1); - - memcpy (mem, home_drive, home_drive_len); - memcpy (mem + home_drive_len, home_path, home_path_len + 1); - home_dir = mem; - } - else - home_dir = "c:/users/default"; /* poor default */ + /* Windows NT defines HOMEDRIVE and HOMEPATH. But give + preference to HOME, because the user can change HOME. */ + const char *home_drive = getenv ("HOMEDRIVE"); + const char *home_path = getenv ("HOMEPATH"); + + if (home_drive != NULL && home_path != NULL) + { + size_t home_drive_len = strlen (home_drive); + size_t home_path_len = strlen (home_path); + char *mem = alloca (home_drive_len + home_path_len + 1); + + memcpy (mem, home_drive, home_drive_len); + memcpy (mem + home_drive_len, home_path, home_path_len + 1); + home_dir = mem; + } + else + home_dir = "c:/users/default"; /* poor default */ #else - int err; - struct passwd *p; - struct passwd pwbuf; - struct scratch_buffer s; - scratch_buffer_init (&s); - while (true) - { - p = NULL; - err = __getlogin_r (s.data, s.length); - if (err == 0) - { + int err; + struct passwd *p; + struct passwd pwbuf; + struct scratch_buffer s; + scratch_buffer_init (&s); + while (true) + { + p = NULL; + err = __getlogin_r (s.data, s.length); + if (err == 0) + { # if defined HAVE_GETPWNAM_R || defined _LIBC - size_t ssize = strlen (s.data) + 1; - char *sdata = s.data; - err = getpwnam_r (sdata, &pwbuf, sdata + ssize, - s.length - ssize, &p); + size_t ssize = strlen (s.data) + 1; + char *sdata = s.data; + err = getpwnam_r (sdata, &pwbuf, sdata + ssize, + s.length - ssize, &p); # else - p = getpwnam (s.data); - if (p == NULL) - err = errno; + p = getpwnam (s.data); + if (p == NULL) + err = errno; # endif - } - if (err != ERANGE) - break; - if (!scratch_buffer_grow (&s)) - { - retval = GLOB_NOSPACE; - goto out; - } - } - if (err == 0) - { - home_dir = strdup (p->pw_dir); - malloc_home_dir = 1; - } - scratch_buffer_free (&s); - if (err == 0 && home_dir == NULL) - { - retval = GLOB_NOSPACE; - goto out; - } + } + if (err != ERANGE) + break; + if (!scratch_buffer_grow (&s)) + { + retval = GLOB_NOSPACE; + goto out; + } + } + if (err == 0) + { + home_dir = strdup (p->pw_dir); + malloc_home_dir = 1; + } + scratch_buffer_free (&s); + if (err == 0 && home_dir == NULL) + { + retval = GLOB_NOSPACE; + goto out; + } #endif /* WINDOWS32 */ - } - if (home_dir == NULL || home_dir[0] == '\0') - { - if (__glibc_unlikely (malloc_home_dir)) - free (home_dir); - if (flags & GLOB_TILDE_CHECK) - { - retval = GLOB_NOMATCH; - goto out; - } - else - { - home_dir = (char *) "~"; /* No luck. */ - malloc_home_dir = 0; - } - } - /* Now construct the full directory. */ - if (dirname[1] == '\0') - { - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - - dirname = home_dir; - dirlen = strlen (dirname); - malloc_dirname = malloc_home_dir; - } - else - { - char *newp; - size_t home_len = strlen (home_dir); - int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); - if (use_alloca) - newp = alloca_account (home_len + dirlen, alloca_used); - else - { - newp = malloc (home_len + dirlen); - if (newp == NULL) - { - if (__glibc_unlikely (malloc_home_dir)) - free (home_dir); - retval = GLOB_NOSPACE; - goto out; - } - } - - mempcpy (mempcpy (newp, home_dir, home_len), - &dirname[1], dirlen); - - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - - dirname = newp; - dirlen += home_len - 1; - malloc_dirname = !use_alloca; - - if (__glibc_unlikely (malloc_home_dir)) - free (home_dir); - } - dirname_modified = 1; - } + } + if (home_dir == NULL || home_dir[0] == '\0') + { + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); + if (flags & GLOB_TILDE_CHECK) + { + retval = GLOB_NOMATCH; + goto out; + } + else + { + home_dir = (char *) "~"; /* No luck. */ + malloc_home_dir = 0; + } + } + /* Now construct the full directory. */ + if (dirname[1] == '\0') + { + if (__glibc_unlikely (malloc_dirname)) + free (dirname); + + dirname = home_dir; + dirlen = strlen (dirname); + malloc_dirname = malloc_home_dir; + } + else + { + char *newp; + size_t home_len = strlen (home_dir); + int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); + if (use_alloca) + newp = alloca_account (home_len + dirlen, alloca_used); + else + { + newp = malloc (home_len + dirlen); + if (newp == NULL) + { + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); + retval = GLOB_NOSPACE; + goto out; + } + } + + mempcpy (mempcpy (newp, home_dir, home_len), + &dirname[1], dirlen); + + if (__glibc_unlikely (malloc_dirname)) + free (dirname); + + dirname = newp; + dirlen += home_len - 1; + malloc_dirname = !use_alloca; + + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); + } + dirname_modified = 1; + } else - { + { #ifndef WINDOWS32 - char *end_name = strchr (dirname, '/'); - char *user_name; - int malloc_user_name = 0; - char *unescape = NULL; - - if (!(flags & GLOB_NOESCAPE)) - { - if (end_name == NULL) - { - unescape = strchr (dirname, '\\'); - if (unescape) - end_name = strchr (unescape, '\0'); - } - else - unescape = memchr (dirname, '\\', end_name - dirname); - } - if (end_name == NULL) - user_name = dirname + 1; - else - { - char *newp; - if (glob_use_alloca (alloca_used, end_name - dirname)) - newp = alloca_account (end_name - dirname, alloca_used); - else - { - newp = malloc (end_name - dirname); - if (newp == NULL) - { - retval = GLOB_NOSPACE; - goto out; - } - malloc_user_name = 1; - } - if (unescape != NULL) - { - char *p = mempcpy (newp, dirname + 1, - unescape - dirname - 1); - char *q = unescape; - while (q != end_name) - { - if (*q == '\\') - { - if (q + 1 == end_name) - { - /* "~fo\\o\\" unescape to user_name "foo\\", - but "~fo\\o\\/" unescape to user_name - "foo". */ - if (filename == NULL) - *p++ = '\\'; - break; - } - ++q; - } - *p++ = *q++; - } - *p = '\0'; - } - else - *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1)) - = '\0'; - user_name = newp; - } - - /* Look up specific user's home directory. */ - { - struct passwd *p; - struct scratch_buffer pwtmpbuf; - scratch_buffer_init (&pwtmpbuf); + char *end_name = strchr (dirname, '/'); + char *user_name; + int malloc_user_name = 0; + char *unescape = NULL; + + if (!(flags & GLOB_NOESCAPE)) + { + if (end_name == NULL) + { + unescape = strchr (dirname, '\\'); + if (unescape) + end_name = strchr (unescape, '\0'); + } + else + unescape = memchr (dirname, '\\', end_name - dirname); + } + if (end_name == NULL) + user_name = dirname + 1; + else + { + char *newp; + if (glob_use_alloca (alloca_used, end_name - dirname)) + newp = alloca_account (end_name - dirname, alloca_used); + else + { + newp = malloc (end_name - dirname); + if (newp == NULL) + { + retval = GLOB_NOSPACE; + goto out; + } + malloc_user_name = 1; + } + if (unescape != NULL) + { + char *p = mempcpy (newp, dirname + 1, + unescape - dirname - 1); + char *q = unescape; + while (q != end_name) + { + if (*q == '\\') + { + if (q + 1 == end_name) + { + /* "~fo\\o\\" unescape to user_name "foo\\", + but "~fo\\o\\/" unescape to user_name + "foo". */ + if (filename == NULL) + *p++ = '\\'; + break; + } + ++q; + } + *p++ = *q++; + } + *p = '\0'; + } + else + *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1)) + = '\0'; + user_name = newp; + } + + /* Look up specific user's home directory. */ + { + struct passwd *p; + struct scratch_buffer pwtmpbuf; + scratch_buffer_init (&pwtmpbuf); # if defined HAVE_GETPWNAM_R || defined _LIBC - struct passwd pwbuf; - - while (getpwnam_r (user_name, &pwbuf, - pwtmpbuf.data, pwtmpbuf.length, &p) - == ERANGE) - { - if (!scratch_buffer_grow (&pwtmpbuf)) - { - retval = GLOB_NOSPACE; - goto out; - } - } + struct passwd pwbuf; + + while (getpwnam_r (user_name, &pwbuf, + pwtmpbuf.data, pwtmpbuf.length, &p) + == ERANGE) + { + if (!scratch_buffer_grow (&pwtmpbuf)) + { + retval = GLOB_NOSPACE; + goto out; + } + } # else - p = getpwnam (user_name); + p = getpwnam (user_name); # endif - if (__glibc_unlikely (malloc_user_name)) - free (user_name); - - /* If we found a home directory use this. */ - if (p != NULL) - { - size_t home_len = strlen (p->pw_dir); - size_t rest_len = end_name == NULL ? 0 : strlen (end_name); - char *d, *newp; - bool use_alloca = glob_use_alloca (alloca_used, - home_len + rest_len + 1); - - if (use_alloca) - newp = alloca_account (home_len + rest_len + 1, alloca_used); - else - { - newp = malloc (home_len + rest_len + 1); - if (newp == NULL) - { - scratch_buffer_free (&pwtmpbuf); - retval = GLOB_NOSPACE; - goto out; - } - } - d = mempcpy (newp, p->pw_dir, home_len); - if (end_name != NULL) - d = mempcpy (d, end_name, rest_len); - *d = '\0'; - - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - dirname = newp; - malloc_dirname = !use_alloca; - - dirlen = home_len + rest_len; - dirname_modified = 1; - } - else - { - if (flags & GLOB_TILDE_CHECK) - { - /* We have to regard it as an error if we cannot find the - home directory. */ - retval = GLOB_NOMATCH; - goto out; - } - } - scratch_buffer_free (&pwtmpbuf); - } + if (__glibc_unlikely (malloc_user_name)) + free (user_name); + + /* If we found a home directory use this. */ + if (p != NULL) + { + size_t home_len = strlen (p->pw_dir); + size_t rest_len = end_name == NULL ? 0 : strlen (end_name); + /* dirname contains end_name; we can't free it now. */ + char *prev_dirname = + (__glibc_unlikely (malloc_dirname) ? dirname : NULL); + char *d; + + malloc_dirname = 0; + + if (glob_use_alloca (alloca_used, home_len + rest_len + 1)) + dirname = alloca_account (home_len + rest_len + 1, + alloca_used); + else + { + dirname = malloc (home_len + rest_len + 1); + if (dirname == NULL) + { + free (prev_dirname); + scratch_buffer_free (&pwtmpbuf); + retval = GLOB_NOSPACE; + goto out; + } + malloc_dirname = 1; + } + d = mempcpy (dirname, p->pw_dir, home_len); + if (end_name != NULL) + d = mempcpy (d, end_name, rest_len); + *d = '\0'; + + free (prev_dirname); + + dirlen = home_len + rest_len; + dirname_modified = 1; + } + else + { + if (flags & GLOB_TILDE_CHECK) + { + /* We have to regard it as an error if we cannot find the + home directory. */ + retval = GLOB_NOMATCH; + goto out; + } + } + scratch_buffer_free (&pwtmpbuf); + } #endif /* !WINDOWS32 */ - } + } } /* Now test whether we looked for "~" or "~NAME". In this case we can give the answer now. */ if (filename == NULL) { - size_t newcount = pglob->gl_pathc + pglob->gl_offs; - char **new_gl_pathv; - - if (newcount > SIZE_MAX / sizeof (char *) - 2) - { - nospace: - free (pglob->gl_pathv); - pglob->gl_pathv = NULL; - pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; - } - - new_gl_pathv = realloc (pglob->gl_pathv, - (newcount + 2) * sizeof (char *)); - if (new_gl_pathv == NULL) - goto nospace; - pglob->gl_pathv = new_gl_pathv; - - if (flags & GLOB_MARK && is_dir (dirname, flags, pglob)) - { - char *p; - pglob->gl_pathv[newcount] = malloc (dirlen + 2); - if (pglob->gl_pathv[newcount] == NULL) - goto nospace; - p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); - p[0] = '/'; - p[1] = '\0'; - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - } - else - { - if (__glibc_unlikely (malloc_dirname)) - pglob->gl_pathv[newcount] = dirname; - else - { - pglob->gl_pathv[newcount] = strdup (dirname); - if (pglob->gl_pathv[newcount] == NULL) - goto nospace; - } - } - pglob->gl_pathv[++newcount] = NULL; - ++pglob->gl_pathc; - pglob->gl_flags = flags; - - return 0; + size_t newcount = pglob->gl_pathc + pglob->gl_offs; + char **new_gl_pathv; + + if (newcount > SIZE_MAX / sizeof (char *) - 2) + { + nospace: + free (pglob->gl_pathv); + pglob->gl_pathv = NULL; + pglob->gl_pathc = 0; + retval = GLOB_NOSPACE; + goto out; + } + + new_gl_pathv = realloc (pglob->gl_pathv, + (newcount + 2) * sizeof (char *)); + if (new_gl_pathv == NULL) + goto nospace; + pglob->gl_pathv = new_gl_pathv; + + if (flags & GLOB_MARK && is_dir (dirname, flags, pglob)) + { + char *p; + pglob->gl_pathv[newcount] = malloc (dirlen + 2); + if (pglob->gl_pathv[newcount] == NULL) + goto nospace; + p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); + p[0] = '/'; + p[1] = '\0'; + if (__glibc_unlikely (malloc_dirname)) + free (dirname); + } + else + { + if (__glibc_unlikely (malloc_dirname)) + pglob->gl_pathv[newcount] = dirname; + else + { + pglob->gl_pathv[newcount] = strdup (dirname); + if (pglob->gl_pathv[newcount] == NULL) + goto nospace; + } + } + pglob->gl_pathv[++newcount] = NULL; + ++pglob->gl_pathc; + pglob->gl_flags = flags; + + return 0; } meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE)); @@ -927,135 +947,135 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (meta & (GLOBPAT_SPECIAL | GLOBPAT_BRACKET)) { /* The directory name contains metacharacters, so we - have to glob for the directory, and then glob for - the pattern in each directory found. */ + have to glob for the directory, and then glob for + the pattern in each directory found. */ size_t i; if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\') - { - /* "foo\\/bar". Remove the final backslash from dirname - if it has not been quoted. */ - char *p = (char *) &dirname[dirlen - 1]; + { + /* "foo\\/bar". Remove the final backslash from dirname + if it has not been quoted. */ + char *p = (char *) &dirname[dirlen - 1]; - while (p > dirname && p[-1] == '\\') --p; - if ((&dirname[dirlen] - p) & 1) - *(char *) &dirname[--dirlen] = '\0'; - } + while (p > dirname && p[-1] == '\\') --p; + if ((&dirname[dirlen] - p) & 1) + *(char *) &dirname[--dirlen] = '\0'; + } if (__glibc_unlikely ((flags & GLOB_ALTDIRFUNC) != 0)) - { - /* Use the alternative access functions also in the recursive - call. */ - dirs.gl_opendir = pglob->gl_opendir; - dirs.gl_readdir = pglob->gl_readdir; - dirs.gl_closedir = pglob->gl_closedir; - dirs.gl_stat = pglob->gl_stat; - dirs.gl_lstat = pglob->gl_lstat; - } + { + /* Use the alternative access functions also in the recursive + call. */ + dirs.gl_opendir = pglob->gl_opendir; + dirs.gl_readdir = pglob->gl_readdir; + dirs.gl_closedir = pglob->gl_closedir; + dirs.gl_stat = pglob->gl_stat; + dirs.gl_lstat = pglob->gl_lstat; + } status = __glob (dirname, - ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC)) - | GLOB_NOSORT | GLOB_ONLYDIR), - errfunc, &dirs); + ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC)) + | GLOB_NOSORT | GLOB_ONLYDIR), + errfunc, &dirs); if (status != 0) - { - if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) - { - retval = status; - goto out; - } - goto no_matches; - } + { + if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) + { + retval = status; + goto out; + } + goto no_matches; + } /* We have successfully globbed the preceding directory name. - For each name we found, call glob_in_dir on it and FILENAME, - appending the results to PGLOB. */ + For each name we found, call glob_in_dir on it and FILENAME, + appending the results to PGLOB. */ for (i = 0; i < dirs.gl_pathc; ++i) - { - size_t old_pathc; - - old_pathc = pglob->gl_pathc; - status = glob_in_dir (filename, dirs.gl_pathv[i], - ((flags | GLOB_APPEND) - & ~(GLOB_NOCHECK | GLOB_NOMAGIC)), - errfunc, pglob, alloca_used); - if (status == GLOB_NOMATCH) - /* No matches in this directory. Try the next. */ - continue; - - if (status != 0) - { - globfree (&dirs); - globfree (pglob); - pglob->gl_pathc = 0; - retval = status; - goto out; - } - - /* Stick the directory on the front of each name. */ - if (prefix_array (dirs.gl_pathv[i], - &pglob->gl_pathv[old_pathc + pglob->gl_offs], - pglob->gl_pathc - old_pathc)) - { - globfree (&dirs); - globfree (pglob); - pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; - } - } + { + size_t old_pathc; + + old_pathc = pglob->gl_pathc; + status = glob_in_dir (filename, dirs.gl_pathv[i], + ((flags | GLOB_APPEND) + & ~(GLOB_NOCHECK | GLOB_NOMAGIC)), + errfunc, pglob, alloca_used); + if (status == GLOB_NOMATCH) + /* No matches in this directory. Try the next. */ + continue; + + if (status != 0) + { + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; + retval = status; + goto out; + } + + /* Stick the directory on the front of each name. */ + if (prefix_array (dirs.gl_pathv[i], + &pglob->gl_pathv[old_pathc + pglob->gl_offs], + pglob->gl_pathc - old_pathc)) + { + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; + retval = GLOB_NOSPACE; + goto out; + } + } flags |= GLOB_MAGCHAR; /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls. - But if we have not found any matching entry and the GLOB_NOCHECK - flag was set we must return the input pattern itself. */ + But if we have not found any matching entry and the GLOB_NOCHECK + flag was set we must return the input pattern itself. */ if (pglob->gl_pathc + pglob->gl_offs == oldcount) - { - no_matches: - /* No matches. */ - if (flags & GLOB_NOCHECK) - { - size_t newcount = pglob->gl_pathc + pglob->gl_offs; - char **new_gl_pathv; - - if (newcount > SIZE_MAX / sizeof (char *) - 2) - { - nospace2: - globfree (&dirs); - retval = GLOB_NOSPACE; - goto out; - } - - new_gl_pathv = realloc (pglob->gl_pathv, - (newcount + 2) * sizeof (char *)); - if (new_gl_pathv == NULL) - goto nospace2; - pglob->gl_pathv = new_gl_pathv; - - pglob->gl_pathv[newcount] = strdup (pattern); - if (pglob->gl_pathv[newcount] == NULL) - { - globfree (&dirs); - globfree (pglob); - pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; - } - - ++pglob->gl_pathc; - ++newcount; - - pglob->gl_pathv[newcount] = NULL; - pglob->gl_flags = flags; - } - else - { - globfree (&dirs); - retval = GLOB_NOMATCH; - goto out; - } - } + { + no_matches: + /* No matches. */ + if (flags & GLOB_NOCHECK) + { + size_t newcount = pglob->gl_pathc + pglob->gl_offs; + char **new_gl_pathv; + + if (newcount > SIZE_MAX / sizeof (char *) - 2) + { + nospace2: + globfree (&dirs); + retval = GLOB_NOSPACE; + goto out; + } + + new_gl_pathv = realloc (pglob->gl_pathv, + (newcount + 2) * sizeof (char *)); + if (new_gl_pathv == NULL) + goto nospace2; + pglob->gl_pathv = new_gl_pathv; + + pglob->gl_pathv[newcount] = strdup (pattern); + if (pglob->gl_pathv[newcount] == NULL) + { + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; + retval = GLOB_NOSPACE; + goto out; + } + + ++pglob->gl_pathc; + ++newcount; + + pglob->gl_pathv[newcount] = NULL; + pglob->gl_flags = flags; + } + else + { + globfree (&dirs); + retval = GLOB_NOMATCH; + goto out; + } + } globfree (&dirs); } @@ -1065,57 +1085,57 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), int orig_flags = flags; if (meta & GLOBPAT_BACKSLASH) - { - char *p = strchr (dirname, '\\'), *q; - /* We need to unescape the dirname string. It is certainly - allocated by alloca, as otherwise filename would be NULL - or dirname wouldn't contain backslashes. */ - q = p; - do - { - if (*p == '\\') - { - *q = *++p; - --dirlen; - } - else - *q = *p; - ++q; - } - while (*p++ != '\0'); - dirname_modified = 1; - } + { + char *p = strchr (dirname, '\\'), *q; + /* We need to unescape the dirname string. It is certainly + allocated by alloca, as otherwise filename would be NULL + or dirname wouldn't contain backslashes. */ + q = p; + do + { + if (*p == '\\') + { + *q = *++p; + --dirlen; + } + else + *q = *p; + ++q; + } + while (*p++ != '\0'); + dirname_modified = 1; + } if (dirname_modified) - flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); + flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); status = glob_in_dir (filename, dirname, flags, errfunc, pglob, - alloca_used); + alloca_used); if (status != 0) - { - if (status == GLOB_NOMATCH && flags != orig_flags - && pglob->gl_pathc + pglob->gl_offs == oldcount) - { - /* Make sure globfree (&dirs); is a nop. */ - dirs.gl_pathv = NULL; - flags = orig_flags; - goto no_matches; - } - retval = status; - goto out; - } + { + if (status == GLOB_NOMATCH && flags != orig_flags + && pglob->gl_pathc + pglob->gl_offs == oldcount) + { + /* Make sure globfree (&dirs); is a nop. */ + dirs.gl_pathv = NULL; + flags = orig_flags; + goto no_matches; + } + retval = status; + goto out; + } if (dirlen > 0) - { - /* Stick the directory on the front of each name. */ - if (prefix_array (dirname, - &pglob->gl_pathv[old_pathc + pglob->gl_offs], - pglob->gl_pathc - old_pathc)) - { - globfree (pglob); - pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; - } - } + { + /* Stick the directory on the front of each name. */ + if (prefix_array (dirname, + &pglob->gl_pathv[old_pathc + pglob->gl_offs], + pglob->gl_pathc - old_pathc)) + { + globfree (pglob); + pglob->gl_pathc = 0; + retval = GLOB_NOSPACE; + goto out; + } + } } if (flags & GLOB_MARK) @@ -1124,28 +1144,28 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), size_t i; for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i) - if (is_dir (pglob->gl_pathv[i], flags, pglob)) - { - size_t len = strlen (pglob->gl_pathv[i]) + 2; - char *new = realloc (pglob->gl_pathv[i], len); - if (new == NULL) - { - globfree (pglob); - pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; - } - strcpy (&new[len - 2], "/"); - pglob->gl_pathv[i] = new; - } + if (is_dir (pglob->gl_pathv[i], flags, pglob)) + { + size_t len = strlen (pglob->gl_pathv[i]) + 2; + char *new = realloc (pglob->gl_pathv[i], len); + if (new == NULL) + { + globfree (pglob); + pglob->gl_pathc = 0; + retval = GLOB_NOSPACE; + goto out; + } + strcpy (&new[len - 2], "/"); + pglob->gl_pathv[i] = new; + } } if (!(flags & GLOB_NOSORT)) { /* Sort the vector. */ qsort (&pglob->gl_pathv[oldcount], - pglob->gl_pathc + pglob->gl_offs - oldcount, - sizeof (char *), collated_compare); + pglob->gl_pathc + pglob->gl_offs - oldcount, + sizeof (char *), collated_compare); } out: @@ -1197,14 +1217,14 @@ prefix_array (const char *dirname, char **array, size_t n) if (dirlen > 1) { if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':') - /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ - --dirlen; + /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ + --dirlen; else if (dirname[dirlen - 1] == ':') - { - /* DIRNAME is "d:". Use ':' instead of '/'. */ - --dirlen; - dirsep_char = ':'; - } + { + /* DIRNAME is "d:". Use ':' instead of '/'. */ + --dirlen; + dirsep_char = ':'; + } } #endif @@ -1213,16 +1233,16 @@ prefix_array (const char *dirname, char **array, size_t n) size_t eltlen = strlen (array[i]) + 1; char *new = malloc (dirlen + 1 + eltlen); if (new == NULL) - { - while (i > 0) - free (array[--i]); - return 1; - } + { + while (i > 0) + free (array[--i]); + return 1; + } { - char *endp = mempcpy (new, dirname, dirlen); - *endp++ = dirsep_char; - mempcpy (endp, array[i], eltlen); + char *endp = mempcpy (new, dirname, dirlen); + *endp++ = dirsep_char; + mempcpy (endp, array[i], eltlen); } free (array[i]); array[i] = new; @@ -1237,8 +1257,8 @@ prefix_array (const char *dirname, char **array, size_t n) The GLOB_APPEND flag is assumed to be set (always appends). */ static int glob_in_dir (const char *pattern, const char *directory, int flags, - int (*errfunc) (const char *, int), - glob_t *pglob, size_t alloca_used) + int (*errfunc) (const char *, int), + glob_t *pglob, size_t alloca_used) { size_t dirlen = strlen (directory); void *stream = NULL; @@ -1266,8 +1286,8 @@ glob_in_dir (const char *pattern, const char *directory, int flags, if (meta == GLOBPAT_NONE && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) { /* We need not do any tests. The PATTERN contains no meta - characters and we must not return an error therefore the - result will always contain exactly one name. */ + characters and we must not return an error therefore the + result will always contain exactly one name. */ flags |= GLOB_NOCHECK; } else if (meta == GLOBPAT_NONE) @@ -1281,102 +1301,102 @@ glob_in_dir (const char *pattern, const char *directory, int flags, if (alloca_fullname) fullname = alloca_account (fullsize, alloca_used); else - { - fullname = malloc (fullsize); - if (fullname == NULL) - return GLOB_NOSPACE; - } + { + fullname = malloc (fullsize); + if (fullname == NULL) + return GLOB_NOSPACE; + } mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), - "/", 1), - pattern, patlen + 1); + "/", 1), + pattern, patlen + 1); if (glob_lstat (pglob, flags, fullname) == 0 - || errno == EOVERFLOW) - /* We found this file to be existing. Now tell the rest - of the function to copy this name into the result. */ - flags |= GLOB_NOCHECK; + || errno == EOVERFLOW) + /* We found this file to be existing. Now tell the rest + of the function to copy this name into the result. */ + flags |= GLOB_NOCHECK; if (__glibc_unlikely (!alloca_fullname)) - free (fullname); + free (fullname); } else { stream = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) - ? (*pglob->gl_opendir) (directory) - : opendir (directory)); + ? (*pglob->gl_opendir) (directory) + : opendir (directory)); if (stream == NULL) - { - if (errno != ENOTDIR - && ((errfunc != NULL && (*errfunc) (directory, errno)) - || (flags & GLOB_ERR))) - return GLOB_ABORTED; - } + { + if (errno != ENOTDIR + && ((errfunc != NULL && (*errfunc) (directory, errno)) + || (flags & GLOB_ERR))) + return GLOB_ABORTED; + } else - { - int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) - | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); - flags |= GLOB_MAGCHAR; - - while (1) - { - struct readdir_result d; - { - if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) - d = convert_dirent (GL_READDIR (pglob, stream)); - else - { + { + int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) + | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); + flags |= GLOB_MAGCHAR; + + while (1) + { + struct readdir_result d; + { + if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) + d = convert_dirent (GL_READDIR (pglob, stream)); + else + { #ifdef COMPILE_GLOB64 - d = convert_dirent (__readdir (stream)); + d = convert_dirent (__readdir (stream)); #else - d = convert_dirent64 (__readdir64 (stream)); + d = convert_dirent64 (__readdir64 (stream)); #endif - } - } - if (d.name == NULL) - break; - - /* If we shall match only directories use the information - provided by the dirent call if possible. */ - if (flags & GLOB_ONLYDIR) - switch (readdir_result_type (d)) - { - case DT_DIR: case DT_LNK: case DT_UNKNOWN: break; - default: continue; - } - - if (fnmatch (pattern, d.name, fnm_flags) == 0) - { - if (cur == names->count) - { - struct globnames *newnames; - size_t count = names->count * 2; - size_t nameoff = offsetof (struct globnames, name); - size_t size = FLEXSIZEOF (struct globnames, name, - count * sizeof (char *)); - if ((SIZE_MAX - nameoff) / 2 / sizeof (char *) - < names->count) - goto memory_error; - if (glob_use_alloca (alloca_used, size)) - newnames = names_alloca - = alloca_account (size, alloca_used); - else if ((newnames = malloc (size)) - == NULL) - goto memory_error; - newnames->count = count; - newnames->next = names; - names = newnames; - cur = 0; - } - names->name[cur] = strdup (d.name); - if (names->name[cur] == NULL) - goto memory_error; - ++cur; - ++nfound; - if (SIZE_MAX - pglob->gl_offs <= nfound) - goto memory_error; - } - } - } + } + } + if (d.name == NULL) + break; + + /* If we shall match only directories use the information + provided by the dirent call if possible. */ + if (flags & GLOB_ONLYDIR) + switch (readdir_result_type (d)) + { + case DT_DIR: case DT_LNK: case DT_UNKNOWN: break; + default: continue; + } + + if (fnmatch (pattern, d.name, fnm_flags) == 0) + { + if (cur == names->count) + { + struct globnames *newnames; + size_t count = names->count * 2; + size_t nameoff = offsetof (struct globnames, name); + size_t size = FLEXSIZEOF (struct globnames, name, + count * sizeof (char *)); + if ((SIZE_MAX - nameoff) / 2 / sizeof (char *) + < names->count) + goto memory_error; + if (glob_use_alloca (alloca_used, size)) + newnames = names_alloca + = alloca_account (size, alloca_used); + else if ((newnames = malloc (size)) + == NULL) + goto memory_error; + newnames->count = count; + newnames->next = names; + names = newnames; + cur = 0; + } + names->name[cur] = strdup (d.name); + if (names->name[cur] == NULL) + goto memory_error; + ++cur; + ++nfound; + if (SIZE_MAX - pglob->gl_offs <= nfound) + goto memory_error; + } + } + } } if (nfound == 0 && (flags & GLOB_NOCHECK)) @@ -1385,7 +1405,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags, nfound = 1; names->name[cur] = malloc (len + 1); if (names->name[cur] == NULL) - goto memory_error; + goto memory_error; *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0'; } @@ -1396,80 +1416,80 @@ glob_in_dir (const char *pattern, const char *directory, int flags, result = 0; if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc - < pglob->gl_offs + nfound + 1) - goto memory_error; + < pglob->gl_offs + nfound + 1) + goto memory_error; new_gl_pathv - = realloc (pglob->gl_pathv, - (pglob->gl_pathc + pglob->gl_offs + nfound + 1) - * sizeof (char *)); + = realloc (pglob->gl_pathv, + (pglob->gl_pathc + pglob->gl_offs + nfound + 1) + * sizeof (char *)); if (new_gl_pathv == NULL) - { - memory_error: - while (1) - { - struct globnames *old = names; - for (size_t i = 0; i < cur; ++i) - free (names->name[i]); - names = names->next; - /* NB: we will not leak memory here if we exit without - freeing the current block assigned to OLD. At least - the very first block is always allocated on the stack - and this is the block assigned to OLD here. */ - if (names == NULL) - { - assert (old == init_names); - break; - } - cur = names->count; - if (old == names_alloca) - names_alloca = names; - else - free (old); - } - result = GLOB_NOSPACE; - } + { + memory_error: + while (1) + { + struct globnames *old = names; + for (size_t i = 0; i < cur; ++i) + free (names->name[i]); + names = names->next; + /* NB: we will not leak memory here if we exit without + freeing the current block assigned to OLD. At least + the very first block is always allocated on the stack + and this is the block assigned to OLD here. */ + if (names == NULL) + { + assert (old == init_names); + break; + } + cur = names->count; + if (old == names_alloca) + names_alloca = names; + else + free (old); + } + result = GLOB_NOSPACE; + } else - { - while (1) - { - struct globnames *old = names; - for (size_t i = 0; i < cur; ++i) - new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++] - = names->name[i]; - names = names->next; - /* NB: we will not leak memory here if we exit without - freeing the current block assigned to OLD. At least - the very first block is always allocated on the stack - and this is the block assigned to OLD here. */ - if (names == NULL) - { - assert (old == init_names); - break; - } - cur = names->count; - if (old == names_alloca) - names_alloca = names; - else - free (old); - } - - pglob->gl_pathv = new_gl_pathv; - - pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; - - pglob->gl_flags = flags; - } + { + while (1) + { + struct globnames *old = names; + for (size_t i = 0; i < cur; ++i) + new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++] + = names->name[i]; + names = names->next; + /* NB: we will not leak memory here if we exit without + freeing the current block assigned to OLD. At least + the very first block is always allocated on the stack + and this is the block assigned to OLD here. */ + if (names == NULL) + { + assert (old == init_names); + break; + } + cur = names->count; + if (old == names_alloca) + names_alloca = names; + else + free (old); + } + + pglob->gl_pathv = new_gl_pathv; + + pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + + pglob->gl_flags = flags; + } } if (stream != NULL) { save = errno; if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)) - (*pglob->gl_closedir) (stream); + (*pglob->gl_closedir) (stream); else - closedir (stream); + closedir (stream); __set_errno (save); } diff --git a/posix/glob_pattern_p.c b/posix/glob_pattern_p.c index f187baa1a5..436d38126d 100644 --- a/posix/glob_pattern_p.c +++ b/posix/glob_pattern_p.c @@ -17,7 +17,7 @@ . */ #ifndef _LIBC -# include +# include #endif #include diff --git a/posix/globfree.c b/posix/globfree.c index 162b90341a..1144fdd69f 100644 --- a/posix/globfree.c +++ b/posix/globfree.c @@ -17,7 +17,7 @@ . */ #ifndef _LIBC -# include +# include #endif #include