@@ -9,11 +9,13 @@ import (
99 "os/exec"
1010 "path/filepath"
1111 "runtime"
12+ "slices"
1213 "strings"
1314
1415 "github.com/sagernet/sing-box/cmd/internal/build_shared"
1516 "github.com/sagernet/sing-box/common/windivert"
1617 "github.com/sagernet/sing-box/log"
18+ "github.com/sagernet/sing-usbip/driverassets"
1719 E "github.com/sagernet/sing/common/exceptions"
1820)
1921
@@ -102,6 +104,67 @@ func build() error {
102104 if err != nil {
103105 return err
104106 }
107+ err = stageUSBIPDrivers (architecture , filepath .Dir (absoluteOutputPath ))
108+ if err != nil {
109+ return err
110+ }
111+ }
112+ return nil
113+ }
114+
115+ func stageUSBIPDrivers (architecture string , outputDirectory string ) error {
116+ driverPackages := []struct {
117+ assets map [string ]driverassets.Package
118+ assetDir string
119+ }{
120+ {driverassets .VBoxUSB , filepath .Join ("internal" , "vboxusb" , "assets" )},
121+ {driverassets .VHCI , filepath .Join ("internal" , "usbipvhci" , "assets" )},
122+ }
123+ var moduleDirectory string
124+ for _ , driverPackage := range driverPackages {
125+ staged := driverPackage .assets [architecture ]
126+ for _ , architecturePackage := range driverPackage .assets {
127+ for _ , file := range architecturePackage .Files {
128+ if slices .ContainsFunc (staged .Files , func (stagedFile driverassets.File ) bool {
129+ return stagedFile .Name == file .Name
130+ }) {
131+ continue
132+ }
133+ err := os .Remove (filepath .Join (outputDirectory , file .Name ))
134+ if err != nil && ! os .IsNotExist (err ) {
135+ return E .Cause (err , "remove stale " , file .Name )
136+ }
137+ }
138+ }
139+ if len (staged .Files ) == 0 {
140+ continue
141+ }
142+ if moduleDirectory == "" {
143+ listOutput , err := exec .Command ("go" , "list" , "-m" , "-f" , "{{.Dir}}" , "github.com/sagernet/sing-usbip" ).Output ()
144+ if err != nil {
145+ return E .Cause (err , "locate sing-usbip module directory" )
146+ }
147+ moduleDirectory = strings .TrimSpace (string (listOutput ))
148+ }
149+ for _ , file := range staged .Files {
150+ content , err := os .ReadFile (filepath .Join (moduleDirectory , driverPackage .assetDir , architecture , file .Name ))
151+ if err != nil {
152+ return E .Cause (err , "read " , file .Name )
153+ }
154+ checksum := sha256 .Sum256 (content )
155+ if hex .EncodeToString (checksum [:]) != file .SHA256 {
156+ return E .New (file .Name , " does not match the digest declared in sing-usbip/driverassets" )
157+ }
158+ targetPath := filepath .Join (outputDirectory , file .Name )
159+ stagedContent , err := os .ReadFile (targetPath )
160+ if err == nil && bytes .Equal (stagedContent , content ) {
161+ continue
162+ }
163+ err = os .WriteFile (targetPath , content , 0o644 )
164+ if err != nil {
165+ return E .Cause (err , "write " , file .Name )
166+ }
167+ }
105168 }
106169 return nil
107170}
@@ -164,7 +227,7 @@ func buildTags(operatingSystem string, architecture string, cgoEnabled bool) ([]
164227 }
165228 tags := strings .Split (strings .TrimSpace (string (content )), "," )
166229 if operatingSystem == "windows" {
167- tags = append (tags , "with_external_windivert" )
230+ tags = append (tags , "with_external_windivert" , "with_external_usbip_drivers" )
168231 }
169232 if debugEnabled {
170233 tags = append (tags , "debug" )
0 commit comments