@@ -14,14 +14,14 @@ import (
1414 "fmt"
1515 "io"
1616 "net/http"
17- "regexp"
1817 "slices"
1918 "sort"
2019 "strconv"
2120 "strings"
2221 "time"
2322
2423 "cloud.google.com/go/storage"
24+ "github.com/bmatcuk/doublestar/v4"
2525 "github.com/fsouza/fake-gcs-server/internal/backend"
2626 "github.com/fsouza/fake-gcs-server/internal/notification"
2727 "github.com/fsouza/fake-gcs-server/internal/urlhelper"
@@ -405,7 +405,7 @@ func (s *Server) ListObjectsWithOptionsPaginated(bucketName string, options List
405405 continue
406406 }
407407
408- if options .MatchGlob != "" && ! matchGlob (options .MatchGlob , obj .Name ) {
408+ if options .MatchGlob != "" && ! doublestar . MatchUnvalidated (options .MatchGlob , obj .Name ) {
409409 continue
410410 }
411411
@@ -1462,120 +1462,3 @@ func (s *Server) composeObject(r *http.Request) jsonResponse {
14621462
14631463 return jsonResponse {data : newObjectResponse (obj .ObjectAttrs , urlhelper .GetBaseURL (r ))}
14641464}
1465-
1466- // matchGlob matches a glob pattern against a string following GCS glob syntax.
1467- // See https://cloud.google.com/storage/docs/json_api/v1/objects/list#list-object-glob
1468- // Supports:
1469- // - * matches zero or more characters (excluding /)
1470- // - ** matches zero or more characters (including /)
1471- // - ? matches any single character (excluding /)
1472- // - [abc] matches exactly one character in the set
1473- // - [a-z] matches one character in a range
1474- // - [!abc] or [^abc] matches one character NOT in the set
1475- // - {abc,xyz} matches one of the specified options
1476- // Doesn't currently support:
1477- // - nested {} braces
1478- // - patterns inside {} braces e.g. {*foo,bar*}
1479- func matchGlob (pattern , name string ) bool {
1480- regex := globToRegex (pattern )
1481- matched , err := regexp .MatchString (regex , name )
1482- if err != nil {
1483- return false
1484- }
1485- return matched
1486- }
1487-
1488- func globToRegex (pattern string ) string {
1489- var result strings.Builder
1490- result .WriteString ("^" )
1491-
1492- i := 0
1493- for i < len (pattern ) {
1494- switch pattern [i ] {
1495- case '*' :
1496- if i + 1 < len (pattern ) && pattern [i + 1 ] == '*' {
1497- // ** matches zero or more characters including /
1498- result .WriteString (".*" )
1499- i += 2
1500- } else {
1501- // * matches zero or more characters excluding /
1502- result .WriteString ("[^/]*" )
1503- i ++
1504- }
1505- case '?' :
1506- // ? matches any single character excluding /
1507- result .WriteString ("[^/]" )
1508- i ++
1509- case '[' :
1510- // Character class [abc] or [a-z] or [!abc] or [^abc]
1511- j := i + 1
1512- if j < len (pattern ) && (pattern [j ] == '!' || pattern [j ] == '^' ) {
1513- j ++
1514- }
1515- for j < len (pattern ) && pattern [j ] != ']' {
1516- j ++
1517- }
1518- if j < len (pattern ) {
1519- // Valid character class
1520- charClass := pattern [i : j + 1 ]
1521- // Convert [!...] to [^...] for regex
1522- if strings .HasPrefix (charClass , "[!" ) {
1523- charClass = "[^" + charClass [2 :]
1524- }
1525- result .WriteString (charClass )
1526- i = j + 1
1527- } else {
1528- // Invalid character class, treat as literal
1529- result .WriteString (regexp .QuoteMeta (string (pattern [i ])))
1530- i ++
1531- }
1532- case '{' :
1533- // Brace expansion {abc,xyz}
1534- j := i + 1
1535- depth := 1
1536- for j < len (pattern ) && depth > 0 {
1537- switch pattern [j ] {
1538- case '{' :
1539- depth ++
1540- case '}' :
1541- depth --
1542- }
1543- j ++
1544- }
1545- if depth == 0 {
1546- // Valid brace expansion
1547- braceContent := pattern [i + 1 : j - 1 ]
1548- options := strings .Split (braceContent , "," )
1549- result .WriteString ("(" )
1550- for k , option := range options {
1551- if k > 0 {
1552- result .WriteString ("|" )
1553- }
1554- result .WriteString (regexp .QuoteMeta (option ))
1555- }
1556- result .WriteString (")" )
1557- i = j
1558- } else {
1559- // Invalid brace expansion, treat as literal
1560- result .WriteString (regexp .QuoteMeta (string (pattern [i ])))
1561- i ++
1562- }
1563- case '\\' :
1564- // Escape character
1565- if i + 1 < len (pattern ) {
1566- result .WriteString (regexp .QuoteMeta (string (pattern [i + 1 ])))
1567- i += 2
1568- } else {
1569- result .WriteString (regexp .QuoteMeta (string (pattern [i ])))
1570- i ++
1571- }
1572- default :
1573- // Regular character, escape for regex
1574- result .WriteString (regexp .QuoteMeta (string (pattern [i ])))
1575- i ++
1576- }
1577- }
1578-
1579- result .WriteString ("$" )
1580- return result .String ()
1581- }
0 commit comments