]> git.r.bdr.sh - rbdr/mobius/blame - hotline/transfer.go
Fix and refactor file transfers to handle resource forks
[rbdr/mobius] / hotline / transfer.go
CommitLineData
6988a057
JH
1package hotline
2
3import (
4 "bytes"
5 "encoding/binary"
6 "errors"
85767504 7 "io"
6988a057
JH
8)
9
df2735b2 10type transfer struct {
6988a057
JH
11 Protocol [4]byte // "HTXF" 0x48545846
12 ReferenceNumber [4]byte // Unique ID generated for the transfer
13 DataSize [4]byte // File size
14 RSVD [4]byte // Not implemented in Hotline Protocol
15}
16
df2735b2 17var HTXF = [4]byte{0x48, 0x54, 0x58, 0x46} // (HTXF) is the only supported transfer protocol
6988a057 18
df2735b2
JH
19func (tf *transfer) Write(b []byte) (int, error) {
20 if err := binary.Read(bytes.NewReader(b), binary.BigEndian, tf); err != nil {
21 return 0, err
6988a057
JH
22 }
23
df2735b2
JH
24 if tf.Protocol != HTXF {
25 return 0, errors.New("invalid protocol")
6988a057
JH
26 }
27
df2735b2 28 return len(b), nil
6988a057 29}
85767504
JH
30
31func receiveFile(conn io.Reader, targetFile io.Writer, resForkFile io.Writer) error {
32 ffhBuf := make([]byte, 24)
33 if _, err := conn.Read(ffhBuf); err != nil {
34 return err
35 }
36
37 var ffh FlatFileHeader
38 err := binary.Read(bytes.NewReader(ffhBuf), binary.BigEndian, &ffh)
39 if err != nil {
40 return err
41 }
42
43 ffifhBuf := make([]byte, 16)
44 if _, err := conn.Read(ffifhBuf); err != nil {
45 return err
46 }
47
48 var ffifh FlatFileInformationForkHeader
49 err = binary.Read(bytes.NewReader(ffifhBuf), binary.BigEndian, &ffifh)
50 if err != nil {
51 return err
52 }
53
54 var ffif FlatFileInformationFork
55
56 dataLen := binary.BigEndian.Uint32(ffifh.DataSize[:])
57 ffifBuf := make([]byte, dataLen)
58 if _, err := conn.Read(ffifBuf); err != nil {
59 return err
60 }
61 if err := ffif.UnmarshalBinary(ffifBuf); err != nil {
62 return err
63 }
64
65 var ffdfh FlatFileDataForkHeader
66 ffdfhBuf := make([]byte, 16)
67 if _, err := conn.Read(ffdfhBuf); err != nil {
68 return err
69 }
70 err = binary.Read(bytes.NewReader(ffdfhBuf), binary.BigEndian, &ffdfh)
71 if err != nil {
72 return err
73 }
74
75 // this will be zero if the file only has a resource fork
76 fileSize := int(binary.BigEndian.Uint32(ffdfh.DataSize[:]))
77
78 // Copy N bytes from conn to upload file
79 _, err = io.CopyN(targetFile, conn, int64(fileSize))
80 if err != nil {
81 return err
82 }
83
84 if ffh.ForkCount == [2]byte{0, 3} {
85 var resForkHeader FlatFileDataForkHeader
86 resForkBuf := make([]byte, 16)
87
88 if _, err := conn.Read(resForkBuf); err != nil {
89 return err
90 }
91 err = binary.Read(bytes.NewReader(resForkBuf), binary.BigEndian, &resForkHeader)
92 if err != nil {
93 return err
94 }
95
96 fileSize = int(binary.BigEndian.Uint32(resForkHeader.DataSize[:]))
97
98 _, err = io.CopyN(resForkFile, conn, int64(fileSize))
99 if err != nil {
100 return err
101 }
102 }
103 return nil
104}