packet.go 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295
  1. package sftp
  2. import (
  3. "bytes"
  4. "encoding"
  5. "encoding/binary"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "os"
  10. "reflect"
  11. )
  12. var (
  13. errLongPacket = errors.New("packet too long")
  14. errShortPacket = errors.New("packet too short")
  15. errUnknownExtendedPacket = errors.New("unknown extended packet")
  16. )
  17. const (
  18. maxMsgLength = 256 * 1024
  19. debugDumpTxPacket = false
  20. debugDumpRxPacket = false
  21. debugDumpTxPacketBytes = false
  22. debugDumpRxPacketBytes = false
  23. )
  24. func marshalUint32(b []byte, v uint32) []byte {
  25. return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
  26. }
  27. func marshalUint64(b []byte, v uint64) []byte {
  28. return marshalUint32(marshalUint32(b, uint32(v>>32)), uint32(v))
  29. }
  30. func marshalString(b []byte, v string) []byte {
  31. return append(marshalUint32(b, uint32(len(v))), v...)
  32. }
  33. func marshalFileInfo(b []byte, fi os.FileInfo) []byte {
  34. // attributes variable struct, and also variable per protocol version
  35. // spec version 3 attributes:
  36. // uint32 flags
  37. // uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE
  38. // uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID
  39. // uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID
  40. // uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
  41. // uint32 atime present only if flag SSH_FILEXFER_ACMODTIME
  42. // uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME
  43. // uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
  44. // string extended_type
  45. // string extended_data
  46. // ... more extended data (extended_type - extended_data pairs),
  47. // so that number of pairs equals extended_count
  48. flags, fileStat := fileStatFromInfo(fi)
  49. b = marshalUint32(b, flags)
  50. if flags&sshFileXferAttrSize != 0 {
  51. b = marshalUint64(b, fileStat.Size)
  52. }
  53. if flags&sshFileXferAttrUIDGID != 0 {
  54. b = marshalUint32(b, fileStat.UID)
  55. b = marshalUint32(b, fileStat.GID)
  56. }
  57. if flags&sshFileXferAttrPermissions != 0 {
  58. b = marshalUint32(b, fileStat.Mode)
  59. }
  60. if flags&sshFileXferAttrACmodTime != 0 {
  61. b = marshalUint32(b, fileStat.Atime)
  62. b = marshalUint32(b, fileStat.Mtime)
  63. }
  64. if flags&sshFileXferAttrExtended != 0 {
  65. b = marshalUint32(b, uint32(len(fileStat.Extended)))
  66. for _, attr := range fileStat.Extended {
  67. b = marshalString(b, attr.ExtType)
  68. b = marshalString(b, attr.ExtData)
  69. }
  70. }
  71. return b
  72. }
  73. func marshalStatus(b []byte, err StatusError) []byte {
  74. b = marshalUint32(b, err.Code)
  75. b = marshalString(b, err.msg)
  76. b = marshalString(b, err.lang)
  77. return b
  78. }
  79. func marshal(b []byte, v interface{}) []byte {
  80. if v == nil {
  81. return b
  82. }
  83. switch v := v.(type) {
  84. case uint8:
  85. return append(b, v)
  86. case uint32:
  87. return marshalUint32(b, v)
  88. case uint64:
  89. return marshalUint64(b, v)
  90. case string:
  91. return marshalString(b, v)
  92. case os.FileInfo:
  93. return marshalFileInfo(b, v)
  94. default:
  95. switch d := reflect.ValueOf(v); d.Kind() {
  96. case reflect.Struct:
  97. for i, n := 0, d.NumField(); i < n; i++ {
  98. b = marshal(b, d.Field(i).Interface())
  99. }
  100. return b
  101. case reflect.Slice:
  102. for i, n := 0, d.Len(); i < n; i++ {
  103. b = marshal(b, d.Index(i).Interface())
  104. }
  105. return b
  106. default:
  107. panic(fmt.Sprintf("marshal(%#v): cannot handle type %T", v, v))
  108. }
  109. }
  110. }
  111. func unmarshalUint32(b []byte) (uint32, []byte) {
  112. v := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
  113. return v, b[4:]
  114. }
  115. func unmarshalUint32Safe(b []byte) (uint32, []byte, error) {
  116. var v uint32
  117. if len(b) < 4 {
  118. return 0, nil, errShortPacket
  119. }
  120. v, b = unmarshalUint32(b)
  121. return v, b, nil
  122. }
  123. func unmarshalUint64(b []byte) (uint64, []byte) {
  124. h, b := unmarshalUint32(b)
  125. l, b := unmarshalUint32(b)
  126. return uint64(h)<<32 | uint64(l), b
  127. }
  128. func unmarshalUint64Safe(b []byte) (uint64, []byte, error) {
  129. var v uint64
  130. if len(b) < 8 {
  131. return 0, nil, errShortPacket
  132. }
  133. v, b = unmarshalUint64(b)
  134. return v, b, nil
  135. }
  136. func unmarshalString(b []byte) (string, []byte) {
  137. n, b := unmarshalUint32(b)
  138. return string(b[:n]), b[n:]
  139. }
  140. func unmarshalStringSafe(b []byte) (string, []byte, error) {
  141. n, b, err := unmarshalUint32Safe(b)
  142. if err != nil {
  143. return "", nil, err
  144. }
  145. if int64(n) > int64(len(b)) {
  146. return "", nil, errShortPacket
  147. }
  148. return string(b[:n]), b[n:], nil
  149. }
  150. func unmarshalAttrs(b []byte) (*FileStat, []byte) {
  151. flags, b := unmarshalUint32(b)
  152. return unmarshalFileStat(flags, b)
  153. }
  154. func unmarshalFileStat(flags uint32, b []byte) (*FileStat, []byte) {
  155. var fs FileStat
  156. if flags&sshFileXferAttrSize == sshFileXferAttrSize {
  157. fs.Size, b, _ = unmarshalUint64Safe(b)
  158. }
  159. if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID {
  160. fs.UID, b, _ = unmarshalUint32Safe(b)
  161. }
  162. if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID {
  163. fs.GID, b, _ = unmarshalUint32Safe(b)
  164. }
  165. if flags&sshFileXferAttrPermissions == sshFileXferAttrPermissions {
  166. fs.Mode, b, _ = unmarshalUint32Safe(b)
  167. }
  168. if flags&sshFileXferAttrACmodTime == sshFileXferAttrACmodTime {
  169. fs.Atime, b, _ = unmarshalUint32Safe(b)
  170. fs.Mtime, b, _ = unmarshalUint32Safe(b)
  171. }
  172. if flags&sshFileXferAttrExtended == sshFileXferAttrExtended {
  173. var count uint32
  174. count, b, _ = unmarshalUint32Safe(b)
  175. ext := make([]StatExtended, count)
  176. for i := uint32(0); i < count; i++ {
  177. var typ string
  178. var data string
  179. typ, b, _ = unmarshalStringSafe(b)
  180. data, b, _ = unmarshalStringSafe(b)
  181. ext[i] = StatExtended{
  182. ExtType: typ,
  183. ExtData: data,
  184. }
  185. }
  186. fs.Extended = ext
  187. }
  188. return &fs, b
  189. }
  190. func unmarshalStatus(id uint32, data []byte) error {
  191. sid, data := unmarshalUint32(data)
  192. if sid != id {
  193. return &unexpectedIDErr{id, sid}
  194. }
  195. code, data := unmarshalUint32(data)
  196. msg, data, _ := unmarshalStringSafe(data)
  197. lang, _, _ := unmarshalStringSafe(data)
  198. return &StatusError{
  199. Code: code,
  200. msg: msg,
  201. lang: lang,
  202. }
  203. }
  204. type packetMarshaler interface {
  205. marshalPacket() (header, payload []byte, err error)
  206. }
  207. func marshalPacket(m encoding.BinaryMarshaler) (header, payload []byte, err error) {
  208. if m, ok := m.(packetMarshaler); ok {
  209. return m.marshalPacket()
  210. }
  211. header, err = m.MarshalBinary()
  212. return
  213. }
  214. // sendPacket marshals p according to RFC 4234.
  215. func sendPacket(w io.Writer, m encoding.BinaryMarshaler) error {
  216. header, payload, err := marshalPacket(m)
  217. if err != nil {
  218. return fmt.Errorf("binary marshaller failed: %w", err)
  219. }
  220. length := len(header) + len(payload) - 4 // subtract the uint32(length) from the start
  221. if debugDumpTxPacketBytes {
  222. debug("send packet: %s %d bytes %x%x", fxp(header[4]), length, header[5:], payload)
  223. } else if debugDumpTxPacket {
  224. debug("send packet: %s %d bytes", fxp(header[4]), length)
  225. }
  226. binary.BigEndian.PutUint32(header[:4], uint32(length))
  227. if _, err := w.Write(header); err != nil {
  228. return fmt.Errorf("failed to send packet: %w", err)
  229. }
  230. if len(payload) > 0 {
  231. if _, err := w.Write(payload); err != nil {
  232. return fmt.Errorf("failed to send packet payload: %w", err)
  233. }
  234. }
  235. return nil
  236. }
  237. func recvPacket(r io.Reader, alloc *allocator, orderID uint32) (uint8, []byte, error) {
  238. var b []byte
  239. if alloc != nil {
  240. b = alloc.GetPage(orderID)
  241. } else {
  242. b = make([]byte, 4)
  243. }
  244. if _, err := io.ReadFull(r, b[:4]); err != nil {
  245. return 0, nil, err
  246. }
  247. length, _ := unmarshalUint32(b)
  248. if length > maxMsgLength {
  249. debug("recv packet %d bytes too long", length)
  250. return 0, nil, errLongPacket
  251. }
  252. if length == 0 {
  253. debug("recv packet of 0 bytes too short")
  254. return 0, nil, errShortPacket
  255. }
  256. if alloc == nil {
  257. b = make([]byte, length)
  258. }
  259. if _, err := io.ReadFull(r, b[:length]); err != nil {
  260. // ReadFull only returns EOF if it has read no bytes.
  261. // In this case, that means a partial packet, and thus unexpected.
  262. if err == io.EOF {
  263. err = io.ErrUnexpectedEOF
  264. }
  265. debug("recv packet %d bytes: err %v", length, err)
  266. return 0, nil, err
  267. }
  268. if debugDumpRxPacketBytes {
  269. debug("recv packet: %s %d bytes %x", fxp(b[0]), length, b[1:length])
  270. } else if debugDumpRxPacket {
  271. debug("recv packet: %s %d bytes", fxp(b[0]), length)
  272. }
  273. return b[0], b[1:length], nil
  274. }
  275. type extensionPair struct {
  276. Name string
  277. Data string
  278. }
  279. func unmarshalExtensionPair(b []byte) (extensionPair, []byte, error) {
  280. var ep extensionPair
  281. var err error
  282. ep.Name, b, err = unmarshalStringSafe(b)
  283. if err != nil {
  284. return ep, b, err
  285. }
  286. ep.Data, b, err = unmarshalStringSafe(b)
  287. return ep, b, err
  288. }
  289. // Here starts the definition of packets along with their MarshalBinary
  290. // implementations.
  291. // Manually writing the marshalling logic wins us a lot of time and
  292. // allocation.
  293. type sshFxInitPacket struct {
  294. Version uint32
  295. Extensions []extensionPair
  296. }
  297. func (p *sshFxInitPacket) MarshalBinary() ([]byte, error) {
  298. l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(version)
  299. for _, e := range p.Extensions {
  300. l += 4 + len(e.Name) + 4 + len(e.Data)
  301. }
  302. b := make([]byte, 4, l)
  303. b = append(b, sshFxpInit)
  304. b = marshalUint32(b, p.Version)
  305. for _, e := range p.Extensions {
  306. b = marshalString(b, e.Name)
  307. b = marshalString(b, e.Data)
  308. }
  309. return b, nil
  310. }
  311. func (p *sshFxInitPacket) UnmarshalBinary(b []byte) error {
  312. var err error
  313. if p.Version, b, err = unmarshalUint32Safe(b); err != nil {
  314. return err
  315. }
  316. for len(b) > 0 {
  317. var ep extensionPair
  318. ep, b, err = unmarshalExtensionPair(b)
  319. if err != nil {
  320. return err
  321. }
  322. p.Extensions = append(p.Extensions, ep)
  323. }
  324. return nil
  325. }
  326. type sshFxVersionPacket struct {
  327. Version uint32
  328. Extensions []sshExtensionPair
  329. }
  330. type sshExtensionPair struct {
  331. Name, Data string
  332. }
  333. func (p *sshFxVersionPacket) MarshalBinary() ([]byte, error) {
  334. l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(version)
  335. for _, e := range p.Extensions {
  336. l += 4 + len(e.Name) + 4 + len(e.Data)
  337. }
  338. b := make([]byte, 4, l)
  339. b = append(b, sshFxpVersion)
  340. b = marshalUint32(b, p.Version)
  341. for _, e := range p.Extensions {
  342. b = marshalString(b, e.Name)
  343. b = marshalString(b, e.Data)
  344. }
  345. return b, nil
  346. }
  347. func marshalIDStringPacket(packetType byte, id uint32, str string) ([]byte, error) {
  348. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  349. 4 + len(str)
  350. b := make([]byte, 4, l)
  351. b = append(b, packetType)
  352. b = marshalUint32(b, id)
  353. b = marshalString(b, str)
  354. return b, nil
  355. }
  356. func unmarshalIDString(b []byte, id *uint32, str *string) error {
  357. var err error
  358. *id, b, err = unmarshalUint32Safe(b)
  359. if err != nil {
  360. return err
  361. }
  362. *str, _, err = unmarshalStringSafe(b)
  363. return err
  364. }
  365. type sshFxpReaddirPacket struct {
  366. ID uint32
  367. Handle string
  368. }
  369. func (p *sshFxpReaddirPacket) id() uint32 { return p.ID }
  370. func (p *sshFxpReaddirPacket) MarshalBinary() ([]byte, error) {
  371. return marshalIDStringPacket(sshFxpReaddir, p.ID, p.Handle)
  372. }
  373. func (p *sshFxpReaddirPacket) UnmarshalBinary(b []byte) error {
  374. return unmarshalIDString(b, &p.ID, &p.Handle)
  375. }
  376. type sshFxpOpendirPacket struct {
  377. ID uint32
  378. Path string
  379. }
  380. func (p *sshFxpOpendirPacket) id() uint32 { return p.ID }
  381. func (p *sshFxpOpendirPacket) MarshalBinary() ([]byte, error) {
  382. return marshalIDStringPacket(sshFxpOpendir, p.ID, p.Path)
  383. }
  384. func (p *sshFxpOpendirPacket) UnmarshalBinary(b []byte) error {
  385. return unmarshalIDString(b, &p.ID, &p.Path)
  386. }
  387. type sshFxpLstatPacket struct {
  388. ID uint32
  389. Path string
  390. }
  391. func (p *sshFxpLstatPacket) id() uint32 { return p.ID }
  392. func (p *sshFxpLstatPacket) MarshalBinary() ([]byte, error) {
  393. return marshalIDStringPacket(sshFxpLstat, p.ID, p.Path)
  394. }
  395. func (p *sshFxpLstatPacket) UnmarshalBinary(b []byte) error {
  396. return unmarshalIDString(b, &p.ID, &p.Path)
  397. }
  398. type sshFxpStatPacket struct {
  399. ID uint32
  400. Path string
  401. }
  402. func (p *sshFxpStatPacket) id() uint32 { return p.ID }
  403. func (p *sshFxpStatPacket) MarshalBinary() ([]byte, error) {
  404. return marshalIDStringPacket(sshFxpStat, p.ID, p.Path)
  405. }
  406. func (p *sshFxpStatPacket) UnmarshalBinary(b []byte) error {
  407. return unmarshalIDString(b, &p.ID, &p.Path)
  408. }
  409. type sshFxpFstatPacket struct {
  410. ID uint32
  411. Handle string
  412. }
  413. func (p *sshFxpFstatPacket) id() uint32 { return p.ID }
  414. func (p *sshFxpFstatPacket) MarshalBinary() ([]byte, error) {
  415. return marshalIDStringPacket(sshFxpFstat, p.ID, p.Handle)
  416. }
  417. func (p *sshFxpFstatPacket) UnmarshalBinary(b []byte) error {
  418. return unmarshalIDString(b, &p.ID, &p.Handle)
  419. }
  420. type sshFxpClosePacket struct {
  421. ID uint32
  422. Handle string
  423. }
  424. func (p *sshFxpClosePacket) id() uint32 { return p.ID }
  425. func (p *sshFxpClosePacket) MarshalBinary() ([]byte, error) {
  426. return marshalIDStringPacket(sshFxpClose, p.ID, p.Handle)
  427. }
  428. func (p *sshFxpClosePacket) UnmarshalBinary(b []byte) error {
  429. return unmarshalIDString(b, &p.ID, &p.Handle)
  430. }
  431. type sshFxpRemovePacket struct {
  432. ID uint32
  433. Filename string
  434. }
  435. func (p *sshFxpRemovePacket) id() uint32 { return p.ID }
  436. func (p *sshFxpRemovePacket) MarshalBinary() ([]byte, error) {
  437. return marshalIDStringPacket(sshFxpRemove, p.ID, p.Filename)
  438. }
  439. func (p *sshFxpRemovePacket) UnmarshalBinary(b []byte) error {
  440. return unmarshalIDString(b, &p.ID, &p.Filename)
  441. }
  442. type sshFxpRmdirPacket struct {
  443. ID uint32
  444. Path string
  445. }
  446. func (p *sshFxpRmdirPacket) id() uint32 { return p.ID }
  447. func (p *sshFxpRmdirPacket) MarshalBinary() ([]byte, error) {
  448. return marshalIDStringPacket(sshFxpRmdir, p.ID, p.Path)
  449. }
  450. func (p *sshFxpRmdirPacket) UnmarshalBinary(b []byte) error {
  451. return unmarshalIDString(b, &p.ID, &p.Path)
  452. }
  453. type sshFxpSymlinkPacket struct {
  454. ID uint32
  455. // The order of the arguments to the SSH_FXP_SYMLINK method was inadvertently reversed.
  456. // Unfortunately, the reversal was not noticed until the server was widely deployed.
  457. // Covered in Section 4.1 of https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
  458. Targetpath string
  459. Linkpath string
  460. }
  461. func (p *sshFxpSymlinkPacket) id() uint32 { return p.ID }
  462. func (p *sshFxpSymlinkPacket) MarshalBinary() ([]byte, error) {
  463. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  464. 4 + len(p.Targetpath) +
  465. 4 + len(p.Linkpath)
  466. b := make([]byte, 4, l)
  467. b = append(b, sshFxpSymlink)
  468. b = marshalUint32(b, p.ID)
  469. b = marshalString(b, p.Targetpath)
  470. b = marshalString(b, p.Linkpath)
  471. return b, nil
  472. }
  473. func (p *sshFxpSymlinkPacket) UnmarshalBinary(b []byte) error {
  474. var err error
  475. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  476. return err
  477. } else if p.Targetpath, b, err = unmarshalStringSafe(b); err != nil {
  478. return err
  479. } else if p.Linkpath, _, err = unmarshalStringSafe(b); err != nil {
  480. return err
  481. }
  482. return nil
  483. }
  484. type sshFxpHardlinkPacket struct {
  485. ID uint32
  486. Oldpath string
  487. Newpath string
  488. }
  489. func (p *sshFxpHardlinkPacket) id() uint32 { return p.ID }
  490. func (p *sshFxpHardlinkPacket) MarshalBinary() ([]byte, error) {
  491. const ext = "hardlink@openssh.com"
  492. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  493. 4 + len(ext) +
  494. 4 + len(p.Oldpath) +
  495. 4 + len(p.Newpath)
  496. b := make([]byte, 4, l)
  497. b = append(b, sshFxpExtended)
  498. b = marshalUint32(b, p.ID)
  499. b = marshalString(b, ext)
  500. b = marshalString(b, p.Oldpath)
  501. b = marshalString(b, p.Newpath)
  502. return b, nil
  503. }
  504. type sshFxpReadlinkPacket struct {
  505. ID uint32
  506. Path string
  507. }
  508. func (p *sshFxpReadlinkPacket) id() uint32 { return p.ID }
  509. func (p *sshFxpReadlinkPacket) MarshalBinary() ([]byte, error) {
  510. return marshalIDStringPacket(sshFxpReadlink, p.ID, p.Path)
  511. }
  512. func (p *sshFxpReadlinkPacket) UnmarshalBinary(b []byte) error {
  513. return unmarshalIDString(b, &p.ID, &p.Path)
  514. }
  515. type sshFxpRealpathPacket struct {
  516. ID uint32
  517. Path string
  518. }
  519. func (p *sshFxpRealpathPacket) id() uint32 { return p.ID }
  520. func (p *sshFxpRealpathPacket) MarshalBinary() ([]byte, error) {
  521. return marshalIDStringPacket(sshFxpRealpath, p.ID, p.Path)
  522. }
  523. func (p *sshFxpRealpathPacket) UnmarshalBinary(b []byte) error {
  524. return unmarshalIDString(b, &p.ID, &p.Path)
  525. }
  526. type sshFxpNameAttr struct {
  527. Name string
  528. LongName string
  529. Attrs []interface{}
  530. }
  531. func (p *sshFxpNameAttr) MarshalBinary() ([]byte, error) {
  532. var b []byte
  533. b = marshalString(b, p.Name)
  534. b = marshalString(b, p.LongName)
  535. for _, attr := range p.Attrs {
  536. b = marshal(b, attr)
  537. }
  538. return b, nil
  539. }
  540. type sshFxpNamePacket struct {
  541. ID uint32
  542. NameAttrs []*sshFxpNameAttr
  543. }
  544. func (p *sshFxpNamePacket) marshalPacket() ([]byte, []byte, error) {
  545. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  546. 4
  547. b := make([]byte, 4, l)
  548. b = append(b, sshFxpName)
  549. b = marshalUint32(b, p.ID)
  550. b = marshalUint32(b, uint32(len(p.NameAttrs)))
  551. var payload []byte
  552. for _, na := range p.NameAttrs {
  553. ab, err := na.MarshalBinary()
  554. if err != nil {
  555. return nil, nil, err
  556. }
  557. payload = append(payload, ab...)
  558. }
  559. return b, payload, nil
  560. }
  561. func (p *sshFxpNamePacket) MarshalBinary() ([]byte, error) {
  562. header, payload, err := p.marshalPacket()
  563. return append(header, payload...), err
  564. }
  565. type sshFxpOpenPacket struct {
  566. ID uint32
  567. Path string
  568. Pflags uint32
  569. Flags uint32 // ignored
  570. }
  571. func (p *sshFxpOpenPacket) id() uint32 { return p.ID }
  572. func (p *sshFxpOpenPacket) MarshalBinary() ([]byte, error) {
  573. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  574. 4 + len(p.Path) +
  575. 4 + 4
  576. b := make([]byte, 4, l)
  577. b = append(b, sshFxpOpen)
  578. b = marshalUint32(b, p.ID)
  579. b = marshalString(b, p.Path)
  580. b = marshalUint32(b, p.Pflags)
  581. b = marshalUint32(b, p.Flags)
  582. return b, nil
  583. }
  584. func (p *sshFxpOpenPacket) UnmarshalBinary(b []byte) error {
  585. var err error
  586. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  587. return err
  588. } else if p.Path, b, err = unmarshalStringSafe(b); err != nil {
  589. return err
  590. } else if p.Pflags, b, err = unmarshalUint32Safe(b); err != nil {
  591. return err
  592. } else if p.Flags, _, err = unmarshalUint32Safe(b); err != nil {
  593. return err
  594. }
  595. return nil
  596. }
  597. type sshFxpReadPacket struct {
  598. ID uint32
  599. Len uint32
  600. Offset uint64
  601. Handle string
  602. }
  603. func (p *sshFxpReadPacket) id() uint32 { return p.ID }
  604. func (p *sshFxpReadPacket) MarshalBinary() ([]byte, error) {
  605. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  606. 4 + len(p.Handle) +
  607. 8 + 4 // uint64 + uint32
  608. b := make([]byte, 4, l)
  609. b = append(b, sshFxpRead)
  610. b = marshalUint32(b, p.ID)
  611. b = marshalString(b, p.Handle)
  612. b = marshalUint64(b, p.Offset)
  613. b = marshalUint32(b, p.Len)
  614. return b, nil
  615. }
  616. func (p *sshFxpReadPacket) UnmarshalBinary(b []byte) error {
  617. var err error
  618. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  619. return err
  620. } else if p.Handle, b, err = unmarshalStringSafe(b); err != nil {
  621. return err
  622. } else if p.Offset, b, err = unmarshalUint64Safe(b); err != nil {
  623. return err
  624. } else if p.Len, _, err = unmarshalUint32Safe(b); err != nil {
  625. return err
  626. }
  627. return nil
  628. }
  629. // We need allocate bigger slices with extra capacity to avoid a re-allocation in sshFxpDataPacket.MarshalBinary
  630. // So, we need: uint32(length) + byte(type) + uint32(id) + uint32(data_length)
  631. const dataHeaderLen = 4 + 1 + 4 + 4
  632. func (p *sshFxpReadPacket) getDataSlice(alloc *allocator, orderID uint32) []byte {
  633. dataLen := p.Len
  634. if dataLen > maxTxPacket {
  635. dataLen = maxTxPacket
  636. }
  637. if alloc != nil {
  638. // GetPage returns a slice with capacity = maxMsgLength this is enough to avoid new allocations in
  639. // sshFxpDataPacket.MarshalBinary
  640. return alloc.GetPage(orderID)[:dataLen]
  641. }
  642. // allocate with extra space for the header
  643. return make([]byte, dataLen, dataLen+dataHeaderLen)
  644. }
  645. type sshFxpRenamePacket struct {
  646. ID uint32
  647. Oldpath string
  648. Newpath string
  649. }
  650. func (p *sshFxpRenamePacket) id() uint32 { return p.ID }
  651. func (p *sshFxpRenamePacket) MarshalBinary() ([]byte, error) {
  652. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  653. 4 + len(p.Oldpath) +
  654. 4 + len(p.Newpath)
  655. b := make([]byte, 4, l)
  656. b = append(b, sshFxpRename)
  657. b = marshalUint32(b, p.ID)
  658. b = marshalString(b, p.Oldpath)
  659. b = marshalString(b, p.Newpath)
  660. return b, nil
  661. }
  662. func (p *sshFxpRenamePacket) UnmarshalBinary(b []byte) error {
  663. var err error
  664. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  665. return err
  666. } else if p.Oldpath, b, err = unmarshalStringSafe(b); err != nil {
  667. return err
  668. } else if p.Newpath, _, err = unmarshalStringSafe(b); err != nil {
  669. return err
  670. }
  671. return nil
  672. }
  673. type sshFxpPosixRenamePacket struct {
  674. ID uint32
  675. Oldpath string
  676. Newpath string
  677. }
  678. func (p *sshFxpPosixRenamePacket) id() uint32 { return p.ID }
  679. func (p *sshFxpPosixRenamePacket) MarshalBinary() ([]byte, error) {
  680. const ext = "posix-rename@openssh.com"
  681. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  682. 4 + len(ext) +
  683. 4 + len(p.Oldpath) +
  684. 4 + len(p.Newpath)
  685. b := make([]byte, 4, l)
  686. b = append(b, sshFxpExtended)
  687. b = marshalUint32(b, p.ID)
  688. b = marshalString(b, ext)
  689. b = marshalString(b, p.Oldpath)
  690. b = marshalString(b, p.Newpath)
  691. return b, nil
  692. }
  693. type sshFxpWritePacket struct {
  694. ID uint32
  695. Length uint32
  696. Offset uint64
  697. Handle string
  698. Data []byte
  699. }
  700. func (p *sshFxpWritePacket) id() uint32 { return p.ID }
  701. func (p *sshFxpWritePacket) marshalPacket() ([]byte, []byte, error) {
  702. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  703. 4 + len(p.Handle) +
  704. 8 + // uint64
  705. 4
  706. b := make([]byte, 4, l)
  707. b = append(b, sshFxpWrite)
  708. b = marshalUint32(b, p.ID)
  709. b = marshalString(b, p.Handle)
  710. b = marshalUint64(b, p.Offset)
  711. b = marshalUint32(b, p.Length)
  712. return b, p.Data, nil
  713. }
  714. func (p *sshFxpWritePacket) MarshalBinary() ([]byte, error) {
  715. header, payload, err := p.marshalPacket()
  716. return append(header, payload...), err
  717. }
  718. func (p *sshFxpWritePacket) UnmarshalBinary(b []byte) error {
  719. var err error
  720. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  721. return err
  722. } else if p.Handle, b, err = unmarshalStringSafe(b); err != nil {
  723. return err
  724. } else if p.Offset, b, err = unmarshalUint64Safe(b); err != nil {
  725. return err
  726. } else if p.Length, b, err = unmarshalUint32Safe(b); err != nil {
  727. return err
  728. } else if uint32(len(b)) < p.Length {
  729. return errShortPacket
  730. }
  731. p.Data = b[:p.Length]
  732. return nil
  733. }
  734. type sshFxpMkdirPacket struct {
  735. ID uint32
  736. Flags uint32 // ignored
  737. Path string
  738. }
  739. func (p *sshFxpMkdirPacket) id() uint32 { return p.ID }
  740. func (p *sshFxpMkdirPacket) MarshalBinary() ([]byte, error) {
  741. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  742. 4 + len(p.Path) +
  743. 4 // uint32
  744. b := make([]byte, 4, l)
  745. b = append(b, sshFxpMkdir)
  746. b = marshalUint32(b, p.ID)
  747. b = marshalString(b, p.Path)
  748. b = marshalUint32(b, p.Flags)
  749. return b, nil
  750. }
  751. func (p *sshFxpMkdirPacket) UnmarshalBinary(b []byte) error {
  752. var err error
  753. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  754. return err
  755. } else if p.Path, b, err = unmarshalStringSafe(b); err != nil {
  756. return err
  757. } else if p.Flags, _, err = unmarshalUint32Safe(b); err != nil {
  758. return err
  759. }
  760. return nil
  761. }
  762. type sshFxpSetstatPacket struct {
  763. ID uint32
  764. Flags uint32
  765. Path string
  766. Attrs interface{}
  767. }
  768. type sshFxpFsetstatPacket struct {
  769. ID uint32
  770. Flags uint32
  771. Handle string
  772. Attrs interface{}
  773. }
  774. func (p *sshFxpSetstatPacket) id() uint32 { return p.ID }
  775. func (p *sshFxpFsetstatPacket) id() uint32 { return p.ID }
  776. func (p *sshFxpSetstatPacket) marshalPacket() ([]byte, []byte, error) {
  777. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  778. 4 + len(p.Path) +
  779. 4 // uint32
  780. b := make([]byte, 4, l)
  781. b = append(b, sshFxpSetstat)
  782. b = marshalUint32(b, p.ID)
  783. b = marshalString(b, p.Path)
  784. b = marshalUint32(b, p.Flags)
  785. payload := marshal(nil, p.Attrs)
  786. return b, payload, nil
  787. }
  788. func (p *sshFxpSetstatPacket) MarshalBinary() ([]byte, error) {
  789. header, payload, err := p.marshalPacket()
  790. return append(header, payload...), err
  791. }
  792. func (p *sshFxpFsetstatPacket) marshalPacket() ([]byte, []byte, error) {
  793. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  794. 4 + len(p.Handle) +
  795. 4 // uint32
  796. b := make([]byte, 4, l)
  797. b = append(b, sshFxpFsetstat)
  798. b = marshalUint32(b, p.ID)
  799. b = marshalString(b, p.Handle)
  800. b = marshalUint32(b, p.Flags)
  801. payload := marshal(nil, p.Attrs)
  802. return b, payload, nil
  803. }
  804. func (p *sshFxpFsetstatPacket) MarshalBinary() ([]byte, error) {
  805. header, payload, err := p.marshalPacket()
  806. return append(header, payload...), err
  807. }
  808. func (p *sshFxpSetstatPacket) UnmarshalBinary(b []byte) error {
  809. var err error
  810. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  811. return err
  812. } else if p.Path, b, err = unmarshalStringSafe(b); err != nil {
  813. return err
  814. } else if p.Flags, b, err = unmarshalUint32Safe(b); err != nil {
  815. return err
  816. }
  817. p.Attrs = b
  818. return nil
  819. }
  820. func (p *sshFxpFsetstatPacket) UnmarshalBinary(b []byte) error {
  821. var err error
  822. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  823. return err
  824. } else if p.Handle, b, err = unmarshalStringSafe(b); err != nil {
  825. return err
  826. } else if p.Flags, b, err = unmarshalUint32Safe(b); err != nil {
  827. return err
  828. }
  829. p.Attrs = b
  830. return nil
  831. }
  832. type sshFxpHandlePacket struct {
  833. ID uint32
  834. Handle string
  835. }
  836. func (p *sshFxpHandlePacket) MarshalBinary() ([]byte, error) {
  837. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  838. 4 + len(p.Handle)
  839. b := make([]byte, 4, l)
  840. b = append(b, sshFxpHandle)
  841. b = marshalUint32(b, p.ID)
  842. b = marshalString(b, p.Handle)
  843. return b, nil
  844. }
  845. type sshFxpStatusPacket struct {
  846. ID uint32
  847. StatusError
  848. }
  849. func (p *sshFxpStatusPacket) MarshalBinary() ([]byte, error) {
  850. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  851. 4 +
  852. 4 + len(p.StatusError.msg) +
  853. 4 + len(p.StatusError.lang)
  854. b := make([]byte, 4, l)
  855. b = append(b, sshFxpStatus)
  856. b = marshalUint32(b, p.ID)
  857. b = marshalStatus(b, p.StatusError)
  858. return b, nil
  859. }
  860. type sshFxpDataPacket struct {
  861. ID uint32
  862. Length uint32
  863. Data []byte
  864. }
  865. func (p *sshFxpDataPacket) marshalPacket() ([]byte, []byte, error) {
  866. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  867. 4
  868. b := make([]byte, 4, l)
  869. b = append(b, sshFxpData)
  870. b = marshalUint32(b, p.ID)
  871. b = marshalUint32(b, p.Length)
  872. return b, p.Data, nil
  873. }
  874. // MarshalBinary encodes the receiver into a binary form and returns the result.
  875. // To avoid a new allocation the Data slice must have a capacity >= Length + 9
  876. //
  877. // This is hand-coded rather than just append(header, payload...),
  878. // in order to try and reuse the r.Data backing store in the packet.
  879. func (p *sshFxpDataPacket) MarshalBinary() ([]byte, error) {
  880. b := append(p.Data, make([]byte, dataHeaderLen)...)
  881. copy(b[dataHeaderLen:], p.Data[:p.Length])
  882. // b[0:4] will be overwritten with the length in sendPacket
  883. b[4] = sshFxpData
  884. binary.BigEndian.PutUint32(b[5:9], p.ID)
  885. binary.BigEndian.PutUint32(b[9:13], p.Length)
  886. return b, nil
  887. }
  888. func (p *sshFxpDataPacket) UnmarshalBinary(b []byte) error {
  889. var err error
  890. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  891. return err
  892. } else if p.Length, b, err = unmarshalUint32Safe(b); err != nil {
  893. return err
  894. } else if uint32(len(b)) < p.Length {
  895. return errShortPacket
  896. }
  897. p.Data = b[:p.Length]
  898. return nil
  899. }
  900. type sshFxpStatvfsPacket struct {
  901. ID uint32
  902. Path string
  903. }
  904. func (p *sshFxpStatvfsPacket) id() uint32 { return p.ID }
  905. func (p *sshFxpStatvfsPacket) MarshalBinary() ([]byte, error) {
  906. const ext = "statvfs@openssh.com"
  907. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  908. 4 + len(ext) +
  909. 4 + len(p.Path)
  910. b := make([]byte, 4, l)
  911. b = append(b, sshFxpExtended)
  912. b = marshalUint32(b, p.ID)
  913. b = marshalString(b, ext)
  914. b = marshalString(b, p.Path)
  915. return b, nil
  916. }
  917. // A StatVFS contains statistics about a filesystem.
  918. type StatVFS struct {
  919. ID uint32
  920. Bsize uint64 /* file system block size */
  921. Frsize uint64 /* fundamental fs block size */
  922. Blocks uint64 /* number of blocks (unit f_frsize) */
  923. Bfree uint64 /* free blocks in file system */
  924. Bavail uint64 /* free blocks for non-root */
  925. Files uint64 /* total file inodes */
  926. Ffree uint64 /* free file inodes */
  927. Favail uint64 /* free file inodes for to non-root */
  928. Fsid uint64 /* file system id */
  929. Flag uint64 /* bit mask of f_flag values */
  930. Namemax uint64 /* maximum filename length */
  931. }
  932. // TotalSpace calculates the amount of total space in a filesystem.
  933. func (p *StatVFS) TotalSpace() uint64 {
  934. return p.Frsize * p.Blocks
  935. }
  936. // FreeSpace calculates the amount of free space in a filesystem.
  937. func (p *StatVFS) FreeSpace() uint64 {
  938. return p.Frsize * p.Bfree
  939. }
  940. // marshalPacket converts to ssh_FXP_EXTENDED_REPLY packet binary format
  941. func (p *StatVFS) marshalPacket() ([]byte, []byte, error) {
  942. header := []byte{0, 0, 0, 0, sshFxpExtendedReply}
  943. var buf bytes.Buffer
  944. err := binary.Write(&buf, binary.BigEndian, p)
  945. return header, buf.Bytes(), err
  946. }
  947. // MarshalBinary encodes the StatVFS as an SSH_FXP_EXTENDED_REPLY packet.
  948. func (p *StatVFS) MarshalBinary() ([]byte, error) {
  949. header, payload, err := p.marshalPacket()
  950. return append(header, payload...), err
  951. }
  952. type sshFxpFsyncPacket struct {
  953. ID uint32
  954. Handle string
  955. }
  956. func (p *sshFxpFsyncPacket) id() uint32 { return p.ID }
  957. func (p *sshFxpFsyncPacket) MarshalBinary() ([]byte, error) {
  958. const ext = "fsync@openssh.com"
  959. l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id)
  960. 4 + len(ext) +
  961. 4 + len(p.Handle)
  962. b := make([]byte, 4, l)
  963. b = append(b, sshFxpExtended)
  964. b = marshalUint32(b, p.ID)
  965. b = marshalString(b, ext)
  966. b = marshalString(b, p.Handle)
  967. return b, nil
  968. }
  969. type sshFxpExtendedPacket struct {
  970. ID uint32
  971. ExtendedRequest string
  972. SpecificPacket interface {
  973. serverRespondablePacket
  974. readonly() bool
  975. }
  976. }
  977. func (p *sshFxpExtendedPacket) id() uint32 { return p.ID }
  978. func (p *sshFxpExtendedPacket) readonly() bool {
  979. if p.SpecificPacket == nil {
  980. return true
  981. }
  982. return p.SpecificPacket.readonly()
  983. }
  984. func (p *sshFxpExtendedPacket) respond(svr *Server) responsePacket {
  985. if p.SpecificPacket == nil {
  986. return statusFromError(p.ID, nil)
  987. }
  988. return p.SpecificPacket.respond(svr)
  989. }
  990. func (p *sshFxpExtendedPacket) UnmarshalBinary(b []byte) error {
  991. var err error
  992. bOrig := b
  993. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  994. return err
  995. } else if p.ExtendedRequest, _, err = unmarshalStringSafe(b); err != nil {
  996. return err
  997. }
  998. // specific unmarshalling
  999. switch p.ExtendedRequest {
  1000. case "statvfs@openssh.com":
  1001. p.SpecificPacket = &sshFxpExtendedPacketStatVFS{}
  1002. case "posix-rename@openssh.com":
  1003. p.SpecificPacket = &sshFxpExtendedPacketPosixRename{}
  1004. case "hardlink@openssh.com":
  1005. p.SpecificPacket = &sshFxpExtendedPacketHardlink{}
  1006. default:
  1007. return fmt.Errorf("packet type %v: %w", p.SpecificPacket, errUnknownExtendedPacket)
  1008. }
  1009. return p.SpecificPacket.UnmarshalBinary(bOrig)
  1010. }
  1011. type sshFxpExtendedPacketStatVFS struct {
  1012. ID uint32
  1013. ExtendedRequest string
  1014. Path string
  1015. }
  1016. func (p *sshFxpExtendedPacketStatVFS) id() uint32 { return p.ID }
  1017. func (p *sshFxpExtendedPacketStatVFS) readonly() bool { return true }
  1018. func (p *sshFxpExtendedPacketStatVFS) UnmarshalBinary(b []byte) error {
  1019. var err error
  1020. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  1021. return err
  1022. } else if p.ExtendedRequest, b, err = unmarshalStringSafe(b); err != nil {
  1023. return err
  1024. } else if p.Path, _, err = unmarshalStringSafe(b); err != nil {
  1025. return err
  1026. }
  1027. return nil
  1028. }
  1029. type sshFxpExtendedPacketPosixRename struct {
  1030. ID uint32
  1031. ExtendedRequest string
  1032. Oldpath string
  1033. Newpath string
  1034. }
  1035. func (p *sshFxpExtendedPacketPosixRename) id() uint32 { return p.ID }
  1036. func (p *sshFxpExtendedPacketPosixRename) readonly() bool { return false }
  1037. func (p *sshFxpExtendedPacketPosixRename) UnmarshalBinary(b []byte) error {
  1038. var err error
  1039. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  1040. return err
  1041. } else if p.ExtendedRequest, b, err = unmarshalStringSafe(b); err != nil {
  1042. return err
  1043. } else if p.Oldpath, b, err = unmarshalStringSafe(b); err != nil {
  1044. return err
  1045. } else if p.Newpath, _, err = unmarshalStringSafe(b); err != nil {
  1046. return err
  1047. }
  1048. return nil
  1049. }
  1050. func (p *sshFxpExtendedPacketPosixRename) respond(s *Server) responsePacket {
  1051. err := os.Rename(s.toLocalPath(p.Oldpath), s.toLocalPath(p.Newpath))
  1052. return statusFromError(p.ID, err)
  1053. }
  1054. type sshFxpExtendedPacketHardlink struct {
  1055. ID uint32
  1056. ExtendedRequest string
  1057. Oldpath string
  1058. Newpath string
  1059. }
  1060. // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
  1061. func (p *sshFxpExtendedPacketHardlink) id() uint32 { return p.ID }
  1062. func (p *sshFxpExtendedPacketHardlink) readonly() bool { return true }
  1063. func (p *sshFxpExtendedPacketHardlink) UnmarshalBinary(b []byte) error {
  1064. var err error
  1065. if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
  1066. return err
  1067. } else if p.ExtendedRequest, b, err = unmarshalStringSafe(b); err != nil {
  1068. return err
  1069. } else if p.Oldpath, b, err = unmarshalStringSafe(b); err != nil {
  1070. return err
  1071. } else if p.Newpath, _, err = unmarshalStringSafe(b); err != nil {
  1072. return err
  1073. }
  1074. return nil
  1075. }
  1076. func (p *sshFxpExtendedPacketHardlink) respond(s *Server) responsePacket {
  1077. err := os.Link(s.toLocalPath(p.Oldpath), s.toLocalPath(p.Newpath))
  1078. return statusFromError(p.ID, err)
  1079. }