1// Copyright (c) 2020 Simon Ser <contact@emersion.fr>2// Copyright (c) 2026 Sören Tempel <soeren@soeren-tempel.net>3//4// Permission is hereby granted, free of charge, to any person obtaining a copy5// of this software and associated documentation files (the "Software"), to deal6// in the Software without restriction, including without limitation the rights7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell8// copies of the Software, and to permit persons to whom the Software is9// furnished to do so, subject to the following conditions:10//11// The above copyright notice and this permission notice shall be included in all12// copies or substantial portions of the Software.13//14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20// SOFTWARE.2122package main2324import (25 "errors"26 "flag"27 "fmt"28 "log"29 "net"30 "net/http"31 "os"32 "os/signal"33 "path/filepath"34 "strconv"35 "syscall"3637 "github.com/emersion/go-webdav"38)3940func main() {41 var addr, mode string42 cmdName := filepath.Base(os.Args[0])43 defAddr := filepath.Join(os.TempDir(), cmdName)44 // Keep this backwards-compatible with the default webdav-server options.45 // See https://github.com/emersion/go-webdav/blob/master/cmd/webdav-server/main.go46 flag.StringVar(&addr, "addr", defAddr, "listening address (path for Unix socket)")47 flag.StringVar(&mode, "mode", "", "file mode in octal for the Unix socket")48 flag.Usage = func() {49 fmt.Fprintf(flag.CommandLine.Output(), "usage: %s [options...] [directory]\n", cmdName)50 flag.PrintDefaults()51 }52 flag.Parse()5354 path := flag.Arg(0)55 if path == "" {56 path = "."57 }5859 handler := webdav.Handler{60 FileSystem: webdav.LocalFileSystem(path),61 }6263 ln, err := net.Listen("unix", addr)64 if err != nil {65 log.Fatalf("failed to create listener on address %q: %v", addr, err)66 }67 if mode != "" {68 modeBits, err := strconv.ParseUint(mode, 8, 32)69 if err != nil {70 log.Fatalf("file mode has invalid value %q", mode)71 }72 mode := os.FileMode(modeBits)73 if err := os.Chmod(addr, mode); err != nil {74 log.Fatalf("failed to chmod Unix socket: %v", err)75 }76 }7778 srv := &http.Server{Addr: addr, Handler: &handler}79 defer srv.Close() // This will close 'ln' too.8081 sigCh := make(chan os.Signal, 1)82 signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP)83 go func() {84 <-sigCh85 log.Print("stopping server")86 if err := srv.Close(); err != nil {87 log.Printf("failed to close server: %v", err)88 }89 }()9091 log.Printf("WebDAV server listening on %v", addr)92 if err := srv.Serve(ln); !errors.Is(err, http.ErrServerClosed) {93 log.Fatalf("failed to serve: %v", err)94 }95}