Skip to content

Commit

Permalink
eth, node: use APPDATA env to support cygwin/msys correctly (#17786)
Browse files Browse the repository at this point in the history
This changes default location of the data directory to use the LOCALAPPDATA
environment variable, resolving issues with remote home directories an improving
compatibility with Cygwin.

Fixes #2239 
Fixes #2237 
Fixes #16437
  • Loading branch information
hackmod authored and fjl committed Feb 19, 2019
1 parent d225624 commit f7f6a46
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 7 deletions.
7 changes: 6 additions & 1 deletion cmd/clef/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,12 @@ func DefaultConfigDir() string {
if runtime.GOOS == "darwin" {
return filepath.Join(home, "Library", "Signer")
} else if runtime.GOOS == "windows" {
return filepath.Join(home, "AppData", "Roaming", "Signer")
appdata := os.Getenv("APPDATA")
if appdata != "" {
return filepath.Join(appdata, "Signer")
} else {
return filepath.Join(home, "AppData", "Roaming", "Signer")
}
} else {
return filepath.Join(home, ".clef")
}
Expand Down
11 changes: 9 additions & 2 deletions eth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,15 @@ func init() {
home = user.HomeDir
}
}
if runtime.GOOS == "windows" {
DefaultConfig.Ethash.DatasetDir = filepath.Join(home, "AppData", "Ethash")
if runtime.GOOS == "darwin" {
DefaultConfig.Ethash.DatasetDir = filepath.Join(home, "Library", "Ethash")
} else if runtime.GOOS == "windows" {
localappdata := os.Getenv("LOCALAPPDATA")
if localappdata != "" {
DefaultConfig.Ethash.DatasetDir = filepath.Join(localappdata, "Ethash")
} else {
DefaultConfig.Ethash.DatasetDir = filepath.Join(home, "AppData", "Local", "Ethash")
}
} else {
DefaultConfig.Ethash.DatasetDir = filepath.Join(home, ".ethash")
}
Expand Down
37 changes: 33 additions & 4 deletions node/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,47 @@ func DefaultDataDir() string {
// Try to place the data folder in the user's home dir
home := homeDir()
if home != "" {
if runtime.GOOS == "darwin" {
switch runtime.GOOS {
case "darwin":
return filepath.Join(home, "Library", "Ethereum")
} else if runtime.GOOS == "windows" {
return filepath.Join(home, "AppData", "Roaming", "Ethereum")
} else {
case "windows":
// We used to put everything in %HOME%\AppData\Roaming, but this caused
// problems with non-typical setups. If this fallback location exists and
// is non-empty, use it, otherwise DTRT and check %LOCALAPPDATA%.
fallback := filepath.Join(home, "AppData", "Roaming", "Ethereum")
appdata := windowsAppData()
if appdata == "" || isNonEmptyDir(fallback) {
return fallback
}
return filepath.Join(appdata, "Ethereum")
default:
return filepath.Join(home, ".ethereum")
}
}
// As we cannot guess a stable location, return empty and handle later
return ""
}

func windowsAppData() string {
if v := os.Getenv("LOCALAPPDATA"); v != "" {
return v // Vista+

This comment has been minimized.

Copy link
@MicahZoltu

MicahZoltu Feb 19, 2019

Contributor

I believe Windows 7 had LocalAppData environment variable, I'm not sure how far back you have to go before it wasn't available, but it is a long way.

This comment has been minimized.

Copy link
@MicahZoltu

MicahZoltu Feb 19, 2019

Contributor

A bit of internet sleuthing suggests that Windows XP did not have LocalAppData but did have AppData, but Windows 7+ has both. Does go-ethereum otherwise support Windows XP (I would be mildly surprised)? If not, this conditional and the following can be deleted and the bug in the following resolved.

This comment has been minimized.

Copy link
@fjl

fjl Feb 19, 2019

Contributor

#19132 implements your suggestion. Thank you for reviewing!

}
if v := os.Getenv("APPDATA"); v != "" {

This comment has been minimized.

Copy link
@MicahZoltu

MicahZoltu Feb 19, 2019

Contributor

AppData/Local != LocalAppData. In a default Windows install, AppData is %USERPROFILE%/AppData/Roaming and LocalAppData is %USERPROFILE%/AppData/Local. Note that Roaming and Local are siblings of each other, not parent-child.

This code will result in writing to %USERPROFILE%/AppData/Roaming/Local, which will put the files into the roaming folder, which means they will be synced over the network on login-logout.

This comment has been minimized.

Copy link
@fjl

fjl Feb 19, 2019

Contributor

Thank you. This is a really unlikely case though. I mostly added it for completeness. What would be the right thing to do here? Should we just rely on USERPROFILE being defined and crash if it's empty?

This comment has been minimized.

Copy link
@MicahZoltu

MicahZoltu Feb 19, 2019

Contributor

I actually don't remember what the right place to store local data is on Windows XP. I think there was something like a "Local Settings" somewhere, but I am not sure it had an environment variable? It wasn't really until Windows 7 that Microsoft started getting serious about having well defined locations for files (really the NT line did a good job, but the consumer line didn't and Windows 7 merged the two lines so it was the first time consumers had well defined file storage locations).

Sounds like the plan is to just not support Windows XP (very reasonable choice IMO), so the answer to this question is inconsequential. 😉

return filepath.Join(v, "Local")
}
return ""
}

func isNonEmptyDir(dir string) bool {
f, err := os.Open(dir)
if err != nil {
return false
}
names, _ := f.Readdir(1)
f.Close()
return len(names) > 0
}

func homeDir() string {
if home := os.Getenv("HOME"); home != "" {
return home
Expand Down

0 comments on commit f7f6a46

Please sign in to comment.