|
|
@@ -14,7 +14,7 @@ type DatasetMapFilter struct {
|
|
|
|
|
|
|
|
|
|
|
|
// if set, only valid filter entries can be added using Add()
|
|
|
|
// if set, only valid filter entries can be added using Add()
|
|
|
|
// and Map() will always return an error
|
|
|
|
// and Map() will always return an error
|
|
|
|
filterOnly bool
|
|
|
|
filterMode bool
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type datasetMapFilterEntry struct {
|
|
|
|
type datasetMapFilterEntry struct {
|
|
|
@@ -25,17 +25,17 @@ type datasetMapFilterEntry struct {
|
|
|
|
subtreeMatch bool
|
|
|
|
subtreeMatch bool
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func NewDatasetMapFilter(capacity int, filterOnly bool) *DatasetMapFilter {
|
|
|
|
func NewDatasetMapFilter(capacity int, filterMode bool) *DatasetMapFilter {
|
|
|
|
return &DatasetMapFilter{
|
|
|
|
return &DatasetMapFilter{
|
|
|
|
entries: make([]datasetMapFilterEntry, 0, capacity),
|
|
|
|
entries: make([]datasetMapFilterEntry, 0, capacity),
|
|
|
|
filterOnly: filterOnly,
|
|
|
|
filterMode: filterMode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *DatasetMapFilter) Add(pathPattern, mapping string) (err error) {
|
|
|
|
func (m *DatasetMapFilter) Add(pathPattern, mapping string) (err error) {
|
|
|
|
|
|
|
|
|
|
|
|
if m.filterOnly {
|
|
|
|
if m.filterMode {
|
|
|
|
if _, err = parseDatasetFilterResult(mapping); err != nil {
|
|
|
|
if _, err = m.parseDatasetFilterResult(mapping); err != nil {
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@@ -103,7 +103,7 @@ func (m DatasetMapFilter) mostSpecificPrefixMapping(path *zfs.DatasetPath) (idx
|
|
|
|
|
|
|
|
|
|
|
|
func (m DatasetMapFilter) Map(source *zfs.DatasetPath) (target *zfs.DatasetPath, err error) {
|
|
|
|
func (m DatasetMapFilter) Map(source *zfs.DatasetPath) (target *zfs.DatasetPath, err error) {
|
|
|
|
|
|
|
|
|
|
|
|
if m.filterOnly {
|
|
|
|
if m.filterMode {
|
|
|
|
err = fmt.Errorf("using a filter for mapping simply does not work")
|
|
|
|
err = fmt.Errorf("using a filter for mapping simply does not work")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
@@ -115,6 +115,11 @@ func (m DatasetMapFilter) Map(source *zfs.DatasetPath) (target *zfs.DatasetPath,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
me := m.entries[mi]
|
|
|
|
me := m.entries[mi]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if strings.HasPrefix("!", me.mapping) {
|
|
|
|
|
|
|
|
// reject mapping
|
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
target, err = zfs.NewDatasetPath(me.mapping)
|
|
|
|
target, err = zfs.NewDatasetPath(me.mapping)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("mapping target is not a dataset path: %s", err)
|
|
|
|
err = fmt.Errorf("mapping target is not a dataset path: %s", err)
|
|
|
@@ -135,13 +140,19 @@ func (m DatasetMapFilter) Map(source *zfs.DatasetPath) (target *zfs.DatasetPath,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m DatasetMapFilter) Filter(p *zfs.DatasetPath) (pass bool, err error) {
|
|
|
|
func (m DatasetMapFilter) Filter(p *zfs.DatasetPath) (pass bool, err error) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if !m.filterMode {
|
|
|
|
|
|
|
|
err = fmt.Errorf("using a mapping as a filter does not work")
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mi, hasMapping := m.mostSpecificPrefixMapping(p)
|
|
|
|
mi, hasMapping := m.mostSpecificPrefixMapping(p)
|
|
|
|
if !hasMapping {
|
|
|
|
if !hasMapping {
|
|
|
|
pass = false
|
|
|
|
pass = false
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
me := m.entries[mi]
|
|
|
|
me := m.entries[mi]
|
|
|
|
pass, err = parseDatasetFilterResult(me.mapping)
|
|
|
|
pass, err = m.parseDatasetFilterResult(me.mapping)
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@@ -149,7 +160,7 @@ func (m DatasetMapFilter) Filter(p *zfs.DatasetPath) (pass bool, err error) {
|
|
|
|
// The new filter allows excactly those paths that were not forbidden by the mapping.
|
|
|
|
// The new filter allows excactly those paths that were not forbidden by the mapping.
|
|
|
|
func (m DatasetMapFilter) InvertedFilter() (inv *DatasetMapFilter, err error) {
|
|
|
|
func (m DatasetMapFilter) InvertedFilter() (inv *DatasetMapFilter, err error) {
|
|
|
|
|
|
|
|
|
|
|
|
if m.filterOnly {
|
|
|
|
if m.filterMode {
|
|
|
|
err = errors.Errorf("can only invert mappings")
|
|
|
|
err = errors.Errorf("can only invert mappings")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
@@ -172,28 +183,47 @@ func (m DatasetMapFilter) InvertedFilter() (inv *DatasetMapFilter, err error) {
|
|
|
|
return inv, nil
|
|
|
|
return inv, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Creates a new DatasetMapFilter in filter mode from a mapping
|
|
|
|
|
|
|
|
// All accepting mapping results are mapped to accepting filter results
|
|
|
|
|
|
|
|
// All rejecting mapping results are mapped to rejecting filter results
|
|
|
|
|
|
|
|
func (m DatasetMapFilter) AsFilter() (f *DatasetMapFilter) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
f = &DatasetMapFilter{
|
|
|
|
|
|
|
|
make([]datasetMapFilterEntry, len(m.entries)),
|
|
|
|
|
|
|
|
true,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for i, e := range m.entries {
|
|
|
|
|
|
|
|
var newe datasetMapFilterEntry = e
|
|
|
|
|
|
|
|
if strings.HasPrefix(newe.mapping, "!") {
|
|
|
|
|
|
|
|
newe.mapping = MapFilterResultOmit
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
newe.mapping = MapFilterResultOk
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
f.entries[i] = newe
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return f
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
const (
|
|
|
|
MapFilterResultOk string = "ok"
|
|
|
|
MapFilterResultOk string = "ok"
|
|
|
|
MapFilterResultOmit string = "omit"
|
|
|
|
MapFilterResultOmit string = "!"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// Parse a dataset filter result
|
|
|
|
// Parse a dataset filter result
|
|
|
|
func parseDatasetFilterResult(result string) (pass bool, err error) {
|
|
|
|
func (m DatasetMapFilter) parseDatasetFilterResult(result string) (pass bool, err error) {
|
|
|
|
l := strings.ToLower(result)
|
|
|
|
l := strings.ToLower(result)
|
|
|
|
switch strings.ToLower(l) {
|
|
|
|
if l == MapFilterResultOk {
|
|
|
|
case MapFilterResultOk:
|
|
|
|
return true, nil
|
|
|
|
pass = true
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
case MapFilterResultOmit:
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
err = fmt.Errorf("'%s' is not a valid filter result", result)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
if l == MapFilterResultOmit {
|
|
|
|
|
|
|
|
return false, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, fmt.Errorf("'%s' is not a valid filter result", result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func parseDatasetMapFilter(mi interface{}, filterOnly bool) (f *DatasetMapFilter, err error) {
|
|
|
|
func parseDatasetMapFilter(mi interface{}, filterMode bool) (f *DatasetMapFilter, err error) {
|
|
|
|
|
|
|
|
|
|
|
|
var m map[string]string
|
|
|
|
var m map[string]string
|
|
|
|
if err = mapstructure.Decode(mi, &m); err != nil {
|
|
|
|
if err = mapstructure.Decode(mi, &m); err != nil {
|
|
|
@@ -201,7 +231,7 @@ func parseDatasetMapFilter(mi interface{}, filterOnly bool) (f *DatasetMapFilter
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
f = NewDatasetMapFilter(len(m), filterOnly)
|
|
|
|
f = NewDatasetMapFilter(len(m), filterMode)
|
|
|
|
for pathPattern, mapping := range m {
|
|
|
|
for pathPattern, mapping := range m {
|
|
|
|
if err = f.Add(pathPattern, mapping); err != nil {
|
|
|
|
if err = f.Add(pathPattern, mapping); err != nil {
|
|
|
|
err = fmt.Errorf("invalid mapping entry ['%s':'%s']: %s", pathPattern, mapping, err)
|
|
|
|
err = fmt.Errorf("invalid mapping entry ['%s':'%s']: %s", pathPattern, mapping, err)
|
|
|
|