1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 /* 31 * This code is MKS code ported to Solaris originally with minimum 32 * modifications so that upgrades from MKS would readily integrate. 33 * The MKS basis for this modification was: 34 * 35 * $Id: glob.c 1.31 1994/04/07 22:50:43 mark 36 * 37 * Additional modifications have been made to this code to make it 38 * 64-bit clean. 39 */ 40 41 /* 42 * glob, globfree -- POSIX.2 compatible file name expansion routines. 43 * 44 * Copyright 1985, 1991 by Mortice Kern Systems Inc. All rights reserved. 45 * 46 * Written by Eric Gisin. 47 */ 48 49 #include "synonyms.h" 50 #include <stdio.h> 51 #include <unistd.h> 52 #include <limits.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <dirent.h> 56 #include <sys/stat.h> 57 #include <glob.h> 58 #include <errno.h> 59 #include <fnmatch.h> 60 61 #define GLOB__CHECK 0x80 /* stat generated paths */ 62 63 #define INITIAL 8 /* initial pathv allocation */ 64 #define NULLCPP ((char **)0) /* Null char ** */ 65 #define NAME_MAX 1024 /* something large */ 66 67 static int globit(size_t, const char *, glob_t *, int, 68 int (*)(const char *, int), char **); 69 static int pstrcmp(const void *, const void *); 70 static int append(glob_t *, const char *); 71 72 /* 73 * Free all space consumed by glob. 74 */ 75 void 76 globfree(glob_t *gp) 77 { 78 size_t i; 79 80 if (gp->gl_pathv == 0) 81 return; 82 83 for (i = gp->gl_offs; i < gp->gl_offs + gp->gl_pathc; ++i) 84 free(gp->gl_pathv[i]); 85 free((void *)gp->gl_pathv); 86 87 gp->gl_pathc = 0; 88 gp->gl_pathv = NULLCPP; 89 } 90 91 /* 92 * Do filename expansion. 93 */ 94 int 95 glob(const char *pattern, int flags, 96 int (*errfn)(const char *, int), glob_t *gp) 97 { 98 int rv; 99 size_t i; 100 size_t ipathc; 101 char *path; 102 103 if ((flags & GLOB_DOOFFS) == 0) 104 gp->gl_offs = 0; 105 106 if (!(flags & GLOB_APPEND)) { 107 gp->gl_pathc = 0; 108 gp->gl_pathn = gp->gl_offs + INITIAL; 109 gp->gl_pathv = (char **)malloc(sizeof (char *) * gp->gl_pathn); 110 111 if (gp->gl_pathv == NULLCPP) 112 return (GLOB_NOSPACE); 113 gp->gl_pathp = gp->gl_pathv + gp->gl_offs; 114 115 for (i = 0; i < gp->gl_offs; ++i) 116 gp->gl_pathv[i] = NULL; 117 } 118 119 if ((path = malloc(strlen(pattern)+1)) == NULL) 120 return (GLOB_NOSPACE); 121 122 ipathc = gp->gl_pathc; 123 rv = globit(0, pattern, gp, flags, errfn, &path); 124 125 if (rv == GLOB_ABORTED) { 126 /* 127 * User's error function returned non-zero, or GLOB_ERR was 128 * set, and we encountered a directory we couldn't search. 129 */ 130 free(path); 131 return (GLOB_ABORTED); 132 } 133 134 i = gp->gl_pathc - ipathc; 135 if (i >= 1 && !(flags & GLOB_NOSORT)) { 136 qsort((char *)(gp->gl_pathp+ipathc), i, sizeof (char *), 137 pstrcmp); 138 } 139 if (i == 0) { 140 if (flags & GLOB_NOCHECK) 141 (void) append(gp, pattern); 142 else 143 rv = GLOB_NOMATCH; 144 } 145 gp->gl_pathp[gp->gl_pathc] = NULL; 146 free(path); 147 148 return (rv); 149 } 150 151 152 /* 153 * Recursive routine to match glob pattern, and walk directories. 154 */ 155 int 156 globit(size_t dend, const char *sp, glob_t *gp, int flags, 157 int (*errfn)(const char *, int), char **path) 158 { 159 size_t n; 160 size_t m; 161 ssize_t end = 0; /* end of expanded directory */ 162 char *pat = (char *)sp; /* pattern component */ 163 char *dp = (*path) + dend; 164 int expand = 0; /* path has pattern */ 165 char *cp; 166 struct stat64 sb; 167 DIR *dirp; 168 struct dirent64 *d; 169 int err; 170 171 for (;;) 172 switch (*dp++ = *(unsigned char *)sp++) { 173 case '\0': /* end of source path */ 174 if (expand) 175 goto Expand; 176 else { 177 if (!(flags & GLOB_NOCHECK) || 178 flags & (GLOB__CHECK|GLOB_MARK)) 179 if (stat64(*path, &sb) < 0) { 180 return (0); 181 } 182 if (flags & GLOB_MARK && S_ISDIR(sb.st_mode)) { 183 *dp = '\0'; 184 *--dp = '/'; 185 } 186 if (append(gp, *path) < 0) { 187 return (GLOB_NOSPACE); 188 } 189 return (0); 190 } 191 /*NOTREACHED*/ 192 193 case '*': 194 case '?': 195 case '[': 196 case '\\': 197 ++expand; 198 break; 199 200 case '/': 201 if (expand) 202 goto Expand; 203 end = dp - *path; 204 pat = (char *)sp; 205 break; 206 207 Expand: 208 /* determine directory and open it */ 209 (*path)[end] = '\0'; 210 dirp = opendir(**path == '\0' ? "." : *path); 211 if (dirp == NULL) { 212 if (errfn != 0 && errfn(*path, errno) != 0 || 213 flags&GLOB_ERR) { 214 return (GLOB_ABORTED); 215 } 216 return (0); 217 } 218 219 /* extract pattern component */ 220 n = sp - pat; 221 if ((cp = malloc(n)) == NULL) { 222 (void) closedir(dirp); 223 return (GLOB_NOSPACE); 224 } 225 pat = memcpy(cp, pat, n); 226 pat[n-1] = '\0'; 227 if (*--sp != '\0') 228 flags |= GLOB__CHECK; 229 230 /* expand path to max. expansion */ 231 n = dp - *path; 232 *path = realloc(*path, 233 strlen(*path) + NAME_MAX + strlen(sp) + 1); 234 if (*path == NULL) { 235 (void) closedir(dirp); 236 free(pat); 237 return (GLOB_NOSPACE); 238 } 239 dp = (*path) + n; 240 241 /* read directory and match entries */ 242 err = 0; 243 while ((d = readdir64(dirp)) != NULL) { 244 cp = d->d_name; 245 if ((flags&GLOB_NOESCAPE) 246 ? fnmatch(pat, cp, FNM_PERIOD|FNM_NOESCAPE) 247 : fnmatch(pat, cp, FNM_PERIOD)) 248 continue; 249 250 n = strlen(cp); 251 (void) memcpy((*path) + end, cp, n); 252 m = dp - *path; 253 err = globit(end+n, sp, gp, flags, errfn, path); 254 dp = (*path) + m; /* globit can move path */ 255 if (err != 0) 256 break; 257 } 258 259 (void) closedir(dirp); 260 free(pat); 261 return (err); 262 } 263 /* NOTREACHED */ 264 } 265 266 /* 267 * Comparison routine for two name arguments, called by qsort. 268 */ 269 int 270 pstrcmp(const void *npp1, const void *npp2) 271 { 272 return (strcoll(*(char **)npp1, *(char **)npp2)); 273 } 274 275 /* 276 * Add a new matched filename to the glob_t structure, increasing the 277 * size of that array, as required. 278 */ 279 int 280 append(glob_t *gp, const char *str) 281 { 282 char *cp; 283 284 if ((cp = malloc(strlen(str)+1)) == NULL) 285 return (GLOB_NOSPACE); 286 gp->gl_pathp[gp->gl_pathc++] = strcpy(cp, str); 287 288 if ((gp->gl_pathc + gp->gl_offs) >= gp->gl_pathn) { 289 gp->gl_pathn *= 2; 290 gp->gl_pathv = (char **)realloc((void *)gp->gl_pathv, 291 gp->gl_pathn * sizeof (char *)); 292 if (gp->gl_pathv == NULLCPP) 293 return (GLOB_NOSPACE); 294 gp->gl_pathp = gp->gl_pathv + gp->gl_offs; 295 } 296 return (0); 297 } 298