From b7876711adac8e57ab53de647feb843f7bf010dc Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Fri, 4 Dec 2020 11:37:31 +0100 Subject: [PATCH] Fallback to backup path if storage path is not defined or writable --- internal/config/filenames.go | 13 +++++++++---- pkg/fs/fs.go | 23 ++++++++++++++++++++++- pkg/fs/fs_test.go | 6 ++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/internal/config/filenames.go b/internal/config/filenames.go index d38efdd52..ac1af3e90 100644 --- a/internal/config/filenames.go +++ b/internal/config/filenames.go @@ -275,17 +275,22 @@ func (c *Config) StoragePath() string { storageDir := fs.Abs(dirName) // Find existing directories. - if fs.PathExists(originalsDir) && !c.ReadOnly() { + if fs.PathWritable(originalsDir) && !c.ReadOnly() { return originalsDir - } else if fs.PathExists(storageDir) && c.ReadOnly() { + } else if fs.PathWritable(storageDir) && c.ReadOnly() { return storageDir } + // Fallback to backup storage path. + if fs.PathWritable(c.params.BackupPath) { + return fs.Abs(filepath.Join(c.params.BackupPath, dirName)) + } + // Use .photoprism in home directory? if usr, _ := user.Current(); usr.HomeDir != "" { p := fs.Abs(filepath.Join(usr.HomeDir, fs.HiddenPath, dirName)) - if fs.PathExists(p) || c.ReadOnly() { + if fs.PathWritable(p) || c.ReadOnly() { return p } } @@ -304,7 +309,7 @@ func (c *Config) StoragePath() string { // BackupPath returns the backup storage path. func (c *Config) BackupPath() string { - if fs.PathExists(c.params.BackupPath) { + if fs.PathWritable(c.params.BackupPath) { return fs.Abs(c.params.BackupPath) } diff --git a/pkg/fs/fs.go b/pkg/fs/fs.go index 24b0fb451..d455f0163 100644 --- a/pkg/fs/fs.go +++ b/pkg/fs/fs.go @@ -40,6 +40,8 @@ import ( "os/user" "path/filepath" "strings" + + "github.com/photoprism/photoprism/pkg/rnd" ) const IgnoreFile = ".ppignore" @@ -59,7 +61,7 @@ func FileExists(fileName string) bool { return err == nil && !info.IsDir() } -// PathExists returns true if path exists and is a directory or symlink. +// PathExists tests if a path exists, and is a directory or symlink. func PathExists(path string) bool { if path == "" { return false @@ -76,6 +78,25 @@ func PathExists(path string) bool { return m&os.ModeDir != 0 || m&os.ModeSymlink != 0 } +// PathWritable tests if a path exists and is writable. +func PathWritable(path string) bool { + if !PathExists(path) { + return false + } + + tmpName := filepath.Join(path, "."+rnd.Token(8)) + + if f, err := os.Create(tmpName); err != nil { + return false + } else if err := f.Close(); err != nil { + return false + } else if err := os.Remove(tmpName); err != nil { + return false + } + + return true +} + // Overwrite overwrites the file with data. Creates file if not present. func Overwrite(fileName string, data []byte) bool { f, err := os.Create(fileName) diff --git a/pkg/fs/fs_test.go b/pkg/fs/fs_test.go index 7fca67fbc..6826c249f 100644 --- a/pkg/fs/fs_test.go +++ b/pkg/fs/fs_test.go @@ -20,6 +20,12 @@ func TestPathExists(t *testing.T) { assert.False(t, PathExists("./testdata3ggdtgdg")) } +func TestPathWritable(t *testing.T) { + assert.True(t, PathExists("./testdata")) + assert.False(t, PathExists("./testdata/test.jpg")) + assert.False(t, PathExists("./testdata3ggdtgdg")) +} + func TestOverwrite(t *testing.T) { data := make([]byte, 3) data[1] = 3