boxdd: Add custom working directory support

This commit is contained in:
世界
2026-07-15 12:41:39 +08:00
parent f017aacd7c
commit dd6db11c7d
3 changed files with 47 additions and 14 deletions
+5 -5
View File
@@ -2,9 +2,7 @@ package main
import (
"os"
"path/filepath"
"runtime"
"strings"
"time"
E "github.com/sagernet/sing/common/exceptions"
@@ -29,10 +27,12 @@ func preparePlatformWorkingDirectory() error {
if listenAddress != "" {
return os.MkdirAll(workingDirectory, 0o700)
}
if !strings.EqualFold(filepath.Clean(workingDirectory), filepath.Clean(defaultServiceWorkingDirectory)) {
return E.New("the Windows service working directory must be ", defaultServiceWorkingDirectory)
serviceWorkingDirectory, err := resolveWindowsServiceWorkingDirectory(workingDirectory)
if err != nil {
return err
}
return ensureWindowsWorkingDirectory(workingDirectory)
workingDirectory = serviceWorkingDirectory
return ensureWindowsWorkingDirectory(serviceWorkingDirectory)
}
type windowsService struct{}
+8 -9
View File
@@ -3,7 +3,6 @@ package main
import (
"errors"
"os"
"path/filepath"
"strings"
"time"
@@ -65,19 +64,24 @@ func serviceInstall() error {
if err != nil {
return E.Cause(err, "get executable path")
}
if !strings.EqualFold(filepath.Clean(commandServiceFlagWorkingDirectory), filepath.Clean(defaultServiceWorkingDirectory)) {
return E.New("the Windows service working directory must be ", defaultServiceWorkingDirectory)
serviceWorkingDirectory, err := resolveWindowsServiceWorkingDirectory(commandServiceFlagWorkingDirectory)
if err != nil {
return E.Cause(err, "validate working directory")
}
executablePath, err = secureWindowsInstallation(executablePath, commandServiceFlagAllowUnsafeInstallation)
if err != nil {
return E.Cause(err, "secure installation")
}
err = ensureWindowsWorkingDirectory(serviceWorkingDirectory)
if err != nil {
return E.Cause(err, "secure working directory")
}
manager, err := mgr.Connect()
if err != nil {
return E.Cause(err, "connect to service manager")
}
defer manager.Disconnect()
arguments := []string{"run", "--working-directory", defaultServiceWorkingDirectory}
arguments := []string{"run", "--working-directory", serviceWorkingDirectory}
config := mgr.Config{
DisplayName: serviceDisplayName,
Description: serviceDescriptionText,
@@ -132,11 +136,6 @@ func serviceInstall() error {
rollback()
return E.Cause(err, "secure service")
}
err = ensureWindowsWorkingDirectory(defaultServiceWorkingDirectory)
if err != nil {
rollback()
return E.Cause(err, "secure working directory")
}
err = eventlog.InstallAsEventCreate(serviceName, eventlog.Error|eventlog.Warning|eventlog.Info)
if err != nil && !strings.Contains(err.Error(), "already exists") {
rollback()
+34
View File
@@ -336,6 +336,40 @@ func validateFixedNTFSVolume(path string) (string, error) {
return filepath.Clean(volumePath), nil
}
func resolveWindowsServiceWorkingDirectory(path string) (string, error) {
if path == "" {
return "", E.New("missing daemon working directory")
}
absolutePath, err := filepath.Abs(path)
if err != nil {
return "", E.Cause(err, "resolve daemon working directory")
}
cleanPath := filepath.Clean(absolutePath)
parentPath := filepath.Dir(cleanPath)
parentAttributes, err := windowsFileAttributes(parentPath)
if err != nil {
return "", E.Cause(err, "query daemon working directory parent")
}
if parentAttributes&windows.FILE_ATTRIBUTE_DIRECTORY == 0 {
return "", E.New("daemon working directory parent is not a directory")
}
if parentAttributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
return "", E.New("daemon working directory parent is a reparse point")
}
volumeRoot, err := validateFixedNTFSVolume(parentPath)
if err != nil {
return "", E.Cause(err, "validate daemon working directory volume")
}
if strings.EqualFold(cleanPath, filepath.Clean(volumeRoot)) {
return "", E.New("daemon working directory must not be a volume root")
}
err = validateInstallationAncestors(parentPath, volumeRoot, true)
if err != nil {
return "", E.Cause(err, "validate daemon working directory ancestors")
}
return cleanPath, nil
}
func validateInstallationAncestors(path string, volumeRoot string, validatePermissions bool) error {
currentPath := filepath.Clean(path)
cleanVolumeRoot := filepath.Clean(volumeRoot)