msg_file_query_directory_find.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. package smb
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "io/fs"
  7. "path/filepath"
  8. "sync/atomic"
  9. "imuslab.com/smb/driver/mod/smb/encoder"
  10. )
  11. func init() {
  12. commandRequestMap[CommandFind] = func() DataI {
  13. return &QueryDirectoryRequest{}
  14. }
  15. }
  16. type FindFlags uint8
  17. const (
  18. RestartScans FindFlags = 0x0001
  19. ReturnSingleEntry FindFlags = 0x0002
  20. IndexSpecified FindFlags = 0x0004
  21. Reopen FindFlags = 0x0010
  22. )
  23. func (c FindFlags) MarshalBinary(meta *encoder.Metadata) ([]byte, error) {
  24. return MarshalBinary(c, meta, c)
  25. }
  26. func (c FindFlags) UnmarshalBinary(data []byte, meta *encoder.Metadata) (interface{}, error) {
  27. return UnmarshalBinary(c, data, meta, c)
  28. }
  29. type QueryDirectoryRequest struct {
  30. Header
  31. StructureSize uint16
  32. InfoLevel FileInformationClass
  33. FindFlags FindFlags //1: restart scan
  34. FileIndex uint32
  35. FileId GUID
  36. FileNameOffset uint16 `smb:"offset:FileName"`
  37. FileNameLength uint16 `smb:"len:FileName"`
  38. // BlobOffset uint16 `smb:"offset:Blob"`
  39. // BlobLength uint16 `smb:"len:Blob"`
  40. OutputBufferLength uint32
  41. // Blob []byte //unicode
  42. FileName []byte //unicode
  43. }
  44. type QueryDirectoryResponse struct {
  45. Header
  46. StructureSize uint16
  47. OutputBufferOffset uint16 `smb:"offset:OutputBuffer"`
  48. OutputBufferLength uint32 `smb:"len:OutputBuffer"`
  49. OutputBuffer []byte
  50. }
  51. var KFILEID = uint64(0)
  52. func (data *QueryDirectoryRequest) ServerAction(ctx *DataCtx) (interface{}, error) {
  53. data.Header.Flags = SMB2_FLAGS_RESPONSE
  54. fileid := ctx.FileID(data.FileId)
  55. webfile, ok := ctx.session.openedFiles[fileid]
  56. if !ok {
  57. return ERR(data.Header, STATUS_FILE_CLOSED)
  58. }
  59. stat, err := webfile.Stat()
  60. if err != nil {
  61. return ERR(data.Header, STATUS_INVALID_PARAMETER)
  62. }
  63. if !stat.IsDir() {
  64. if (data.FindFlags & Reopen) != 0 {
  65. return ERR(data.Header, STATUS_NOT_SUPPORTED)
  66. } else {
  67. return ERR(data.Header, STATUS_INVALID_PARAMETER)
  68. }
  69. }
  70. getFileDirInfo := func(fi fs.FileInfo) *FileDirectoryInfo {
  71. mtime := timeToFiletime(fi.ModTime())
  72. filename := filepath.Base(fi.Name())
  73. nameByte := encoder.ToUnicode(filename)
  74. var fa FileAttributes
  75. var AllocationSize, EndOfFile uint64
  76. if fi.IsDir() {
  77. fa |= FILE_ATTRIBUTE_DIRECTORY
  78. } else {
  79. // fa |= FILE_ATTRIBUTE_ARCHIVE
  80. fa |= FILE_ATTRIBUTE_NORMAL
  81. AllocationSize = uint64(fi.Size()) //磁盘大小, 会有碎片, 比endoffile大一点
  82. EndOfFile = uint64(fi.Size()) //文件大小
  83. }
  84. // logx.Printf("fa: %v", fa)
  85. return &FileDirectoryInfo{
  86. CreateTime: mtime,
  87. LastAccessTime: mtime,
  88. LastWriteTime: mtime,
  89. LastChangeTime: mtime,
  90. FileName: nameByte,
  91. AllocationSize: AllocationSize, //磁盘大小, 会有碎片, 比endoffile大一点
  92. EndOfFile: EndOfFile, //文件大小
  93. FileAttributes: fa,
  94. }
  95. }
  96. getFileIdBothDirInfo := func(fi fs.FileInfo) *FileIdBothDirectoryInfo {
  97. mtime := timeToFiletime(fi.ModTime())
  98. filename := filepath.Base(fi.Name())
  99. nameByte := encoder.ToUnicode(filename)
  100. var fa FileAttributes
  101. size := uint32(fi.Size())
  102. var AllocationSize, EndOfFile uint64
  103. if fi.IsDir() {
  104. fa |= FILE_ATTRIBUTE_DIRECTORY
  105. // logx.Printf("fa if: %v", fa)
  106. //TODO
  107. size = 0x011111111
  108. } else {
  109. // fa |= FILE_ATTRIBUTE_ARCHIVE
  110. fa |= FILE_ATTRIBUTE_NORMAL
  111. AllocationSize = uint64(fi.Size()) //磁盘大小, 会有碎片, 比endoffile大一点
  112. EndOfFile = uint64(fi.Size()) //文件大小
  113. if size == 0 {
  114. size = 0x011111111
  115. }
  116. }
  117. // logx.Printf("fa: %v", fa)
  118. fid := atomic.AddUint64(&KFILEID, 1)
  119. return &FileIdBothDirectoryInfo{
  120. CreateTime: mtime,
  121. LastAccessTime: mtime,
  122. LastWriteTime: mtime,
  123. LastChangeTime: mtime,
  124. FileName: nameByte,
  125. AllocationSize: AllocationSize, //磁盘大小, 会有碎片, 比endoffile大一点
  126. EndOfFile: EndOfFile, //文件大小
  127. FileAttributes: fa,
  128. FileId: fid,
  129. EASize: size,
  130. }
  131. }
  132. getFileInfo := func(fi fs.FileInfo, level FileInformationClass) ([]byte, error) {
  133. if level == FileDirectoryInformation {
  134. return encoder.Marshal(getFileDirInfo(fi))
  135. } else if level == FileIdBothDirectoryInformation {
  136. return encoder.Marshal(getFileIdBothDirInfo(fi))
  137. } else {
  138. return nil, errors.New("Unsupported")
  139. }
  140. }
  141. FileName, err := encoder.FromUnicode(data.FileName)
  142. if err != nil {
  143. return ERR(data.Header, STATUS_INVALID_PARAMETER)
  144. }
  145. var OutputBuffer []byte
  146. // if data.FindFlags == 0 {
  147. // return ERR(data.Header, STATUS_NO_MORE_FILES)
  148. // }
  149. // data.FindFlags == 0 RestartScans
  150. switch data.InfoLevel {
  151. case FileDirectoryInformation, FileIdBothDirectoryInformation:
  152. switch FileName {
  153. case "*":
  154. fis, err := webfile.Readdir(0)
  155. if err != nil {
  156. return nil, err
  157. }
  158. var items [][]byte
  159. // selfFI, err := webfile.Stat()
  160. // if err != nil {
  161. // return nil, err
  162. // }
  163. // fis = append(fis, &fileInfoX{FileInfo: selfFI, name: "."})
  164. // fis = append(fis, &fileInfoX{FileInfo: selfFI, name: ".."})
  165. for _, fi := range fis {
  166. itemBuf, err := getFileInfo(fi, data.InfoLevel)
  167. if err != nil {
  168. //如果有错误, 就继续. 这个看以后是否修改.
  169. continue
  170. }
  171. items = append(items, itemBuf)
  172. if (data.FindFlags & ReturnSingleEntry) != 0 {
  173. break
  174. }
  175. }
  176. if true {
  177. for i := 0; i < len(items); i++ {
  178. //需要设置每个包的大小.用来分割包.最后一个包不用.
  179. if i != len(items)-1 {
  180. line := items[i]
  181. binary.LittleEndian.PutUint32(line, uint32(len(line)))
  182. }
  183. }
  184. OutputBuffer = bytes.Join(items, []byte{})
  185. }
  186. data.Header.Status = StatusOk
  187. if len(items) == 0 {
  188. return ERR(data.Header, STATUS_NO_MORE_FILES)
  189. }
  190. default:
  191. fis, err := webfile.Readdir(0)
  192. if err != nil {
  193. return nil, err
  194. }
  195. var fi fs.FileInfo
  196. for _, item := range fis {
  197. if item.Name() == FileName {
  198. fi = item
  199. break
  200. }
  201. }
  202. if fi != nil {
  203. OutputBuffer, err = getFileInfo(fi, data.InfoLevel)
  204. }
  205. data.Header.Status = StatusOk
  206. if len(OutputBuffer) == 0 {
  207. return ERR(data.Header, STATUS_NO_SUCK_FILE)
  208. }
  209. }
  210. default:
  211. return ERR(data.Header, STATUS_NOT_SUPPORTED)
  212. }
  213. if err != nil {
  214. return nil, err
  215. }
  216. resp := QueryDirectoryResponse{
  217. Header: data.Header,
  218. StructureSize: 0x0009,
  219. OutputBuffer: OutputBuffer,
  220. // OutputBufferOffset: 0x0048,
  221. // OutputBufferLength: uint32(len(OutputBuffer)),
  222. }
  223. return &resp, nil
  224. }