diff options
| author | 2023-04-28 01:36:55 +0800 | |
|---|---|---|
| committer | 2023-04-28 01:36:55 +0800 | |
| commit | fc8c5fdce62fb229202659408798a7b6c98f6e8b (patch) | |
| tree | 7554f80e50de4af6fd255afa7c21bcdd58a7af34 /cli/internal/cacheitem/restore_directory.go | |
| parent | dd84b9d64fb98746a230cd24233ff50a562c39c9 (diff) | |
| download | HydroRoll-fc8c5fdce62fb229202659408798a7b6c98f6e8b.tar.gz HydroRoll-fc8c5fdce62fb229202659408798a7b6c98f6e8b.zip | |
Diffstat (limited to 'cli/internal/cacheitem/restore_directory.go')
| -rw-r--r-- | cli/internal/cacheitem/restore_directory.go | 144 |
1 files changed, 0 insertions, 144 deletions
diff --git a/cli/internal/cacheitem/restore_directory.go b/cli/internal/cacheitem/restore_directory.go deleted file mode 100644 index 4704d66..0000000 --- a/cli/internal/cacheitem/restore_directory.go +++ /dev/null @@ -1,144 +0,0 @@ -package cacheitem - -import ( - "archive/tar" - "os" - "path/filepath" - "strings" - - "github.com/vercel/turbo/cli/internal/turbopath" -) - -// restoreDirectory restores a directory. -func restoreDirectory(dirCache *cachedDirTree, anchor turbopath.AbsoluteSystemPath, header *tar.Header) (turbopath.AnchoredSystemPath, error) { - processedName, err := canonicalizeName(header.Name) - if err != nil { - return "", err - } - - // We need to traverse `processedName` from base to root split at - // `os.Separator` to make sure we don't end up following a symlink - // outside of the restore path. - - // Create the directory. - if err := safeMkdirAll(dirCache, anchor, processedName, header.Mode); err != nil { - return "", err - } - - return processedName, nil -} - -type cachedDirTree struct { - anchorAtDepth []turbopath.AbsoluteSystemPath - prefix []turbopath.RelativeSystemPath -} - -func (cr *cachedDirTree) getStartingPoint(path turbopath.AnchoredSystemPath) (turbopath.AbsoluteSystemPath, []turbopath.RelativeSystemPath) { - pathSegmentStrings := strings.Split(path.ToString(), string(os.PathSeparator)) - pathSegments := make([]turbopath.RelativeSystemPath, len(pathSegmentStrings)) - for index, pathSegmentString := range pathSegmentStrings { - pathSegments[index] = turbopath.RelativeSystemPathFromUpstream(pathSegmentString) - } - - i := 0 - for i = 0; i < len(cr.prefix) && i < len(pathSegments); i++ { - if pathSegments[i] != cr.prefix[i] { - break - } - } - - // 0: root anchor, can't remove it. - cr.anchorAtDepth = cr.anchorAtDepth[:i+1] - - // 0: first prefix. - cr.prefix = cr.prefix[:i] - - return cr.anchorAtDepth[i], pathSegments[i:] -} - -func (cr *cachedDirTree) Update(anchor turbopath.AbsoluteSystemPath, newSegment turbopath.RelativeSystemPath) { - cr.anchorAtDepth = append(cr.anchorAtDepth, anchor) - cr.prefix = append(cr.prefix, newSegment) -} - -// safeMkdirAll creates all directories, assuming that the leaf node is a directory. -// FIXME: Recheck the symlink cache before creating a directory. -func safeMkdirAll(dirCache *cachedDirTree, anchor turbopath.AbsoluteSystemPath, processedName turbopath.AnchoredSystemPath, mode int64) error { - // Iterate through path segments by os.Separator, appending them onto the anchor. - // Check to see if that path segment is a symlink with a target outside of anchor. - - // Pull the iteration starting point from thie directory cache. - calculatedAnchor, pathSegments := dirCache.getStartingPoint(processedName) - for _, segment := range pathSegments { - calculatedAnchor, checkPathErr := checkPath(anchor, calculatedAnchor, segment) - // We hit an existing directory or absolute path that was invalid. - if checkPathErr != nil { - return checkPathErr - } - - // Otherwise we continue and check the next segment. - dirCache.Update(calculatedAnchor, segment) - } - - // If we have made it here we know that it is safe to call os.MkdirAll - // on the Join of anchor and processedName. - // - // This could _still_ error, but we don't care. - return processedName.RestoreAnchor(anchor).MkdirAll(os.FileMode(mode)) -} - -// checkPath ensures that the resolved path (if restoring symlinks). -// It makes sure to never traverse outside of the anchor. -func checkPath(originalAnchor turbopath.AbsoluteSystemPath, accumulatedAnchor turbopath.AbsoluteSystemPath, segment turbopath.RelativeSystemPath) (turbopath.AbsoluteSystemPath, error) { - // Check if the segment itself is sneakily an absolute path... - // (looking at you, Windows. CON, AUX...) - if filepath.IsAbs(segment.ToString()) { - return "", errTraversal - } - - // Find out if this portion of the path is a symlink. - combinedPath := accumulatedAnchor.Join(segment) - fileInfo, err := combinedPath.Lstat() - - // Getting an error here means we failed to stat the path. - // Assume that means we're safe and continue. - if err != nil { - return combinedPath, nil - } - - // Find out if we have a symlink. - isSymlink := fileInfo.Mode()&os.ModeSymlink != 0 - - // If we don't have a symlink it's safe. - if !isSymlink { - return combinedPath, nil - } - - // Check to see if the symlink targets outside of the originalAnchor. - // We don't do eval symlinks because we could find ourself in a totally - // different place. - - // 1. Get the target. - linkTarget, readLinkErr := combinedPath.Readlink() - if readLinkErr != nil { - return "", readLinkErr - } - - // 2. See if the target is absolute. - if filepath.IsAbs(linkTarget) { - absoluteLinkTarget := turbopath.AbsoluteSystemPathFromUpstream(linkTarget) - if originalAnchor.HasPrefix(absoluteLinkTarget) { - return absoluteLinkTarget, nil - } - return "", errTraversal - } - - // 3. Target is relative (or absolute Windows on a Unix device) - relativeLinkTarget := turbopath.RelativeSystemPathFromUpstream(linkTarget) - computedTarget := accumulatedAnchor.UntypedJoin(linkTarget) - if computedTarget.HasPrefix(originalAnchor) { - // Need to recurse and make sure the target doesn't link out. - return checkPath(originalAnchor, accumulatedAnchor, relativeLinkTarget) - } - return "", errTraversal -} |
