func SyncFile(localPath string, remote string, timeout int, directIO bool) error {
	fileInfo, err := os.Stat(localPath)
	if err != nil {
		log.Errorf("Failed to get size of source file: %s, err: %s", localPath, err)
		return err
	}
	fileSize := fileInfo.Size()
	if directIO && fileSize%Blocks != 0 {
		return fmt.Errorf("Invalid directIO file block size: %v", fileSize)
	}
	log.Infof("source file size: %d, setting up directIO: %v", fileSize, directIO)
	var fileIo FileIoProcessor
	if directIO {
		fileIo, err = NewDirectFileIoProcessor(localPath, os.O_RDONLY, 0)
	} else {
		fileIo, err = NewBufferedFileIoProcessor(localPath, os.O_RDONLY, 0)
	}
	if err != nil {
		log.Error("Failed to open local source file:", localPath)
		return err
	}
	defer fileIo.Close()
	return SyncContent(fileIo.Name(), fileIo, fileSize, remote, timeout, directIO)
}
SyncFile synchronizes local file to remote host
package sparse
import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
)
const (
	httpClientTimeout = 5
	numBlocksInBatch  = 32
)
type syncClient struct {
	remote   string
	timeout  int
	sourceName string
	size int64
	rw ReaderWriterAt
	directIO bool
	httpClient *http.Client
}
type ReaderWriterAt interface {
	io.ReaderAt
	io.WriterAt
	GetDataLayout (ctx context.Context) (<-chan FileInterval, <-chan error, error)
}
func newHTTPClient() *http.Client {
	t := http.DefaultTransport.(*http.Transport).Clone()
	t.MaxIdleConns = 100
	t.MaxConnsPerHost = 100
	t.MaxIdleConnsPerHost = 100
	return &http.Client{
		Timeout:   httpClientTimeout * time.Second,
		Transport: t,
	}
}
func newSyncClient(remote string, timeout int, sourceName string, size int64, rw ReaderWriterAt, directIO bool) *syncClient {
	return &syncClient{remote: remote, timeout: timeout, sourceName: sourceName, size:size, rw: rw, directIO: directIO, httpClient: newHTTPClient()}
}
const connectionRetries = 5