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  }