Skip to content

Commit

Permalink
Test for hardlink support on Windows before doing it.
Browse files Browse the repository at this point in the history
  • Loading branch information
mitchell-as committed Sep 23, 2024
1 parent 948ebeb commit 818c474
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 7 deletions.
20 changes: 13 additions & 7 deletions pkg/runtime/depot.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ func (e ErrVolumeMismatch) Error() string {
}

type depot struct {
config depotConfig
depotPath string
artifacts map[strfmt.UUID]struct{}
fsMutex *sync.Mutex
config depotConfig
depotPath string
artifacts map[strfmt.UUID]struct{}
fsMutex *sync.Mutex
supportsHardLinks bool
}

func newDepot(runtimePath string) (*depot, error) {
Expand All @@ -74,9 +75,10 @@ func newDepot(runtimePath string) (*depot, error) {
config: depotConfig{
Deployments: map[strfmt.UUID][]deployment{},
},
depotPath: depotPath,
artifacts: map[strfmt.UUID]struct{}{},
fsMutex: &sync.Mutex{},
depotPath: depotPath,
artifacts: map[strfmt.UUID]struct{}{},
fsMutex: &sync.Mutex{},
supportsHardLinks: supportsHardLinks(depotPath),
}

if !fileutils.TargetExists(depotPath) {
Expand Down Expand Up @@ -146,6 +148,10 @@ func (d *depot) Put(id strfmt.UUID) error {

// DeployViaLink will take an artifact from the depot and link it to the target path.
func (d *depot) DeployViaLink(id strfmt.UUID, relativeSrc, absoluteDest string) error {
if !d.supportsHardLinks {
return d.DeployViaCopy(id, relativeSrc, absoluteDest)
}

d.fsMutex.Lock()
defer d.fsMutex.Unlock()

Expand Down
5 changes: 5 additions & 0 deletions pkg/runtime/links_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package runtime

func supportsHardLinks(path string) bool {
return true
}
70 changes: 70 additions & 0 deletions pkg/runtime/links_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package runtime

import (
"os"
"path/filepath"
"syscall"

"github.com/ActiveState/cli/internal/fileutils"
"github.com/ActiveState/cli/internal/logging"
"github.com/ActiveState/cli/internal/multilog"
"github.com/ActiveState/cli/internal/smartlink"
)

const linkTarget = "__target__"
const link = "__link__"

func supportsHardLinks(path string) (supported bool) {
logging.Debug("Determining if hard links are supported for drive associated with '%s'", path)
defer func() {
log := "Yes they are"
if !supported {
log = "No they are not"
}
logging.Debug(log)
}()

target := filepath.Join(path, linkTarget)
if !fileutils.TargetExists(target) {
err := fileutils.Touch(target)
if err != nil {
multilog.Error("Error touching target: %v", err)
return false
}
}

lnk := filepath.Join(path, link)
if !fileutils.TargetExists(target) {
err := smartlink.LinkContents(target, lnk)
if err != nil {
multilog.Error("Error creating link: %v", err)
return false
}
}

infoTarget, err := os.Stat(target)
if err != nil {
multilog.Error("Error reading target: %v", err)
return false
}

infoLink, err := os.Stat(lnk)
if err != nil {
multilog.Error("Error reading link: %v", err)
return false
}

statTarget, ok := infoTarget.Sys().(*syscall.Stat_t)
if !ok {
multilog.Error("Error casting target info")
return false
}

statLink, ok := infoLink.Sys().(*syscall.Stat_t)
if !ok {
multilog.Error("Error casting link info")
return false
}

return statTarget.Dev == statLink.Dev && statTarget.Ino == statLink.Ino
}

0 comments on commit 818c474

Please sign in to comment.