|
15 | 15 | package types |
16 | 16 |
|
17 | 17 | import ( |
18 | | - "github.com/coreos/ignition/v2/config/shared/errors" |
19 | | - "github.com/coreos/ignition/v2/config/util" |
| 18 | + "path/filepath" |
| 19 | + "sort" |
| 20 | + "strings" |
20 | 21 |
|
21 | 22 | "github.com/coreos/go-semver/semver" |
| 23 | + "github.com/coreos/ignition/v2/config/shared/errors" |
| 24 | + "github.com/coreos/ignition/v2/config/util" |
22 | 25 | "github.com/coreos/vcontext/path" |
23 | 26 | "github.com/coreos/vcontext/report" |
24 | 27 | ) |
|
30 | 33 | } |
31 | 34 | ) |
32 | 35 |
|
| 36 | +type pathEntry struct { |
| 37 | + Path string |
| 38 | + Type string |
| 39 | +} |
| 40 | + |
33 | 41 | func (cfg Config) Validate(c path.ContextPath) (r report.Report) { |
34 | 42 | systemdPath := "/etc/systemd/system/" |
35 | 43 | unitPaths := map[string]struct{}{} |
@@ -60,5 +68,69 @@ func (cfg Config) Validate(c path.ContextPath) (r report.Report) { |
60 | 68 | r.AddOnError(c.Append("storage", "links", i, "path"), errors.ErrPathConflictsSystemd) |
61 | 69 | } |
62 | 70 | } |
63 | | - return |
| 71 | + |
| 72 | + entries, r := cfg.validateParents(c) |
| 73 | + for i, entry := range entries { |
| 74 | + if i > 0 && isWithin(entry.Path, entries[i-1].Path) { |
| 75 | + if entries[i-1].Type == "directory" { |
| 76 | + r.AddOnError(c.Append("storage", "directories", i, "path"), errors.ErrPathConflictsParentDir) |
| 77 | + return r |
| 78 | + } |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + return r |
| 83 | +} |
| 84 | + |
| 85 | +func (cfg Config) validateParents(c path.ContextPath) ([]pathEntry, report.Report) { |
| 86 | + paths := map[string]struct{}{} |
| 87 | + entries := []pathEntry{} |
| 88 | + r := report.Report{} |
| 89 | + |
| 90 | + for i, f := range cfg.Storage.Files { |
| 91 | + if _, exists := paths[f.Path]; exists { |
| 92 | + r.AddOnError(c.Append("storage", "files", i, "path"), errors.ErrPathConflictsParentDir) //TODO: should add different error? |
| 93 | + return nil, r |
| 94 | + } |
| 95 | + paths[f.Path] = struct{}{} |
| 96 | + entries = append(entries, pathEntry{Path: f.Path, Type: "file"}) |
| 97 | + } |
| 98 | + |
| 99 | + for i, d := range cfg.Storage.Directories { |
| 100 | + if _, exists := paths[d.Path]; exists { |
| 101 | + r.AddOnError(c.Append("storage", "directories", i, "path"), errors.ErrPathConflictsParentDir) //TODO: should add different error? |
| 102 | + return nil, r |
| 103 | + } |
| 104 | + paths[d.Path] = struct{}{} |
| 105 | + entries = append(entries, pathEntry{Path: d.Path, Type: "directory"}) |
| 106 | + } |
| 107 | + |
| 108 | + for i, l := range cfg.Storage.Links { |
| 109 | + if _, exists := paths[l.Path]; exists { |
| 110 | + r.AddOnError(c.Append("storage", "links", i, "path"), errors.ErrPathConflictsParentDir) //TODO: should add different error? |
| 111 | + return nil, r |
| 112 | + } |
| 113 | + paths[l.Path] = struct{}{} |
| 114 | + entries = append(entries, pathEntry{Path: l.Path, Type: "link"}) |
| 115 | + } |
| 116 | + |
| 117 | + sort.Slice(entries, func(i, j int) bool { |
| 118 | + return depth(entries[i].Path) < depth(entries[j].Path) |
| 119 | + }) |
| 120 | + |
| 121 | + return entries, r |
| 122 | +} |
| 123 | + |
| 124 | +// check the depth |
| 125 | +func depth(path string) uint { |
| 126 | + var count uint |
| 127 | + for p := filepath.Clean(path); p != "/" && p != "."; count++ { |
| 128 | + p = filepath.Dir(p) |
| 129 | + } |
| 130 | + return count |
| 131 | +} |
| 132 | + |
| 133 | +// isWithin checks if newPath is within prevPath. |
| 134 | +func isWithin(newPath, prevPath string) bool { |
| 135 | + return strings.HasPrefix(newPath, prevPath) && newPath != prevPath |
64 | 136 | } |
0 commit comments