Treat symlinks to directories like directories
This allows symlinking to create additional subalbums. Closes: #431
This commit is contained in:
parent
2e4f83abbf
commit
0129cb7703
|
@ -181,7 +181,13 @@ func findMediaForAlbum(album *models.Album, cache *scanner_cache.AlbumScannerCac
|
||||||
for _, item := range dirContent {
|
for _, item := range dirContent {
|
||||||
photoPath := path.Join(album.Path, item.Name())
|
photoPath := path.Join(album.Path, item.Name())
|
||||||
|
|
||||||
if !item.IsDir() && cache.IsPathMedia(photoPath) {
|
isDirSymlink, err := utils.IsDirSymlink(photoPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Cannot detect whether %s is symlink to a directory. Pretending it is not", photoPath)
|
||||||
|
isDirSymlink = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !item.IsDir() && !isDirSymlink && cache.IsPathMedia(photoPath) {
|
||||||
// Match file against ignore data
|
// Match file against ignore data
|
||||||
if albumIgnore.MatchesPath(item.Name()) {
|
if albumIgnore.MatchesPath(item.Name()) {
|
||||||
log.Printf("File %s ignored\n", item.Name())
|
log.Printf("File %s ignored\n", item.Name())
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/photoview/photoview/api/graphql/models"
|
"github.com/photoview/photoview/api/graphql/models"
|
||||||
"github.com/photoview/photoview/api/scanner/scanner_cache"
|
"github.com/photoview/photoview/api/scanner/scanner_cache"
|
||||||
"github.com/photoview/photoview/api/scanner/scanner_utils"
|
"github.com/photoview/photoview/api/scanner/scanner_utils"
|
||||||
|
"github.com/photoview/photoview/api/utils"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
ignore "github.com/sabhiram/go-gitignore"
|
ignore "github.com/sabhiram/go-gitignore"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
@ -198,7 +199,13 @@ func findAlbumsForUser(db *gorm.DB, user *models.User, album_cache *scanner_cach
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if item.IsDir() && directoryContainsPhotos(subalbumPath, album_cache, albumIgnore) {
|
isDirSymlink, err := utils.IsDirSymlink(subalbumPath)
|
||||||
|
if err != nil {
|
||||||
|
scanErrors = append(scanErrors, errors.Wrapf(err, "could not check for symlink target of %s", subalbumPath))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.IsDir() || isDirSymlink) && directoryContainsPhotos(subalbumPath, album_cache, albumIgnore) {
|
||||||
scanQueue.PushBack(scanInfo{
|
scanQueue.PushBack(scanInfo{
|
||||||
path: subalbumPath,
|
path: subalbumPath,
|
||||||
parent: album,
|
parent: album,
|
||||||
|
|
|
@ -5,7 +5,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenerateToken() string {
|
func GenerateToken() string {
|
||||||
|
@ -80,3 +84,32 @@ func FaceRecognitionModelsPath() string {
|
||||||
|
|
||||||
return EnvFaceRecognitionModelsPath.GetValue()
|
return EnvFaceRecognitionModelsPath.GetValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsDirSymlink checks that the given path is a symlink and resolves to a
|
||||||
|
// directory.
|
||||||
|
func IsDirSymlink(path string) (bool, error) {
|
||||||
|
isDirSymlink := false
|
||||||
|
|
||||||
|
fileInfo, err := os.Lstat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrapf(err, "could not stat %s", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Resolve symlinks
|
||||||
|
if fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||||
|
resolvedPath, err := filepath.EvalSymlinks(path)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrapf(err, "Cannot resolve linktarget of %s, ignoring it", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvedFile, err := os.Stat(resolvedPath)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrapf(err, "Cannot get fileinfo of linktarget %s of symlink %s, ignoring it", resolvedPath, path)
|
||||||
|
}
|
||||||
|
isDirSymlink = resolvedFile.IsDir()
|
||||||
|
|
||||||
|
return isDirSymlink, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
package utils_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/photoview/photoview/api/test_utils"
|
||||||
|
"github.com/photoview/photoview/api/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
os.Exit(test_utils.IntegrationTestRun(m))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsDirSymlink(t *testing.T) {
|
||||||
|
test_utils.FilesystemTest(t)
|
||||||
|
|
||||||
|
// Prepare a temporary directory for testing purposes
|
||||||
|
dir, err := ioutil.TempDir("", "testing")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create temp directory for testing")
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
// Create regular file
|
||||||
|
_, err = os.Create(path.Join(dir, "regular_file"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create regular file for testing")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create directory
|
||||||
|
err = os.Mkdir(path.Join(dir, "directory"), 0755)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create directory for testing")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create symlink to regular file
|
||||||
|
err = os.Symlink(path.Join(dir, "regular_file"), path.Join(dir, "file_link"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create file link for testing")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create symlink to directory
|
||||||
|
err = os.Symlink(path.Join(dir, "directory"), path.Join(dir, "dir_link"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create dir link for testing")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the actual tests
|
||||||
|
|
||||||
|
isDirLink, _ := utils.IsDirSymlink(path.Join(dir, "regular_file"))
|
||||||
|
if isDirLink {
|
||||||
|
t.Error("Failed detection of regular file")
|
||||||
|
}
|
||||||
|
|
||||||
|
isDirLink, _ = utils.IsDirSymlink(path.Join(dir, "directory"))
|
||||||
|
if isDirLink {
|
||||||
|
t.Error("Failed detection of directory")
|
||||||
|
}
|
||||||
|
|
||||||
|
isDirLink, _ = utils.IsDirSymlink(path.Join(dir, "file_link"))
|
||||||
|
if isDirLink {
|
||||||
|
t.Error("Failed detection of link to regular file")
|
||||||
|
}
|
||||||
|
|
||||||
|
isDirLink, _ = utils.IsDirSymlink(path.Join(dir, "dir_link"))
|
||||||
|
if !isDirLink {
|
||||||
|
t.Error("Failed detection of link to directory")
|
||||||
|
}
|
||||||
|
|
||||||
|
isDirLink, err = utils.IsDirSymlink(path.Join(dir, "non_existant"))
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Missing error for non-existant file")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue