github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/dokan/loaddll.go (about) 1 // Copyright 2018 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 //go:build windows 6 // +build windows 7 8 package dokan 9 10 /* 11 #include "bridge.h" 12 */ 13 import "C" 14 15 import ( 16 "bytes" 17 "fmt" 18 "path/filepath" 19 "runtime" 20 21 "golang.org/x/sys/windows" 22 ) 23 24 const firstSafeDokanVersion = 121 25 26 const shortPath = `DOKAN1.DLL` 27 const syswow64 = `C:\WINDOWS\SYSWOW64\` 28 const system32 = `C:\WINDOWS\SYSTEM32\` 29 30 type errorPrinter struct { 31 buf bytes.Buffer 32 } 33 34 func (ep *errorPrinter) Printf(s string, os ...interface{}) { 35 fmt.Fprintf(&ep.buf, s, os...) 36 } 37 38 // loadLibrary calls win32 LoadLibrary and logs the result. 39 func loadLibrary(epc *errorPrinter, path string) (windows.Handle, error) { 40 hdl, err := windows.LoadLibrary(path) 41 epc.Printf("LoadLibrary(%q) -> %v,%v\n", path, hdl, err) 42 return hdl, err 43 } 44 45 // doLoadDLL tries to load the dokan DLL from various locations. 46 func doLoadDLL(epc *errorPrinter, path string) (windows.Handle, error) { 47 var guessPath bool 48 epc.Printf("loadDokanDLL %q\n", path) 49 if path == "" { 50 path = shortPath 51 guessPath = true 52 } else { 53 path = filepath.FromSlash(path) 54 } 55 const loadLibrarySearchSystem32 = 0x800 56 const flags = loadLibrarySearchSystem32 57 hdl, err := windows.LoadLibraryEx(path, 0, flags) 58 epc.Printf("loadDokanDLL LoadLibraryEx(%q,0,%x) -> %v,%v\n", path, flags, hdl, err) 59 if err == nil || !guessPath { 60 return hdl, err 61 } 62 // User probably has not installed KB2533623 which is a security update 63 // from 2011. Without this Windows security update loading libraries 64 // is unsafe on Windows. 65 // Continue to try to load the DLL regardless. 66 67 if runtime.GOARCH == `386` { 68 hdl, err = loadLibrary(epc, syswow64+shortPath) 69 if err == nil { 70 return hdl, nil 71 } 72 } 73 hdl, err = loadLibrary(epc, system32+shortPath) 74 if err == nil { 75 return hdl, nil 76 } 77 hdl, err = loadLibrary(epc, shortPath) 78 if err == nil { 79 return hdl, nil 80 } 81 err = fmt.Errorf("loadDokanDLL: cannot load Dokan DLL: %v", err) 82 epc.Printf("ERROR: %v\n", err) 83 return 0, err 84 } 85 86 func doLoadDokanAndGetSymbols(epc *errorPrinter, path string) error { 87 hdl, err := doLoadDLL(epc, path) 88 if err != nil { 89 return err 90 } 91 var dokanVersionProc, dokanDriverVersionProc C.uintptr_t 92 for _, v := range []struct { 93 name string 94 ptr *C.uintptr_t 95 }{{`DokanRemoveMountPoint`, &C.kbfsLibdokanPtr_RemoveMountPoint}, 96 {`DokanOpenRequestorToken`, &C.kbfsLibdokanPtr_OpenRequestorToken}, 97 {`DokanMain`, &C.kbfsLibdokanPtr_Main}, 98 {`DokanVersion`, &dokanVersionProc}, 99 {`DokanDriverVersion`, &dokanDriverVersionProc}} { 100 uptr, err := windows.GetProcAddress(hdl, v.name) 101 if err != nil { 102 return fmt.Errorf(`GetProcAddress(%q) -> %v,%v`, v.name, uptr, err) 103 } 104 *v.ptr = C.uintptr_t(uptr) 105 } 106 ver := C.kbfsLibDokan_GetVersion(dokanVersionProc) 107 epc.Printf("Dokan version: %d driver %d, required %d\n", 108 ver, C.kbfsLibDokan_GetVersion(dokanDriverVersionProc), 109 firstSafeDokanVersion) 110 111 if ver < firstSafeDokanVersion { 112 windows.Close(hdl) 113 return fmt.Errorf("Aborting due to too old Dokan: detected %d < required %d", 114 ver, firstSafeDokanVersion) 115 } 116 return nil 117 } 118 119 // loadDokanDLL tries to load the dokan DLL from 120 // the given path. Empty path is allowed and will 121 // result in the location being guessed. 122 func loadDokanDLL(cfg *Config) error { 123 var epc errorPrinter 124 err := doLoadDokanAndGetSymbols(&epc, cfg.DllPath) 125 cfg.FileSystem.Printf("%s", epc.buf.Bytes()) 126 return err 127 }