msg_file_query_info.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package smb
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "os"
  7. "path/filepath"
  8. "sync/atomic"
  9. "imuslab.com/smb/driver/mod/smb/encoder"
  10. )
  11. func init() {
  12. commandRequestMap[CommandQueryInfo] = func() DataI {
  13. return &QueryInfoRequest{}
  14. }
  15. }
  16. type QueryInfoRequest struct {
  17. Header
  18. StructureSize uint16
  19. Class InfoType //Class
  20. InfoLevel uint8 //FileSystemInformationClass or FileInformationClass
  21. OutputBufferLength uint32 //max response size
  22. InputBufferOffset uint16 `smb:"offset:InputBuffer"`
  23. Reserved uint16
  24. InputBufferLength uint32 `smb:"len:InputBuffer"`
  25. AdditionalInformation uint32
  26. Flags uint32
  27. FileId GUID
  28. InputBuffer []byte
  29. }
  30. type QueryInfoResponse struct {
  31. Header
  32. StructureSize uint16
  33. OutputBufferOffset uint16 `smb:"offset:OutputBuffer"`
  34. OutputBufferLength uint32 `smb:"len:OutputBuffer"`
  35. OutputBuffer []byte
  36. }
  37. func (data *QueryInfoRequest) ServerAction(ctx *DataCtx) (interface{}, error) {
  38. data.Header.Flags = SMB2_FLAGS_RESPONSE
  39. fileid := ctx.FileID(data.FileId)
  40. webfile, ok := ctx.session.openedFiles[fileid]
  41. if !ok {
  42. return ERR(data.Header, STATUS_FILE_CLOSED)
  43. }
  44. var OutputBuffer []byte
  45. var err error
  46. switch data.Class {
  47. case SMB2_0_INFO_FILE:
  48. switch FileInformationClass(data.InfoLevel) {
  49. case FileStreamInformation:
  50. ff := webfile.(*os.File)
  51. var infos [][]byte
  52. if true {
  53. fi, err := ff.Stat()
  54. if err != nil {
  55. return nil, err
  56. }
  57. datakey := "::$DATA"
  58. name := encoder.ToUnicode(datakey)
  59. info := &FileStreamInformationX{
  60. StreamSize: uint64(fi.Size()),
  61. StreamAllocationSize: uint64(fi.Size()),
  62. StreamName: name,
  63. }
  64. infobuf, err := encoder.Marshal(info)
  65. if err != nil {
  66. panic(-1)
  67. }
  68. infos = append(infos, Duiqi4Byte(infobuf))
  69. }
  70. keys, err := XAttrGetKeys(ff.Name())
  71. if err != nil {
  72. return nil, fmt.Errorf("err")
  73. }
  74. for _, key := range keys {
  75. datakey := fmt.Sprintf(":%v:$DATA", key)
  76. name := encoder.ToUnicode(datakey)
  77. data, err := XAttrGet(ff.Name(), key)
  78. if err != nil {
  79. continue
  80. }
  81. info := &FileStreamInformationX{
  82. StreamSize: uint64(len(data)),
  83. StreamAllocationSize: uint64(len(data)),
  84. StreamName: name,
  85. }
  86. infobuf, err := encoder.Marshal(info)
  87. if err != nil {
  88. continue
  89. }
  90. infos = append(infos, Duiqi4Byte(infobuf))
  91. }
  92. //write offset
  93. for i, info := range infos {
  94. if i != len(infos)-1 {
  95. binary.LittleEndian.PutUint32(info, uint32(len(info)))
  96. }
  97. }
  98. OutputBuffer = bytes.Join(infos, []byte{})
  99. case FileAllInformation:
  100. fi, _ := webfile.Stat()
  101. fname := filepath.Base(fi.Name())
  102. IsDirectory := 0
  103. fid := uint64(0)
  104. FileAttributes := uint32(0x000020)
  105. if fi.IsDir() {
  106. IsDirectory = 1
  107. FileAttributes = uint32(0x000010)
  108. } else {
  109. fid = atomic.AddUint64(&KFILEID, 1)
  110. }
  111. mtime := timeToFiletime(fi.ModTime())
  112. info := SMB2_FILE_ALL_INFO{
  113. CreateTime: mtime,
  114. LastAccessTime: mtime,
  115. LastWriteTime: mtime,
  116. LastChangeTime: mtime,
  117. AccessMask: AllAccessMask,
  118. NumberOfLinks: 18,
  119. FileID: fid,
  120. FileAttributes: FileAttributes,
  121. IsDirectory: uint8(IsDirectory),
  122. FileName: encoder.ToUnicode(fname),
  123. }
  124. OutputBuffer, err = encoder.Marshal(info)
  125. if err != nil {
  126. return ERR(data.Header, STATUS_INVALID_PARAMETER)
  127. }
  128. // logx.Printf("FileAllInformation: \n%v", hex.Dump(OutputBuffer))
  129. }
  130. case SMB2_0_INFO_FILESYSTEM:
  131. switch FileSystemInformationClass(data.InfoLevel) {
  132. case FileFsAttributeInformation:
  133. //TODO 获取FSInfo
  134. ntfs := encoder.ToUnicode("NTFS")
  135. info := FileFsAttributeInformationX{
  136. FSAttributes: 0x10400c6,
  137. MaxNameLength: 256,
  138. FSName: ntfs,
  139. }
  140. OutputBuffer, err = encoder.Marshal(info)
  141. if err != nil {
  142. return ERR(data.Header, STATUS_INVALID_PARAMETER)
  143. }
  144. case FileFsSizeInformation:
  145. //TODO 计算磁盘剩余大小.
  146. info := FileFsSizeInformationX{
  147. AllocationSize: 0xfffffff,
  148. FreeUnits: 0xffffff,
  149. SectorsUnit: 1,
  150. BytesPerSector: 4096,
  151. }
  152. OutputBuffer, err = encoder.Marshal(info)
  153. if err != nil {
  154. return ERR(data.Header, STATUS_INVALID_PARAMETER)
  155. }
  156. }
  157. }
  158. data.Header.Status = StatusOk
  159. resp := QueryInfoResponse{
  160. Header: data.Header,
  161. StructureSize: 9,
  162. OutputBuffer: OutputBuffer,
  163. }
  164. return &resp, nil
  165. }