aboutsummaryrefslogtreecommitdiff
path: root/object/tree/mode/parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'object/tree/mode/parse.go')
-rw-r--r--object/tree/mode/parse.go43
1 files changed, 43 insertions, 0 deletions
diff --git a/object/tree/mode/parse.go b/object/tree/mode/parse.go
new file mode 100644
index 00000000..7839a89a
--- /dev/null
+++ b/object/tree/mode/parse.go
@@ -0,0 +1,43 @@
+package mode
+
+import (
+ "errors"
+ "fmt"
+)
+
+// ErrInvalidMode indicates a malformed or unsupported tree entry mode.
+var ErrInvalidMode = errors.New("object/tree/mode: invalid mode")
+
+// Parse decodes a canonical octal tree entry mode.
+//
+// It accepts only the modes Git itself writes
+// and rejects malformed, unsupported, and zero-padded encodings.
+func Parse(raw []byte) (Mode, error) {
+ if len(raw) == 0 {
+ return 0, fmt.Errorf("%w: empty mode", ErrInvalidMode)
+ }
+
+ if raw[0] == '0' {
+ return 0, fmt.Errorf("%w: zero-padded mode %q", ErrInvalidMode, raw)
+ }
+
+ if len(raw) > maxModeDigits {
+ return 0, fmt.Errorf("%w: mode %q too long", ErrInvalidMode, raw)
+ }
+
+ var mode Mode
+
+ for _, c := range raw {
+ if c < '0' || c > '7' {
+ return 0, fmt.Errorf("%w: non-octal byte in mode %q", ErrInvalidMode, raw)
+ }
+
+ mode = mode<<3 | Mode(c-'0')
+ }
+
+ if !mode.IsValid() {
+ return 0, fmt.Errorf("%w: unsupported mode %q", ErrInvalidMode, raw)
+ }
+
+ return mode, nil
+}