local: continue listing files/folders when a circular symlink is detected

Before this change a circular symlink would cause rclone to error out from the listings.

After this change rclone will skip a circular symlink and carry on the listing,
producing an error at the end.

Fixes #4743
This commit is contained in:
Manish Gupta 2020-11-12 17:02:55 +05:30 committed by GitHub
parent 2708a7569e
commit 95d0410baa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 2 deletions

View File

@ -456,8 +456,8 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
if f.opt.FollowSymlinks && (mode&os.ModeSymlink) != 0 { if f.opt.FollowSymlinks && (mode&os.ModeSymlink) != 0 {
localPath := filepath.Join(fsDirPath, name) localPath := filepath.Join(fsDirPath, name)
fi, err = os.Stat(localPath) fi, err = os.Stat(localPath)
if os.IsNotExist(err) { if os.IsNotExist(err) || isCircularSymlinkError(err) {
// Skip bad symlinks // Skip bad symlinks and circular symlinks
err = fserrors.NoRetryError(errors.Wrap(err, "symlink")) err = fserrors.NoRetryError(errors.Wrap(err, "symlink"))
fs.Errorf(newRemote, "Listing error: %v", err) fs.Errorf(newRemote, "Listing error: %v", err)
err = accounting.Stats(ctx).Error(err) err = accounting.Stats(ctx).Error(err)

22
backend/local/symlink.go Normal file
View File

@ -0,0 +1,22 @@
// +build !windows,!plan9,!js
package local
import (
"os"
"syscall"
)
// isCircularSymlinkError checks if the current error code is because of a circular symlink
func isCircularSymlinkError(err error) bool {
if err != nil {
if newerr, ok := err.(*os.PathError); ok {
if errcode, ok := newerr.Err.(syscall.Errno); ok {
if errcode == syscall.ELOOP {
return true
}
}
}
}
return false
}

View File

@ -0,0 +1,17 @@
// +build windows plan9 js
package local
import (
"strings"
)
// isCircularSymlinkError checks if the current error code is because of a circular symlink
func isCircularSymlinkError(err error) bool {
if err != nil {
if strings.Contains(err.Error(), "The name of the file cannot be resolved by the system") {
return true
}
}
return false
}