aminal/hints/perms.go

161 lines
2.5 KiB
Go

package hints
import (
"fmt"
"regexp"
"strings"
)
type fileType uint8
const (
file fileType = iota
directory
characterSpecialFile
)
type perms struct {
Type fileType
Owner access
Group access
World access
SetUID bool
SetGID bool
Sticky bool
}
type accessType uint8
const (
owner accessType = iota
group
world
)
type access struct {
Type accessType
Read bool
Write bool
Execute bool
}
func (p perms) Numeric() string {
return p.Owner.Numeric() + p.Group.Numeric() + p.World.Numeric()
}
func (a access) Nice() string {
all := []string{}
if a.Read {
all = append(all, "read")
}
if a.Write {
all = append(all, "write")
}
if a.Execute {
all = append(all, "execute")
}
return strings.Join(all, ", ")
}
func (a access) Numeric() string {
var n uint8
if a.Read {
n += 4
}
if a.Write {
n += 2
}
if a.Execute {
n++
}
return fmt.Sprintf("%d", n)
}
func parsePermissionString(s string) (perms, error) {
if !isPermString(s) {
return perms{}, fmt.Errorf("Invalid permission string")
}
p := perms{}
switch s[0] {
case 'c':
p.Type = characterSpecialFile
case 'd':
p.Type = directory
default:
p.Type = file
}
p.SetUID = s[3] == 's' || s[3] == 'S'
p.SetGID = s[6] == 's' || s[6] == 'S'
p.Sticky = s[9] == 't' || s[9] == 'T'
p.Owner.Type = owner
p.Owner.Read = s[1] == 'r'
p.Owner.Write = s[2] == 'w'
p.Owner.Execute = s[3] == 'x' || s[3] == 's'
p.Group.Type = group
p.Group.Read = s[4] == 'r'
p.Group.Write = s[5] == 'w'
p.Group.Execute = s[6] == 'x' || s[6] == 's'
p.World.Type = world
p.World.Read = s[7] == 'r'
p.World.Write = s[8] == 'w'
p.World.Execute = s[9] == 'x'
return p, nil
}
func init() {
hinters = append(hinters, hintPerms)
}
func hintPerms(word string, context string, wordX uint16, wordY uint16) *Hint {
item := NewHint(word, context, wordX, wordY)
if wordX == 0 {
p, err := parsePermissionString(word)
if err != nil {
return nil
}
typ := "file"
switch p.Type {
case directory:
typ = "directory"
case characterSpecialFile:
typ = "character special file"
}
item.Description = fmt.Sprintf(`Permissions:
Type: %s
Numeric: %s
Owner: %s
Group: %s
World: %s
Setuid: %t
Setgid: %t
Sticky: %t
`,
typ,
p.Numeric(),
p.Owner.Nice(),
p.Group.Nice(),
p.World.Nice(),
p.SetUID,
p.SetGID,
p.Sticky,
)
return item
}
return nil
}
func isPermString(s string) bool {
re := regexp.MustCompile("[cdl\\-sS]{1}[sStTrwx\\-]{9}")
return re.MatchString(s)
}