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