예제 #1
0
bool checkPackageMapMatchesTarget(const char *target, const char *match)
{
    if (!match || !*match)
        return false;
    if (isWildString(match))
        return WildMatch(target, match);
    return streq(target, match);
}
예제 #2
0
/**
	Do a case insensitive find for the pattern.

	\param text The text to match an ignore pattern against.
	\return Returns true if the directory should be ignored, false otherwise.
**/
bool FileGlobBase::MatchIgnorePattern( const char* text )
{
	for ( StringList::iterator it = m_ignorePatterns.begin();
			it != m_ignorePatterns.end(); ++it )
	{
		if ( WildMatch( (*it).c_str(), text, false  ) )
			return true;
	}

	return false;
}
예제 #3
0
 ForEachItemIn(idx, patterns)
 {
     bool match;
     const char *pattern = patterns.item(idx);
     if (strchr(pattern, '*'))
     {
         match = WildMatch(name, pattern, true);
     }
     else
         match = streq(name, pattern);
     if (match)
         return true;
 }
예제 #4
0
파일: nameinfo.c 프로젝트: kbarber/cfng
void
GetNameInfo(void)
{
    int i, found = false;
    char *sp, *sp2;
    time_t tloc;
    struct hostent *hp;
    struct sockaddr_in cin;
#ifdef AIX
    char real_version[_SYS_NMLN];
#endif
#ifdef IRIX
    char real_version[256]; /* see <sys/syssgi.h> */
#endif
#ifdef HAVE_SYSINFO
#ifdef SI_ARCHITECTURE
    long sz;
#endif
#endif

    Debug("GetNameInfo()\n");

    g_vfqname[0] = g_vuqname[0] = '\0';

    if (uname(&g_vsysname) == -1) {
        perror("uname ");
        FatalError("Uname couldn't get kernel name info!!\n");
    }

#ifdef AIX
    snprintf(real_version, _SYS_NMLN, "%.80s.%.80s",
            g_vsysname.version, g_vsysname.release);
    strncpy(g_vsysname.release, real_version, _SYS_NMLN);
#elif defined IRIX
/* This gets us something like `6.5.19m' rather than just `6.5'.  */
    syssgi (SGI_RELEASE_NAME, 256, real_version);
#endif

    for (sp = g_vsysname.sysname; *sp != '\0'; sp++) {
        *sp = ToLower(*sp);
    }

    for (sp = g_vsysname.machine; *sp != '\0'; sp++) {
        *sp = ToLower(*sp);
    }

    for (i = 0; g_classattributes[i][0] != '\0'; i++) {

        if (WildMatch(g_classattributes[i][0],
                    ToLowerStr(g_vsysname.sysname))) {

            if (WildMatch(g_classattributes[i][1], 
                        g_vsysname.machine)) {

                if (WildMatch(g_classattributes[i][2], 
                            g_vsysname.release)) {

                    if (g_underscore_classes) {
                        snprintf(g_vbuff, CF_BUFSIZE, "_%s", g_classtext[i]);
                        AddClassToHeap(g_vbuff);
                    } else {
                        AddClassToHeap(g_classtext[i]);
                    }
                    found = true;
                    g_vsystemhardclass = (enum classes) i;
                    break;
                }
            } else {
                Debug2("Cfengine: I recognize %s but not %s\n",
                        g_vsysname.sysname, g_vsysname.machine);
                    continue;
            }
        }
   }

    if ((sp = malloc(strlen(g_vsysname.nodename)+1)) == NULL) {
        FatalError("malloc failure in initialize()");
    }

    strcpy(sp, g_vsysname.nodename);
    SetDomainName(sp);

    /* Truncate fully qualified name */
    for (sp2=sp; *sp2 != '\0'; sp2++) {
        if (*sp2 == '.') {
            *sp2 = '\0';
            Debug("Truncating fully qualified hostname %s to %s\n",
                    g_vsysname.nodename,sp);
            break;
        }
    }

    g_vdefaultbinserver.name = sp;

    AddClassToHeap(CanonifyName(sp));


    if ((tloc = time((time_t *)NULL)) == -1) {
        printf("Couldn't read system clock\n");
    }

    if (g_verbose || g_debug || g_d2 || g_d3) {
        if (g_underscore_classes) {
            snprintf(g_vbuff, CF_BUFSIZE, "_%s", g_classtext[i]);
        } else {
            snprintf(g_vbuff, CF_BUFSIZE, "%s", g_classtext[i]);
        }

        if (g_iscfengine) {
            printf ("cfng: configuration agent (cfagent) - \n%s\n%s\n\n",
                    VERSION, g_copyright);
        } else {
            printf ("cfng: configuration server (cfservd) - \n%s\n%s\n\n",
                    VERSION, g_copyright);
        }

        printf ("------------------------------------------------------------------------\n\n");
        printf ("Host name is: %s\n", g_vsysname.nodename);
        printf ("Operating System Type is %s\n", g_vsysname.sysname);
        printf ("Operating System Release is %s\n", g_vsysname.release);
        printf ("Architecture = %s\n\n\n", g_vsysname.machine);
        printf ("Using internal soft-class %s for host %s\n\n",
                g_vbuff, g_classtext[g_vsystemhardclass]);
        printf ("The time is now %s\n\n", ctime(&tloc));
        printf ("------------------------------------------------------------------------\n\n");

    }

    sprintf(g_vbuff, "%d_bit", sizeof(long)*8);
    AddClassToHeap(g_vbuff);
    Verbose("Additional hard class defined as: %s\n", CanonifyName(g_vbuff));

    snprintf(g_vbuff, CF_BUFSIZE, "%s_%s", g_vsysname.sysname,
            g_vsysname.release);
    AddClassToHeap(CanonifyName(g_vbuff));

#ifdef IRIX
    /* 
     * Get something like `irix64_6_5_19m' defined as well as
     * `irix64_6_5'.  Just copying the latter into g_vsysname.release
     * wouldn't be backwards-compatible.
     */
    snprintf(g_vbuff, CF_BUFSIZE, "%s_%s", g_vsysname.sysname, real_version);
    AddClassToHeap(CanonifyName(g_vbuff));
#endif

    AddClassToHeap(CanonifyName(g_vsysname.machine));

    Verbose("Additional hard class defined as: %s\n",CanonifyName(g_vbuff));

    snprintf(g_vbuff, CF_BUFSIZE,"%s_%s", g_vsysname.sysname,
            g_vsysname.machine);
    AddClassToHeap(CanonifyName(g_vbuff));

    Verbose("Additional hard class defined as: %s\n",CanonifyName(g_vbuff));

    snprintf(g_vbuff, CF_BUFSIZE, "%s_%s_%s",
            g_vsysname.sysname, g_vsysname.machine, g_vsysname.release);

    AddClassToHeap(CanonifyName(g_vbuff));

    Verbose("Additional hard class defined as: %s\n", CanonifyName(g_vbuff));

#ifdef HAVE_SYSINFO
#ifdef SI_ARCHITECTURE
    sz = sysinfo(SI_ARCHITECTURE, g_vbuff, CF_BUFSIZE);
    if (sz == -1) {
        Verbose("cfagent internal: sysinfo returned -1\n");
    } else {
        AddClassToHeap(CanonifyName(g_vbuff));
        Verbose("Additional hard class defined as: %s\n", g_vbuff);
    }
#endif
#endif

    snprintf(g_vbuff, CF_BUFSIZE, "%s_%s_%s_%s",
            g_vsysname.sysname, g_vsysname.machine, g_vsysname.release,
            g_vsysname.version);

    if (strlen(g_vbuff) < CF_MAXVARSIZE-2) {
        g_varch = strdup(CanonifyName(g_vbuff));
    } else {

        Verbose("cfagent internal: $(arch) overflows CF_MAXVARSIZE! Truncating\n");
        g_varch = strdup(CanonifyName(g_vsysname.sysname));
    }

    snprintf(g_vbuff, CF_BUFSIZE, "%s_%s",
            g_vsysname.sysname, g_vsysname.machine);

    g_varch2 = strdup(CanonifyName(g_vbuff));

    AddClassToHeap(g_varch);

    Verbose("Additional hard class defined as: %s\n", g_varch);

    if (! found) {

        CfLog(cferror,"Cfengine: I don't understand "
                "what architecture this is!","");

    }

    strcpy(g_vbuff, "compiled_on_");
    strcat(g_vbuff, CanonifyName(AUTOCONF_SYSNAME));

    AddClassToHeap(CanonifyName(g_vbuff));

    Verbose("\nGNU autoconf class from compile time: %s\n\n", g_vbuff);

    /* Get IP address from nameserver */
    if ((hp = gethostbyname(g_vsysname.nodename)) == NULL) {
        return;
    } else {
        memset(&cin, 0, sizeof(cin));
        cin.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
        Verbose("Address given by nameserver: %s\n", inet_ntoa(cin.sin_addr));
        strcpy(g_vipaddress, inet_ntoa(cin.sin_addr));

        for (i=0; hp->h_aliases[i] != NULL; i++) {
            Debug("Adding alias %s..\n", hp->h_aliases[i]);
            AddClassToHeap(CanonifyName(hp->h_aliases[i]));
        }
    }
}
bool FileUtils::WildMatch(const wxString& mask, const wxString& filename)
{
    return WildMatch(mask, wxFileName(filename));
}
예제 #6
0
    void next(size_t maxfilenamesize, char *outfilename, bool &isdir, rfs_fpos_t &filesizeout, time_t &outmodifiedtime)
    {
#ifdef _WIN32
        WIN32_FIND_DATA info;
        bool nocase = true;
#else
        struct dirent *entry;
        bool nocase = false;
#endif
        while (1) {
            *outfilename = 0;
            if (level<0)
                return;
            if (first) {
                first = false;
                handles = (_Handle *)realloc(handles,sizeof(_Handle)*(level+1));
#ifdef _WIN32
                path.appendc('*');
                handles[level] = FindFirstFile(path.str(), &info);
                path.decLength();
#else
                handles[level] = opendir(path.str());
                if (handles[level])
                    entry = readdir(handles[level]);  // don't need _r here
#endif
            }
            else {
#ifdef _WIN32
                if (!FindNextFile(handles[level], &info)) {
                    FindClose(handles[level]);
#else
                entry = readdir(handles[level]);  // don't need _r here
                if (!entry) {
                    closedir(handles[level]);
#endif
                    handles[level] = INVALID_HANDLE_VALUE;
                }
            }
            if (handles[level]!=INVALID_HANDLE_VALUE) {
                free(tail);
#ifdef _WIN32
                tail = _strdup(info.cFileName);
                isdir = ((info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)!=0);
#else
                tail = _strdup(entry->d_name);
#endif
                size_t hs = path.length()-pathhead;
                size_t ts = strlen(tail);
                if (hs>=maxfilenamesize)
                    hs = maxfilenamesize-1;
                if (hs+ts>=maxfilenamesize)
                    ts = maxfilenamesize-1-hs;
                memcpy(outfilename,path.str()+pathhead,hs);
                memcpy(outfilename+hs,tail,ts);
                outfilename[hs+ts] = 0;
#ifndef _WIN32
                struct stat info;
                if (stat(outfilename, &info) != 0)  // will follow link
                    continue;
                isdir = S_ISDIR(info.st_mode);
#endif

                if ((strcmp(tail,".")==0)||(strcmp(tail,"..")==0))
                    continue;
                bool matched = (mask&&*mask)?WildMatch(tail,mask,nocase):false;
                if (!matched&&(!recursive||!isdir))
                    continue;
                if (isdir&&!recursive&&!includedirs)
                    continue;
                if (isdir) {
                    if (recursive) {
                        // add name
                        path.appends(tail);
                        if (path.lastChar()!='\\')
                            path.appendc('\\');
                        first = true;
                        level++;
                    }
                    if (!includedirs||!matched)
                        continue;
                    filesizeout = (rfs_fpos_t)0;
                }
                else {
#ifdef _WIN32
                    LARGE_INTEGER x;
                    x.LowPart = info.nFileSizeLow;
                    x.HighPart = info.nFileSizeHigh;
                    filesizeout = (rfs_fpos_t)x.QuadPart;
                }
                outmodifiedtime = FileTimeToUnixTime(&info.ftLastWriteTime);
#else
                    filesizeout = info.st_size;
                }
                outmodifiedtime = info.st_mtime;
#endif
                break;
            }
            level--;
            if (level<0)
                return;
            if (path.lastChar()=='\\')
                path.decLength();
            while (path.length()) {
                if (path.lastChar()=='\\')
                    break;
                path.decLength();

            }
        }
    }
