github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/data/path.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 data 6 7 import ( 8 "fmt" 9 "strings" 10 11 "github.com/keybase/client/go/kbfs/tlf" 12 "github.com/keybase/client/go/kbfs/tlfhandle" 13 ) 14 15 // Path represents the full KBFS path to a particular location, so 16 // that a flush can traverse backwards and fix up ids along the way. 17 type Path struct { 18 FolderBranch 19 Path []PathNode 20 ChildObfuscator Obfuscator 21 } 22 23 // IsValid returns true if the path has at least one node (for the 24 // root). 25 func (p Path) IsValid() bool { 26 if p.Tlf == tlf.NullID { 27 return false 28 } 29 30 if len(p.Path) < 1 { 31 return false 32 } 33 34 for _, n := range p.Path { 35 if !n.IsValid() { 36 return false 37 } 38 } 39 40 return true 41 } 42 43 // IsValidForNotification returns true if the path has at least one 44 // node (for the root), and the first element of the path is non-empty 45 // and does not start with "<", which indicates an unnotifiable path. 46 func (p Path) IsValidForNotification() bool { 47 if !p.IsValid() { 48 return false 49 } 50 51 if p.Tlf == (tlf.NullID) { 52 return false 53 } 54 55 namePlain := p.Path[0].Name.Plaintext() 56 return len(namePlain) > 0 && !strings.HasPrefix(namePlain, "<") 57 } 58 59 // HasValidParent returns true if this path is valid and 60 // `ParentPath()` is a valid path. 61 func (p Path) HasValidParent() bool { 62 return len(p.Path) >= 2 && p.ParentPath().IsValid() 63 } 64 65 // TailName returns the name of the final node in the Path. Must be 66 // called with a valid path. 67 func (p Path) TailName() PathPartString { 68 return p.Path[len(p.Path)-1].Name 69 } 70 71 // TailPointer returns the BlockPointer of the final node in the Path. 72 // Must be called with a valid path. 73 func (p Path) TailPointer() BlockPointer { 74 return p.Path[len(p.Path)-1].BlockPointer 75 } 76 77 // TailRef returns the BlockRef of the final node in the Path. Must 78 // be called with a valid path. 79 func (p Path) TailRef() BlockRef { 80 return p.Path[len(p.Path)-1].Ref() 81 } 82 83 // DebugString returns a string representation of the path with all 84 // branch and pointer information. 85 func (p Path) DebugString() string { 86 debugNames := make([]string, 0, len(p.Path)) 87 for _, node := range p.Path { 88 debugNames = append(debugNames, node.DebugString()) 89 } 90 return fmt.Sprintf("%s:%s", p.FolderBranch, strings.Join(debugNames, "/")) 91 } 92 93 // String implements the fmt.Stringer interface for Path. 94 func (p Path) String() string { 95 names := make([]string, 0, len(p.Path)) 96 for _, node := range p.Path { 97 names = append(names, node.Name.String()) 98 } 99 return strings.Join(names, "/") 100 } 101 102 // Plaintext returns an unobfuscated string for this path. 103 func (p Path) Plaintext() string { 104 names := make([]string, 0, len(p.Path)) 105 for _, node := range p.Path { 106 names = append(names, node.Name.Plaintext()) 107 } 108 return strings.Join(names, "/") 109 } 110 111 // PlaintextSansTlf returns an unobfuscated string for this path, rooted at the 112 // TLF. 113 // 114 // Examples: /keybase/private/alice -> "/", true 115 // 116 // /keybase/private/alice/folder -> "/folder", true 117 // /keybase/private -> "", false 118 func (p Path) PlaintextSansTlf() (string, bool) { 119 if len(p.Path) == 0 { 120 return "", false 121 } 122 names := make([]string, 0, len(p.Path)-1) 123 for _, node := range p.Path[1:] { 124 names = append(names, node.Name.Plaintext()) 125 } 126 return "/" + strings.Join(names, "/"), true 127 } 128 129 // CanonicalPathString returns an obfuscated canonical 130 // representation of the full path, always prefaced by /keybase. This 131 // may require conversion to a platform specific path, for example, by 132 // replacing /keybase with the appropriate drive letter on Windows. It 133 // also, might need conversion if on a different run mode, for 134 // example, /keybase.staging on Unix type platforms. 135 func (p Path) CanonicalPathString() string { 136 return tlfhandle.BuildCanonicalPathForTlf(p.Tlf, p.String()) 137 } 138 139 // CanonicalPathPlaintext returns an un-obfuscated canonical 140 // representation of the full path, always prefaced by /keybase. This 141 // may require conversion to a platform specific path, for example, by 142 // replacing /keybase with the appropriate drive letter on Windows. It 143 // also, might need conversion if on a different run mode, for 144 // example, /keybase.staging on Unix type platforms. 145 func (p Path) CanonicalPathPlaintext() string { 146 return tlfhandle.BuildCanonicalPathForTlf(p.Tlf, p.Plaintext()) 147 } 148 149 // ParentPath returns a new Path representing the parent subdirectory 150 // of this Path. Must be called with a valid path. Should not be 151 // called with a path of only a single node, as that would produce an 152 // invalid path. 153 func (p Path) ParentPath() *Path { 154 return &Path{ 155 FolderBranch: p.FolderBranch, 156 Path: p.Path[:len(p.Path)-1], 157 ChildObfuscator: p.Path[len(p.Path)-1].Name.Obfuscator(), 158 } 159 } 160 161 // ChildPath returns a new Path with the addition of a new entry 162 // with the given name and BlockPointer. 163 func (p Path) ChildPath( 164 name PathPartString, ptr BlockPointer, childObfuscator Obfuscator) Path { 165 child := Path{ 166 FolderBranch: p.FolderBranch, 167 Path: make([]PathNode, len(p.Path), len(p.Path)+1), 168 ChildObfuscator: childObfuscator, 169 } 170 copy(child.Path, p.Path) 171 child.Path = append(child.Path, PathNode{Name: name, BlockPointer: ptr}) 172 return child 173 } 174 175 // ChildPathNoPtr returns a new Path with the addition of a new entry 176 // with the given name. That final PathNode will have no BlockPointer. 177 func (p Path) ChildPathNoPtr( 178 name PathPartString, childObfuscator Obfuscator) Path { 179 return p.ChildPath(name, BlockPointer{}, childObfuscator) 180 } 181 182 // Obfuscator returns the obfuscator of the tail node in this path. 183 func (p Path) Obfuscator() Obfuscator { 184 return p.ChildObfuscator 185 } 186 187 // PathNode is a single node along an KBFS path, pointing to the top 188 // block for that node of the path. 189 type PathNode struct { 190 BlockPointer 191 Name PathPartString 192 } 193 194 // IsValid returns true if this node contains a valid block pointer. 195 func (n PathNode) IsValid() bool { 196 return n.BlockPointer.IsValid() 197 } 198 199 // DebugString returns a string representation of the node with all 200 // pointer information. 201 func (n PathNode) DebugString() string { 202 return fmt.Sprintf("%s(ptr=%s)", n.Name, n.BlockPointer) 203 }