github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/install/fuse_status_windows.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 //go:build windows 5 // +build windows 6 7 package install 8 9 import ( 10 "path/filepath" 11 "regexp" 12 13 "github.com/keybase/client/go/libkb" 14 "github.com/keybase/client/go/protocol/keybase1" 15 "golang.org/x/sys/windows/registry" 16 ) 17 18 func isDokanCurrent(log Log, path string) (bool, error) { 19 v, err := GetFileVersion(path) 20 if err != nil { 21 return false, err 22 } 23 // we're looking for 1.4.0.1000 24 result := v.Major > 1 || (v.Major == 1 && (v.Minor > 4 || (v.Minor == 4 && (v.Patch > 0 || (v.Patch == 0 && v.Build >= 1000))))) 25 26 if !result { 27 log.Info("dokan1.dll version: %d.%d.%d.%d, result %v\n", v.Major, v.Minor, v.Patch, v.Build, result) 28 } 29 return result, nil 30 } 31 32 func detectDokanDll(dokanPath string, log Log) bool { 33 exists, _ := libkb.FileExists(dokanPath) 34 35 log.Info("detectDokanDll: returning %v", exists) 36 return exists 37 } 38 39 // Read all the uninstall subkeys and find the ones with DisplayName starting with "Dokan Library" 40 // and containing "Bundle" 41 func findDokanUninstall(log Log, wow64 bool) (result string) { 42 dokanRegexp := regexp.MustCompile("^Dokan Library.*Bundle") 43 var access uint32 = registry.ENUMERATE_SUB_KEYS | registry.QUERY_VALUE 44 // Assume this is build 64 bit, so we need this flag to see 32 bit WOW registry 45 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa384129(v=vs.110).aspx 46 if wow64 { 47 access = access | registry.WOW64_32KEY 48 } 49 50 k, err := registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", access) 51 if err != nil { 52 log.Info("Error %s opening uninstall subkeys\n", err.Error()) 53 return 54 } 55 defer k.Close() 56 57 names, err := k.ReadSubKeyNames(-1) 58 if err != nil { 59 log.Info("Error %s reading subkeys\n", err.Error()) 60 return 61 } 62 for _, name := range names { 63 subKey, err := registry.OpenKey(k, name, registry.QUERY_VALUE) 64 if err != nil { 65 log.Info("Error %s opening subkey %s\n", err.Error(), name) 66 } 67 68 displayName, _, err := subKey.GetStringValue("DisplayName") 69 if err != nil { 70 // this error is not interesting to log 71 continue 72 } 73 if !dokanRegexp.MatchString(displayName) { 74 continue 75 } 76 77 result, _, err := subKey.GetStringValue("UninstallString") 78 if err != nil { 79 result, _, err = subKey.GetStringValue("QuietUninstallString") 80 } 81 if err != nil { 82 log.Info("Error %s opening subkey UninstallString", err.Error()) 83 } else { 84 return result 85 } 86 87 } 88 return 89 } 90 91 func KeybaseFuseStatus(bundleVersion string, log Log) keybase1.FuseStatus { 92 status := keybase1.FuseStatus{ 93 InstallStatus: keybase1.InstallStatus_NOT_INSTALLED, 94 InstallAction: keybase1.InstallAction_INSTALL, 95 } 96 dir, err := libkb.SystemDir() 97 if err != nil { 98 log.Info("KeybaseFuseStatus error getting system directory: %v", err) 99 return status 100 } 101 dokanPath := filepath.Join(dir, "dokan1.dll") 102 if !detectDokanDll(dokanPath, log) { 103 return status 104 } 105 status.InstallStatus = keybase1.InstallStatus_INSTALLED 106 status.InstallAction = keybase1.InstallAction_NONE 107 status.KextStarted = true 108 current, err := isDokanCurrent(log, dokanPath) 109 if err != nil { 110 log.Errorf(err.Error()) 111 return status 112 } 113 if !current { 114 status.InstallAction = keybase1.InstallAction_UPGRADE 115 } 116 uninstallString := findDokanUninstall(log, true) 117 if uninstallString == "" { 118 uninstallString = findDokanUninstall(log, false) 119 } 120 if uninstallString != "" { 121 status.Status.Fields = append(status.Status.Fields, keybase1.StringKVPair{Key: "uninstallString", Value: uninstallString}) 122 } else { 123 log.Info("No Dokan uninstall string found\n") 124 } 125 return status 126 }