X-Git-Url: https://git.r.bdr.sh/rbdr/mobius/blobdiff_plain/df2735b25a21d839746be31b43edb9e348086b0a..d4c152a4dba0eec7c8ecd13732900909f51b1c97:/hotline/transfer.go diff --git a/hotline/transfer.go b/hotline/transfer.go index fa431ce..78bd888 100644 --- a/hotline/transfer.go +++ b/hotline/transfer.go @@ -1,9 +1,11 @@ package hotline import ( + "bufio" "bytes" "encoding/binary" "errors" + "io" ) type transfer struct { @@ -26,3 +28,86 @@ func (tf *transfer) Write(b []byte) (int, error) { return len(b), nil } + +const fileCopyBufSize = 524288 // 512k +func receiveFile(conn io.Reader, targetFile io.Writer, resForkFile io.Writer) error { + ffhBuf := make([]byte, 24) + if _, err := conn.Read(ffhBuf); err != nil { + return err + } + + var ffh FlatFileHeader + err := binary.Read(bytes.NewReader(ffhBuf), binary.BigEndian, &ffh) + if err != nil { + return err + } + + ffifhBuf := make([]byte, 16) + if _, err := conn.Read(ffifhBuf); err != nil { + return err + } + + var ffifh FlatFileInformationForkHeader + err = binary.Read(bytes.NewReader(ffifhBuf), binary.BigEndian, &ffifh) + if err != nil { + return err + } + + var ffif FlatFileInformationFork + + dataLen := binary.BigEndian.Uint32(ffifh.DataSize[:]) + ffifBuf := make([]byte, dataLen) + if _, err := conn.Read(ffifBuf); err != nil { + return err + } + if err := ffif.UnmarshalBinary(ffifBuf); err != nil { + return err + } + + var ffdfh FlatFileDataForkHeader + ffdfhBuf := make([]byte, 16) + if _, err := conn.Read(ffdfhBuf); err != nil { + return err + } + err = binary.Read(bytes.NewReader(ffdfhBuf), binary.BigEndian, &ffdfh) + if err != nil { + return err + } + + // this will be zero if the file only has a resource fork + fileSize := int(binary.BigEndian.Uint32(ffdfh.DataSize[:])) + + bw := bufio.NewWriterSize(targetFile, fileCopyBufSize) + _, err = io.CopyN(bw, conn, int64(fileSize)) + if err != nil { + return err + } + if err := bw.Flush(); err != nil { + return err + } + + if ffh.ForkCount == [2]byte{0, 3} { + var resForkHeader FlatFileDataForkHeader + resForkBuf := make([]byte, 16) + resForkBufWrter := bufio.NewWriterSize(resForkFile, 16) + if _, err := io.CopyN(resForkBufWrter, conn, 16); err != nil { + return err + } + err = binary.Read(bytes.NewReader(resForkBuf), binary.BigEndian, &resForkHeader) + if err != nil { + return err + } + + fileSize = int(binary.BigEndian.Uint32(resForkHeader.DataSize[:])) + + bw = bufio.NewWriterSize(resForkFile, fileCopyBufSize) + _, err = io.CopyN(resForkFile, conn, int64(fileSize)) + if err != nil { + return err + } + if err := bw.Flush(); err != nil { + return err + } + } + return nil +}