lxd/rsync.go
func RsyncSend(name string, path string, conn *websocket.Conn, readWrapper func(io.ReadCloser) io.ReadCloser, features []string, bwlimit string, execPath string) error {
	cmd, dataSocket, stderr, err := rsyncSendSetup(name, path, bwlimit, execPath, features)
	if err != nil {
		return err
	}

	if dataSocket != nil {
		defer dataSocket.Close()
	}

	readPipe := io.ReadCloser(dataSocket)
	if readWrapper != nil {
		readPipe = readWrapper(dataSocket)
	}

	readDone, writeDone := shared.WebsocketMirror(conn, dataSocket, readPipe, nil, nil)

	chError := make(chan error, 1)
	go func() {
		err = cmd.Wait()
		if err != nil {
			dataSocket.Close()
			readPipe.Close()
		}
		chError <- err
	}()

	output, err := ioutil.ReadAll(stderr)
	if err != nil {
		cmd.Process.Kill()
	}

	err = <-chError
	if err != nil {
		logger.Errorf("Rsync send failed: %s: %s: %s", path, err, string(output))
	}

	<-readDone
	<-writeDone

	return err
}
func RsyncSend(name string, path string, conn *websocket.Conn, readWrapper func(io.ReadCloser) io.ReadCloser, features []string, bwlimit string, execPath string) error {
	cmd, dataSocket, stderr, err := rsyncSendSetup(name, path, bwlimit, execPath, features)
	if err != nil {
		return err
	}

	if dataSocket != nil {
		defer dataSocket.Close()
	}

	readPipe := io.ReadCloser(dataSocket)
	if readWrapper != nil {
		readPipe = readWrapper(dataSocket)
	}

	readDone, writeDone := shared.WebsocketMirror(conn, dataSocket, readPipe, nil, nil)

	chError := make(chan error, 1)
	go func() {
		err = cmd.Wait()
		if err != nil {
			dataSocket.Close()
			readPipe.Close()
		}
		chError <- err
	}()

	output, err := ioutil.ReadAll(stderr)
	if err != nil {
		cmd.Process.Kill()
	}

	err = <-chError
	if err != nil {
		logger.Errorf("Rsync send failed: %s: %s: %s", path, err, string(output))
	}

	<-readDone
	<-writeDone

	return err
}
// RsyncSend sets up the sending half of an rsync, to recursively send the
// directory pointed to by path over the websocket.