github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/filesystem/mode.go (about) 1 package filesystem 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 ) 8 9 const ( 10 // ModePermissionsMask is a bit mask that isolates portable permission bits. 11 ModePermissionsMask = Mode(0777) 12 13 // ModePermissionUserRead is the user readable bit. 14 ModePermissionUserRead = Mode(0400) 15 // ModePermissionUserWrite is the user writable bit. 16 ModePermissionUserWrite = Mode(0200) 17 // ModePermissionUserExecute is the user executable bit. 18 ModePermissionUserExecute = Mode(0100) 19 // ModePermissionGroupRead is the group readable bit. 20 ModePermissionGroupRead = Mode(0040) 21 // ModePermissionGroupWrite is the group writable bit. 22 ModePermissionGroupWrite = Mode(0020) 23 // ModePermissionGroupExecute is the group executable bit. 24 ModePermissionGroupExecute = Mode(0010) 25 // ModePermissionOthersRead is the others readable bit. 26 ModePermissionOthersRead = Mode(0004) 27 // ModePermissionOthersWrite is the others writable bit. 28 ModePermissionOthersWrite = Mode(0002) 29 // ModePermissionOthersExecute is the others executable bit. 30 ModePermissionOthersExecute = Mode(0001) 31 ) 32 33 // parseMode parses a user-specified octal string and verifies that it is 34 // limited to the bits specified in mask. It allows, but does not require, the 35 // string to begin with a 0 (or several 0s). The provided string must not be 36 // empty. 37 func parseMode(value string, mask Mode) (Mode, error) { 38 if m, err := strconv.ParseUint(value, 8, 32); err != nil { 39 return 0, fmt.Errorf("unable to parse numeric value: %w", err) 40 } else if mode := Mode(m); mode&mask != mode { 41 return 0, errors.New("mode contains disallowed bits") 42 } else { 43 return mode, nil 44 } 45 } 46 47 // MarshalText implements encoding.TextMarshaler.MarshalText. 48 func (m Mode) MarshalText() ([]byte, error) { 49 result := "0" + strconv.FormatUint(uint64(m), 8) 50 return []byte(result), nil 51 } 52 53 // UnmarshalText implements encoding.TextUnmarshaler.UnmarshalText. It requires 54 // that the specified mode bits lie within ModePermissionsMask, otherwise an 55 // error is returned. If an error is returned, the mode is unmodified. 56 func (m *Mode) UnmarshalText(textBytes []byte) error { 57 // Convert the bytes to a string. 58 text := string(textBytes) 59 60 // Perform parsing. We only allow the mode itself to be modified if parsing 61 // is successful. 62 if result, err := parseMode(text, ModePermissionsMask); err != nil { 63 return err 64 } else { 65 *m = result 66 } 67 68 // Success. 69 return nil 70 }