github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/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 sfs *simplefs.SimpleFS 55 sfs, shutdownSimpleFS = simplefs.NewSimpleFS( 56 libkbfsCtx, config) 57 config.AddResetForLoginTarget(sfs) 58 return keybase1.SimpleFSProtocol(sfs), nil 59 } 60 // Hook git implementation in. 61 shutdownGit := func() {} 62 createGitHandler := func( 63 libkbfsCtx libkbfs.Context, config libkbfs.Config) (rpc.Protocol, error) { 64 var handler keybase1.KBFSGitInterface 65 handler, shutdownGit = libgit.NewRPCHandlerWithCtx( 66 libkbfsCtx, config, &options.KbfsParams) 67 return keybase1.KBFSGitProtocol(handler), nil 68 } 69 defer func() { 70 err := shutdownSimpleFS(context.Background()) 71 if err != nil { 72 fmt.Fprintf(os.Stderr, "Couldn't shut down SimpleFS: %+v\n", err) 73 } 74 shutdownGit() 75 }() 76 77 // Patch the kbfsParams to inject two additional protocols. 78 options.KbfsParams.AdditionalProtocolCreators = []libkbfs.AdditionalProtocolCreator{ 79 createSimpleFS, createGitHandler, 80 } 81 82 log, err := libkbfs.InitLog(options.KbfsParams, kbCtx) 83 if err != nil { 84 return libfs.InitError(err.Error()) 85 } 86 87 mi := libfs.NewMountInterrupter(log) 88 ctx := context.Background() 89 config, err := libkbfs.Init( 90 ctx, kbCtx, options.KbfsParams, nil, mi.Done, log) 91 if err != nil { 92 return libfs.InitError(err.Error()) 93 } 94 95 defer libkbfs.Shutdown() 96 97 libfs.AddRootWrapper(config) 98 99 if options.RuntimeDir != "" { 100 err := os.MkdirAll(options.RuntimeDir, libkb.PermDir) 101 if err != nil { 102 return libfs.InitError(err.Error()) 103 } 104 info := libkb.NewServiceInfo(libkb.Version, libkbfs.PrereleaseBuild, options.Label, os.Getpid()) 105 err = info.WriteFile(path.Join(options.RuntimeDir, "kbfs.info"), log) 106 if err != nil { 107 return libfs.InitError(err.Error()) 108 } 109 } 110 111 if options.KbfsParams.Debug { 112 // Turn on debugging. TODO: allow a proper log file and 113 // style to be specified. 114 log.Configure("", true, "") 115 } 116 117 ctx, cancel := context.WithCancel(ctx) 118 defer cancel() 119 120 if options.MountPoint == "" { 121 // The mounter will detect this case and pick up the path from DokanConfig 122 options.MountPoint, err = config.KeybaseService().EstablishMountDir(ctx) 123 if err != nil { 124 return libfs.InitError(err.Error()) 125 } 126 log.CInfof(ctx, "Got mount dir from service: -%s-", options.MountPoint) 127 } 128 129 // There is misleading documentation that causes people to set their mount point to 130 // 'K' instead of 'K:'. Fix this here, rather than correct all the users with problems. 131 if len(options.MountPoint) == 1 { 132 options.MountPoint += ":" 133 log.CInfof(ctx, "Invalid single letter mount point, patching to %q", options.MountPoint) 134 } 135 136 options.DokanConfig.Path = options.MountPoint 137 138 if !options.SkipMount && !strings.EqualFold(options.MountPoint, "none") { 139 140 fs, err := NewFS(ctx, config, log) 141 if err != nil { 142 return libfs.InitError(err.Error()) 143 } 144 options.DokanConfig.FileSystem = fs 145 146 if newFolderNameErr != nil { 147 log.CWarningf(ctx, "Error guessing new folder name: %v", newFolderNameErr) 148 } 149 log.CDebugf(ctx, "New folder name guess: %q %q", newFolderName, newFolderAltName) 150 151 st, err := os.Lstat(options.MountPoint) 152 log.CDebugf(ctx, "Before mount check (should fail) Lstat(%q): %v,%v", options.MountPoint, st, err) 153 154 err = startMounting(options, log, mi) 155 if err != nil { 156 logDokanInfo(ctx, log) 157 // Abort on error if we were force mounting, otherwise continue. 158 if options.ForceMount { 159 // Cleanup when exiting in case the mount got dirty. 160 err = mi.Done() 161 if err != nil { 162 log.CErrorf(ctx, "Couldn't mount: %v", err) 163 } 164 return libfs.MountError(err.Error()) 165 } 166 log.CErrorf(ctx, "Running KBFS without a filesystem mount due to: %v", err) 167 } 168 } 169 170 log.CDebugf(ctx, "Entering mount wait") 171 mi.Wait() 172 log.CDebugf(ctx, "Filesystem unmounted - mount wait returned - exiting") 173 return nil 174 }