fbc7f2e61b
This replaces built-in os.MkdirAll with a patched version that stops the recursion when reaching the volume part of the path. The original version would continue recursion, and for extended length paths end up with \\? as the top-level directory, and the error message would then be something like: mkdir \\?: The filename, directory name, or volume label syntax is incorrect.
101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
package docker
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
|
|
"github.com/rclone/rclone/fs"
|
|
"github.com/rclone/rclone/lib/atexit"
|
|
"github.com/rclone/rclone/lib/file"
|
|
)
|
|
|
|
// Server connects plugin with docker daemon by protocol
|
|
type Server http.Server
|
|
|
|
// NewServer creates new docker plugin server
|
|
func NewServer(drv *Driver) *Server {
|
|
return &Server{Handler: newRouter(drv)}
|
|
}
|
|
|
|
// Shutdown the server
|
|
func (s *Server) Shutdown(ctx context.Context) error {
|
|
hs := (*http.Server)(s)
|
|
return hs.Shutdown(ctx)
|
|
}
|
|
|
|
func (s *Server) serve(listener net.Listener, addr, tempFile string) error {
|
|
if tempFile != "" {
|
|
atexit.Register(func() {
|
|
// remove spec file or self-created unix socket
|
|
fs.Debugf(nil, "Removing stale file %s", tempFile)
|
|
_ = os.Remove(tempFile)
|
|
})
|
|
}
|
|
hs := (*http.Server)(s)
|
|
return hs.Serve(listener)
|
|
}
|
|
|
|
// ServeUnix makes the handler to listen for requests in a unix socket.
|
|
// It also creates the socket file in the right directory for docker to read.
|
|
func (s *Server) ServeUnix(path string, gid int) error {
|
|
listener, socketPath, err := newUnixListener(path, gid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if socketPath != "" {
|
|
path = socketPath
|
|
fs.Infof(nil, "Serving unix socket: %s", path)
|
|
} else {
|
|
fs.Infof(nil, "Serving systemd socket")
|
|
}
|
|
return s.serve(listener, path, socketPath)
|
|
}
|
|
|
|
// ServeTCP makes the handler listen for request on a given TCP address.
|
|
// It also writes the spec file in the right directory for docker to read.
|
|
func (s *Server) ServeTCP(addr, specDir string, tlsConfig *tls.Config, noSpec bool) error {
|
|
listener, err := net.Listen("tcp", addr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if tlsConfig != nil {
|
|
tlsConfig.NextProtos = []string{"http/1.1"}
|
|
listener = tls.NewListener(listener, tlsConfig)
|
|
}
|
|
addr = listener.Addr().String()
|
|
specFile := ""
|
|
if !noSpec {
|
|
specFile, err = writeSpecFile(addr, "tcp", specDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
fs.Infof(nil, "Serving TCP socket: %s", addr)
|
|
return s.serve(listener, addr, specFile)
|
|
}
|
|
|
|
func writeSpecFile(addr, proto, specDir string) (string, error) {
|
|
if specDir == "" && runtime.GOOS == "windows" {
|
|
specDir = os.TempDir()
|
|
}
|
|
if specDir == "" {
|
|
specDir = defSpecDir
|
|
}
|
|
if err := file.MkdirAll(specDir, 0755); err != nil {
|
|
return "", err
|
|
}
|
|
specFile := filepath.Join(specDir, "rclone.spec")
|
|
url := fmt.Sprintf("%s://%s", proto, addr)
|
|
if err := ioutil.WriteFile(specFile, []byte(url), 0644); err != nil {
|
|
return "", err
|
|
}
|
|
fs.Debugf(nil, "Plugin spec has been written to %s", specFile)
|
|
return specFile, nil
|
|
}
|