feature.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package lscolors
  2. import (
  3. "os"
  4. "src.elv.sh/pkg/fsutil"
  5. )
  6. type feature int
  7. const (
  8. featureInvalid feature = iota
  9. featureOrphanedSymlink
  10. featureSymlink
  11. featureMultiHardLink
  12. featureNamedPipe
  13. featureSocket
  14. featureDoor
  15. featureBlockDevice
  16. featureCharDevice
  17. featureWorldWritableStickyDirectory
  18. featureWorldWritableDirectory
  19. featureStickyDirectory
  20. featureDirectory
  21. featureCapability
  22. featureSetuid
  23. featureSetgid
  24. featureExecutable
  25. featureRegular
  26. )
  27. const (
  28. // Some platforms, such as Windows, have simulated UNIX style permission masks.
  29. // On Windows the only two permission masks are 0o666 (RW) and 0o444 (RO).
  30. worldWritable = 0o002
  31. )
  32. func determineFeature(fname string, mh bool) (feature, error) {
  33. stat, err := os.Lstat(fname)
  34. if err != nil {
  35. return featureInvalid, err
  36. }
  37. m := stat.Mode()
  38. // Symlink and OrphanedSymlink has highest precedence
  39. if is(m, os.ModeSymlink) {
  40. _, err := os.Stat(fname)
  41. if err != nil {
  42. return featureOrphanedSymlink, nil
  43. }
  44. return featureSymlink, nil
  45. }
  46. // featureMultiHardLink
  47. if mh && isMultiHardlink(stat) {
  48. return featureMultiHardLink, nil
  49. }
  50. // type bits features
  51. switch {
  52. case is(m, os.ModeNamedPipe):
  53. return featureNamedPipe, nil
  54. case is(m, os.ModeSocket): // Never on Windows
  55. return featureSocket, nil
  56. case isDoor(stat):
  57. return featureDoor, nil
  58. case is(m, os.ModeCharDevice):
  59. return featureCharDevice, nil
  60. case is(m, os.ModeDevice):
  61. // There is no dedicated os.Mode* flag for block device. On all
  62. // supported Unix platforms, when os.ModeDevice is set but
  63. // os.ModeCharDevice is not, the file is a block device (i.e.
  64. // syscall.S_IFBLK is set). On Windows, this branch is unreachable.
  65. //
  66. // On Plan9, this in inaccurate.
  67. return featureBlockDevice, nil
  68. case is(m, os.ModeDir):
  69. // Perm bits features for directory
  70. perm := m.Perm()
  71. switch {
  72. case is(m, os.ModeSticky) && is(perm, worldWritable):
  73. return featureWorldWritableStickyDirectory, nil
  74. case is(perm, worldWritable):
  75. return featureWorldWritableDirectory, nil
  76. case is(m, os.ModeSticky):
  77. return featureStickyDirectory, nil
  78. default:
  79. return featureDirectory, nil
  80. }
  81. }
  82. // TODO(xiaq): Support featureCapacity
  83. // Perm bits features for regular files
  84. switch {
  85. case is(m, os.ModeSetuid):
  86. return featureSetuid, nil
  87. case is(m, os.ModeSetgid):
  88. return featureSetgid, nil
  89. case fsutil.IsExecutable(stat):
  90. return featureExecutable, nil
  91. }
  92. // Check extension
  93. return featureRegular, nil
  94. }
  95. func is(m, p os.FileMode) bool {
  96. return m&p == p
  97. }