]> git.r.bdr.sh - rbdr/mobius/blob - hotline/transfer.go
Initial implementation of file transfer resume
[rbdr/mobius] / hotline / transfer.go
1 package hotline
2
3 import (
4 "bufio"
5 "bytes"
6 "encoding/binary"
7 "errors"
8 "io"
9 )
10
11 type transfer struct {
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
18 var HTXF = [4]byte{0x48, 0x54, 0x58, 0x46} // (HTXF) is the only supported transfer protocol
19
20 func (tf *transfer) Write(b []byte) (int, error) {
21 if err := binary.Read(bytes.NewReader(b), binary.BigEndian, tf); err != nil {
22 return 0, err
23 }
24
25 if tf.Protocol != HTXF {
26 return 0, errors.New("invalid protocol")
27 }
28
29 return len(b), nil
30 }
31
32 const fileCopyBufSize = 524288 // 512k
33 func 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
80 bw := bufio.NewWriterSize(targetFile, fileCopyBufSize)
81 _, err = io.CopyN(bw, conn, int64(fileSize))
82 if err != nil {
83 return err
84 }
85 if err := bw.Flush(); err != nil {
86 return err
87 }
88
89 if ffh.ForkCount == [2]byte{0, 3} {
90 var resForkHeader FlatFileDataForkHeader
91 resForkBuf := make([]byte, 16)
92 resForkBufWrter := bufio.NewWriterSize(resForkFile, 16)
93 if _, err := io.CopyN(resForkBufWrter, conn, 16); 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
103 bw = bufio.NewWriterSize(resForkFile, fileCopyBufSize)
104 _, err = io.CopyN(resForkFile, conn, int64(fileSize))
105 if err != nil {
106 return err
107 }
108 if err := bw.Flush(); err != nil {
109 return err
110 }
111 }
112 return nil
113 }