]>
Commit | Line | Data |
---|---|---|
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 | } |