github.com/keybase/client/go@v0.0.0-20240424154521-52f30ea26cb1/kbfs/libdokan/start.go (about) 1 // Copyright 2016 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 package libdokan 6 7 import ( 8 "fmt" 9 "os" 10 "path" 11 "strings" 12 13 "github.com/keybase/client/go/kbfs/dokan" 14 "github.com/keybase/client/go/kbfs/libfs" 15 "github.com/keybase/client/go/kbfs/libgit" 16 "github.com/keybase/client/go/kbfs/libkbfs" 17 "github.com/keybase/client/go/kbfs/simplefs" 18 "github.com/keybase/client/go/libkb" 19 "github.com/keybase/client/go/logger" 20 "github.com/keybase/client/go/protocol/keybase1" 21 "github.com/keybase/go-framed-msgpack-rpc/rpc" 22 "golang.org/x/net/context" 23 ) 24 25 // StartOptions are options for starting up 26 type StartOptions struct { 27 KbfsParams libkbfs.InitParams 28 RuntimeDir string 29 Label string 30 DokanConfig dokan.Config 31 ForceMount bool 32 SkipMount bool 33 MountPoint string 34 } 35 36 func startMounting(options StartOptions, 37 log logger.Logger, mi *libfs.MountInterrupter) error { 38 log.Info("Starting mount with options: %#v", options) 39 var mounter = &mounter{options: options, log: log} 40 err := mi.MountAndSetUnmount(mounter) 41 if err != nil { 42 return err 43 } 44 log.Info("Mounting the filesystem was a success!") 45 return mounter.c.BlockTillDone() 46 } 47 48 // Start the filesystem 49 func Start(options StartOptions, kbCtx libkbfs.Context) *libfs.Error { 50 // Hook simplefs implementation in. 51 shutdownSimpleFS := func(_ context.Context) error { return nil } 52 createSimpleFS := func( 53 libkbfsCtx libkbfs.Context, config libkbfs.Config) (rpc.Protocol, error) { 54 var simplefsIface keybase1.SimpleFSInterface 55 simplefsIface, shutdownSimpleFS = simplefs.NewSimpleFS( 56 libkbfsCtx, config) 57 return keybase1.SimpleFSProtocol(simplefsIface), nil 58 } 59 // Hook git implementation in. 60 shutdownGit := func() {} 61 createGitHandler := func( 62 libkbfsCtx libkbfs.Context, config libkbfs.Config) (rpc.Protocol, error) { 63 var handler keybase1.KBFSGitInterface 64 handler, shutdownGit = libgit.NewRPCHandlerWithCtx( 65 libkbfsCtx, config, &options.KbfsParams) 66 return keybase1.KBFSGitProtocol(handler), nil 67 } 68 defer func() { 69 err := shutdownSimpleFS(context.Background()) 70 if err != nil { 71 fmt.Fprintf(os.Stderr, "Couldn't shut down SimpleFS: %+v\n", err) 72 } 73 shutdownGit() 74 }() 75 76 // Patch the kbfsParams to inject two additional protocols. 77 options.KbfsParams.AdditionalProtocolCreators = []libkbfs.AdditionalProtocolCreator{ 78 createSimpleFS, createGitHandler, 79 } 80 81 log, err := libkbfs.InitLog(options.KbfsParams, kbCtx) 82 if err != nil { 83 return libfs.InitError(err.Error()) 84 } 85 86 mi := libfs.NewMountInterrupter(log) 87 ctx := context.Background() 88 config, err := libkbfs.Init( 89 ctx, kbCtx, options.KbfsParams, nil, mi.Done, log) 90 if err != nil { 91 return libfs.InitError(err.Error()) 92 } 93 94 defer libkbfs.Shutdown() 95 96 libfs.AddRootWrapper(config) 97 98 if options.RuntimeDir != "" { 99 err := os.MkdirAll(options.RuntimeDir, libkb.PermDir) 100 if err != nil { 101 return libfs.InitError(err.Error()) 102 } 103 info := libkb.NewServiceInfo(libkb.Version, libkbfs.PrereleaseBuild, options.Label, os.Getpid()) 104 err = info.WriteFile(path.Join(options.RuntimeDir, "kbfs.info"), log) 105 if err != nil { 106 return libfs.InitError(err.Error()) 107 } 108 } 109 110 if options.KbfsParams.Debug { 111 // Turn on debugging. TODO: allow a proper log file and 112 // style to be specified. 113 log.Configure("", true, "") 114 } 115 116 ctx, cancel := context.WithCancel(ctx) 117 defer cancel() 118 119 if options.MountPoint == "" { 120 // The mounter will detect this case and pick up the path from DokanConfig 121 options.MountPoint, err = config.KeybaseService().EstablishMountDir(ctx) 122 if err != nil { 123 return libfs.InitError(err.Error()) 124 } 125 log.CInfof(ctx, "Got mount dir from service: -%s-", options.MountPoint) 126 } 127 128 // There is misleading documentation that causes people to set their mount point to 129 // 'K' instead of 'K:'. Fix this here, rather than correct all the users with problems. 130 if len(options.MountPoint) == 1 { 131 options.MountPoint += ":" 132 log.CInfof(ctx, "Invalid single letter mount point, patching to %q", options.MountPoint) 133 } 134 135 options.DokanConfig.Path = options.MountPoint 136 137 if !options.SkipMount && !strings.EqualFold(options.MountPoint, "none") { 138 139 fs, err := NewFS(ctx, config, log) 140 if err != nil { 141 return libfs.InitError(err.Error()) 142 } 143 options.DokanConfig.FileSystem = fs 144 145 if newFolderNameErr != nil { 146 log.CWarningf(ctx, "Error guessing new folder name: %v", newFolderNameErr) 147 } 148 log.CDebugf(ctx, "New folder name guess: %q %q", newFolderName, newFolderAltName) 149 150 st, err := os.Lstat(options.MountPoint) 151 log.CDebugf(ctx, "Before mount check (should fail) Lstat(%q): %v,%v", options.MountPoint, st, err) 152 153 err = startMounting(options, log, mi) 154 if err != nil { 155 logDokanInfo(ctx, log) 156 // Abort on error if we were force mounting, otherwise continue. 157 if options.ForceMount { 158 // Cleanup when exiting in case the mount got dirty. 159 err = mi.Done() 160 if err != nil { 161 log.CErrorf(ctx, "Couldn't mount: %v", err) 162 } 163 return libfs.MountError(err.Error()) 164 } 165 log.CErrorf(ctx, "Running KBFS without a filesystem mount due to: %v", err) 166 } 167 } 168 169 log.CDebugf(ctx, "Entering mount wait") 170 mi.Wait() 171 log.CDebugf(ctx, "Filesystem unmounted - mount wait returned - exiting") 172 return nil 173 }