server_unix.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
  2. // +build cgo
  3. package sftp
  4. import (
  5. "fmt"
  6. "os"
  7. "path"
  8. "syscall"
  9. "time"
  10. )
  11. func runLsTypeWord(dirent os.FileInfo) string {
  12. // find first character, the type char
  13. // b Block special file.
  14. // c Character special file.
  15. // d Directory.
  16. // l Symbolic link.
  17. // s Socket link.
  18. // p FIFO.
  19. // - Regular file.
  20. tc := '-'
  21. mode := dirent.Mode()
  22. if (mode & os.ModeDir) != 0 {
  23. tc = 'd'
  24. } else if (mode & os.ModeDevice) != 0 {
  25. tc = 'b'
  26. if (mode & os.ModeCharDevice) != 0 {
  27. tc = 'c'
  28. }
  29. } else if (mode & os.ModeSymlink) != 0 {
  30. tc = 'l'
  31. } else if (mode & os.ModeSocket) != 0 {
  32. tc = 's'
  33. } else if (mode & os.ModeNamedPipe) != 0 {
  34. tc = 'p'
  35. }
  36. // owner
  37. orc := '-'
  38. if (mode & 0400) != 0 {
  39. orc = 'r'
  40. }
  41. owc := '-'
  42. if (mode & 0200) != 0 {
  43. owc = 'w'
  44. }
  45. oxc := '-'
  46. ox := (mode & 0100) != 0
  47. setuid := (mode & os.ModeSetuid) != 0
  48. if ox && setuid {
  49. oxc = 's'
  50. } else if setuid {
  51. oxc = 'S'
  52. } else if ox {
  53. oxc = 'x'
  54. }
  55. // group
  56. grc := '-'
  57. if (mode & 040) != 0 {
  58. grc = 'r'
  59. }
  60. gwc := '-'
  61. if (mode & 020) != 0 {
  62. gwc = 'w'
  63. }
  64. gxc := '-'
  65. gx := (mode & 010) != 0
  66. setgid := (mode & os.ModeSetgid) != 0
  67. if gx && setgid {
  68. gxc = 's'
  69. } else if setgid {
  70. gxc = 'S'
  71. } else if gx {
  72. gxc = 'x'
  73. }
  74. // all / others
  75. arc := '-'
  76. if (mode & 04) != 0 {
  77. arc = 'r'
  78. }
  79. awc := '-'
  80. if (mode & 02) != 0 {
  81. awc = 'w'
  82. }
  83. axc := '-'
  84. ax := (mode & 01) != 0
  85. sticky := (mode & os.ModeSticky) != 0
  86. if ax && sticky {
  87. axc = 't'
  88. } else if sticky {
  89. axc = 'T'
  90. } else if ax {
  91. axc = 'x'
  92. }
  93. return fmt.Sprintf("%c%c%c%c%c%c%c%c%c%c", tc, orc, owc, oxc, grc, gwc, gxc, arc, awc, axc)
  94. }
  95. func runLsStatt(dirname string, dirent os.FileInfo, statt *syscall.Stat_t) string {
  96. // example from openssh sftp server:
  97. // crw-rw-rw- 1 root wheel 0 Jul 31 20:52 ttyvd
  98. // format:
  99. // {directory / char device / etc}{rwxrwxrwx} {number of links} owner group size month day [time (this year) | year (otherwise)] name
  100. typeword := runLsTypeWord(dirent)
  101. numLinks := statt.Nlink
  102. uid := statt.Uid
  103. gid := statt.Gid
  104. username := fmt.Sprintf("%d", uid)
  105. groupname := fmt.Sprintf("%d", gid)
  106. // TODO FIXME: uid -> username, gid -> groupname lookup for ls -l format output
  107. mtime := dirent.ModTime()
  108. monthStr := mtime.Month().String()[0:3]
  109. day := mtime.Day()
  110. year := mtime.Year()
  111. now := time.Now()
  112. isOld := mtime.Before(now.Add(-time.Hour * 24 * 365 / 2))
  113. yearOrTime := fmt.Sprintf("%02d:%02d", mtime.Hour(), mtime.Minute())
  114. if isOld {
  115. yearOrTime = fmt.Sprintf("%d", year)
  116. }
  117. return fmt.Sprintf("%s %4d %-8s %-8s %8d %s %2d %5s %s", typeword, numLinks, username, groupname, dirent.Size(), monthStr, day, yearOrTime, dirent.Name())
  118. }
  119. // ls -l style output for a file, which is in the 'long output' section of a readdir response packet
  120. // this is a very simple (lazy) implementation, just enough to look almost like openssh in a few basic cases
  121. func runLs(dirname string, dirent os.FileInfo) string {
  122. dsys := dirent.Sys()
  123. if dsys == nil {
  124. } else if statt, ok := dsys.(*syscall.Stat_t); !ok {
  125. } else {
  126. return runLsStatt(dirname, dirent, statt)
  127. }
  128. return path.Join(dirname, dirent.Name())
  129. }