예제 #7
0
파일: process.c 프로젝트: kbarber/cfng
int
FindMatches(struct Process *pp, struct Item *procdata,
        struct Item **killlist)
{
    struct Item *ip, *ip2;
    char *sp,saveuid[16];
    int pid=-1, ret, matches=0, got, i;
    regex_t rx,rxcache;
    regmatch_t pmatch;
    pid_t cfengine_pid = getpid();
    char *names[CF_PROCCOLS];      /* ps headers */
    int start[CF_PROCCOLS];
    int end[CF_PROCCOLS];

    Debug2("Looking for process %s\n",pp->expr);

    if (CfRegcomp(&rxcache,pp->expr,REG_EXTENDED) != 0) {
        return 0;
    }

    GetProcessColumns(procdata->name,(char **)names,start,end);

    for (ip = procdata; ip != NULL; ip=ip->next) {

        /* To fix a bug on some implementations where rx gets emptied */
        bcopy(&rxcache,&rx,sizeof(rx));

        if (regexec(&rx,ip->name,1,&pmatch,0) == 0) {
            pid = -1;
            got = true;
            Debug("Regex %s matched %s\n",ip->name,pp->expr);

            for (ip2 = pp->inclusions; ip2 != NULL; ip2 = ip2->next) {
                got = false;

                if (strstr(ip->name,ip2->name) ||
                        WildMatch(ip2->name,ip->name)) {
                    got = true;
                    break;
                }
            }

            if (!got) {
                continue;
            }

            got = false;

            for (ip2 = pp->exclusions; ip2 != NULL; ip2 = ip2->next) {
                if (strstr(ip->name,ip2->name) ||
                        WildMatch(ip2->name,ip->name)) {
                    got = true;
                    break;
                }
            }

            if (!ProcessFilter(ip->name,pp->filters,names,start,end)) {
                Debug("%s Filtered away\n",ip->name);
                continue;
            }

            if (got) {
                continue;
            }

            Debug("Matched proc[%s]\n",ip->name);

            /* if first field contains alpha, skip */
            for (sp = ip->name; *sp != '\0'; sp++) {
                while (true) {
                    while (!isdigit((int)*sp) && (*sp != '\0')) {
                        sp++;
                    }

                    /* Username contains number*/
                    if ((sp > ip->name) && isalnum((int)*(sp-1))) {
                        sp++;
                    } else {
                        break;
                    }
                }

                sscanf(sp,"%d",&pid);

                if (pid != -1) {
                    break;
                }
            }

            if (pid == -1) {
                snprintf(g_output,CF_BUFSIZE*2,
                        "Unable to extract pid while looking for %s\n",
                        pp->expr);
                CfLog(cfverbose,g_output,"");
                continue;
            }

            Debug2("Found matching pid %d\n",pid);

            matches++;

            if (pid == 1 && pp->signal == cfhup) {
                Verbose("(Okay to send HUP to init)\n");
            } else if (pid < 4) {
                Verbose("%s: will not signal or restart processes 0,1,2,3\n",
                        g_vprefix);
                Verbose("%s: occurred while looking for %s\n",
                        g_vprefix,pp->expr);
                continue;
            }

            if (pp->action == 'w') {
                snprintf(g_output,CF_BUFSIZE*2,"Process alert: %s\n",
                        procdata->name);
                CfLog(cferror,g_output,"");
                snprintf(g_output,CF_BUFSIZE*2,"Process alert: %s\n",ip->name);
                CfLog(cferror,g_output,"");
                continue;
            }

            if (pp->signal != cfnosignal) {
                if (!g_dontdo) {
                    if (pid == cfengine_pid) {
                        CfLog(cfverbose,"Cfengine will not kill itself!\n","");
                        continue;
                    }

                    if (pp->action == 'm') {
                        sprintf(saveuid,"%d",pid);
                        PrependItem(killlist,saveuid,"");
                    } else {
                        if ((ret = kill((pid_t)pid,pp->signal)) < 0) {
                            snprintf(g_output,CF_BUFSIZE*2,
                                    "Couldn't send signal to pid %d\n",pid);
                            CfLog(cfverbose,g_output,"kill");

                            continue;
                        }

                        snprintf(g_output,CF_BUFSIZE*2,
                            "Signalled process %d (%s) with %s\n",pid,
                            pp->expr,g_signals[pp->signal]);
                        CfLog(cfinform,g_output,"");

                        if ((pp->signal == cfkill || pp->signal == cfterm) &&
                                ret >= 0) {
                            snprintf(g_output, CF_BUFSIZE*2,
                                    "Killed: %s\n",ip->name);
                            CfLog(cfinform,g_output,"");
                        }
                    }
                }
            }
        }
    }

