getPathSpecFromContainer builds a pathSpecifier from a container location
(originalPath string, conSpec *oci.Spec, containerHostRoot string)
| 137 | |
| 138 | // getPathSpecFromContainer builds a pathSpecifier from a container location |
| 139 | func getPathSpecFromContainer(originalPath string, conSpec *oci.Spec, containerHostRoot string) (*pathSpecifier, error) { |
| 140 | pathSpec := &pathSpecifier{ |
| 141 | originalPath: originalPath, |
| 142 | endsWithSeparator: strings.HasSuffix(originalPath, string(os.PathSeparator)), |
| 143 | endsWithSeparatorDot: filepath.Base(originalPath) == ".", |
| 144 | } |
| 145 | |
| 146 | path := originalPath |
| 147 | |
| 148 | // Path may still be relative at this point. If it is, join it to the root |
| 149 | // NOTE: this is specifically called out in the docker reference. Paths in the container are assumed |
| 150 | // relative to the root, and not to the current (container) working directory. |
| 151 | // Though this seems like a questionable decision, it is set. |
| 152 | if !filepath.IsAbs(path) { |
| 153 | path = string(os.PathSeparator) + path |
| 154 | } |
| 155 | |
| 156 | // Now, fully resolve the path - resolving all symlinks and cleaning-up the end result, following across mounts |
| 157 | pathResolver := newResolver(conSpec, containerHostRoot) |
| 158 | resolvedContainerPath, err := pathResolver.resolvePath(path) |
| 159 | |
| 160 | // Errors we get from that are from Lstat or Readlink |
| 161 | // Either the object does not exist, or we have a dangling symlink, or otherwise hosed filesystem entries |
| 162 | if err != nil && !errors.Is(err, os.ErrNotExist) { |
| 163 | if errors.Is(err, syscall.ENOTDIR) { |
| 164 | return nil, errors.Join(errIsNotADir, err) |
| 165 | } |
| 166 | |
| 167 | // errors.New("EvalSymlinks: too many links") |
| 168 | // other errors would come from lstat |
| 169 | return nil, err |
| 170 | } |
| 171 | |
| 172 | pathSpec.exists = err == nil |
| 173 | |
| 174 | // If the resource does not exist |
| 175 | if !pathSpec.exists { |
| 176 | // Try the parent |
| 177 | cleaned := strings.TrimRight(strings.TrimSuffix(path, string(os.PathSeparator)+"."), string(os.PathSeparator)) |
| 178 | for len(cleaned) < len(path) { |
| 179 | path = cleaned |
| 180 | cleaned = strings.TrimRight(strings.TrimSuffix(path, string(os.PathSeparator)+"."), string(os.PathSeparator)) |
| 181 | } |
| 182 | |
| 183 | base := filepath.Base(path) |
| 184 | path = strings.TrimSuffix(path, string(os.PathSeparator)+base) |
| 185 | |
| 186 | resolvedContainerPath, err = pathResolver.resolvePath(path) |
| 187 | |
| 188 | // Error? That is the end |
| 189 | if err != nil { |
| 190 | if errors.Is(err, os.ErrNotExist) { |
| 191 | return nil, errors.Join(errDoesNotExist, err) |
| 192 | } else if errors.Is(err, syscall.ENOTDIR) { |
| 193 | return nil, errors.Join(errIsNotADir, err) |
| 194 | } |
| 195 | |
| 196 | return nil, err |
no test coverage detected
searching dependent graphs…