From 7cf15465b1faf38010f63ba65f2647aeb8e9435b Mon Sep 17 00:00:00 2001 From: Alex Aizman Date: Mon, 30 Sep 2024 17:43:22 -0400 Subject: [PATCH] trim prefix: list-objects; bucket-summary; multi-obj operations * rtrim(prefix, '*') to satisfy one common expectation * proxy only; leaving rest of the code and CLI intact Signed-off-by: Alex Aizman --- ais/proxy.go | 5 +++++ cmn/cos/strings.go | 11 +++++++++++ cmn/cos/template.go | 2 +- cmn/objlist_utils.go | 6 ++++-- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/ais/proxy.go b/ais/proxy.go index 4b1e1f2bdb..865f32fbbd 100644 --- a/ais/proxy.go +++ b/ais/proxy.go @@ -632,6 +632,7 @@ func (p *proxy) httpbckget(w http.ResponseWriter, r *http.Request, dpq *dpq) { p.writeErrf(w, r, cmn.FmtErrMorphUnmarshal, p.si, msg.Action, msg.Value, err) return } + summMsg.Prefix = cos.TrimPrefix(summMsg.Prefix) if qbck.IsBucket() { bck := (*meta.Bck)(qbck) bckArgs := bctx{p: p, w: w, r: r, msg: msg, perms: apc.AceBckHEAD, bck: bck, dpq: dpq} @@ -685,6 +686,7 @@ func (p *proxy) httpbckget(w http.ResponseWriter, r *http.Request, dpq *dpq) { p.writeErrf(w, r, cmn.FmtErrMorphUnmarshal, p.si, msg.Action, msg.Value, err) return } + lsmsg.Prefix = cos.TrimPrefix(lsmsg.Prefix) if err := cmn.ValidatePrefix("bad list-objects request", lsmsg.Prefix); err != nil { p.statsT.IncErr(stats.ErrListCount) p.writeErr(w, r, err) @@ -1348,6 +1350,7 @@ func (p *proxy) _bckpost(w http.ResponseWriter, r *http.Request, msg *apc.ActMsg p.writeErr(w, r, err) return } + tcbmsg.Prefix = cos.TrimPrefix(tcbmsg.Prefix) if bckFrom.Equal(bckTo, true, true) { if !bckFrom.IsRemote() { p.writeErrf(w, r, "cannot %s bucket %q onto itself", msg.Action, bckFrom) @@ -1408,6 +1411,7 @@ func (p *proxy) _bckpost(w http.ResponseWriter, r *http.Request, msg *apc.ActMsg p.writeErrf(w, r, errPrependSync, tcomsg.Prepend) return } + tcomsg.Prefix = cos.TrimPrefix(tcomsg.Prefix) bckTo = meta.CloneBck(&tcomsg.ToBck) if bck.Equal(bckTo, true, true) { @@ -1932,6 +1936,7 @@ func (p *proxy) httpbckhead(w http.ResponseWriter, r *http.Request, apireq *apiR for _, s := range items[2:] { prefix += "/" + s } + prefix = cos.TrimPrefix(prefix) apireq.after = 2 } } diff --git a/cmn/cos/strings.go b/cmn/cos/strings.go index b56fb81d02..d96a410797 100644 --- a/cmn/cos/strings.go +++ b/cmn/cos/strings.go @@ -36,6 +36,17 @@ func TrimLastB(s string, b byte) string { return s } +// [NOTE] common *nix expectation in re: `ls aaa/bbb*` and similar +// - `?` not supported +// - `\*` not supported +// see also: cmn.ObjHasPrefix and friends +func TrimPrefix(s string) string { + if l := len(s); l > 0 && s[l-1] == WildcardMatchAll[0] { + return s[:l-1] + } + return s +} + // left if non-empty; otherwise right func Left(left, right string) string { if left != "" { diff --git a/cmn/cos/template.go b/cmn/cos/template.go index f634ccf20c..4ce8626ed7 100644 --- a/cmn/cos/template.go +++ b/cmn/cos/template.go @@ -102,7 +102,7 @@ func NewParsedTemplate(template string) (parsed ParsedTemplate, err error) { } // "pure" prefix w/ no ranges - return ParsedTemplate{Prefix: template}, nil + return ParsedTemplate{Prefix: TrimPrefix(template)}, nil } func (pt *ParsedTemplate) Clone() *ParsedTemplate { diff --git a/cmn/objlist_utils.go b/cmn/objlist_utils.go index d03b813b03..8e6b1f474e 100644 --- a/cmn/objlist_utils.go +++ b/cmn/objlist_utils.go @@ -219,14 +219,16 @@ func MergeLso(lists []*LsoRes, lsmsg *apc.LsoMsg, maxSize int) *LsoRes { // already listed and must be skipped). Note that string `>=` is lexicographic. func TokenGreaterEQ(token, objName string) bool { return token >= objName } -// Directory has to either: +// directory has to either: // - include (or match) prefix, or // - be contained in prefix - motivation: don't SkipDir a/b when looking for a/b/c -// An alternative name for this function could be smth. like SameBranch() +// an alternative name for this function could be smth. like SameBranch() +// see also: cos.TrimPrefix func DirHasOrIsPrefix(dirPath, prefix string) bool { return prefix == "" || (strings.HasPrefix(prefix, dirPath) || strings.HasPrefix(dirPath, prefix)) } +// see also: cos.TrimPrefix func ObjHasPrefix(objName, prefix string) bool { return prefix == "" || strings.HasPrefix(objName, prefix) }