github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/cli/lscolors/feature.go (about)

     1  package lscolors
     2  
     3  import (
     4  	"os"
     5  )
     6  
     7  type feature int
     8  
     9  const (
    10  	featureInvalid feature = iota
    11  
    12  	featureOrphanedSymlink
    13  	featureSymlink
    14  
    15  	featureMultiHardLink
    16  
    17  	featureNamedPipe
    18  	featureSocket
    19  	featureDoor
    20  	featureBlockDevice
    21  	featureCharDevice
    22  
    23  	featureWorldWritableStickyDirectory
    24  	featureWorldWritableDirectory
    25  	featureStickyDirectory
    26  	featureDirectory
    27  
    28  	featureCapability
    29  
    30  	featureSetuid
    31  	featureSetgid
    32  	featureExecutable
    33  
    34  	featureRegular
    35  )
    36  
    37  // Weirdly, permission masks for group and other are missing on platforms other
    38  // than linux, darwin and netbsd. So we replicate some of them here.
    39  const (
    40  	worldWritable = 02   // Writable by other
    41  	executable    = 0111 // Executable
    42  )
    43  
    44  func determineFeature(fname string, mh bool) (feature, error) {
    45  	stat, err := os.Lstat(fname)
    46  
    47  	if err != nil {
    48  		return featureInvalid, err
    49  	}
    50  
    51  	m := stat.Mode()
    52  
    53  	// Symlink and OrphanedSymlink has highest precedence
    54  	if is(m, os.ModeSymlink) {
    55  		_, err := os.Stat(fname)
    56  		if err != nil {
    57  			return featureOrphanedSymlink, nil
    58  		}
    59  		return featureSymlink, nil
    60  	}
    61  
    62  	// featureMultiHardLink
    63  	if mh && isMultiHardlink(stat) {
    64  		return featureMultiHardLink, nil
    65  	}
    66  
    67  	// type bits features
    68  	switch {
    69  	case is(m, os.ModeNamedPipe):
    70  		return featureNamedPipe, nil
    71  	case is(m, os.ModeSocket): // Never on Windows
    72  		return featureSocket, nil
    73  	case isDoor(stat):
    74  		return featureDoor, nil
    75  	case is(m, os.ModeCharDevice):
    76  		return featureCharDevice, nil
    77  	case is(m, os.ModeDevice):
    78  		// There is no dedicated os.Mode* flag for block device. On all
    79  		// supported Unix platforms, when os.ModeDevice is set but
    80  		// os.ModeCharDevice is not, the file is a block device (i.e.
    81  		// syscall.S_IFBLK is set). On Windows, this branch is unreachable.
    82  		//
    83  		// On Plan9, this in inaccurate.
    84  		return featureBlockDevice, nil
    85  	case is(m, os.ModeDir):
    86  		// Perm bits features for directory
    87  		perm := m.Perm()
    88  		switch {
    89  		case is(m, os.ModeSticky) && is(perm, worldWritable):
    90  			return featureWorldWritableStickyDirectory, nil
    91  		case is(perm, worldWritable):
    92  			return featureWorldWritableDirectory, nil
    93  		case is(m, os.ModeSticky):
    94  			return featureStickyDirectory, nil
    95  		default:
    96  			return featureDirectory, nil
    97  		}
    98  	}
    99  
   100  	// TODO(xiaq): Support featureCapacity
   101  
   102  	// Perm bits features for regular files
   103  	switch {
   104  	case is(m, os.ModeSetuid):
   105  		return featureSetuid, nil
   106  	case is(m, os.ModeSetgid):
   107  		return featureSetgid, nil
   108  	case m&executable != 0:
   109  		return featureExecutable, nil
   110  	}
   111  
   112  	// Check extension
   113  	return featureRegular, nil
   114  }
   115  
   116  func is(m, p os.FileMode) bool {
   117  	return m&p == p
   118  }