17c478bd9Sstevel@tonic-gate /* 2a5229c74SGary Mills * Copyright (c) 2013 Gary Mills 3a5229c74SGary Mills */ 4a5229c74SGary Mills /* $OpenBSD: glob.c,v 1.39 2012/01/20 07:09:42 tedu Exp $ */ 5a5229c74SGary Mills /* 6a5229c74SGary Mills * Copyright (c) 1989, 1993 7a5229c74SGary Mills * The Regents of the University of California. All rights reserved. 87c478bd9Sstevel@tonic-gate * 9a5229c74SGary Mills * This code is derived from software contributed to Berkeley by 10a5229c74SGary Mills * Guido van Rossum. 117c478bd9Sstevel@tonic-gate * 12a5229c74SGary Mills * Redistribution and use in source and binary forms, with or without 13a5229c74SGary Mills * modification, are permitted provided that the following conditions 14a5229c74SGary Mills * are met: 15a5229c74SGary Mills * 1. Redistributions of source code must retain the above copyright 16a5229c74SGary Mills * notice, this list of conditions and the following disclaimer. 17a5229c74SGary Mills * 2. Redistributions in binary form must reproduce the above copyright 18a5229c74SGary Mills * notice, this list of conditions and the following disclaimer in the 19a5229c74SGary Mills * documentation and/or other materials provided with the distribution. 20a5229c74SGary Mills * 3. Neither the name of the University nor the names of its contributors 21a5229c74SGary Mills * may be used to endorse or promote products derived from this software 22a5229c74SGary Mills * without specific prior written permission. 237c478bd9Sstevel@tonic-gate * 24a5229c74SGary Mills * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25a5229c74SGary Mills * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26a5229c74SGary Mills * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27a5229c74SGary Mills * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28a5229c74SGary Mills * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29a5229c74SGary Mills * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30a5229c74SGary Mills * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31a5229c74SGary Mills * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32a5229c74SGary Mills * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33a5229c74SGary Mills * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34a5229c74SGary Mills * SUCH DAMAGE. 357c478bd9Sstevel@tonic-gate */ 36e8031f0aSraf 377c478bd9Sstevel@tonic-gate /* 38a5229c74SGary Mills * glob(3) -- a superset of the one defined in POSIX 1003.2. 39a5229c74SGary Mills * 40a5229c74SGary Mills * The [!...] convention to negate a range is supported (SysV, Posix, ksh). 41a5229c74SGary Mills * 42a5229c74SGary Mills * Optional extra services, controlled by flags not defined by POSIX: 43a5229c74SGary Mills * 44a5229c74SGary Mills * GLOB_QUOTE: 45a5229c74SGary Mills * Escaping convention: \ inhibits any special meaning the following 46a5229c74SGary Mills * character might have (except \ at end of string is retained). 47a5229c74SGary Mills * GLOB_MAGCHAR: 48a5229c74SGary Mills * Set in gl_flags if pattern contained a globbing character. 49a5229c74SGary Mills * GLOB_NOMAGIC: 50a5229c74SGary Mills * Same as GLOB_NOCHECK, but it will only append pattern if it did 51a5229c74SGary Mills * not contain any magic characters. [Used in csh style globbing] 52a5229c74SGary Mills * GLOB_ALTDIRFUNC: 53a5229c74SGary Mills * Use alternately specified directory access functions. 54a5229c74SGary Mills * GLOB_TILDE: 55a5229c74SGary Mills * expand ~user/foo to the /home/dir/of/user/foo 56a5229c74SGary Mills * GLOB_BRACE: 57a5229c74SGary Mills * expand {1,2}{a,b} to 1a 1b 2a 2b 58a5229c74SGary Mills * gl_matchc: 59a5229c74SGary Mills * Number of matches in the current invocation of glob. 607c478bd9Sstevel@tonic-gate */ 617c478bd9Sstevel@tonic-gate 627257d1b4Sraf #include "lint.h" 63a5229c74SGary Mills 64a5229c74SGary Mills #include <sys/param.h> 65a5229c74SGary Mills #include <sys/stat.h> 66a5229c74SGary Mills 67a5229c74SGary Mills #include <ctype.h> 68a5229c74SGary Mills #include <dirent.h> 69a5229c74SGary Mills #include <errno.h> 70a5229c74SGary Mills #include <glob.h> 717c478bd9Sstevel@tonic-gate #include <limits.h> 72a5229c74SGary Mills #include <pwd.h> 73a5229c74SGary Mills #include <stdio.h> 747c478bd9Sstevel@tonic-gate #include <stdlib.h> 757c478bd9Sstevel@tonic-gate #include <string.h> 76a5229c74SGary Mills #include <unistd.h> 77a5229c74SGary Mills #include <wchar.h> 78a5229c74SGary Mills #include <wctype.h> 797c478bd9Sstevel@tonic-gate 80a5229c74SGary Mills /* 81a5229c74SGary Mills * This is the legacy glob_t prior to illumos enhancement 1097, 82a5229c74SGary Mills * used when old programs call the old libc glob functions. 83a5229c74SGary Mills * (New programs call the _glob_ext, _globfree_ext functions.) 84a5229c74SGary Mills * This struct should be considered "carved in stone". 85a5229c74SGary Mills */ 86a5229c74SGary Mills typedef struct old_glob { 87a5229c74SGary Mills size_t gl_pathc; /* Count of paths matched by pattern */ 88a5229c74SGary Mills char **gl_pathv; /* List of matched pathnames */ 89a5229c74SGary Mills size_t gl_offs; /* # of slots reserved in gl_pathv */ 90a5229c74SGary Mills /* following are internal to the implementation */ 91a5229c74SGary Mills char **gl_pathp; /* gl_pathv + gl_offs */ 92a5229c74SGary Mills int gl_pathn; /* # of elements allocated */ 93a5229c74SGary Mills } old_glob_t; 94a5229c74SGary Mills 95a5229c74SGary Mills /* 96a5229c74SGary Mills * For old programs, the external names need to be the old names: 97a5229c74SGary Mills * glob() and globfree() . We've redefined those already to 98a5229c74SGary Mills * _glob_ext() and _globfree_ext() . Now redefine old_glob() 99a5229c74SGary Mills * and old_globfree() to glob() and globfree() . 100a5229c74SGary Mills */ 101a5229c74SGary Mills #ifdef __PRAGMA_REDEFINE_EXTNAME 102a5229c74SGary Mills #pragma redefine_extname old_glob glob 103a5229c74SGary Mills #pragma redefine_extname old_globfree globfree 104a5229c74SGary Mills #endif /* __PRAGMA_REDEFINE_EXTNAME */ 105a5229c74SGary Mills extern int old_glob(const char *, int, int (*)(const char *, int), 106a5229c74SGary Mills old_glob_t *); 107a5229c74SGary Mills extern void old_globfree(old_glob_t *); 108a5229c74SGary Mills 109*33e8313dSRobert Mustacchi /* 110*33e8313dSRobert Mustacchi * The various extensions to glob(3C) allow for stat and dirent structures to 111*33e8313dSRobert Mustacchi * show up whose size may change in a largefile environment. If libc defines 112*33e8313dSRobert Mustacchi * _FILE_OFFSET_BITS to be 64 that is the key to indicate that we're building 113*33e8313dSRobert Mustacchi * the LFS version of this file. As such, we rename the public functions here, 114*33e8313dSRobert Mustacchi * _glob_ext() and _globfree_ext() to have a 64 suffix. When building the LFS 115*33e8313dSRobert Mustacchi * version, we do not include the old versions. 116*33e8313dSRobert Mustacchi */ 117*33e8313dSRobert Mustacchi #if !defined(_LP64) && _FILE_OFFSET_BITS == 64 118*33e8313dSRobert Mustacchi #define _glob_ext _glob_ext64 119*33e8313dSRobert Mustacchi #define _globfree_ext _globfree_ext64 120*33e8313dSRobert Mustacchi #endif /* !_LP64 && _FILE_OFFSET_BITS == 64 */ 121*33e8313dSRobert Mustacchi 122a5229c74SGary Mills #define DOLLAR '$' 123a5229c74SGary Mills #define DOT '.' 124a5229c74SGary Mills #define EOS '\0' 125a5229c74SGary Mills #define LBRACKET '[' 126a5229c74SGary Mills #define NOT '!' 127a5229c74SGary Mills #define QUESTION '?' 128a5229c74SGary Mills #define QUOTE '\\' 129a5229c74SGary Mills #define RANGE '-' 130a5229c74SGary Mills #define RBRACKET ']' 131a5229c74SGary Mills #define SEP '/' 132a5229c74SGary Mills #define STAR '*' 133a5229c74SGary Mills #define TILDE '~' 134a5229c74SGary Mills #define UNDERSCORE '_' 135a5229c74SGary Mills #define LBRACE '{' 136a5229c74SGary Mills #define RBRACE '}' 137a5229c74SGary Mills #define SLASH '/' 138a5229c74SGary Mills #define COMMA ',' 139a5229c74SGary Mills #define COLON ':' 140a5229c74SGary Mills 141a5229c74SGary Mills #define M_QUOTE 0x800000 142a5229c74SGary Mills #define M_PROTECT 0x400000 143a5229c74SGary Mills 144a5229c74SGary Mills typedef struct wcat { 145a5229c74SGary Mills wchar_t w_wc; 146a5229c74SGary Mills uint_t w_at; 147a5229c74SGary Mills } wcat_t; 148a5229c74SGary Mills 149a5229c74SGary Mills #define M_ALL '*' /* Plus M_QUOTE */ 150a5229c74SGary Mills #define M_END ']' /* Plus M_QUOTE */ 151a5229c74SGary Mills #define M_NOT '!' /* Plus M_QUOTE */ 152a5229c74SGary Mills #define M_ONE '?' /* Plus M_QUOTE */ 153a5229c74SGary Mills #define M_RNG '-' /* Plus M_QUOTE */ 154a5229c74SGary Mills #define M_SET '[' /* Plus M_QUOTE */ 155a5229c74SGary Mills #define M_CLASS ':' /* Plus M_QUOTE */ 156a5229c74SGary Mills #define ismeta(c) (((c).w_at&M_QUOTE) != 0) 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate #define INITIAL 8 /* initial pathv allocation */ 1597c478bd9Sstevel@tonic-gate 160a5229c74SGary Mills #define GLOB_LIMIT_MALLOC 65536 161a5229c74SGary Mills #define GLOB_LIMIT_STAT 2048 162a5229c74SGary Mills #define GLOB_LIMIT_READDIR 16384 163a5229c74SGary Mills 164a5229c74SGary Mills /* Limit of recursion during matching attempts. */ 165a5229c74SGary Mills #define GLOB_LIMIT_RECUR 64 166a5229c74SGary Mills 167a5229c74SGary Mills struct glob_lim { 168a5229c74SGary Mills size_t glim_malloc; 169a5229c74SGary Mills size_t glim_stat; 170a5229c74SGary Mills size_t glim_readdir; 171a5229c74SGary Mills }; 172a5229c74SGary Mills 173a5229c74SGary Mills struct glob_path_stat { 174a5229c74SGary Mills char *gps_path; 175a5229c74SGary Mills struct stat *gps_stat; 176a5229c74SGary Mills }; 177a5229c74SGary Mills 178a5229c74SGary Mills static int compare(const void *, const void *); 179a5229c74SGary Mills static int compare_gps(const void *, const void *); 180a5229c74SGary Mills static int g_Ctoc(const wcat_t *, char *, uint_t); 181a5229c74SGary Mills static int g_lstat(wcat_t *, struct stat *, glob_t *); 182a5229c74SGary Mills static DIR *g_opendir(wcat_t *, glob_t *); 183a5229c74SGary Mills static wcat_t *g_strchr(const wcat_t *, wchar_t); 184a5229c74SGary Mills static int g_stat(wcat_t *, struct stat *, glob_t *); 185a5229c74SGary Mills static int glob0(const wcat_t *, glob_t *, struct glob_lim *, 186a5229c74SGary Mills int (*)(const char *, int)); 187a5229c74SGary Mills static int glob1(wcat_t *, wcat_t *, glob_t *, struct glob_lim *, 188a5229c74SGary Mills int (*)(const char *, int)); 189a5229c74SGary Mills static int glob2(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *, 190a5229c74SGary Mills wcat_t *, glob_t *, struct glob_lim *, 191a5229c74SGary Mills int (*)(const char *, int)); 192a5229c74SGary Mills static int glob3(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *, 193a5229c74SGary Mills wcat_t *, wcat_t *, glob_t *, struct glob_lim *, 194a5229c74SGary Mills int (*)(const char *, int)); 195a5229c74SGary Mills static int globextend(const wcat_t *, glob_t *, struct glob_lim *, 196a5229c74SGary Mills struct stat *); 197a5229c74SGary Mills static 198a5229c74SGary Mills const wcat_t *globtilde(const wcat_t *, wcat_t *, size_t, glob_t *); 199a5229c74SGary Mills static int globexp1(const wcat_t *, glob_t *, struct glob_lim *, 200a5229c74SGary Mills int (*)(const char *, int)); 201a5229c74SGary Mills static int globexp2(const wcat_t *, const wcat_t *, glob_t *, 202a5229c74SGary Mills struct glob_lim *, int (*)(const char *, int)); 203a5229c74SGary Mills static int match(wcat_t *, wcat_t *, wcat_t *, int); 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate /* 206a5229c74SGary Mills * Extended glob() function, selected by #pragma redefine_extname 207a5229c74SGary Mills * in glob.h with the external name _glob_ext() . 2087c478bd9Sstevel@tonic-gate */ 2097c478bd9Sstevel@tonic-gate int 210a5229c74SGary Mills _glob_ext(const char *pattern, int flags, int (*errfunc)(const char *, int), 211a5229c74SGary Mills glob_t *pglob) 2127c478bd9Sstevel@tonic-gate { 213a5229c74SGary Mills const char *patnext; 214a5229c74SGary Mills int n; 215a5229c74SGary Mills size_t patlen; 216a5229c74SGary Mills wchar_t c; 217a5229c74SGary Mills wcat_t *bufnext, *bufend, patbuf[MAXPATHLEN]; 218a5229c74SGary Mills struct glob_lim limit = { 0, 0, 0 }; 2197c478bd9Sstevel@tonic-gate 220a5229c74SGary Mills if ((patlen = strnlen(pattern, PATH_MAX)) == PATH_MAX) 221a5229c74SGary Mills return (GLOB_NOMATCH); 2227c478bd9Sstevel@tonic-gate 223a5229c74SGary Mills patnext = pattern; 2247c478bd9Sstevel@tonic-gate if (!(flags & GLOB_APPEND)) { 225a5229c74SGary Mills pglob->gl_pathc = 0; 226a5229c74SGary Mills pglob->gl_pathn = 0; 227a5229c74SGary Mills pglob->gl_pathv = NULL; 228a5229c74SGary Mills if ((flags & GLOB_KEEPSTAT) != 0) 229a5229c74SGary Mills pglob->gl_statv = NULL; 230a5229c74SGary Mills if (!(flags & GLOB_DOOFFS)) 231a5229c74SGary Mills pglob->gl_offs = 0; 232a5229c74SGary Mills } 233a5229c74SGary Mills pglob->gl_flags = flags & ~GLOB_MAGCHAR; 234a5229c74SGary Mills pglob->gl_matchc = 0; 2357c478bd9Sstevel@tonic-gate 236a5229c74SGary Mills if (pglob->gl_offs >= INT_MAX || pglob->gl_pathc >= INT_MAX || 237a5229c74SGary Mills pglob->gl_pathc >= INT_MAX - pglob->gl_offs - 1) 2387c478bd9Sstevel@tonic-gate return (GLOB_NOSPACE); 2397c478bd9Sstevel@tonic-gate 240a5229c74SGary Mills bufnext = patbuf; 241a5229c74SGary Mills bufend = bufnext + MAXPATHLEN - 1; 242a5229c74SGary Mills patlen += 1; 243a5229c74SGary Mills if (flags & GLOB_NOESCAPE) { 244a5229c74SGary Mills while (bufnext < bufend) { 245a5229c74SGary Mills if ((n = mbtowc(&c, patnext, patlen)) > 0) { 246a5229c74SGary Mills patnext += n; 247a5229c74SGary Mills patlen -= n; 248a5229c74SGary Mills bufnext->w_at = 0; 249a5229c74SGary Mills (bufnext++)->w_wc = c; 250a5229c74SGary Mills } else if (n == 0) { 251a5229c74SGary Mills break; 252a5229c74SGary Mills } else { 253a5229c74SGary Mills return (GLOB_NOMATCH); 254a5229c74SGary Mills } 255a5229c74SGary Mills } 256a5229c74SGary Mills } else { 257a5229c74SGary Mills /* Protect the quoted characters. */ 258a5229c74SGary Mills while (bufnext < bufend) { 259a5229c74SGary Mills if ((n = mbtowc(&c, patnext, patlen)) > 0) { 260a5229c74SGary Mills patnext += n; 261a5229c74SGary Mills patlen -= n; 262a5229c74SGary Mills if (c == QUOTE) { 263a5229c74SGary Mills n = mbtowc(&c, patnext, patlen); 264a5229c74SGary Mills if (n < 0) 265a5229c74SGary Mills return (GLOB_NOMATCH); 266a5229c74SGary Mills if (n > 0) { 267a5229c74SGary Mills patnext += n; 268a5229c74SGary Mills patlen -= n; 269a5229c74SGary Mills } 270a5229c74SGary Mills if (n == 0) 271a5229c74SGary Mills c = QUOTE; 272a5229c74SGary Mills bufnext->w_at = M_PROTECT; 273a5229c74SGary Mills (bufnext++)->w_wc = c; 274a5229c74SGary Mills } else { 275a5229c74SGary Mills bufnext->w_at = 0; 276a5229c74SGary Mills (bufnext++)->w_wc = c; 277a5229c74SGary Mills } 278a5229c74SGary Mills } else if (n == 0) { 279a5229c74SGary Mills break; 280a5229c74SGary Mills } else { 281a5229c74SGary Mills return (GLOB_NOMATCH); 282a5229c74SGary Mills } 283a5229c74SGary Mills } 284a5229c74SGary Mills } 285a5229c74SGary Mills bufnext->w_at = 0; 286a5229c74SGary Mills bufnext->w_wc = EOS; 287a5229c74SGary Mills 288a5229c74SGary Mills if (flags & GLOB_BRACE) 289a5229c74SGary Mills return (globexp1(patbuf, pglob, &limit, errfunc)); 290a5229c74SGary Mills else 291a5229c74SGary Mills return (glob0(patbuf, pglob, &limit, errfunc)); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate /* 295a5229c74SGary Mills * Expand recursively a glob {} pattern. When there is no more expansion 296a5229c74SGary Mills * invoke the standard globbing routine to glob the rest of the magic 297a5229c74SGary Mills * characters 2987c478bd9Sstevel@tonic-gate */ 299a5229c74SGary Mills static int 300a5229c74SGary Mills globexp1(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp, 301a5229c74SGary Mills int (*errfunc)(const char *, int)) 302a5229c74SGary Mills { 303a5229c74SGary Mills const wcat_t *ptr = pattern; 304a5229c74SGary Mills 305a5229c74SGary Mills /* Protect a single {}, for find(1), like csh */ 306a5229c74SGary Mills if (pattern[0].w_wc == LBRACE && pattern[1].w_wc == RBRACE && 307a5229c74SGary Mills pattern[2].w_wc == EOS) 308a5229c74SGary Mills return (glob0(pattern, pglob, limitp, errfunc)); 309a5229c74SGary Mills 310a5229c74SGary Mills if ((ptr = (const wcat_t *) g_strchr(ptr, LBRACE)) != NULL) 311a5229c74SGary Mills return (globexp2(ptr, pattern, pglob, limitp, errfunc)); 312a5229c74SGary Mills 313a5229c74SGary Mills return (glob0(pattern, pglob, limitp, errfunc)); 314a5229c74SGary Mills } 315a5229c74SGary Mills 316a5229c74SGary Mills 317a5229c74SGary Mills /* 318a5229c74SGary Mills * Recursive brace globbing helper. Tries to expand a single brace. 319a5229c74SGary Mills * If it succeeds then it invokes globexp1 with the new pattern. 320a5229c74SGary Mills * If it fails then it tries to glob the rest of the pattern and returns. 321a5229c74SGary Mills */ 322a5229c74SGary Mills static int 323a5229c74SGary Mills globexp2(const wcat_t *ptr, const wcat_t *pattern, glob_t *pglob, 324a5229c74SGary Mills struct glob_lim *limitp, int (*errfunc)(const char *, int)) 325a5229c74SGary Mills { 326a5229c74SGary Mills int i, rv; 327a5229c74SGary Mills wcat_t *lm, *ls; 328a5229c74SGary Mills const wcat_t *pe, *pm, *pl; 329a5229c74SGary Mills wcat_t patbuf[MAXPATHLEN]; 330a5229c74SGary Mills 331a5229c74SGary Mills /* copy part up to the brace */ 332a5229c74SGary Mills for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) 333a5229c74SGary Mills ; 334a5229c74SGary Mills lm->w_at = 0; 335a5229c74SGary Mills lm->w_wc = EOS; 336a5229c74SGary Mills ls = lm; 337a5229c74SGary Mills 338a5229c74SGary Mills /* Find the balanced brace */ 339a5229c74SGary Mills for (i = 0, pe = ++ptr; pe->w_wc != EOS; pe++) 340a5229c74SGary Mills if (pe->w_wc == LBRACKET) { 341a5229c74SGary Mills /* Ignore everything between [] */ 342a5229c74SGary Mills for (pm = pe++; pe->w_wc != RBRACKET && 343a5229c74SGary Mills pe->w_wc != EOS; pe++) 344a5229c74SGary Mills ; 345a5229c74SGary Mills if (pe->w_wc == EOS) { 346a5229c74SGary Mills /* 347a5229c74SGary Mills * We could not find a matching RBRACKET. 348a5229c74SGary Mills * Ignore and just look for RBRACE 349a5229c74SGary Mills */ 350a5229c74SGary Mills pe = pm; 351a5229c74SGary Mills } 352a5229c74SGary Mills } else if (pe->w_wc == LBRACE) { 353a5229c74SGary Mills i++; 354a5229c74SGary Mills } else if (pe->w_wc == RBRACE) { 355a5229c74SGary Mills if (i == 0) 356a5229c74SGary Mills break; 357a5229c74SGary Mills i--; 358a5229c74SGary Mills } 359a5229c74SGary Mills 360a5229c74SGary Mills /* Non matching braces; just glob the pattern */ 361a5229c74SGary Mills if (i != 0 || pe->w_wc == EOS) 362a5229c74SGary Mills return (glob0(patbuf, pglob, limitp, errfunc)); 363a5229c74SGary Mills 364a5229c74SGary Mills for (i = 0, pl = pm = ptr; pm <= pe; pm++) { 365a5229c74SGary Mills switch (pm->w_wc) { 366a5229c74SGary Mills case LBRACKET: 367a5229c74SGary Mills /* Ignore everything between [] */ 368a5229c74SGary Mills for (pl = pm++; pm->w_wc != RBRACKET && pm->w_wc != EOS; 369a5229c74SGary Mills pm++) 370a5229c74SGary Mills ; 371a5229c74SGary Mills if (pm->w_wc == EOS) { 372a5229c74SGary Mills /* 373a5229c74SGary Mills * We could not find a matching RBRACKET. 374a5229c74SGary Mills * Ignore and just look for RBRACE 375a5229c74SGary Mills */ 376a5229c74SGary Mills pm = pl; 377a5229c74SGary Mills } 378a5229c74SGary Mills break; 379a5229c74SGary Mills 380a5229c74SGary Mills case LBRACE: 381a5229c74SGary Mills i++; 382a5229c74SGary Mills break; 383a5229c74SGary Mills 384a5229c74SGary Mills case RBRACE: 385a5229c74SGary Mills if (i) { 386a5229c74SGary Mills i--; 387a5229c74SGary Mills break; 388a5229c74SGary Mills } 389a5229c74SGary Mills /* FALLTHROUGH */ 390a5229c74SGary Mills case COMMA: 391a5229c74SGary Mills if (i && pm->w_wc == COMMA) 392a5229c74SGary Mills break; 393a5229c74SGary Mills else { 394a5229c74SGary Mills /* Append the current string */ 395a5229c74SGary Mills for (lm = ls; (pl < pm); *lm++ = *pl++) 396a5229c74SGary Mills ; 397a5229c74SGary Mills 398a5229c74SGary Mills /* 399a5229c74SGary Mills * Append the rest of the pattern after the 400a5229c74SGary Mills * closing brace 401a5229c74SGary Mills */ 402a5229c74SGary Mills for (pl = pe + 1; 403a5229c74SGary Mills (*lm++ = *pl++).w_wc != EOS; /* */) 404a5229c74SGary Mills ; 405a5229c74SGary Mills 406a5229c74SGary Mills /* Expand the current pattern */ 407a5229c74SGary Mills rv = globexp1(patbuf, pglob, limitp, errfunc); 408a5229c74SGary Mills if (rv && rv != GLOB_NOMATCH) 409a5229c74SGary Mills return (rv); 410a5229c74SGary Mills 411a5229c74SGary Mills /* move after the comma, to the next string */ 412a5229c74SGary Mills pl = pm + 1; 413a5229c74SGary Mills } 414a5229c74SGary Mills break; 415a5229c74SGary Mills 416a5229c74SGary Mills default: 417a5229c74SGary Mills break; 418a5229c74SGary Mills } 419a5229c74SGary Mills } 420a5229c74SGary Mills return (0); 421a5229c74SGary Mills } 422a5229c74SGary Mills 423a5229c74SGary Mills 424a5229c74SGary Mills 425a5229c74SGary Mills /* 426a5229c74SGary Mills * expand tilde from the passwd file. 427a5229c74SGary Mills */ 428a5229c74SGary Mills static const wcat_t * 429a5229c74SGary Mills globtilde(const wcat_t *pattern, wcat_t *patbuf, size_t patbuf_len, 430a5229c74SGary Mills glob_t *pglob) 431a5229c74SGary Mills { 432a5229c74SGary Mills struct passwd *pwd; 433a5229c74SGary Mills char *h; 434a5229c74SGary Mills const wcat_t *p; 435a5229c74SGary Mills wcat_t *b, *eb, *q; 436a5229c74SGary Mills int n; 437a5229c74SGary Mills size_t lenh; 438a5229c74SGary Mills wchar_t c; 439a5229c74SGary Mills 440a5229c74SGary Mills if (pattern->w_wc != TILDE || !(pglob->gl_flags & GLOB_TILDE)) 441a5229c74SGary Mills return (pattern); 442a5229c74SGary Mills 443a5229c74SGary Mills /* Copy up to the end of the string or / */ 444a5229c74SGary Mills eb = &patbuf[patbuf_len - 1]; 445a5229c74SGary Mills for (p = pattern + 1, q = patbuf; 446a5229c74SGary Mills q < eb && p->w_wc != EOS && p->w_wc != SLASH; *q++ = *p++) 447a5229c74SGary Mills ; 448a5229c74SGary Mills 449a5229c74SGary Mills q->w_at = 0; 450a5229c74SGary Mills q->w_wc = EOS; 451a5229c74SGary Mills 452a5229c74SGary Mills /* What to do if patbuf is full? */ 453a5229c74SGary Mills 454a5229c74SGary Mills if (patbuf[0].w_wc == EOS) { 455a5229c74SGary Mills /* 456a5229c74SGary Mills * handle a plain ~ or ~/ by expanding $HOME 457a5229c74SGary Mills * first and then trying the password file 458a5229c74SGary Mills */ 459a5229c74SGary Mills if (issetugid() != 0) 460a5229c74SGary Mills return (pattern); 461a5229c74SGary Mills if ((h = getenv("HOME")) == NULL) { 462a5229c74SGary Mills if ((pwd = getpwuid(getuid())) == NULL) 463a5229c74SGary Mills return (pattern); 464a5229c74SGary Mills else 465a5229c74SGary Mills h = pwd->pw_dir; 466a5229c74SGary Mills } 467a5229c74SGary Mills } else { 468a5229c74SGary Mills /* 469a5229c74SGary Mills * Expand a ~user 470a5229c74SGary Mills */ 471a5229c74SGary Mills if ((pwd = getpwnam((char *)patbuf)) == NULL) 472a5229c74SGary Mills return (pattern); 473a5229c74SGary Mills else 474a5229c74SGary Mills h = pwd->pw_dir; 475a5229c74SGary Mills } 476a5229c74SGary Mills 477a5229c74SGary Mills /* Copy the home directory */ 478a5229c74SGary Mills lenh = strlen(h) + 1; 479a5229c74SGary Mills for (b = patbuf; b < eb && *h != EOS; b++) { 480a5229c74SGary Mills if ((n = mbtowc(&c, h, lenh)) > 0) { 481a5229c74SGary Mills h += n; 482a5229c74SGary Mills lenh -= n; 483a5229c74SGary Mills b->w_at = 0; 484a5229c74SGary Mills b->w_wc = c; 485a5229c74SGary Mills } else if (n < 0) { 486a5229c74SGary Mills return (pattern); 487a5229c74SGary Mills } else { 488a5229c74SGary Mills break; 489a5229c74SGary Mills } 490a5229c74SGary Mills } 491a5229c74SGary Mills 492a5229c74SGary Mills /* Append the rest of the pattern */ 493a5229c74SGary Mills while (b < eb && (*b++ = *p++).w_wc != EOS) 494a5229c74SGary Mills ; 495a5229c74SGary Mills b->w_at = 0; 496a5229c74SGary Mills b->w_wc = EOS; 497a5229c74SGary Mills 498a5229c74SGary Mills return (patbuf); 499a5229c74SGary Mills } 500a5229c74SGary Mills 501a5229c74SGary Mills static int 502a5229c74SGary Mills g_charclass(const wcat_t **patternp, wcat_t **bufnextp) 503a5229c74SGary Mills { 504a5229c74SGary Mills const wcat_t *pattern = *patternp + 1; 505a5229c74SGary Mills wcat_t *bufnext = *bufnextp; 506a5229c74SGary Mills const wcat_t *colon; 507a5229c74SGary Mills char cbuf[MB_LEN_MAX + 32]; 508a5229c74SGary Mills wctype_t cc; 509a5229c74SGary Mills size_t len; 510a5229c74SGary Mills 511a5229c74SGary Mills if ((colon = g_strchr(pattern, COLON)) == NULL || 512a5229c74SGary Mills colon[1].w_wc != RBRACKET) 513a5229c74SGary Mills return (1); /* not a character class */ 514a5229c74SGary Mills 515a5229c74SGary Mills len = (size_t)(colon - pattern); 516a5229c74SGary Mills if (len + MB_LEN_MAX + 1 > sizeof (cbuf)) 517a5229c74SGary Mills return (-1); /* invalid character class */ 518a5229c74SGary Mills { 519a5229c74SGary Mills wchar_t w; 520a5229c74SGary Mills const wcat_t *s1 = pattern; 521a5229c74SGary Mills char *s2 = cbuf; 522a5229c74SGary Mills size_t n = len; 523a5229c74SGary Mills 524a5229c74SGary Mills /* Copy the string. */ 525a5229c74SGary Mills while (n > 0) { 526a5229c74SGary Mills w = (s1++)->w_wc; 527a5229c74SGary Mills /* Character class names must be ASCII. */ 528a5229c74SGary Mills if (iswascii(w)) { 529a5229c74SGary Mills n--; 530a5229c74SGary Mills *s2++ = w; 531a5229c74SGary Mills } else { 532a5229c74SGary Mills return (-1); /* invalid character class */ 533a5229c74SGary Mills } 534a5229c74SGary Mills } 535a5229c74SGary Mills *s2 = EOS; 536a5229c74SGary Mills } 537a5229c74SGary Mills if ((cc = wctype(cbuf)) == 0) 538a5229c74SGary Mills return (-1); /* invalid character class */ 539a5229c74SGary Mills bufnext->w_at = M_QUOTE; 540a5229c74SGary Mills (bufnext++)->w_wc = M_CLASS; 541a5229c74SGary Mills bufnext->w_at = 0; 542a5229c74SGary Mills (bufnext++)->w_wc = cc; 543a5229c74SGary Mills *bufnextp = bufnext; 544a5229c74SGary Mills *patternp += len + 3; 545a5229c74SGary Mills 546a5229c74SGary Mills return (0); 547a5229c74SGary Mills } 548a5229c74SGary Mills 549a5229c74SGary Mills /* 550a5229c74SGary Mills * The main glob() routine: compiles the pattern (optionally processing 551a5229c74SGary Mills * quotes), calls glob1() to do the real pattern matching, and finally 552a5229c74SGary Mills * sorts the list (unless unsorted operation is requested). Returns 0 553a5229c74SGary Mills * if things went well, nonzero if errors occurred. It is not an error 554a5229c74SGary Mills * to find no matches. 555a5229c74SGary Mills */ 556a5229c74SGary Mills static int 557a5229c74SGary Mills glob0(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp, 558a5229c74SGary Mills int (*errfunc)(const char *, int)) 559a5229c74SGary Mills { 560a5229c74SGary Mills const wcat_t *qpatnext; 561a5229c74SGary Mills int err, oldpathc; 562a5229c74SGary Mills wchar_t c; 563a5229c74SGary Mills int a; 564a5229c74SGary Mills wcat_t *bufnext, patbuf[MAXPATHLEN]; 565a5229c74SGary Mills 566a5229c74SGary Mills qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob); 567a5229c74SGary Mills oldpathc = pglob->gl_pathc; 568a5229c74SGary Mills bufnext = patbuf; 569a5229c74SGary Mills 570a5229c74SGary Mills /* 571a5229c74SGary Mills * We don't need to check for buffer overflow any more. 572a5229c74SGary Mills * The pattern has already been copied to an internal buffer. 573a5229c74SGary Mills */ 574a5229c74SGary Mills while ((a = qpatnext->w_at), (c = (qpatnext++)->w_wc) != EOS) { 575a5229c74SGary Mills switch (c) { 576a5229c74SGary Mills case LBRACKET: 577a5229c74SGary Mills if (a != 0) { 578a5229c74SGary Mills bufnext->w_at = a; 579a5229c74SGary Mills (bufnext++)->w_wc = c; 580a5229c74SGary Mills break; 581a5229c74SGary Mills } 582a5229c74SGary Mills a = qpatnext->w_at; 583a5229c74SGary Mills c = qpatnext->w_wc; 584a5229c74SGary Mills if (a == 0 && c == NOT) 585a5229c74SGary Mills ++qpatnext; 586a5229c74SGary Mills if (qpatnext->w_wc == EOS || 587a5229c74SGary Mills g_strchr(qpatnext+1, RBRACKET) == NULL) { 588a5229c74SGary Mills bufnext->w_at = 0; 589a5229c74SGary Mills (bufnext++)->w_wc = LBRACKET; 590a5229c74SGary Mills if (a == 0 && c == NOT) 591a5229c74SGary Mills --qpatnext; 592a5229c74SGary Mills break; 593a5229c74SGary Mills } 594a5229c74SGary Mills bufnext->w_at = M_QUOTE; 595a5229c74SGary Mills (bufnext++)->w_wc = M_SET; 596a5229c74SGary Mills if (a == 0 && c == NOT) { 597a5229c74SGary Mills bufnext->w_at = M_QUOTE; 598a5229c74SGary Mills (bufnext++)->w_wc = M_NOT; 599a5229c74SGary Mills } 600a5229c74SGary Mills a = qpatnext->w_at; 601a5229c74SGary Mills c = (qpatnext++)->w_wc; 602a5229c74SGary Mills do { 603a5229c74SGary Mills if (a == 0 && c == LBRACKET && 604a5229c74SGary Mills qpatnext->w_wc == COLON) { 605a5229c74SGary Mills do { 606a5229c74SGary Mills err = g_charclass(&qpatnext, 607a5229c74SGary Mills &bufnext); 608a5229c74SGary Mills if (err) 609a5229c74SGary Mills break; 610a5229c74SGary Mills a = qpatnext->w_at; 611a5229c74SGary Mills c = (qpatnext++)->w_wc; 612a5229c74SGary Mills } while (a == 0 && c == LBRACKET && 613a5229c74SGary Mills qpatnext->w_wc == COLON); 614a5229c74SGary Mills if (err == -1 && 615a5229c74SGary Mills !(pglob->gl_flags & GLOB_NOCHECK)) 616a5229c74SGary Mills return (GLOB_NOMATCH); 617a5229c74SGary Mills if (a == 0 && c == RBRACKET) 618a5229c74SGary Mills break; 619a5229c74SGary Mills } 620a5229c74SGary Mills bufnext->w_at = a; 621a5229c74SGary Mills (bufnext++)->w_wc = c; 622a5229c74SGary Mills if (qpatnext->w_at == 0 && 623a5229c74SGary Mills qpatnext->w_wc == RANGE) { 624a5229c74SGary Mills a = qpatnext[1].w_at; 625a5229c74SGary Mills c = qpatnext[1].w_wc; 626a5229c74SGary Mills if (qpatnext[1].w_at != 0 || 627a5229c74SGary Mills qpatnext[1].w_wc != RBRACKET) { 628a5229c74SGary Mills bufnext->w_at = M_QUOTE; 629a5229c74SGary Mills (bufnext++)->w_wc = M_RNG; 630a5229c74SGary Mills bufnext->w_at = a; 631a5229c74SGary Mills (bufnext++)->w_wc = c; 632a5229c74SGary Mills qpatnext += 2; 633a5229c74SGary Mills } 634a5229c74SGary Mills } 635a5229c74SGary Mills a = qpatnext->w_at; 636a5229c74SGary Mills c = (qpatnext++)->w_wc; 637a5229c74SGary Mills } while (a != 0 || c != RBRACKET); 638a5229c74SGary Mills pglob->gl_flags |= GLOB_MAGCHAR; 639a5229c74SGary Mills bufnext->w_at = M_QUOTE; 640a5229c74SGary Mills (bufnext++)->w_wc = M_END; 641a5229c74SGary Mills break; 642a5229c74SGary Mills case QUESTION: 643a5229c74SGary Mills if (a != 0) { 644a5229c74SGary Mills bufnext->w_at = a; 645a5229c74SGary Mills (bufnext++)->w_wc = c; 646a5229c74SGary Mills break; 647a5229c74SGary Mills } 648a5229c74SGary Mills pglob->gl_flags |= GLOB_MAGCHAR; 649a5229c74SGary Mills bufnext->w_at = M_QUOTE; 650a5229c74SGary Mills (bufnext++)->w_wc = M_ONE; 651a5229c74SGary Mills break; 652a5229c74SGary Mills case STAR: 653a5229c74SGary Mills if (a != 0) { 654a5229c74SGary Mills bufnext->w_at = a; 655a5229c74SGary Mills (bufnext++)->w_wc = c; 656a5229c74SGary Mills break; 657a5229c74SGary Mills } 658a5229c74SGary Mills pglob->gl_flags |= GLOB_MAGCHAR; 659a5229c74SGary Mills /* 660a5229c74SGary Mills * collapse adjacent stars to one, 661a5229c74SGary Mills * to avoid exponential behavior 662a5229c74SGary Mills */ 663a5229c74SGary Mills if (bufnext == patbuf || 664a5229c74SGary Mills bufnext[-1].w_at != M_QUOTE || 665a5229c74SGary Mills bufnext[-1].w_wc != M_ALL) { 666a5229c74SGary Mills bufnext->w_at = M_QUOTE; 667a5229c74SGary Mills (bufnext++)->w_wc = M_ALL; 668a5229c74SGary Mills } 669a5229c74SGary Mills break; 670a5229c74SGary Mills default: 671a5229c74SGary Mills bufnext->w_at = a; 672a5229c74SGary Mills (bufnext++)->w_wc = c; 673a5229c74SGary Mills break; 674a5229c74SGary Mills } 675a5229c74SGary Mills } 676a5229c74SGary Mills bufnext->w_at = 0; 677a5229c74SGary Mills bufnext->w_wc = EOS; 678a5229c74SGary Mills 679a5229c74SGary Mills if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, limitp, errfunc)) 680a5229c74SGary Mills != 0) 681a5229c74SGary Mills return (err); 682a5229c74SGary Mills 683a5229c74SGary Mills /* 684a5229c74SGary Mills * If there was no match we are going to append the pattern 685a5229c74SGary Mills * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified 686a5229c74SGary Mills * and the pattern did not contain any magic characters 687a5229c74SGary Mills * GLOB_NOMAGIC is there just for compatibility with csh. 688a5229c74SGary Mills */ 689a5229c74SGary Mills if (pglob->gl_pathc == oldpathc) { 690a5229c74SGary Mills if ((pglob->gl_flags & GLOB_NOCHECK) || 691a5229c74SGary Mills ((pglob->gl_flags & GLOB_NOMAGIC) && 692a5229c74SGary Mills !(pglob->gl_flags & GLOB_MAGCHAR))) 693a5229c74SGary Mills return (globextend(pattern, pglob, limitp, NULL)); 694a5229c74SGary Mills else 695a5229c74SGary Mills return (GLOB_NOMATCH); 696a5229c74SGary Mills } 697a5229c74SGary Mills if (!(pglob->gl_flags & GLOB_NOSORT)) { 698a5229c74SGary Mills if ((pglob->gl_flags & GLOB_KEEPSTAT)) { 699a5229c74SGary Mills /* Keep the paths and stat info synced during sort */ 700a5229c74SGary Mills struct glob_path_stat *path_stat; 701a5229c74SGary Mills int i; 702a5229c74SGary Mills int n = pglob->gl_pathc - oldpathc; 703a5229c74SGary Mills int o = pglob->gl_offs + oldpathc; 704a5229c74SGary Mills 705a5229c74SGary Mills if ((path_stat = calloc(n, sizeof (*path_stat))) == 706a5229c74SGary Mills NULL) 707a5229c74SGary Mills return (GLOB_NOSPACE); 708a5229c74SGary Mills for (i = 0; i < n; i++) { 709a5229c74SGary Mills path_stat[i].gps_path = pglob->gl_pathv[o + i]; 710a5229c74SGary Mills path_stat[i].gps_stat = pglob->gl_statv[o + i]; 711a5229c74SGary Mills } 712a5229c74SGary Mills qsort(path_stat, n, sizeof (*path_stat), compare_gps); 713a5229c74SGary Mills for (i = 0; i < n; i++) { 714a5229c74SGary Mills pglob->gl_pathv[o + i] = path_stat[i].gps_path; 715a5229c74SGary Mills pglob->gl_statv[o + i] = path_stat[i].gps_stat; 716a5229c74SGary Mills } 717a5229c74SGary Mills free(path_stat); 718a5229c74SGary Mills } else { 719a5229c74SGary Mills qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, 720a5229c74SGary Mills pglob->gl_pathc - oldpathc, sizeof (char *), 721a5229c74SGary Mills compare); 722a5229c74SGary Mills } 723a5229c74SGary Mills } 724a5229c74SGary Mills return (0); 725a5229c74SGary Mills } 726a5229c74SGary Mills 727a5229c74SGary Mills static int 728a5229c74SGary Mills compare(const void *p, const void *q) 729a5229c74SGary Mills { 730a5229c74SGary Mills return (strcmp(*(char **)p, *(char **)q)); 731a5229c74SGary Mills } 732a5229c74SGary Mills 733a5229c74SGary Mills static int 734a5229c74SGary Mills compare_gps(const void *_p, const void *_q) 735a5229c74SGary Mills { 736a5229c74SGary Mills const struct glob_path_stat *p = (const struct glob_path_stat *)_p; 737a5229c74SGary Mills const struct glob_path_stat *q = (const struct glob_path_stat *)_q; 738a5229c74SGary Mills 739a5229c74SGary Mills return (strcmp(p->gps_path, q->gps_path)); 740a5229c74SGary Mills } 741a5229c74SGary Mills 742a5229c74SGary Mills static int 743a5229c74SGary Mills glob1(wcat_t *pattern, wcat_t *pattern_last, glob_t *pglob, 744a5229c74SGary Mills struct glob_lim *limitp, int (*errfunc)(const char *, int)) 745a5229c74SGary Mills { 746a5229c74SGary Mills wcat_t pathbuf[MAXPATHLEN]; 747a5229c74SGary Mills 748a5229c74SGary Mills /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ 749a5229c74SGary Mills if (pattern->w_wc == EOS) 750a5229c74SGary Mills return (0); 751a5229c74SGary Mills return (glob2(pathbuf, pathbuf+MAXPATHLEN-1, 752a5229c74SGary Mills pathbuf, pathbuf+MAXPATHLEN-1, 753a5229c74SGary Mills pattern, pattern_last, pglob, limitp, errfunc)); 754a5229c74SGary Mills } 755a5229c74SGary Mills 756a5229c74SGary Mills /* 757a5229c74SGary Mills * The functions glob2 and glob3 are mutually recursive; there is one level 758a5229c74SGary Mills * of recursion for each segment in the pattern that contains one or more 759a5229c74SGary Mills * meta characters. 760a5229c74SGary Mills */ 761a5229c74SGary Mills static int 762a5229c74SGary Mills glob2(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend, 763a5229c74SGary Mills wcat_t *pathend_last, wcat_t *pattern, wcat_t *pattern_last, 764a5229c74SGary Mills glob_t *pglob, struct glob_lim *limitp, int (*errfunc)(const char *, int)) 765a5229c74SGary Mills { 766a5229c74SGary Mills struct stat sb; 767a5229c74SGary Mills wcat_t *p, *q; 768a5229c74SGary Mills int anymeta; 769a5229c74SGary Mills 770a5229c74SGary Mills /* 771a5229c74SGary Mills * Loop over pattern segments until end of pattern or until 772a5229c74SGary Mills * segment with meta character found. 773a5229c74SGary Mills */ 774a5229c74SGary Mills for (anymeta = 0; ; ) { 775a5229c74SGary Mills if (pattern->w_wc == EOS) { /* End of pattern? */ 776a5229c74SGary Mills pathend->w_at = 0; 777a5229c74SGary Mills pathend->w_wc = EOS; 778a5229c74SGary Mills 779a5229c74SGary Mills if ((pglob->gl_flags & GLOB_LIMIT) && 780a5229c74SGary Mills limitp->glim_stat++ >= GLOB_LIMIT_STAT) { 781a5229c74SGary Mills errno = 0; 782a5229c74SGary Mills pathend->w_at = 0; 783a5229c74SGary Mills (pathend++)->w_wc = SEP; 784a5229c74SGary Mills pathend->w_at = 0; 785a5229c74SGary Mills pathend->w_wc = EOS; 786a5229c74SGary Mills return (GLOB_NOSPACE); 787a5229c74SGary Mills } 788a5229c74SGary Mills if (g_lstat(pathbuf, &sb, pglob)) 789a5229c74SGary Mills return (0); 790a5229c74SGary Mills 791a5229c74SGary Mills if (((pglob->gl_flags & GLOB_MARK) && 792a5229c74SGary Mills (pathend[-1].w_at != 0 || 793a5229c74SGary Mills pathend[-1].w_wc != SEP)) && 794a5229c74SGary Mills (S_ISDIR(sb.st_mode) || 795a5229c74SGary Mills (S_ISLNK(sb.st_mode) && 796a5229c74SGary Mills (g_stat(pathbuf, &sb, pglob) == 0) && 797a5229c74SGary Mills S_ISDIR(sb.st_mode)))) { 798a5229c74SGary Mills if (pathend+1 > pathend_last) 799a5229c74SGary Mills return (GLOB_NOSPACE); 800a5229c74SGary Mills pathend->w_at = 0; 801a5229c74SGary Mills (pathend++)->w_wc = SEP; 802a5229c74SGary Mills pathend->w_at = 0; 803a5229c74SGary Mills pathend->w_wc = EOS; 804a5229c74SGary Mills } 805a5229c74SGary Mills ++pglob->gl_matchc; 806a5229c74SGary Mills return (globextend(pathbuf, pglob, limitp, &sb)); 807a5229c74SGary Mills } 808a5229c74SGary Mills 809a5229c74SGary Mills /* Find end of next segment, copy tentatively to pathend. */ 810a5229c74SGary Mills q = pathend; 811a5229c74SGary Mills p = pattern; 812a5229c74SGary Mills while (p->w_wc != EOS && p->w_wc != SEP) { 813a5229c74SGary Mills if (ismeta(*p)) 814a5229c74SGary Mills anymeta = 1; 815a5229c74SGary Mills if (q+1 > pathend_last) 816a5229c74SGary Mills return (GLOB_NOSPACE); 817a5229c74SGary Mills *q++ = *p++; 818a5229c74SGary Mills } 819a5229c74SGary Mills 820a5229c74SGary Mills if (!anymeta) { /* No expansion, do next segment. */ 821a5229c74SGary Mills pathend = q; 822a5229c74SGary Mills pattern = p; 823a5229c74SGary Mills while (pattern->w_wc == SEP) { 824a5229c74SGary Mills if (pathend+1 > pathend_last) 825a5229c74SGary Mills return (GLOB_NOSPACE); 826a5229c74SGary Mills *pathend++ = *pattern++; 827a5229c74SGary Mills } 828a5229c74SGary Mills } else { 829a5229c74SGary Mills /* Need expansion, recurse. */ 830a5229c74SGary Mills return (glob3(pathbuf, pathbuf_last, pathend, 831a5229c74SGary Mills pathend_last, pattern, p, pattern_last, 832a5229c74SGary Mills pglob, limitp, errfunc)); 833a5229c74SGary Mills } 834a5229c74SGary Mills } 835a5229c74SGary Mills /* NOTREACHED */ 836a5229c74SGary Mills } 837a5229c74SGary Mills 838a5229c74SGary Mills static int 839a5229c74SGary Mills glob3(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend, 840a5229c74SGary Mills wcat_t *pathend_last, wcat_t *pattern, wcat_t *restpattern, 841a5229c74SGary Mills wcat_t *restpattern_last, glob_t *pglob, struct glob_lim *limitp, 842a5229c74SGary Mills int (*errfunc)(const char *, int)) 843a5229c74SGary Mills { 844a5229c74SGary Mills struct dirent *dp; 845a5229c74SGary Mills DIR *dirp; 846a5229c74SGary Mills int err; 847a5229c74SGary Mills char buf[MAXPATHLEN]; 848a5229c74SGary Mills 849a5229c74SGary Mills /* 850a5229c74SGary Mills * The readdirfunc declaration can't be prototyped, because it is 851a5229c74SGary Mills * assigned, below, to two functions which are prototyped in glob.h 852a5229c74SGary Mills * and dirent.h as taking pointers to differently typed opaque 853a5229c74SGary Mills * structures. 854a5229c74SGary Mills */ 855a5229c74SGary Mills struct dirent *(*readdirfunc)(void *); 856a5229c74SGary Mills 857a5229c74SGary Mills if (pathend > pathend_last) 858a5229c74SGary Mills return (GLOB_NOSPACE); 859a5229c74SGary Mills pathend->w_at = 0; 860a5229c74SGary Mills pathend->w_wc = EOS; 861a5229c74SGary Mills errno = 0; 862a5229c74SGary Mills 863a5229c74SGary Mills if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { 864a5229c74SGary Mills /* TODO: don't call for ENOENT or ENOTDIR? */ 865a5229c74SGary Mills if (errfunc) { 866a5229c74SGary Mills if (g_Ctoc(pathbuf, buf, sizeof (buf))) 867a5229c74SGary Mills return (GLOB_ABORTED); 868a5229c74SGary Mills if (errfunc(buf, errno) || 869a5229c74SGary Mills pglob->gl_flags & GLOB_ERR) 8707c478bd9Sstevel@tonic-gate return (GLOB_ABORTED); 8717c478bd9Sstevel@tonic-gate } 872a5229c74SGary Mills return (0); 873a5229c74SGary Mills } 8747c478bd9Sstevel@tonic-gate 875a5229c74SGary Mills err = 0; 876a5229c74SGary Mills 877a5229c74SGary Mills /* Search directory for matching names. */ 878a5229c74SGary Mills if (pglob->gl_flags & GLOB_ALTDIRFUNC) 879a5229c74SGary Mills readdirfunc = pglob->gl_readdir; 8807c478bd9Sstevel@tonic-gate else 881a5229c74SGary Mills readdirfunc = (struct dirent *(*)(void *))readdir; 882a5229c74SGary Mills while ((dp = (*readdirfunc)(dirp))) { 883a5229c74SGary Mills char *sc; 884a5229c74SGary Mills wcat_t *dc; 885a5229c74SGary Mills int n; 886a5229c74SGary Mills int lensc; 887a5229c74SGary Mills wchar_t w; 888a5229c74SGary Mills 889a5229c74SGary Mills if ((pglob->gl_flags & GLOB_LIMIT) && 890a5229c74SGary Mills limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) { 891a5229c74SGary Mills errno = 0; 892a5229c74SGary Mills pathend->w_at = 0; 893a5229c74SGary Mills (pathend++)->w_wc = SEP; 894a5229c74SGary Mills pathend->w_at = 0; 895a5229c74SGary Mills pathend->w_wc = EOS; 896a5229c74SGary Mills err = GLOB_NOSPACE; 897a5229c74SGary Mills break; 8987c478bd9Sstevel@tonic-gate } 899a5229c74SGary Mills 900a5229c74SGary Mills /* Initial DOT must be matched literally. */ 901a5229c74SGary Mills if (dp->d_name[0] == DOT && pattern->w_wc != DOT) 902a5229c74SGary Mills continue; 903a5229c74SGary Mills dc = pathend; 904a5229c74SGary Mills sc = dp->d_name; 905a5229c74SGary Mills lensc = strlen(sc) + 1; 906a5229c74SGary Mills while (dc < pathend_last) { 907a5229c74SGary Mills if ((n = mbtowc(&w, sc, lensc)) <= 0) { 908a5229c74SGary Mills sc += 1; 909a5229c74SGary Mills lensc -= 1; 910a5229c74SGary Mills dc->w_at = 0; 911a5229c74SGary Mills dc->w_wc = EOS; 912a5229c74SGary Mills } else { 913a5229c74SGary Mills sc += n; 914a5229c74SGary Mills lensc -= n; 915a5229c74SGary Mills dc->w_at = 0; 916a5229c74SGary Mills dc->w_wc = w; 917a5229c74SGary Mills } 918a5229c74SGary Mills dc++; 919a5229c74SGary Mills if (n <= 0) 920a5229c74SGary Mills break; 921a5229c74SGary Mills } 922a5229c74SGary Mills if (dc >= pathend_last) { 923a5229c74SGary Mills dc->w_at = 0; 924a5229c74SGary Mills dc->w_wc = EOS; 925a5229c74SGary Mills err = GLOB_NOSPACE; 926a5229c74SGary Mills break; 927a5229c74SGary Mills } 928a5229c74SGary Mills if (n < 0) { 929a5229c74SGary Mills err = GLOB_NOMATCH; 930a5229c74SGary Mills break; 931a5229c74SGary Mills } 932a5229c74SGary Mills 933a5229c74SGary Mills if (!match(pathend, pattern, restpattern, GLOB_LIMIT_RECUR)) { 934a5229c74SGary Mills pathend->w_at = 0; 935a5229c74SGary Mills pathend->w_wc = EOS; 936a5229c74SGary Mills continue; 937a5229c74SGary Mills } 938a5229c74SGary Mills err = glob2(pathbuf, pathbuf_last, --dc, pathend_last, 939a5229c74SGary Mills restpattern, restpattern_last, pglob, limitp, 940a5229c74SGary Mills errfunc); 941a5229c74SGary Mills if (err) 942a5229c74SGary Mills break; 943a5229c74SGary Mills } 944a5229c74SGary Mills 945a5229c74SGary Mills if (pglob->gl_flags & GLOB_ALTDIRFUNC) 946a5229c74SGary Mills (*pglob->gl_closedir)(dirp); 947a5229c74SGary Mills else 948a5229c74SGary Mills (void) closedir(dirp); 949a5229c74SGary Mills return (err); 950a5229c74SGary Mills } 951a5229c74SGary Mills 952a5229c74SGary Mills 953a5229c74SGary Mills /* 954a5229c74SGary Mills * Extend the gl_pathv member of a glob_t structure to accommodate a new item, 955a5229c74SGary Mills * add the new item, and update gl_pathc. Avoids excessive reallocation 956a5229c74SGary Mills * by doubling the number of elements each time. Uses gl_pathn to contain 957a5229c74SGary Mills * the number. 958a5229c74SGary Mills * 959a5229c74SGary Mills * Return 0 if new item added, error code if memory couldn't be allocated. 960a5229c74SGary Mills * 961a5229c74SGary Mills * Invariant of the glob_t structure: 962a5229c74SGary Mills * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 963a5229c74SGary Mills * gl_pathv points to (gl_offs + gl_pathc + 1) items. 964a5229c74SGary Mills */ 965a5229c74SGary Mills static int 966a5229c74SGary Mills globextend(const wcat_t *path, glob_t *pglob, struct glob_lim *limitp, 967a5229c74SGary Mills struct stat *sb) 968a5229c74SGary Mills { 969a5229c74SGary Mills char **pathv; 970a5229c74SGary Mills ssize_t i; 971a5229c74SGary Mills size_t allocn, newn, len; 972a5229c74SGary Mills char *copy = NULL; 973a5229c74SGary Mills const wcat_t *p; 974a5229c74SGary Mills struct stat **statv; 975a5229c74SGary Mills char junk[MB_LEN_MAX]; 976a5229c74SGary Mills int n; 977a5229c74SGary Mills 978a5229c74SGary Mills allocn = pglob->gl_pathn; 979a5229c74SGary Mills newn = 2 + pglob->gl_pathc + pglob->gl_offs; 980a5229c74SGary Mills 981a5229c74SGary Mills if (newn <= allocn) { 982a5229c74SGary Mills pathv = pglob->gl_pathv; 983a5229c74SGary Mills if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) 984a5229c74SGary Mills statv = pglob->gl_statv; 985a5229c74SGary Mills } else { 986a5229c74SGary Mills if (allocn == 0) 987a5229c74SGary Mills allocn = pglob->gl_offs + INITIAL; 988a5229c74SGary Mills allocn *= 2; 989a5229c74SGary Mills if (pglob->gl_offs >= INT_MAX || 990a5229c74SGary Mills pglob->gl_pathc >= INT_MAX || 991a5229c74SGary Mills allocn >= INT_MAX || 992a5229c74SGary Mills SIZE_MAX / sizeof (*pathv) <= allocn || 993a5229c74SGary Mills SIZE_MAX / sizeof (*statv) <= allocn) { 994a5229c74SGary Mills nospace: 995a5229c74SGary Mills for (i = pglob->gl_offs; i < (ssize_t)(newn - 2); 996a5229c74SGary Mills i++) { 997a5229c74SGary Mills if (pglob->gl_pathv && pglob->gl_pathv[i]) 998a5229c74SGary Mills free(pglob->gl_pathv[i]); 999a5229c74SGary Mills if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 && 1000a5229c74SGary Mills pglob->gl_statv && pglob->gl_statv[i]) 1001a5229c74SGary Mills free(pglob->gl_statv[i]); 1002a5229c74SGary Mills } 1003a5229c74SGary Mills if (pglob->gl_pathv) { 1004a5229c74SGary Mills free(pglob->gl_pathv); 1005a5229c74SGary Mills pglob->gl_pathv = NULL; 1006a5229c74SGary Mills } 1007a5229c74SGary Mills if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 && 1008a5229c74SGary Mills pglob->gl_statv) { 1009a5229c74SGary Mills free(pglob->gl_statv); 1010a5229c74SGary Mills pglob->gl_statv = NULL; 1011a5229c74SGary Mills } 1012a5229c74SGary Mills return (GLOB_NOSPACE); 1013a5229c74SGary Mills } 1014a5229c74SGary Mills limitp->glim_malloc += allocn * sizeof (*pathv); 1015a5229c74SGary Mills pathv = realloc(pglob->gl_pathv, allocn * sizeof (*pathv)); 1016a5229c74SGary Mills if (pathv == NULL) 1017a5229c74SGary Mills goto nospace; 1018a5229c74SGary Mills if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) { 1019a5229c74SGary Mills limitp->glim_malloc += allocn * sizeof (*statv); 1020a5229c74SGary Mills statv = realloc(pglob->gl_statv, 1021a5229c74SGary Mills allocn * sizeof (*statv)); 1022a5229c74SGary Mills if (statv == NULL) 1023a5229c74SGary Mills goto nospace; 1024a5229c74SGary Mills } 1025a5229c74SGary Mills } 1026a5229c74SGary Mills pglob->gl_pathn = allocn; 1027a5229c74SGary Mills 1028a5229c74SGary Mills if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 1029a5229c74SGary Mills /* first time around -- clear initial gl_offs items */ 1030a5229c74SGary Mills pathv += pglob->gl_offs; 1031a5229c74SGary Mills for (i = pglob->gl_offs; --i >= 0; ) 1032a5229c74SGary Mills *--pathv = NULL; 1033a5229c74SGary Mills } 1034a5229c74SGary Mills pglob->gl_pathv = pathv; 1035a5229c74SGary Mills 1036a5229c74SGary Mills if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) { 1037a5229c74SGary Mills if (pglob->gl_statv == NULL && pglob->gl_offs > 0) { 1038a5229c74SGary Mills /* first time around -- clear initial gl_offs items */ 1039a5229c74SGary Mills statv += pglob->gl_offs; 1040a5229c74SGary Mills for (i = pglob->gl_offs; --i >= 0; ) 1041a5229c74SGary Mills *--statv = NULL; 1042a5229c74SGary Mills } 1043a5229c74SGary Mills pglob->gl_statv = statv; 1044a5229c74SGary Mills if (sb == NULL) 1045a5229c74SGary Mills statv[pglob->gl_offs + pglob->gl_pathc] = NULL; 1046a5229c74SGary Mills else { 1047a5229c74SGary Mills limitp->glim_malloc += sizeof (**statv); 1048a5229c74SGary Mills if ((statv[pglob->gl_offs + pglob->gl_pathc] = 1049a5229c74SGary Mills malloc(sizeof (**statv))) == NULL) 1050a5229c74SGary Mills goto copy_error; 1051a5229c74SGary Mills (void) memcpy(statv[pglob->gl_offs + pglob->gl_pathc], 1052a5229c74SGary Mills sb, sizeof (*sb)); 1053a5229c74SGary Mills } 1054a5229c74SGary Mills statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL; 1055a5229c74SGary Mills } 1056a5229c74SGary Mills 1057a5229c74SGary Mills len = MB_LEN_MAX; 1058a5229c74SGary Mills p = path; 1059a5229c74SGary Mills while ((n = wctomb(junk, p->w_wc)) > 0) { 1060a5229c74SGary Mills len += n; 1061a5229c74SGary Mills if ((p++)->w_wc == EOS) 1062a5229c74SGary Mills break; 1063a5229c74SGary Mills } 1064a5229c74SGary Mills if (n < 0) 1065a5229c74SGary Mills return (GLOB_NOMATCH); 1066a5229c74SGary Mills 1067a5229c74SGary Mills limitp->glim_malloc += len; 1068a5229c74SGary Mills if ((copy = malloc(len)) != NULL) { 1069a5229c74SGary Mills if (g_Ctoc(path, copy, len)) { 1070a5229c74SGary Mills free(copy); 1071a5229c74SGary Mills return (GLOB_NOSPACE); 1072a5229c74SGary Mills } 1073a5229c74SGary Mills pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; 1074a5229c74SGary Mills } 1075a5229c74SGary Mills pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 1076a5229c74SGary Mills 1077a5229c74SGary Mills if ((pglob->gl_flags & GLOB_LIMIT) && 1078a5229c74SGary Mills limitp->glim_malloc >= GLOB_LIMIT_MALLOC) { 1079a5229c74SGary Mills errno = 0; 1080a5229c74SGary Mills return (GLOB_NOSPACE); 1081a5229c74SGary Mills } 1082a5229c74SGary Mills copy_error: 1083a5229c74SGary Mills return (copy == NULL ? GLOB_NOSPACE : 0); 1084a5229c74SGary Mills } 1085a5229c74SGary Mills 1086a5229c74SGary Mills 1087a5229c74SGary Mills /* 1088a5229c74SGary Mills * pattern matching function for filenames. Each occurrence of the * 1089a5229c74SGary Mills * pattern causes a recursion level. 1090a5229c74SGary Mills */ 1091a5229c74SGary Mills static int 1092a5229c74SGary Mills match(wcat_t *name, wcat_t *pat, wcat_t *patend, int recur) 1093a5229c74SGary Mills { 1094a5229c74SGary Mills int ok, negate_range; 1095a5229c74SGary Mills wcat_t c, k; 1096a5229c74SGary Mills 1097a5229c74SGary Mills if (recur-- == 0) 1098a5229c74SGary Mills return (1); 1099a5229c74SGary Mills 1100a5229c74SGary Mills while (pat < patend) { 1101a5229c74SGary Mills c = *pat++; 1102a5229c74SGary Mills switch (c.w_wc) { 1103a5229c74SGary Mills case M_ALL: 1104a5229c74SGary Mills if (c.w_at != M_QUOTE) { 1105a5229c74SGary Mills k = *name++; 1106a5229c74SGary Mills if (k.w_at != c.w_at || k.w_wc != c.w_wc) 1107a5229c74SGary Mills return (0); 1108a5229c74SGary Mills break; 1109a5229c74SGary Mills } 1110a5229c74SGary Mills while (pat < patend && pat->w_at == M_QUOTE && 1111a5229c74SGary Mills pat->w_wc == M_ALL) 1112a5229c74SGary Mills pat++; /* eat consecutive '*' */ 1113a5229c74SGary Mills if (pat == patend) 1114a5229c74SGary Mills return (1); 1115a5229c74SGary Mills do { 1116a5229c74SGary Mills if (match(name, pat, patend, recur)) 1117a5229c74SGary Mills return (1); 1118a5229c74SGary Mills } while ((name++)->w_wc != EOS); 1119a5229c74SGary Mills return (0); 1120a5229c74SGary Mills case M_ONE: 1121a5229c74SGary Mills if (c.w_at != M_QUOTE) { 1122a5229c74SGary Mills k = *name++; 1123a5229c74SGary Mills if (k.w_at != c.w_at || k.w_wc != c.w_wc) 1124a5229c74SGary Mills return (0); 1125a5229c74SGary Mills break; 1126a5229c74SGary Mills } 1127a5229c74SGary Mills if ((name++)->w_wc == EOS) 1128a5229c74SGary Mills return (0); 1129a5229c74SGary Mills break; 1130a5229c74SGary Mills case M_SET: 1131a5229c74SGary Mills if (c.w_at != M_QUOTE) { 1132a5229c74SGary Mills k = *name++; 1133a5229c74SGary Mills if (k.w_at != c.w_at || k.w_wc != c.w_wc) 1134a5229c74SGary Mills return (0); 1135a5229c74SGary Mills break; 1136a5229c74SGary Mills } 1137a5229c74SGary Mills ok = 0; 1138a5229c74SGary Mills if ((k = *name++).w_wc == EOS) 1139a5229c74SGary Mills return (0); 1140a5229c74SGary Mills if ((negate_range = (pat->w_at == M_QUOTE && 1141a5229c74SGary Mills pat->w_wc == M_NOT)) != 0) 1142a5229c74SGary Mills ++pat; 1143a5229c74SGary Mills while (((c = *pat++).w_at != M_QUOTE) || 1144a5229c74SGary Mills c.w_wc != M_END) { 1145a5229c74SGary Mills if (c.w_at == M_QUOTE && c.w_wc == M_CLASS) { 1146a5229c74SGary Mills wcat_t cc; 1147a5229c74SGary Mills 1148a5229c74SGary Mills cc.w_at = pat->w_at; 1149a5229c74SGary Mills cc.w_wc = pat->w_wc; 1150a5229c74SGary Mills if (iswctype(k.w_wc, cc.w_wc)) 1151a5229c74SGary Mills ok = 1; 1152a5229c74SGary Mills ++pat; 1153a5229c74SGary Mills } 1154a5229c74SGary Mills if (pat->w_at == M_QUOTE && 1155a5229c74SGary Mills pat->w_wc == M_RNG) { 1156a5229c74SGary Mills if (c.w_wc <= k.w_wc && 1157a5229c74SGary Mills k.w_wc <= pat[1].w_wc) 1158a5229c74SGary Mills ok = 1; 1159a5229c74SGary Mills pat += 2; 1160a5229c74SGary Mills } else if (c.w_wc == k.w_wc) 1161a5229c74SGary Mills ok = 1; 1162a5229c74SGary Mills } 1163a5229c74SGary Mills if (ok == negate_range) 1164a5229c74SGary Mills return (0); 1165a5229c74SGary Mills break; 1166a5229c74SGary Mills default: 1167a5229c74SGary Mills k = *name++; 1168a5229c74SGary Mills if (k.w_at != c.w_at || k.w_wc != c.w_wc) 1169a5229c74SGary Mills return (0); 1170a5229c74SGary Mills break; 1171a5229c74SGary Mills } 1172a5229c74SGary Mills } 1173a5229c74SGary Mills return (name->w_wc == EOS); 1174a5229c74SGary Mills } 1175a5229c74SGary Mills 1176a5229c74SGary Mills /* 1177a5229c74SGary Mills * Extended globfree() function, selected by #pragma redefine_extname 1178a5229c74SGary Mills * in glob.h with the external name _globfree_ext() . 1179a5229c74SGary Mills */ 1180a5229c74SGary Mills void 1181a5229c74SGary Mills _globfree_ext(glob_t *pglob) 1182a5229c74SGary Mills { 1183a5229c74SGary Mills int i; 1184a5229c74SGary Mills char **pp; 1185a5229c74SGary Mills 1186a5229c74SGary Mills if (pglob->gl_pathv != NULL) { 1187a5229c74SGary Mills pp = pglob->gl_pathv + pglob->gl_offs; 1188a5229c74SGary Mills for (i = pglob->gl_pathc; i--; ++pp) 1189a5229c74SGary Mills if (*pp) 1190a5229c74SGary Mills free(*pp); 1191a5229c74SGary Mills free(pglob->gl_pathv); 1192a5229c74SGary Mills pglob->gl_pathv = NULL; 1193a5229c74SGary Mills } 1194a5229c74SGary Mills if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 && 1195a5229c74SGary Mills pglob->gl_statv != NULL) { 1196a5229c74SGary Mills for (i = 0; i < pglob->gl_pathc; i++) { 1197a5229c74SGary Mills if (pglob->gl_statv[i] != NULL) 1198a5229c74SGary Mills free(pglob->gl_statv[i]); 1199a5229c74SGary Mills } 1200a5229c74SGary Mills free(pglob->gl_statv); 1201a5229c74SGary Mills pglob->gl_statv = NULL; 1202a5229c74SGary Mills } 1203a5229c74SGary Mills } 1204a5229c74SGary Mills 1205a5229c74SGary Mills static DIR * 1206a5229c74SGary Mills g_opendir(wcat_t *str, glob_t *pglob) 1207a5229c74SGary Mills { 1208a5229c74SGary Mills char buf[MAXPATHLEN]; 1209a5229c74SGary Mills 1210a5229c74SGary Mills if (str->w_wc == EOS) 1211a5229c74SGary Mills (void) strlcpy(buf, ".", sizeof (buf)); 1212a5229c74SGary Mills else { 1213a5229c74SGary Mills if (g_Ctoc(str, buf, sizeof (buf))) 1214a5229c74SGary Mills return (NULL); 1215a5229c74SGary Mills } 1216a5229c74SGary Mills 1217a5229c74SGary Mills if (pglob->gl_flags & GLOB_ALTDIRFUNC) 1218a5229c74SGary Mills return ((*pglob->gl_opendir)(buf)); 1219a5229c74SGary Mills 1220a5229c74SGary Mills return (opendir(buf)); 1221a5229c74SGary Mills } 1222a5229c74SGary Mills 1223a5229c74SGary Mills static int 1224a5229c74SGary Mills g_lstat(wcat_t *fn, struct stat *sb, glob_t *pglob) 1225a5229c74SGary Mills { 1226a5229c74SGary Mills char buf[MAXPATHLEN]; 1227a5229c74SGary Mills 1228a5229c74SGary Mills if (g_Ctoc(fn, buf, sizeof (buf))) 1229a5229c74SGary Mills return (-1); 1230a5229c74SGary Mills if (pglob->gl_flags & GLOB_ALTDIRFUNC) 1231a5229c74SGary Mills return ((*pglob->gl_lstat)(buf, sb)); 1232a5229c74SGary Mills return (lstat(buf, sb)); 1233a5229c74SGary Mills } 1234a5229c74SGary Mills 1235a5229c74SGary Mills static int 1236a5229c74SGary Mills g_stat(wcat_t *fn, struct stat *sb, glob_t *pglob) 1237a5229c74SGary Mills { 1238a5229c74SGary Mills char buf[MAXPATHLEN]; 1239a5229c74SGary Mills 1240a5229c74SGary Mills if (g_Ctoc(fn, buf, sizeof (buf))) 1241a5229c74SGary Mills return (-1); 1242a5229c74SGary Mills if (pglob->gl_flags & GLOB_ALTDIRFUNC) 1243a5229c74SGary Mills return ((*pglob->gl_stat)(buf, sb)); 1244a5229c74SGary Mills return (stat(buf, sb)); 1245a5229c74SGary Mills } 1246a5229c74SGary Mills 1247a5229c74SGary Mills static wcat_t * 1248a5229c74SGary Mills g_strchr(const wcat_t *str, wchar_t ch) 1249a5229c74SGary Mills { 1250a5229c74SGary Mills do { 1251a5229c74SGary Mills if (str->w_at == 0 && str->w_wc == ch) 1252a5229c74SGary Mills return ((wcat_t *)str); 1253a5229c74SGary Mills } while ((str++)->w_wc != EOS); 1254a5229c74SGary Mills return (NULL); 1255a5229c74SGary Mills } 1256a5229c74SGary Mills 1257a5229c74SGary Mills static int 1258a5229c74SGary Mills g_Ctoc(const wcat_t *str, char *buf, uint_t len) 1259a5229c74SGary Mills { 1260a5229c74SGary Mills int n; 1261a5229c74SGary Mills wchar_t w; 1262a5229c74SGary Mills 1263a5229c74SGary Mills while (len >= MB_LEN_MAX) { 1264a5229c74SGary Mills w = (str++)->w_wc; 1265a5229c74SGary Mills if ((n = wctomb(buf, w)) > 0) { 1266a5229c74SGary Mills len -= n; 1267a5229c74SGary Mills buf += n; 1268a5229c74SGary Mills } 1269a5229c74SGary Mills if (n < 0) 1270a5229c74SGary Mills break; 1271a5229c74SGary Mills if (w == EOS) 1272a5229c74SGary Mills return (0); 1273a5229c74SGary Mills } 1274a5229c74SGary Mills return (1); 1275a5229c74SGary Mills } 1276a5229c74SGary Mills 1277*33e8313dSRobert Mustacchi #if defined(_LP64) || _FILE_OFFSET_BITS != 64 1278*33e8313dSRobert Mustacchi 1279a5229c74SGary Mills /* glob() function with legacy glob structure */ 1280a5229c74SGary Mills int 1281a5229c74SGary Mills old_glob(const char *pattern, int flags, int (*errfunc)(const char *, int), 1282a5229c74SGary Mills old_glob_t *pglob) 1283a5229c74SGary Mills { 1284a5229c74SGary Mills 1285a5229c74SGary Mills glob_t gl; 1286a5229c74SGary Mills int rv; 1287a5229c74SGary Mills 1288a5229c74SGary Mills flags &= GLOB_POSIX; 1289a5229c74SGary Mills 1290a5229c74SGary Mills (void) memset(&gl, 0, sizeof (gl)); 1291a5229c74SGary Mills 1292a5229c74SGary Mills /* 1293a5229c74SGary Mills * Copy all the members, old to new. There's 1294a5229c74SGary Mills * really no point in micro-optimizing the copying. 1295a5229c74SGary Mills * Other members are set to zero. 1296a5229c74SGary Mills */ 1297a5229c74SGary Mills gl.gl_pathc = pglob->gl_pathc; 1298a5229c74SGary Mills gl.gl_pathv = pglob->gl_pathv; 1299a5229c74SGary Mills gl.gl_offs = pglob->gl_offs; 1300a5229c74SGary Mills gl.gl_pathp = pglob->gl_pathp; 1301a5229c74SGary Mills gl.gl_pathn = pglob->gl_pathn; 1302a5229c74SGary Mills 1303a5229c74SGary Mills rv = _glob_ext(pattern, flags, errfunc, &gl); 1304a5229c74SGary Mills 1305a5229c74SGary Mills /* 1306a5229c74SGary Mills * Copy all the members, new to old. There's 1307a5229c74SGary Mills * really no point in micro-optimizing the copying. 1308a5229c74SGary Mills */ 1309a5229c74SGary Mills pglob->gl_pathc = gl.gl_pathc; 1310a5229c74SGary Mills pglob->gl_pathv = gl.gl_pathv; 1311a5229c74SGary Mills pglob->gl_offs = gl.gl_offs; 1312a5229c74SGary Mills pglob->gl_pathp = gl.gl_pathp; 1313a5229c74SGary Mills pglob->gl_pathn = gl.gl_pathn; 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate return (rv); 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate 1318a5229c74SGary Mills /* globfree() function with legacy glob structure */ 1319a5229c74SGary Mills void 1320a5229c74SGary Mills old_globfree(old_glob_t *pglob) 1321a5229c74SGary Mills { 1322a5229c74SGary Mills glob_t gl; 1323a5229c74SGary Mills 1324a5229c74SGary Mills (void) memset(&gl, 0, sizeof (gl)); 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate /* 1327a5229c74SGary Mills * Copy all the members, old to new. There's 1328a5229c74SGary Mills * really no point in micro-optimizing the copying. 1329a5229c74SGary Mills * Other members are set to zero. 13307c478bd9Sstevel@tonic-gate */ 1331a5229c74SGary Mills gl.gl_pathc = pglob->gl_pathc; 1332a5229c74SGary Mills gl.gl_pathv = pglob->gl_pathv; 1333a5229c74SGary Mills gl.gl_offs = pglob->gl_offs; 1334a5229c74SGary Mills gl.gl_pathp = pglob->gl_pathp; 1335a5229c74SGary Mills gl.gl_pathn = pglob->gl_pathn; 13367c478bd9Sstevel@tonic-gate 1337a5229c74SGary Mills _globfree_ext(&gl); 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate /* 1340a5229c74SGary Mills * Copy all the members, new to old. There's 1341a5229c74SGary Mills * really no point in micro-optimizing the copying. 13427c478bd9Sstevel@tonic-gate */ 1343a5229c74SGary Mills pglob->gl_pathc = gl.gl_pathc; 1344a5229c74SGary Mills pglob->gl_pathv = gl.gl_pathv; 1345a5229c74SGary Mills pglob->gl_offs = gl.gl_offs; 1346a5229c74SGary Mills pglob->gl_pathp = gl.gl_pathp; 1347a5229c74SGary Mills pglob->gl_pathn = gl.gl_pathn; 1348a5229c74SGary Mills 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate 1351*33e8313dSRobert Mustacchi #endif /* _LP64 || _FILE_OFFSET_BITS != 64 */ 1352