    for (i = 0; i < CF_PROCCOLS; i++) {
        if (names[i] != NULL) {
            free(names[i]);
        }
    }

    regfree(&rx);
    return matches;
}
예제 #8
0
//////////////////////////////////////////////////////////////////////////////
// Compare a location/channel string against the filter string
// filter_str contains a comma separated list of location/channel pairs
// chan_str contatins a single location/channel
// Wildcards *,? are allowed in filter_str, not in chan_str
// Returns 1 if filter_str is NULL
// Returns 1 if chan_str matches one of the filters
// Returns 0 if chan_str does not match one of the filters
// Returns -1 if there is a syntax error in filter_str
int check_filter(const char *filter_str, const char *chan_str)
{
  char *entry_ptr;
  char entry_str[16];
  char pattern_str[4];
  char target_str[4];
  int  i,j;

  if (filter_str == NULL)
    return 1;

  // Loop through each entry in filter_str
  for (entry_ptr = (char *)filter_str; *entry_ptr != 0;) 
  {
    // Copy entry
    for (i=0; *entry_ptr != 0 && *entry_ptr != ','; i++, entry_ptr++)
    {
      entry_str[i] = *entry_ptr;
      if (i > 5) return -1; // loc/channel is never more than 6 chars
    }
    if (*entry_ptr == ',') entry_ptr++;
    entry_str[i] = 0;
    if (i < 2) return -1;  // shortest legal filter is "/*"

    // Compare locations
    strncpy(target_str, chan_str, 2);
    target_str[2] = 0;

    for (i=0; i < 2; i++)
    {
      if (entry_str[0] == '/')
      {
        strcpy(pattern_str, "  ");
        j = 2;
        break;
      }

      if (entry_str[i] != '/')
      {
        pattern_str[i] = entry_str[i];
      }

      if (entry_str[i] == '/') break;
    } // Copy pattern location
    pattern_str[i] = 0;
    if (entry_str[i] != '/') return -1;  // Syntax error in filter location

    if (!WildMatch(pattern_str, target_str)) continue;

    // Match channel strings
    strncpy(target_str, &chan_str[3], 3);
    target_str[3] = 0;

    strncpy(pattern_str, &entry_str[i+1], 3);
    pattern_str[3] = 0;
    if (strlen(entry_str) - i > 4)
    {
      if (gDebug)
        fprintf(stderr, "check_filter entry_str '%s' %d > %d+%d+1\n",
              entry_str, strlen(entry_str), i,4);
      else
        syslog(LOG_ERR, "check_filter entry_str '%s' %d > %d+%d+1\n",
              entry_str, strlen(entry_str), i,4);
      return -1;  // channel name too long
    }

    if (WildMatch(pattern_str, target_str))
    {
     if (VERBOSE)
       fprintf(stderr, "Matched filter '%s' against '%s'\n",
              entry_str, chan_str);
      return 1;
    }
  } // loop through all filter pairs

  // If we get here then there was no match
  return 0;
} // check_filter()
예제 #9
0
/**
	\internal Does all the actual globbing.
	\author Matthias Wandel ([email protected]) http://http://www.sentex.net/~mwandel/
	\author Joshua Jensen ([email protected])

	Matthias Wandel wrote the original C algorithm, which is contained in
	his Exif Jpeg header parser at http://www.sentex.net/~mwandel/jhead/ under
	the filename MyGlob.c.  It should be noted that the MAJORITY of this
	function is his, albeit rebranded style-wise.

	I have made the following extensions:

	-	Support for ignoring directories.
	-	Perforce-style (and DJGPP-style) ... for recursion, instead of **.
	-	Automatic conversion from ...Stuff to .../*Stuff.  Allows lookup of
		files by extension, too: '....h' translates to '.../*.h'.
	-	Ability to handle forward slashes and backslashes.
	-	A minimal C++ class design.
	-	Wildcard matching not based on FindFirstFile().  Should allow greater
		control in the future and patching in of the POSIX fnmatch() function
		on systems that support it.
**/
void FileGlobBase::GlobHelper( const char* inPattern )
{
	char patternBuf[ _MAX_PATH * 2 ];
	strcpy( patternBuf, inPattern );

DoRecursion:
	char basePath[ _MAX_PATH ];
	char* basePathEndPtr = basePath;
	char* recurseAtPtr = NULL;

	// Split the path into base path and pattern to match against.
	bool hasWildcard = false;

	char* pattern;
	for ( pattern = patternBuf; *pattern != '\0'; ++pattern )
	{
		char ch = *pattern;

		// Is it a '?' ?
		if ( ch == '?' )
			hasWildcard = true;

		// Is it a '*' ?
		else if ( ch == '*' )
		{
			hasWildcard = true;

			// Is there a '**'?
			if ( pattern[ 1 ] == '*' )
			{
				// If we're just starting the pattern or the characters immediately
				// preceding the pattern are a drive letter ':' or a directory path
				// '/', then set up the internals for later recursion.
				if ( pattern == patternBuf  ||  pattern[ -1 ] == '/'  ||
					pattern[ -1 ] == ':')
				{
					char ch2 = pattern[ 2 ];
					if ( ch2 == '/' )
					{
						recurseAtPtr = pattern;
						memcpy(pattern, pattern + 3, strlen( pattern ) - 2 );
					}
					else if ( ch2 == '\0' )
					{
						recurseAtPtr = pattern;
						*pattern = '\0';
					}
				}
			}
		}

		// Is there a '/' or ':' in the pattern at this location?
		if ( ch == '/'  ||  ch == ':' )
		{
			if ( hasWildcard )
				break;
			basePathEndPtr = &basePath[ pattern - patternBuf + 1 ];
		}
	}

	// If there is no wildcard this time, then just add the current file and
	// get out of here.
	if ( !hasWildcard )
	{
		// This should refer to a file.
		FoundMatch( patternBuf );
		return;
	}

	// Did we make it to the end of the pattern?  If so, we should match files,
	// since there were no slashes encountered.
	bool matchFiles = *pattern == '\0';

	// Copy the directory down.
	size_t basePathLen = basePathEndPtr - basePath;
	strncpy( basePath, patternBuf, basePathLen );

	// Copy the wildcard matching string.
	char matchPattern[ _MAX_PATH ];
	size_t matchLen = ( pattern - patternBuf ) - basePathLen;
	strncpy( matchPattern, patternBuf + basePathLen, matchLen + 1 );
	if ( matchPattern[ matchLen ] == '/' )
		matchPattern[ matchLen ] = 0;

	StringList fileList;

	// Do the file search with *.* in the directory specified in basePattern.
	strcpy( basePathEndPtr, "*.*" );

	// Start the find.
	WIN32_FIND_DATA fd;
	HANDLE handle = FindFirstFile( basePath, &fd );

	// Clear out the *.* so we can use the original basePattern string.
	*basePathEndPtr = 0;

	// Any files found?
	if ( handle != INVALID_HANDLE_VALUE )
	{
		for ( ;; )
		{
			// Is the file a directory?
			if ( ( fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )  &&  !matchFiles )
			{
				// Do a wildcard match.
				if ( WildMatch( matchPattern, fd.cFileName, false ) )
				{
					// It matched.  Let's see if the file should be ignored.
					bool ignore = false;

					// Knock out "." or ".." if they haven't already been.
					size_t len = strlen( fd.cFileName );
					fd.cFileName[ len ] = '/';
					fd.cFileName[ len + 1 ] = '\0';

					// See if this is a directory to ignore.
					ignore = MatchIgnorePattern( fd.cFileName );

					fd.cFileName[ len ] = 0;

					// Should this file be ignored?
					if ( !ignore )
					{
						// Nope.  Add it to the linked list.
						fileList.push_back( fd.cFileName );
					}
				}
			}
			else if ( !( fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )  &&  matchFiles )
			{
				// Do a wildcard match.
				if ( WildMatch( matchPattern, fd.cFileName, false ) )
				{
					// It matched.  Let's see if the file should be ignored.
					bool ignore = MatchIgnorePattern( fd.cFileName );

					// Is this pattern exclusive?
					if ( !ignore  &&  m_exclusiveFilePatterns.begin() != m_exclusiveFilePatterns.end() )
					{
						ignore = !MatchExclusivePattern( fd.cFileName );
					}

					// Should this file be ignored?
					if ( !ignore )
					{
						// Nope.  Add it to the linked list.
						fileList.push_back( fd.cFileName );
					}
				}
			}

			// Look up the next file.
			if ( !FindNextFile( handle, &fd ) )
				break;
		}

		// Close down the file find handle.
		FindClose( handle );
	}

	// Sort the list.
	fileList.sort();

	// Iterate the file list and either recurse or add the file as a found
	// file.
	if ( !matchFiles )
	{
		for ( StringList::iterator it = fileList.begin(); it != fileList.end(); ++it )
		{
			char combinedName[ _MAX_PATH * 2 ];

			// Need more directories.
			CatPath( combinedName, basePath, (*it).c_str() );
			strcat( combinedName, pattern );
			GlobHelper( combinedName );
		}
	}
	else // if ( !matchFiles )
	{
		for ( StringList::iterator it = fileList.begin(); it != fileList.end(); ++it )
		{
			char combinedName[ _MAX_PATH * 2 ];
			CatPath( combinedName, basePath, (*it).c_str());
			FoundMatch( combinedName );
		}
	}

	// Clear out the file list, so the goto statement below can recurse
	// internally.
	fileList.clear();

	// Do we need to recurse?
	if ( !recurseAtPtr )
		return;

	// Copy in the new recursive pattern to match.
	strcpy( matchPattern, recurseAtPtr );
	strcpy( recurseAtPtr, "*/**/" );
	strcat( patternBuf, matchPattern );

	// As this function context is no longer needed, we can just go back
	// to the top of it to avoid adding another context on the stack.
	goto DoRecursion;
}