| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- package smb
- import (
- "bytes"
- "encoding/binary"
- "fmt"
- "os"
- "path/filepath"
- "sync/atomic"
- "imuslab.com/smb/driver/mod/smb/encoder"
- )
- func init() {
- commandRequestMap[CommandQueryInfo] = func() DataI {
- return &QueryInfoRequest{}
- }
- }
- type QueryInfoRequest struct {
- Header
- StructureSize uint16
- Class InfoType //Class
- InfoLevel uint8 //FileSystemInformationClass or FileInformationClass
- OutputBufferLength uint32 //max response size
- InputBufferOffset uint16 `smb:"offset:InputBuffer"`
- Reserved uint16
- InputBufferLength uint32 `smb:"len:InputBuffer"`
- AdditionalInformation uint32
- Flags uint32
- FileId GUID
- InputBuffer []byte
- }
- type QueryInfoResponse struct {
- Header
- StructureSize uint16
- OutputBufferOffset uint16 `smb:"offset:OutputBuffer"`
- OutputBufferLength uint32 `smb:"len:OutputBuffer"`
- OutputBuffer []byte
- }
- func (data *QueryInfoRequest) ServerAction(ctx *DataCtx) (interface{}, error) {
- data.Header.Flags = SMB2_FLAGS_RESPONSE
- fileid := ctx.FileID(data.FileId)
- webfile, ok := ctx.session.openedFiles[fileid]
- if !ok {
- return ERR(data.Header, STATUS_FILE_CLOSED)
- }
- var OutputBuffer []byte
- var err error
- switch data.Class {
- case SMB2_0_INFO_FILE:
- switch FileInformationClass(data.InfoLevel) {
- case FileStreamInformation:
- ff := webfile.(*os.File)
- var infos [][]byte
- if true {
- fi, err := ff.Stat()
- if err != nil {
- return nil, err
- }
- datakey := "::$DATA"
- name := encoder.ToUnicode(datakey)
- info := &FileStreamInformationX{
- StreamSize: uint64(fi.Size()),
- StreamAllocationSize: uint64(fi.Size()),
- StreamName: name,
- }
- infobuf, err := encoder.Marshal(info)
- if err != nil {
- panic(-1)
- }
- infos = append(infos, Duiqi4Byte(infobuf))
- }
- keys, err := XAttrGetKeys(ff.Name())
- if err != nil {
- return nil, fmt.Errorf("err")
- }
- for _, key := range keys {
- datakey := fmt.Sprintf(":%v:$DATA", key)
- name := encoder.ToUnicode(datakey)
- data, err := XAttrGet(ff.Name(), key)
- if err != nil {
- continue
- }
- info := &FileStreamInformationX{
- StreamSize: uint64(len(data)),
- StreamAllocationSize: uint64(len(data)),
- StreamName: name,
- }
- infobuf, err := encoder.Marshal(info)
- if err != nil {
- continue
- }
- infos = append(infos, Duiqi4Byte(infobuf))
- }
- //write offset
- for i, info := range infos {
- if i != len(infos)-1 {
- binary.LittleEndian.PutUint32(info, uint32(len(info)))
- }
- }
- OutputBuffer = bytes.Join(infos, []byte{})
- case FileAllInformation:
- fi, _ := webfile.Stat()
- fname := filepath.Base(fi.Name())
- IsDirectory := 0
- fid := uint64(0)
- FileAttributes := uint32(0x000020)
- if fi.IsDir() {
- IsDirectory = 1
- FileAttributes = uint32(0x000010)
- } else {
- fid = atomic.AddUint64(&KFILEID, 1)
- }
- mtime := timeToFiletime(fi.ModTime())
- info := SMB2_FILE_ALL_INFO{
- CreateTime: mtime,
- LastAccessTime: mtime,
- LastWriteTime: mtime,
- LastChangeTime: mtime,
- AccessMask: AllAccessMask,
- NumberOfLinks: 18,
- FileID: fid,
- FileAttributes: FileAttributes,
- IsDirectory: uint8(IsDirectory),
- FileName: encoder.ToUnicode(fname),
- }
- OutputBuffer, err = encoder.Marshal(info)
- if err != nil {
- return ERR(data.Header, STATUS_INVALID_PARAMETER)
- }
- // logx.Printf("FileAllInformation: \n%v", hex.Dump(OutputBuffer))
- }
- case SMB2_0_INFO_FILESYSTEM:
- switch FileSystemInformationClass(data.InfoLevel) {
- case FileFsAttributeInformation:
- //TODO 获取FSInfo
- ntfs := encoder.ToUnicode("NTFS")
- info := FileFsAttributeInformationX{
- FSAttributes: 0x10400c6,
- MaxNameLength: 256,
- FSName: ntfs,
- }
- OutputBuffer, err = encoder.Marshal(info)
- if err != nil {
- return ERR(data.Header, STATUS_INVALID_PARAMETER)
- }
- case FileFsSizeInformation:
- //TODO 计算磁盘剩余大小.
- info := FileFsSizeInformationX{
- AllocationSize: 0xfffffff,
- FreeUnits: 0xffffff,
- SectorsUnit: 1,
- BytesPerSector: 4096,
- }
- OutputBuffer, err = encoder.Marshal(info)
- if err != nil {
- return ERR(data.Header, STATUS_INVALID_PARAMETER)
- }
- }
- }
- data.Header.Status = StatusOk
- resp := QueryInfoResponse{
- Header: data.Header,
- StructureSize: 9,
- OutputBuffer: OutputBuffer,
- }
- return &resp, nil
- }
|