140b1a6e6Sjoerg /*-
240b1a6e6Sjoerg * Copyright (c) 2003-2007 Tim Kientzle
340b1a6e6Sjoerg * All rights reserved.
440b1a6e6Sjoerg *
540b1a6e6Sjoerg * Redistribution and use in source and binary forms, with or without
640b1a6e6Sjoerg * modification, are permitted provided that the following conditions
740b1a6e6Sjoerg * are met:
840b1a6e6Sjoerg * 1. Redistributions of source code must retain the above copyright
940b1a6e6Sjoerg * notice, this list of conditions and the following disclaimer
1040b1a6e6Sjoerg * in this position and unchanged.
1140b1a6e6Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1240b1a6e6Sjoerg * notice, this list of conditions and the following disclaimer in the
1340b1a6e6Sjoerg * documentation and/or other materials provided with the distribution.
1440b1a6e6Sjoerg *
1540b1a6e6Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
1640b1a6e6Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1740b1a6e6Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1840b1a6e6Sjoerg * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
1940b1a6e6Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2040b1a6e6Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2140b1a6e6Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2240b1a6e6Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2340b1a6e6Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2440b1a6e6Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2540b1a6e6Sjoerg */
2640b1a6e6Sjoerg
2740b1a6e6Sjoerg #include "archive_platform.h"
2840b1a6e6Sjoerg
2940b1a6e6Sjoerg #ifdef HAVE_STRING_H
3040b1a6e6Sjoerg #include <string.h>
3140b1a6e6Sjoerg #endif
3240b1a6e6Sjoerg #ifdef HAVE_WCHAR_H
3340b1a6e6Sjoerg #include <wchar.h>
3440b1a6e6Sjoerg #endif
3540b1a6e6Sjoerg
3640b1a6e6Sjoerg #include "archive_pathmatch.h"
3740b1a6e6Sjoerg
3840b1a6e6Sjoerg /*
3940b1a6e6Sjoerg * Check whether a character 'c' is matched by a list specification [...]:
4040b1a6e6Sjoerg * * Leading '!' or '^' negates the class.
4140b1a6e6Sjoerg * * <char>-<char> is a range of characters
4240b1a6e6Sjoerg * * \<char> removes any special meaning for <char>
4340b1a6e6Sjoerg *
4440b1a6e6Sjoerg * Some interesting boundary cases:
4540b1a6e6Sjoerg * a-d-e is one range (a-d) followed by two single characters - and e.
4640b1a6e6Sjoerg * \a-\d is same as a-d
4740b1a6e6Sjoerg * a\-d is three single characters: a, d, -
4840b1a6e6Sjoerg * Trailing - is not special (so [a-] is two characters a and -).
4940b1a6e6Sjoerg * Initial - is not special ([a-] is same as [-a] is same as [\\-a])
5040b1a6e6Sjoerg * This function never sees a trailing \.
5140b1a6e6Sjoerg * [] always fails
5240b1a6e6Sjoerg * [!] always succeeds
5340b1a6e6Sjoerg */
5440b1a6e6Sjoerg static int
pm_list(const char * start,const char * end,const char c,int flags)5540b1a6e6Sjoerg pm_list(const char *start, const char *end, const char c, int flags)
5640b1a6e6Sjoerg {
5740b1a6e6Sjoerg const char *p = start;
5840b1a6e6Sjoerg char rangeStart = '\0', nextRangeStart;
5940b1a6e6Sjoerg int match = 1, nomatch = 0;
6040b1a6e6Sjoerg
6140b1a6e6Sjoerg /* This will be used soon... */
6240b1a6e6Sjoerg (void)flags; /* UNUSED */
6340b1a6e6Sjoerg
6440b1a6e6Sjoerg /* If this is a negated class, return success for nomatch. */
6540b1a6e6Sjoerg if ((*p == '!' || *p == '^') && p < end) {
6640b1a6e6Sjoerg match = 0;
6740b1a6e6Sjoerg nomatch = 1;
6840b1a6e6Sjoerg ++p;
6940b1a6e6Sjoerg }
7040b1a6e6Sjoerg
7140b1a6e6Sjoerg while (p < end) {
7240b1a6e6Sjoerg nextRangeStart = '\0';
7340b1a6e6Sjoerg switch (*p) {
7440b1a6e6Sjoerg case '-':
7540b1a6e6Sjoerg /* Trailing or initial '-' is not special. */
7640b1a6e6Sjoerg if ((rangeStart == '\0') || (p == end - 1)) {
7740b1a6e6Sjoerg if (*p == c)
7840b1a6e6Sjoerg return (match);
7940b1a6e6Sjoerg } else {
8040b1a6e6Sjoerg char rangeEnd = *++p;
8140b1a6e6Sjoerg if (rangeEnd == '\\')
8240b1a6e6Sjoerg rangeEnd = *++p;
8340b1a6e6Sjoerg if ((rangeStart <= c) && (c <= rangeEnd))
8440b1a6e6Sjoerg return (match);
8540b1a6e6Sjoerg }
8640b1a6e6Sjoerg break;
8740b1a6e6Sjoerg case '\\':
8840b1a6e6Sjoerg ++p;
8940b1a6e6Sjoerg /* Fall through */
9040b1a6e6Sjoerg default:
9140b1a6e6Sjoerg if (*p == c)
9240b1a6e6Sjoerg return (match);
9340b1a6e6Sjoerg nextRangeStart = *p; /* Possible start of range. */
9440b1a6e6Sjoerg }
9540b1a6e6Sjoerg rangeStart = nextRangeStart;
9640b1a6e6Sjoerg ++p;
9740b1a6e6Sjoerg }
9840b1a6e6Sjoerg return (nomatch);
9940b1a6e6Sjoerg }
10040b1a6e6Sjoerg
10140b1a6e6Sjoerg static int
pm_list_w(const wchar_t * start,const wchar_t * end,const wchar_t c,int flags)10240b1a6e6Sjoerg pm_list_w(const wchar_t *start, const wchar_t *end, const wchar_t c, int flags)
10340b1a6e6Sjoerg {
10440b1a6e6Sjoerg const wchar_t *p = start;
10540b1a6e6Sjoerg wchar_t rangeStart = L'\0', nextRangeStart;
10640b1a6e6Sjoerg int match = 1, nomatch = 0;
10740b1a6e6Sjoerg
10840b1a6e6Sjoerg /* This will be used soon... */
10940b1a6e6Sjoerg (void)flags; /* UNUSED */
11040b1a6e6Sjoerg
11140b1a6e6Sjoerg /* If this is a negated class, return success for nomatch. */
11240b1a6e6Sjoerg if ((*p == L'!' || *p == L'^') && p < end) {
11340b1a6e6Sjoerg match = 0;
11440b1a6e6Sjoerg nomatch = 1;
11540b1a6e6Sjoerg ++p;
11640b1a6e6Sjoerg }
11740b1a6e6Sjoerg
11840b1a6e6Sjoerg while (p < end) {
11940b1a6e6Sjoerg nextRangeStart = L'\0';
12040b1a6e6Sjoerg switch (*p) {
12140b1a6e6Sjoerg case L'-':
12240b1a6e6Sjoerg /* Trailing or initial '-' is not special. */
12340b1a6e6Sjoerg if ((rangeStart == L'\0') || (p == end - 1)) {
12440b1a6e6Sjoerg if (*p == c)
12540b1a6e6Sjoerg return (match);
12640b1a6e6Sjoerg } else {
12740b1a6e6Sjoerg wchar_t rangeEnd = *++p;
12840b1a6e6Sjoerg if (rangeEnd == L'\\')
12940b1a6e6Sjoerg rangeEnd = *++p;
13040b1a6e6Sjoerg if ((rangeStart <= c) && (c <= rangeEnd))
13140b1a6e6Sjoerg return (match);
13240b1a6e6Sjoerg }
13340b1a6e6Sjoerg break;
13440b1a6e6Sjoerg case L'\\':
13540b1a6e6Sjoerg ++p;
13640b1a6e6Sjoerg /* Fall through */
13740b1a6e6Sjoerg default:
13840b1a6e6Sjoerg if (*p == c)
13940b1a6e6Sjoerg return (match);
14040b1a6e6Sjoerg nextRangeStart = *p; /* Possible start of range. */
14140b1a6e6Sjoerg }
14240b1a6e6Sjoerg rangeStart = nextRangeStart;
14340b1a6e6Sjoerg ++p;
14440b1a6e6Sjoerg }
14540b1a6e6Sjoerg return (nomatch);
14640b1a6e6Sjoerg }
14740b1a6e6Sjoerg
14840b1a6e6Sjoerg /*
14940b1a6e6Sjoerg * If s is pointing to "./", ".//", "./././" or the like, skip it.
15040b1a6e6Sjoerg */
15140b1a6e6Sjoerg static const char *
pm_slashskip(const char * s)15240b1a6e6Sjoerg pm_slashskip(const char *s) {
15340b1a6e6Sjoerg while ((*s == '/')
15440b1a6e6Sjoerg || (s[0] == '.' && s[1] == '/')
15540b1a6e6Sjoerg || (s[0] == '.' && s[1] == '\0'))
15640b1a6e6Sjoerg ++s;
15740b1a6e6Sjoerg return (s);
15840b1a6e6Sjoerg }
15940b1a6e6Sjoerg
16040b1a6e6Sjoerg static const wchar_t *
pm_slashskip_w(const wchar_t * s)16140b1a6e6Sjoerg pm_slashskip_w(const wchar_t *s) {
16240b1a6e6Sjoerg while ((*s == L'/')
16340b1a6e6Sjoerg || (s[0] == L'.' && s[1] == L'/')
16440b1a6e6Sjoerg || (s[0] == L'.' && s[1] == L'\0'))
16540b1a6e6Sjoerg ++s;
16640b1a6e6Sjoerg return (s);
16740b1a6e6Sjoerg }
16840b1a6e6Sjoerg
16940b1a6e6Sjoerg static int
pm(const char * p,const char * s,int flags)17040b1a6e6Sjoerg pm(const char *p, const char *s, int flags)
17140b1a6e6Sjoerg {
17240b1a6e6Sjoerg const char *end;
17340b1a6e6Sjoerg
17440b1a6e6Sjoerg /*
17540b1a6e6Sjoerg * Ignore leading './', './/', '././', etc.
17640b1a6e6Sjoerg */
17740b1a6e6Sjoerg if (s[0] == '.' && s[1] == '/')
17840b1a6e6Sjoerg s = pm_slashskip(s + 1);
17940b1a6e6Sjoerg if (p[0] == '.' && p[1] == '/')
18040b1a6e6Sjoerg p = pm_slashskip(p + 1);
18140b1a6e6Sjoerg
18240b1a6e6Sjoerg for (;;) {
18340b1a6e6Sjoerg switch (*p) {
18440b1a6e6Sjoerg case '\0':
18540b1a6e6Sjoerg if (s[0] == '/') {
18640b1a6e6Sjoerg if (flags & PATHMATCH_NO_ANCHOR_END)
18740b1a6e6Sjoerg return (1);
18840b1a6e6Sjoerg /* "dir" == "dir/" == "dir/." */
18940b1a6e6Sjoerg s = pm_slashskip(s);
19040b1a6e6Sjoerg }
19140b1a6e6Sjoerg return (*s == '\0');
19240b1a6e6Sjoerg case '?':
19340b1a6e6Sjoerg /* ? always succeeds, unless we hit end of 's' */
19440b1a6e6Sjoerg if (*s == '\0')
19540b1a6e6Sjoerg return (0);
19640b1a6e6Sjoerg break;
19740b1a6e6Sjoerg case '*':
19840b1a6e6Sjoerg /* "*" == "**" == "***" ... */
19940b1a6e6Sjoerg while (*p == '*')
20040b1a6e6Sjoerg ++p;
20140b1a6e6Sjoerg /* Trailing '*' always succeeds. */
20240b1a6e6Sjoerg if (*p == '\0')
20340b1a6e6Sjoerg return (1);
20440b1a6e6Sjoerg while (*s) {
20540b1a6e6Sjoerg if (archive_pathmatch(p, s, flags))
20640b1a6e6Sjoerg return (1);
20740b1a6e6Sjoerg ++s;
20840b1a6e6Sjoerg }
20940b1a6e6Sjoerg return (0);
21040b1a6e6Sjoerg case '[':
21140b1a6e6Sjoerg /*
21240b1a6e6Sjoerg * Find the end of the [...] character class,
21340b1a6e6Sjoerg * ignoring \] that might occur within the class.
21440b1a6e6Sjoerg */
21540b1a6e6Sjoerg end = p + 1;
21640b1a6e6Sjoerg while (*end != '\0' && *end != ']') {
21740b1a6e6Sjoerg if (*end == '\\' && end[1] != '\0')
21840b1a6e6Sjoerg ++end;
21940b1a6e6Sjoerg ++end;
22040b1a6e6Sjoerg }
22140b1a6e6Sjoerg if (*end == ']') {
22240b1a6e6Sjoerg /* We found [...], try to match it. */
22340b1a6e6Sjoerg if (!pm_list(p + 1, end, *s, flags))
22440b1a6e6Sjoerg return (0);
22540b1a6e6Sjoerg p = end; /* Jump to trailing ']' char. */
22640b1a6e6Sjoerg break;
22740b1a6e6Sjoerg } else
22840b1a6e6Sjoerg /* No final ']', so just match '['. */
22940b1a6e6Sjoerg if (*p != *s)
23040b1a6e6Sjoerg return (0);
23140b1a6e6Sjoerg break;
23240b1a6e6Sjoerg case '\\':
23340b1a6e6Sjoerg /* Trailing '\\' matches itself. */
23440b1a6e6Sjoerg if (p[1] == '\0') {
23540b1a6e6Sjoerg if (*s != '\\')
23640b1a6e6Sjoerg return (0);
23740b1a6e6Sjoerg } else {
23840b1a6e6Sjoerg ++p;
23940b1a6e6Sjoerg if (*p != *s)
24040b1a6e6Sjoerg return (0);
24140b1a6e6Sjoerg }
24240b1a6e6Sjoerg break;
24340b1a6e6Sjoerg case '/':
24440b1a6e6Sjoerg if (*s != '/' && *s != '\0')
24540b1a6e6Sjoerg return (0);
24640b1a6e6Sjoerg /* Note: pattern "/\./" won't match "/";
24740b1a6e6Sjoerg * pm_slashskip() correctly stops at backslash. */
24840b1a6e6Sjoerg p = pm_slashskip(p);
24940b1a6e6Sjoerg s = pm_slashskip(s);
25040b1a6e6Sjoerg if (*p == '\0' && (flags & PATHMATCH_NO_ANCHOR_END))
25140b1a6e6Sjoerg return (1);
25240b1a6e6Sjoerg --p; /* Counteract the increment below. */
25340b1a6e6Sjoerg --s;
25440b1a6e6Sjoerg break;
25540b1a6e6Sjoerg case '$':
25640b1a6e6Sjoerg /* '$' is special only at end of pattern and only
25740b1a6e6Sjoerg * if PATHMATCH_NO_ANCHOR_END is specified. */
25840b1a6e6Sjoerg if (p[1] == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)){
25940b1a6e6Sjoerg /* "dir" == "dir/" == "dir/." */
26040b1a6e6Sjoerg return (*pm_slashskip(s) == '\0');
26140b1a6e6Sjoerg }
26240b1a6e6Sjoerg /* Otherwise, '$' is not special. */
26340b1a6e6Sjoerg /* FALL THROUGH */
26440b1a6e6Sjoerg default:
26540b1a6e6Sjoerg if (*p != *s)
26640b1a6e6Sjoerg return (0);
26740b1a6e6Sjoerg break;
26840b1a6e6Sjoerg }
26940b1a6e6Sjoerg ++p;
27040b1a6e6Sjoerg ++s;
27140b1a6e6Sjoerg }
27240b1a6e6Sjoerg }
27340b1a6e6Sjoerg
27440b1a6e6Sjoerg static int
pm_w(const wchar_t * p,const wchar_t * s,int flags)27540b1a6e6Sjoerg pm_w(const wchar_t *p, const wchar_t *s, int flags)
27640b1a6e6Sjoerg {
27740b1a6e6Sjoerg const wchar_t *end;
27840b1a6e6Sjoerg
27940b1a6e6Sjoerg /*
28040b1a6e6Sjoerg * Ignore leading './', './/', '././', etc.
28140b1a6e6Sjoerg */
28240b1a6e6Sjoerg if (s[0] == L'.' && s[1] == L'/')
28340b1a6e6Sjoerg s = pm_slashskip_w(s + 1);
28440b1a6e6Sjoerg if (p[0] == L'.' && p[1] == L'/')
28540b1a6e6Sjoerg p = pm_slashskip_w(p + 1);
28640b1a6e6Sjoerg
28740b1a6e6Sjoerg for (;;) {
28840b1a6e6Sjoerg switch (*p) {
28940b1a6e6Sjoerg case L'\0':
29040b1a6e6Sjoerg if (s[0] == L'/') {
29140b1a6e6Sjoerg if (flags & PATHMATCH_NO_ANCHOR_END)
29240b1a6e6Sjoerg return (1);
29340b1a6e6Sjoerg /* "dir" == "dir/" == "dir/." */
29440b1a6e6Sjoerg s = pm_slashskip_w(s);
29540b1a6e6Sjoerg }
29640b1a6e6Sjoerg return (*s == L'\0');
29740b1a6e6Sjoerg case L'?':
29840b1a6e6Sjoerg /* ? always succeeds, unless we hit end of 's' */
29940b1a6e6Sjoerg if (*s == L'\0')
30040b1a6e6Sjoerg return (0);
30140b1a6e6Sjoerg break;
30240b1a6e6Sjoerg case L'*':
30340b1a6e6Sjoerg /* "*" == "**" == "***" ... */
30440b1a6e6Sjoerg while (*p == L'*')
30540b1a6e6Sjoerg ++p;
30640b1a6e6Sjoerg /* Trailing '*' always succeeds. */
30740b1a6e6Sjoerg if (*p == L'\0')
30840b1a6e6Sjoerg return (1);
30940b1a6e6Sjoerg while (*s) {
31040b1a6e6Sjoerg if (archive_pathmatch_w(p, s, flags))
31140b1a6e6Sjoerg return (1);
31240b1a6e6Sjoerg ++s;
31340b1a6e6Sjoerg }
31440b1a6e6Sjoerg return (0);
31540b1a6e6Sjoerg case L'[':
31640b1a6e6Sjoerg /*
31740b1a6e6Sjoerg * Find the end of the [...] character class,
31840b1a6e6Sjoerg * ignoring \] that might occur within the class.
31940b1a6e6Sjoerg */
32040b1a6e6Sjoerg end = p + 1;
32140b1a6e6Sjoerg while (*end != L'\0' && *end != L']') {
32240b1a6e6Sjoerg if (*end == L'\\' && end[1] != L'\0')
32340b1a6e6Sjoerg ++end;
32440b1a6e6Sjoerg ++end;
32540b1a6e6Sjoerg }
32640b1a6e6Sjoerg if (*end == L']') {
32740b1a6e6Sjoerg /* We found [...], try to match it. */
32840b1a6e6Sjoerg if (!pm_list_w(p + 1, end, *s, flags))
32940b1a6e6Sjoerg return (0);
33040b1a6e6Sjoerg p = end; /* Jump to trailing ']' char. */
33140b1a6e6Sjoerg break;
33240b1a6e6Sjoerg } else
33340b1a6e6Sjoerg /* No final ']', so just match '['. */
33440b1a6e6Sjoerg if (*p != *s)
33540b1a6e6Sjoerg return (0);
33640b1a6e6Sjoerg break;
33740b1a6e6Sjoerg case L'\\':
33840b1a6e6Sjoerg /* Trailing '\\' matches itself. */
33940b1a6e6Sjoerg if (p[1] == L'\0') {
34040b1a6e6Sjoerg if (*s != L'\\')
34140b1a6e6Sjoerg return (0);
34240b1a6e6Sjoerg } else {
34340b1a6e6Sjoerg ++p;
34440b1a6e6Sjoerg if (*p != *s)
34540b1a6e6Sjoerg return (0);
34640b1a6e6Sjoerg }
34740b1a6e6Sjoerg break;
34840b1a6e6Sjoerg case L'/':
34940b1a6e6Sjoerg if (*s != L'/' && *s != L'\0')
35040b1a6e6Sjoerg return (0);
35140b1a6e6Sjoerg /* Note: pattern "/\./" won't match "/";
35240b1a6e6Sjoerg * pm_slashskip() correctly stops at backslash. */
35340b1a6e6Sjoerg p = pm_slashskip_w(p);
35440b1a6e6Sjoerg s = pm_slashskip_w(s);
35540b1a6e6Sjoerg if (*p == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END))
35640b1a6e6Sjoerg return (1);
35740b1a6e6Sjoerg --p; /* Counteract the increment below. */
35840b1a6e6Sjoerg --s;
35940b1a6e6Sjoerg break;
36040b1a6e6Sjoerg case L'$':
36140b1a6e6Sjoerg /* '$' is special only at end of pattern and only
36240b1a6e6Sjoerg * if PATHMATCH_NO_ANCHOR_END is specified. */
36340b1a6e6Sjoerg if (p[1] == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END)){
36440b1a6e6Sjoerg /* "dir" == "dir/" == "dir/." */
36540b1a6e6Sjoerg return (*pm_slashskip_w(s) == L'\0');
36640b1a6e6Sjoerg }
36740b1a6e6Sjoerg /* Otherwise, '$' is not special. */
36840b1a6e6Sjoerg /* FALL THROUGH */
36940b1a6e6Sjoerg default:
37040b1a6e6Sjoerg if (*p != *s)
37140b1a6e6Sjoerg return (0);
37240b1a6e6Sjoerg break;
37340b1a6e6Sjoerg }
37440b1a6e6Sjoerg ++p;
37540b1a6e6Sjoerg ++s;
37640b1a6e6Sjoerg }
37740b1a6e6Sjoerg }
37840b1a6e6Sjoerg
37940b1a6e6Sjoerg /* Main entry point. */
38040b1a6e6Sjoerg int
__archive_pathmatch(const char * p,const char * s,int flags)38140b1a6e6Sjoerg __archive_pathmatch(const char *p, const char *s, int flags)
38240b1a6e6Sjoerg {
38340b1a6e6Sjoerg /* Empty pattern only matches the empty string. */
38440b1a6e6Sjoerg if (p == NULL || *p == '\0')
38540b1a6e6Sjoerg return (s == NULL || *s == '\0');
386*65e637abSchristos else if (s == NULL)
387*65e637abSchristos return (0);
38840b1a6e6Sjoerg
38940b1a6e6Sjoerg /* Leading '^' anchors the start of the pattern. */
39040b1a6e6Sjoerg if (*p == '^') {
39140b1a6e6Sjoerg ++p;
39240b1a6e6Sjoerg flags &= ~PATHMATCH_NO_ANCHOR_START;
39340b1a6e6Sjoerg }
39440b1a6e6Sjoerg
39540b1a6e6Sjoerg if (*p == '/' && *s != '/')
39640b1a6e6Sjoerg return (0);
39740b1a6e6Sjoerg
39840b1a6e6Sjoerg /* Certain patterns anchor implicitly. */
39940b1a6e6Sjoerg if (*p == '*' || *p == '/') {
40040b1a6e6Sjoerg while (*p == '/')
40140b1a6e6Sjoerg ++p;
40240b1a6e6Sjoerg while (*s == '/')
40340b1a6e6Sjoerg ++s;
40440b1a6e6Sjoerg return (pm(p, s, flags));
40540b1a6e6Sjoerg }
40640b1a6e6Sjoerg
40740b1a6e6Sjoerg /* If start is unanchored, try to match start of each path element. */
40840b1a6e6Sjoerg if (flags & PATHMATCH_NO_ANCHOR_START) {
40940b1a6e6Sjoerg for ( ; s != NULL; s = strchr(s, '/')) {
41040b1a6e6Sjoerg if (*s == '/')
41140b1a6e6Sjoerg s++;
41240b1a6e6Sjoerg if (pm(p, s, flags))
41340b1a6e6Sjoerg return (1);
41440b1a6e6Sjoerg }
41540b1a6e6Sjoerg return (0);
41640b1a6e6Sjoerg }
41740b1a6e6Sjoerg
41840b1a6e6Sjoerg /* Default: Match from beginning. */
41940b1a6e6Sjoerg return (pm(p, s, flags));
42040b1a6e6Sjoerg }
42140b1a6e6Sjoerg
42240b1a6e6Sjoerg int
__archive_pathmatch_w(const wchar_t * p,const wchar_t * s,int flags)42340b1a6e6Sjoerg __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)
42440b1a6e6Sjoerg {
42540b1a6e6Sjoerg /* Empty pattern only matches the empty string. */
42640b1a6e6Sjoerg if (p == NULL || *p == L'\0')
42740b1a6e6Sjoerg return (s == NULL || *s == L'\0');
428*65e637abSchristos else if (s == NULL)
429*65e637abSchristos return (0);
43040b1a6e6Sjoerg
43140b1a6e6Sjoerg /* Leading '^' anchors the start of the pattern. */
43240b1a6e6Sjoerg if (*p == L'^') {
43340b1a6e6Sjoerg ++p;
43440b1a6e6Sjoerg flags &= ~PATHMATCH_NO_ANCHOR_START;
43540b1a6e6Sjoerg }
43640b1a6e6Sjoerg
43740b1a6e6Sjoerg if (*p == L'/' && *s != L'/')
43840b1a6e6Sjoerg return (0);
43940b1a6e6Sjoerg
44040b1a6e6Sjoerg /* Certain patterns anchor implicitly. */
44140b1a6e6Sjoerg if (*p == L'*' || *p == L'/') {
44240b1a6e6Sjoerg while (*p == L'/')
44340b1a6e6Sjoerg ++p;
44440b1a6e6Sjoerg while (*s == L'/')
44540b1a6e6Sjoerg ++s;
44640b1a6e6Sjoerg return (pm_w(p, s, flags));
44740b1a6e6Sjoerg }
44840b1a6e6Sjoerg
44940b1a6e6Sjoerg /* If start is unanchored, try to match start of each path element. */
45040b1a6e6Sjoerg if (flags & PATHMATCH_NO_ANCHOR_START) {
45140b1a6e6Sjoerg for ( ; s != NULL; s = wcschr(s, L'/')) {
45240b1a6e6Sjoerg if (*s == L'/')
45340b1a6e6Sjoerg s++;
45440b1a6e6Sjoerg if (pm_w(p, s, flags))
45540b1a6e6Sjoerg return (1);
45640b1a6e6Sjoerg }
45740b1a6e6Sjoerg return (0);
45840b1a6e6Sjoerg }
45940b1a6e6Sjoerg
46040b1a6e6Sjoerg /* Default: Match from beginning. */
46140b1a6e6Sjoerg return (pm_w(p, s, flags));
46240b1a6e6Sjoerg }
463