mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Handle modified files where the case of the filename changed on case-insensitive filesystems (#6327)
* Find existing files with case insensitivity if filesystem is case insensitive * Handle case change in folders * Optimise to only test file system case sensitivity if the first query found nothing This limits the overhead to new paths, and adds an extra query for new paths to windows installs
This commit is contained in:
@@ -443,7 +443,10 @@ func (s *scanJob) getFolderID(ctx context.Context, path string) (*models.FolderI
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
ret, err := s.Repository.Folder.FindByPath(ctx, path)
|
||||
// assume case sensitive when searching for the folder
|
||||
const caseSensitive = true
|
||||
|
||||
ret, err := s.Repository.Folder.FindByPath(ctx, path, caseSensitive)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -473,7 +476,10 @@ func (s *scanJob) getZipFileID(ctx context.Context, zipFile *scanFile) (*models.
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
ret, err := s.Repository.File.FindByPath(ctx, path)
|
||||
// assume case sensitive when searching for the zip file
|
||||
const caseSensitive = true
|
||||
|
||||
ret, err := s.Repository.File.FindByPath(ctx, path, caseSensitive)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting zip file ID for %q: %w", path, err)
|
||||
}
|
||||
@@ -493,11 +499,26 @@ func (s *scanJob) handleFolder(ctx context.Context, file scanFile) error {
|
||||
defer s.incrementProgress(file)
|
||||
|
||||
// determine if folder already exists in data store (by path)
|
||||
f, err := s.Repository.Folder.FindByPath(ctx, path)
|
||||
// assume case sensitive by default
|
||||
f, err := s.Repository.Folder.FindByPath(ctx, path, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checking for existing folder %q: %w", path, err)
|
||||
}
|
||||
|
||||
// #1426 / #6326 - if folder is in a case-insensitive filesystem, then try
|
||||
// case insensitive searching
|
||||
// assume case sensitive if in zip
|
||||
if f == nil && file.ZipFileID == nil {
|
||||
caseSensitive, _ := file.fs.IsPathCaseSensitive(file.Path)
|
||||
|
||||
if !caseSensitive {
|
||||
f, err = s.Repository.Folder.FindByPath(ctx, path, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checking for existing folder %q: %w", path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if folder not exists, create it
|
||||
if f == nil {
|
||||
f, err = s.onNewFolder(ctx, file)
|
||||
@@ -611,10 +632,18 @@ func (s *scanJob) onExistingFolder(ctx context.Context, f scanFile, existing *mo
|
||||
// update if mod time is changed
|
||||
entryModTime := f.ModTime
|
||||
if !entryModTime.Equal(existing.ModTime) {
|
||||
existing.Path = f.Path
|
||||
existing.ModTime = entryModTime
|
||||
update = true
|
||||
}
|
||||
|
||||
// #6326 - update if path has changed - should only happen if case is
|
||||
// changed and filesystem is case insensitive
|
||||
if existing.Path != f.Path {
|
||||
existing.Path = f.Path
|
||||
update = true
|
||||
}
|
||||
|
||||
// update if zip file ID has changed
|
||||
fZfID := f.ZipFileID
|
||||
existingZfID := existing.ZipFileID
|
||||
@@ -647,15 +676,31 @@ func (s *scanJob) handleFile(ctx context.Context, f scanFile) error {
|
||||
defer s.incrementProgress(f)
|
||||
|
||||
var ff models.File
|
||||
|
||||
// don't use a transaction to check if new or existing
|
||||
if err := s.withDB(ctx, func(ctx context.Context) error {
|
||||
// determine if file already exists in data store
|
||||
// assume case sensitive when searching for the file to begin with
|
||||
var err error
|
||||
ff, err = s.Repository.File.FindByPath(ctx, f.Path)
|
||||
ff, err = s.Repository.File.FindByPath(ctx, f.Path, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checking for existing file %q: %w", f.Path, err)
|
||||
}
|
||||
|
||||
// #1426 / #6326 - if file is in a case-insensitive filesystem, then try
|
||||
// case insensitive search
|
||||
// assume case sensitive if in zip
|
||||
if ff == nil && f.ZipFileID != nil {
|
||||
caseSensitive, _ := f.fs.IsPathCaseSensitive(f.Path)
|
||||
|
||||
if !caseSensitive {
|
||||
ff, err = s.Repository.File.FindByPath(ctx, f.Path, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checking for existing file %q: %w", f.Path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ff == nil {
|
||||
// returns a file only if it is actually new
|
||||
ff, err = s.onNewFile(ctx, f)
|
||||
@@ -879,6 +924,7 @@ func (s *scanJob) handleRename(ctx context.Context, f models.File, fp []models.F
|
||||
// #1426 - if file exists but is a case-insensitive match for the
|
||||
// original filename, and the filesystem is case-insensitive
|
||||
// then treat it as a move
|
||||
// #6326 - this should now be handled earlier, and this shouldn't be necessary
|
||||
if caseSensitive, _ := fs.IsPathCaseSensitive(other.Base().Path); !caseSensitive {
|
||||
// treat as a move
|
||||
missing = append(missing, other)
|
||||
@@ -1026,7 +1072,8 @@ func (s *scanJob) onExistingFile(ctx context.Context, f scanFile, existing model
|
||||
path := base.Path
|
||||
|
||||
fileModTime := f.ModTime
|
||||
updated := !fileModTime.Equal(base.ModTime)
|
||||
// #6326 - also force a rescan if the basename changed
|
||||
updated := !fileModTime.Equal(base.ModTime) || base.Basename != f.Basename
|
||||
forceRescan := s.options.Rescan
|
||||
|
||||
if !updated && !forceRescan {
|
||||
@@ -1041,6 +1088,8 @@ func (s *scanJob) onExistingFile(ctx context.Context, f scanFile, existing model
|
||||
logger.Infof("%s has been updated: rescanning", path)
|
||||
}
|
||||
|
||||
// #6326 - update basename in case it changed
|
||||
base.Basename = f.Basename
|
||||
base.ModTime = fileModTime
|
||||
base.Size = f.Size
|
||||
base.UpdatedAt = time.Now()
|
||||
|
||||
Reference in New Issue
Block a user