msg_file_create.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. package smb
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/binary"
  6. "fmt"
  7. "os"
  8. "strings"
  9. "sync/atomic"
  10. "imuslab.com/smb/driver/mod/smb/encoder"
  11. "imuslab.com/smb/driver/mod/util"
  12. "golang.org/x/net/webdav"
  13. )
  14. func init() {
  15. commandRequestMap[CommandCreate] = func() DataI {
  16. return &CreateRequest{
  17. // CreateContexts: &SMB2_CREATE_CONTEXT{},
  18. }
  19. }
  20. }
  21. // handle_Create
  22. type CreateDisposition uint32
  23. const (
  24. FILE_SUPERSEDE CreateDisposition = 0x00000000 //If the file already exists, supersede it. Otherwise, create the file. This value SHOULD NOT be used for a printer object.<30>
  25. FILE_OPEN CreateDisposition = 0x00000001 //If the file already exists, return success; otherwise, fail the operation. MUST NOT be used for a printer object.
  26. FILE_CREATE CreateDisposition = 0x00000002 //If the file already exists, fail the operation; otherwise, create the file.
  27. FILE_OPEN_IF CreateDisposition = 0x00000003 //Open the file if it already exists; otherwise, create the file. This value SHOULD NOT be used for a printer object.<31>
  28. FILE_OVERWRITE CreateDisposition = 0x00000004 //Overwrite the file if it already exists; otherwise, fail the operation. MUST NOT be used for a printer object.
  29. FILE_OVERWRITE_IF CreateDisposition = 0x00000005 //Overwrite the file if it already exists; otherwise, create the file. This value SHOULD NOT be used for a printer object.<32>
  30. )
  31. var _ encoder.BinaryMarshallable = CreateDisposition(0)
  32. func (c CreateDisposition) MarshalBinary(meta *encoder.Metadata) ([]byte, error) {
  33. return MarshalBinary(c, meta, c)
  34. }
  35. func (c CreateDisposition) UnmarshalBinary(data []byte, meta *encoder.Metadata) (interface{}, error) {
  36. return UnmarshalBinary(c, data, meta, c)
  37. }
  38. type ShareAccess uint32
  39. const (
  40. FILE_SHARE_READ ShareAccess = 0x00000001
  41. FILE_SHARE_WRITE ShareAccess = 0x00000002
  42. FILE_SHARE_DELETE ShareAccess = 0x00000004
  43. )
  44. var _ encoder.BinaryMarshallable = FileAttributes(0)
  45. func (c ShareAccess) MarshalBinary(meta *encoder.Metadata) ([]byte, error) {
  46. return MarshalBinary(c, meta, c)
  47. }
  48. func (c ShareAccess) UnmarshalBinary(data []byte, meta *encoder.Metadata) (interface{}, error) {
  49. return UnmarshalBinary(c, data, meta, c)
  50. }
  51. type CreateOptions uint32
  52. const (
  53. FILE_DIRECTORY_FILE CreateOptions = 0x00000001
  54. FILE_WRITE_THROUGH CreateOptions = 0x00000002
  55. FILE_SEQUENTIAL_ONLY CreateOptions = 0x00000004
  56. FILE_NO_INTERMEDIATE_BUFFERING CreateOptions = 0x00000008
  57. FILE_SYNCHRONOUS_IO_ALERT CreateOptions = 0x00000010
  58. FILE_SYNCHRONOUS_IO_NONALERT CreateOptions = 0x00000020
  59. FILE_NON_DIRECTORY_FILE CreateOptions = 0x00000040
  60. FILE_COMPLETE_IF_OPLOCKED CreateOptions = 0x00000100
  61. FILE_NO_EA_KNOWLEDGE CreateOptions = 0x00000200
  62. FILE_OPEN_REMOTE_INSTANCE CreateOptions = 0x00000400
  63. FILE_RANDOM_ACCESS CreateOptions = 0x00000800
  64. FILE_DELETE_ON_CLOSE CreateOptions = 0x00001000
  65. FILE_OPEN_BY_FILE_ID CreateOptions = 0x00002000
  66. FILE_OPEN_FOR_BACKUP_INTENT CreateOptions = 0x00004000
  67. FILE_NO_COMPRESSION CreateOptions = 0x00008000
  68. FILE_OPEN_REQUIRING_OPLOCK CreateOptions = 0x00010000
  69. FILE_DISALLOW_EXCLUSIVE CreateOptions = 0x00020000
  70. FILE_RESERVE_OPFILTER CreateOptions = 0x00100000
  71. FILE_OPEN_REPARSE_POINT CreateOptions = 0x00200000
  72. FILE_OPEN_NO_RECALL CreateOptions = 0x00400000
  73. FILE_OPEN_FOR_FREE_SPACE_QUERY CreateOptions = 0x00800000
  74. )
  75. var _ encoder.BinaryMarshallable = CreateOptions(0)
  76. func (c CreateOptions) MarshalBinary(meta *encoder.Metadata) ([]byte, error) {
  77. return MarshalBinary(c, meta, c)
  78. }
  79. func (c CreateOptions) UnmarshalBinary(data []byte, meta *encoder.Metadata) (interface{}, error) {
  80. return UnmarshalBinary(c, data, meta, c)
  81. }
  82. type FileAttributes uint32
  83. const (
  84. //https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/ca28ec38-f155-4768-81d6-4bfeb8586fc9
  85. FILE_ATTRIBUTE_READONLY FileAttributes = 0x00000001 //A file or directory that is read-only. For a file, applications can read the file but cannot write to it or delete it. For a directory, applications cannot delete it, but applications can create and delete files from that directory.
  86. FILE_ATTRIBUTE_HIDDEN FileAttributes = 0x00000002 // A file or directory that is hidden. Files and directories marked with this attribute do not appear in an ordinary directory listing.
  87. FILE_ATTRIBUTE_SYSTEM FileAttributes = 0x00000004 // A file or directory that the operating system uses a part of or uses exclusively.
  88. FILE_ATTRIBUTE_DIRECTORY FileAttributes = 0x00000010 // This item is a directory.
  89. FILE_ATTRIBUTE_ARCHIVE FileAttributes = 0x00000020 // A file or directory that requires to be archived. Applications use this attribute to mark files for backup or removal.
  90. FILE_ATTRIBUTE_NORMAL FileAttributes = 0x00000080 // A file that does not have other attributes set. This flag is used to clear all other flags by specifying it with no other flags set.
  91. //This flag MUST be ignored if other flags are set.<161>
  92. FILE_ATTRIBUTE_TEMPORARY FileAttributes = 0x00000100 // A file that is being used for temporary storage. The operating system can choose to store this file's data in memory rather than on mass storage, writing the data to mass storage only if data remains in the file when the file is closed.
  93. FILE_ATTRIBUTE_SPARSE_FILE FileAttributes = 0x00000200 // A file that is a sparse file.
  94. FILE_ATTRIBUTE_REPARSE_POINT FileAttributes = 0x00000400 // A file or directory that has an associated reparse point.
  95. FILE_ATTRIBUTE_COMPRESSED FileAttributes = 0x00000800 // A file or directory that is compressed. For a file, all of the data in the file is compressed. For a directory, compression is the default for newly created files and subdirectories.
  96. FILE_ATTRIBUTE_OFFLINE FileAttributes = 0x00001000 // The data in this file is not available immediately. This attribute indicates that the file data is physically moved to offline storage. This attribute is used by Remote Storage, which is hierarchical storage management software.
  97. FILE_ATTRIBUTE_NOT_CONTENT_INDEXED FileAttributes = 0x00002000 // A file or directory that is not indexed by the content indexing service.
  98. FILE_ATTRIBUTE_ENCRYPTED FileAttributes = 0x00004000 // A file or directory that is encrypted. For a file, all data streams in the file are encrypted. For a directory, encryption is the default for newly created files and subdirectories.
  99. FILE_ATTRIBUTE_INTEGRITY_STREAM FileAttributes = 0x00008000 // A file or directory that is configured with integrity support. For a file, all data streams in the file have integrity support. For a directory, integrity support is the default for newly created files and subdirectories, unless the caller specifies otherwise.<162>
  100. FILE_ATTRIBUTE_NO_SCRUB_DATA FileAttributes = 0x00020000 // A file or directory that is configured to be excluded from the data integrity scan. For a directory configured with FILE_ATTRIBUTE_NO_SCRUB_DATA, the default for newly created files and subdirectories is to inherit the FILE_ATTRIBUTE_NO_SCRUB_DATA attribute.<163>
  101. FILE_ATTRIBUTE_RECALL_ON_OPEN FileAttributes = 0x00040000 // This attribute appears only in directory enumeration classes (FILE_DIRECTORY_INFORMATION, FILE_BOTH_DIR_INFORMATION, etc.). When this attribute is set, it means that the file or directory has no physical representation on the local system; the item is virtual. Opening the item will be more expensive than usual because it will cause at least some of the file or directory content to be fetched from a remote store. This attribute can only be set by kernel-mode components. This attribute is for use with hierarchical storage management software.<164>
  102. FILE_ATTRIBUTE_PINNED FileAttributes = 0x00080000 // This attribute indicates user intent that the file or directory should be kept fully present locally even when not being actively accessed. This attribute is for use with hierarchical storage management software.<165>
  103. FILE_ATTRIBUTE_UNPINNED FileAttributes = 0x00100000 // This attribute indicates that the file or directory should not be kept fully present locally except when being actively accessed. This attribute is for use with hierarchical storage management software.<166>
  104. FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS FileAttributes = 0x00400000
  105. )
  106. var _ encoder.BinaryMarshallable = FileAttributes(0)
  107. func (c FileAttributes) MarshalBinary(meta *encoder.Metadata) ([]byte, error) {
  108. return MarshalBinary(c, meta, c)
  109. }
  110. func (c FileAttributes) UnmarshalBinary(data []byte, meta *encoder.Metadata) (interface{}, error) {
  111. return UnmarshalBinary(c, data, meta, c)
  112. }
  113. type CreateRequest struct {
  114. Header
  115. StructureSize uint16
  116. SecurityFlags uint8 //1字节,保留字段,不得使用
  117. OpLock uint8 //1字节,对应文档RequestedOplockLevel字段
  118. ImpersonationLevel uint32 //4字节,模拟等级
  119. CreateFlags []byte `smb:"fixed:8"` //8字节,保留字段,不得使用
  120. Reserved []byte `smb:"fixed:8"`
  121. AccessMask AccessMask //DesiredAccess //4字节,访问权限
  122. FileAttributes FileAttributes //4字节,文件属性
  123. ShareAccess ShareAccess //ShareAccess//4字节,共享模式
  124. CreateDisposition CreateDisposition //CreateDispositionStat
  125. CreateOptions CreateOptions
  126. NameOffset uint16 `smb:"offset:Filename"`
  127. NameLength uint16 `smb:"len:Filename"`
  128. // Filename []byte `smb:"unicode"`
  129. CreateContextsOffset uint32 `smb:"offset:CreateContexts"`
  130. CreateContextsLength uint32 `smb:"len:CreateContexts"`
  131. // BlankByte []byte `smb:"fixed:8"` //blank space
  132. // Filename []byte
  133. Filename []byte // `smb:"unicode"`
  134. CreateContexts []byte
  135. // CreateContexts *SMB2_CREATE_CONTEXT // []byte `smb:"unicode"`
  136. }
  137. type CreateAction uint32
  138. const (
  139. FILE_SUPERSEDED CreateAction = 0x00000000
  140. FILE_OPENED CreateAction = 0x00000001
  141. FILE_CREATED CreateAction = 0x00000002
  142. FILE_OVERWRITTEN CreateAction = 0x00000003
  143. )
  144. func (c CreateAction) MarshalBinary(meta *encoder.Metadata) ([]byte, error) {
  145. return MarshalBinary(c, meta, c)
  146. }
  147. func (c CreateAction) UnmarshalBinary(data []byte, meta *encoder.Metadata) (interface{}, error) {
  148. return UnmarshalBinary(c, data, meta, c)
  149. }
  150. type CreateResponse struct {
  151. Header
  152. StructureSize uint16
  153. Oplock uint8 //1字节,对应文档RequestedOplockLevel字段
  154. ResponseFlags uint8
  155. CreateAction CreateAction
  156. // CreationTime []byte `smb:"fixed:8"` //8字节,创建时间
  157. // LastAccessTime []byte `smb:"fixed:8"` //8字节
  158. // LastWriteTime []byte `smb:"fixed:8"` //8字节
  159. // LastChangeTime []byte `smb:"fixed:8"` //8字节
  160. // AllocationSize []byte `smb:"fixed:8"` //8字节,文件大小
  161. CreationTime uint64
  162. LastAccessTime uint64
  163. LastWriteTime uint64
  164. ChangeTime uint64
  165. AllocationSize uint64
  166. EndOfFile uint64
  167. FileAttributes FileAttributes
  168. Reserved2 []byte `smb:"fixed:4"`
  169. FileId GUID // []byte `smb:"fixed:16"` //16字节,文件句柄
  170. CreateContextsOffset uint32 `smb:"offset:CreateContexts"`
  171. CreateContextsLength uint32 `smb:"len:CreateContexts"`
  172. CreateContexts []byte
  173. }
  174. type GUID [16]byte
  175. var (
  176. NilGUID GUID = [16]byte{}
  177. LastGUID GUID
  178. )
  179. func init() {
  180. copy(LastGUID[:], bytes.Repeat([]byte{255}, 16)[:16])
  181. copy(NilGUID[:], bytes.Repeat([]byte{0}, 16)[:16])
  182. }
  183. func (g GUID) treeId() uint32 {
  184. return binary.LittleEndian.Uint32(g[:])
  185. }
  186. func (g GUID) IsSvrSvc(s *SessionS) bool {
  187. return bytes.Equal(s.srvsvc[:], g[:])
  188. }
  189. func (g GUID) IsEqual(b GUID) bool {
  190. return bytes.Equal(b[:], g[:])
  191. }
  192. func makeGUID(treeId uint32, fid uint64) GUID {
  193. var guid GUID
  194. binary.LittleEndian.PutUint64(guid[:], uint64(treeId))
  195. binary.LittleEndian.PutUint64(guid[8:], fid)
  196. return guid
  197. }
  198. var xx [16]byte
  199. var _ encoder.BinaryMarshallable = GUID(xx)
  200. func (c GUID) MarshalBinary(meta *encoder.Metadata) ([]byte, error) {
  201. return c[:], nil
  202. }
  203. func (c GUID) UnmarshalBinary(data []byte, meta *encoder.Metadata) (interface{}, error) {
  204. var cc GUID
  205. copy(cc[:], data[:16])
  206. meta.CurrOffset += 16
  207. return cc, nil
  208. }
  209. const k_srvsvc = "srvsvc"
  210. var ipc_file = &webdavFile{filename: "$IPC", filenameAttr: "", webdavType: XATTR_FINDER_INFO_EA_NAME}
  211. func (data *CreateRequest) ServerAction(ctx *DataCtx) (interface{}, error) {
  212. data.Header.Flags = SMB2_FLAGS_RESPONSE
  213. Filename, err := encoder.FromUnicode(data.Filename)
  214. if err != nil {
  215. return ERR(data.Header, STATUS_INVALID_PARAMETER)
  216. }
  217. var createContextsResp []byte = nil
  218. if len(data.CreateContexts) > 0 {
  219. createContextsRequest := &SMB2_CREATE_CONTEXT_REQUEST{}
  220. encoder.Unmarshal(data.CreateContexts, createContextsRequest)
  221. createContextsResp = createContextsRequest.Action(func(ttt SMB2_CREATE_CONTEXT_RESPONSE_TYPE, request interface{}) (interface{}, error) {
  222. switch ttt {
  223. case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_RESPONSE_TAG:
  224. return &SMB2_CREATE_QUERY_MAXIMAL_ACCESS_RESPONSE{MaximalAccess: AllAccessMask}, nil
  225. case SMB2_APPL_CREATE_CONTENT_TAG:
  226. return nil, fmt.Errorf("NA")
  227. return &SMB2_APPL_CREATE_CONTENT_TAG_RESPONSE{}, nil
  228. default:
  229. return nil, fmt.Errorf("NA")
  230. }
  231. })
  232. }
  233. Filename = strings.Replace(Filename, "\\", "/", -1)
  234. var createAction = FILE_SUPERSEDED
  235. openFlags := 0
  236. switch data.CreateDisposition {
  237. case FILE_SUPERSEDE:
  238. createAction = FILE_SUPERSEDED
  239. openFlags = os.O_TRUNC | os.O_CREATE | os.O_RDWR
  240. case FILE_OPEN:
  241. createAction = FILE_OPENED
  242. case FILE_CREATE:
  243. createAction = FILE_CREATED
  244. openFlags = os.O_TRUNC | os.O_CREATE | os.O_RDWR //os.O_EXCL | os.O_RDWR
  245. case FILE_OPEN_IF:
  246. createAction = FILE_CREATED
  247. openFlags = os.O_CREATE
  248. case FILE_OVERWRITE:
  249. createAction = FILE_OVERWRITTEN
  250. openFlags = os.O_TRUNC
  251. case FILE_OVERWRITE_IF:
  252. createAction = FILE_OVERWRITTEN
  253. openFlags = os.O_TRUNC | os.O_CREATE | os.O_RDWR
  254. default:
  255. return ERR(data.Header, STATUS_INVALID_PARAMETER)
  256. }
  257. if true {
  258. if openFlags&os.O_TRUNC > 0 {
  259. absPath := ctx.session.GetAbsPath(Filename)
  260. if util.FileExist(absPath) {
  261. fmt.Printf("truncate")
  262. }
  263. }
  264. }
  265. if data.AccessMask&(FILE_WRITE_DATA|GENERIC_ALL|GENERIC_WRITE) != 0 {
  266. openFlags |= os.O_RDWR
  267. } else if openFlags&os.O_RDWR == 0 {
  268. openFlags |= os.O_RDONLY
  269. }
  270. fid := atomic.AddUint64(&ctx.session.fileNum, 1)
  271. guid := makeGUID(data.TreeID, fid)
  272. data.Header.Status = StatusOk
  273. resp := CreateResponse{
  274. Header: data.Header,
  275. StructureSize: 89,
  276. FileId: guid,
  277. CreateAction: createAction,
  278. }
  279. if data.TreeID == ctx.session.GetAnchor(NamedPipeShareName).tid {
  280. if Filename != k_srvsvc {
  281. return ERR(data.Header, STATUS_OBJECT_NAME_NOT_FOUND)
  282. }
  283. ctx.session.srvsvc = guid
  284. // absPath := ctx.session.GetAbsPath(Filename)
  285. // if !util.FileExist(absPath) {
  286. // f, err := os.Create(absPath)
  287. // if err == nil {
  288. // f.Close()
  289. // }
  290. // }
  291. ctx.session.openedFiles[guid] = ipc_file
  292. resp.FileAttributes |= FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NORMAL
  293. resp.AllocationSize = 0
  294. resp.EndOfFile = 0
  295. } else {
  296. var webfile webdav.File
  297. isDir := data.FileAttributes&FILE_ATTRIBUTE_DIRECTORY > 0
  298. if data.CreateDisposition == FILE_CREATE {
  299. // openFlags = (os.O_RDWR | os.O_CREATE | os.O_TRUNC)
  300. if isDir {
  301. absPath := ctx.session.GetAbsPath(Filename)
  302. err = ctx.Handle().FileSystem.Mkdir(context.Background(), absPath, 07777)
  303. if err != nil {
  304. return ERR(data.Header, STATUS_UNSUCCESSFUL)
  305. }
  306. openFlags = 0
  307. } else {
  308. }
  309. }
  310. ok, path, xattr := IsXAttr(Filename)
  311. if ok { //处理xattr数据
  312. // return ERR(data.Header, STATUS_NOT_IMPLEMENTED)
  313. // } else if (data.AccessMask&FILE_READ_ATTRIBUTES > 0 || data.AccessMask&DELETE > 0) && ok {
  314. absPath := ctx.session.GetAbsPath(path)
  315. absPathAttr := ctx.session.GetAbsPath(Filename)
  316. attrTag := XATTR_Key(xattr)
  317. // // com.apple.lastuseddate#PS
  318. // // com.apple.metadata _kMDItemUserTag s
  319. // // com.apple.metadata _kMDItemFavoriteRank
  320. openFlags = 0 // os.O_TRUNC会重置文件,所以需要把它换成0
  321. // webfile, err = ctx.Handle().FileSystem.OpenFile(context.Background(), absPath, openFlags, 0666)
  322. webfile = &webdavFile{filename: absPath, filenameAttr: absPathAttr, webdavType: attrTag}
  323. _, err = webfile.Stat()
  324. if err != nil {
  325. webfile.Close()
  326. return ERR(data.Header, STATUS_OBJECT_NAME_NOT_FOUND)
  327. }
  328. } else {
  329. absPath := ctx.session.GetAbsPath(Filename)
  330. webfile, err = ctx.Handle().FileSystem.OpenFile(context.Background(), absPath, openFlags, 0666)
  331. if err != nil {
  332. return ERR(data.Header, STATUS_OBJECT_NAME_NOT_FOUND)
  333. }
  334. }
  335. if os.IsNotExist(err) {
  336. return ERR(data.Header, STATUS_OBJECT_NAME_NOT_FOUND)
  337. }
  338. if err != nil {
  339. return ERR(data.Header, STATUS_UNSUCCESSFUL)
  340. }
  341. ctx.session.openedFiles[guid] = webfile
  342. fi, err := webfile.Stat()
  343. if err != nil {
  344. return ERR(data.Header, STATUS_UNSUCCESSFUL)
  345. }
  346. if fi.IsDir() {
  347. resp.FileAttributes |= FILE_ATTRIBUTE_DIRECTORY
  348. } else {
  349. resp.FileAttributes |= FILE_ATTRIBUTE_NORMAL
  350. resp.EndOfFile = uint64(fi.Size())
  351. resp.AllocationSize = uint64(fi.Size())
  352. }
  353. mtime := timeToFiletime(fi.ModTime())
  354. resp.CreationTime = mtime
  355. resp.LastWriteTime = mtime
  356. resp.ChangeTime = mtime
  357. resp.LastAccessTime = 0
  358. }
  359. ctx.latestFileId = guid
  360. resp.CreateContexts = createContextsResp
  361. return resp, nil
  362. }