From 21338691276a138f6e0bb2ead9068683c38ddf9f Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 27 Sep 2017 21:16:22 -0700 Subject: [PATCH] cache: OS-specific cache directories Windows, and to a lesser extent OS X, don't conform to XDG and have their own preferred locations for caches. On Windows, use %LOCALAPPDATA%/restic (i.e., ~/AppData/Local/restic). I can't find authoritative documentation from Microsoft recommending specifically which of %APPDATA%, %LOCALAPPDATA%, and %TEMP% should be used for caches, but %LOCALAPPDATA% is where browsers store their caches, so it seems like a good fit. On OS X, use ~/Library/Caches/restic, which is recommended by the Apple documentation. They do suggest using the application "bundle identifier" as the base folder name, but restic doesn't have one, so I just used "restic". --- internal/cache/cache.go | 2 +- internal/cache/dir.go | 59 ++++++++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/internal/cache/cache.go b/internal/cache/cache.go index 616345ca2..0268b242d 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -84,7 +84,7 @@ func writeCachedirTag(dir string) error { // performReadahead returns true. func New(id string, basedir string) (c *Cache, err error) { if basedir == "" { - basedir, err = getXDGCacheDir() + basedir, err = defaultCacheDir() if err != nil { return nil, err } diff --git a/internal/cache/dir.go b/internal/cache/dir.go index 1f158b5fe..d26db519f 100644 --- a/internal/cache/dir.go +++ b/internal/cache/dir.go @@ -3,27 +3,68 @@ package cache import ( "os" "path/filepath" + "runtime" "github.com/pkg/errors" "github.com/restic/restic/internal/debug" "github.com/restic/restic/internal/fs" ) -// getXDGCacheDir returns the cache directory according to XDG basedir spec, see +// xdgCacheDir returns the cache directory according to XDG basedir spec, see // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html -func getXDGCacheDir() (string, error) { +func xdgCacheDir() (string, error) { xdgcache := os.Getenv("XDG_CACHE_HOME") home := os.Getenv("HOME") - if xdgcache == "" && home == "" { - return "", errors.New("unable to locate cache directory (XDG_CACHE_HOME and HOME unset)") + if xdgcache != "" { + return filepath.Join(xdgcache, "restic"), nil + } else if home != "" { + return filepath.Join(home, ".cache", "restic"), nil } - cachedir := "" - if xdgcache != "" { - cachedir = filepath.Join(xdgcache, "restic") - } else if home != "" { - cachedir = filepath.Join(home, ".cache", "restic") + return "", errors.New("unable to locate cache directory (XDG_CACHE_HOME and HOME unset)") +} + +// windowsCacheDir returns the cache directory for Windows. +// +// Uses LOCALAPPDATA, where application data not synchronized between machines +// is stored. (Browser caches stored here). +func windowsCacheDir() (string, error) { + appdata := os.Getenv("LOCALAPPDATA") + if appdata == "" { + return "", errors.New("unable to locate cache directory (APPDATA unset)") + } + return filepath.Join(appdata, "restic"), nil +} + +// darwinCacheDir returns the cache directory for darwin. +// +// Uses ~/Library/Caches/, which is recommended by Apple, see +// https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html +func darwinCacheDir() (string, error) { + home := os.Getenv("HOME") + if home == "" { + return "", errors.New("unable to locate cache directory (HOME unset)") + } + return filepath.Join(home, "Library", "Caches", "restic"), nil +} + +// defaultCacheDir determines and creates the default cache directory for this +// system. +func defaultCacheDir() (string, error) { + var cachedir string + var err error + switch runtime.GOOS { + case "darwin": + cachedir, err = darwinCacheDir() + case "windows": + cachedir, err = windowsCacheDir() + default: + // Default to XDG for Linux and any other OSes. + cachedir, err = xdgCacheDir() + } + if err != nil { + return "", err } fi, err := fs.Stat(cachedir)