Repository: rclone/rclone
File: vfs/dir.go (Go)

Code before:
	d.delObject(leaf)
}

// read the directory and sets d.items - must be called with the lock held
func (d *Dir) _readDir() error {
	when := time.Now()
	if age, stale := d._age(when); stale {
		if age != 0 {
			fs.Debugf(d.path, "Re-reading directory (%v old)", age)
		}
	} else {
		return nil
	}
	entries, err := list.DirSorted(context.TODO(), d.f, false, d.path)
	if err == fs.ErrorDirNotFound {
		// We treat directory not found as empty because we
		// create directories on the fly
	} else if err != nil {
		return err
	}

	if d.vfs.Opt.BlockNormDupes { // do this only if requested, as it will have a performance hit
		ciLock.Lock()
		defer ciLock.Unlock()
		ctx := context.TODO()
		ci := fs.GetConfig(ctx)
		if d.vfs.Opt.CaseInsensitive {
			ci.IgnoreCaseSync = true
		}

		// sort entries such that NFD comes before NFC of same name
		sort.Slice(entries, func(i, j int) bool {
			if entries[i] != entries[j] && fs.DirEntryType(entries[i]) == fs.DirEntryType(entries[j]) && norm.NFC.String(entries[i].Remote()) == norm.NFC.String(entries[j].Remote()) {
				if norm.NFD.IsNormalString(entries[i].Remote()) && !norm.NFD.IsNormalString(entries[j].Remote()) {
					return true
				}
			}
			return entries.Less(i, j)
		})

		// detect dupes, remove them from the list and log an error
		normalizedNames := make(map[string]struct{}, entries.Len())
		filteredEntries := make(fs.DirEntries, 0)
		for _, e := range entries {
			normName := fmt.Sprintf("%s-%T", operations.ApplyTransforms(ctx, e.Remote()), e) // include type to track objects and dirs separately
			_, found := normalizedNames[normName]
			if found {
				fs.Errorf(e.Remote(), "duplicate normalized names detected - skipping")
				continue
			}
			normalizedNames[normName] = struct{}{}

Review comment (suggestion):
fs.AddConfig preferred here and lose the `ciLock` mutex

Code after:
}

// read the directory and sets d.items - must be called with the lock held
func (d *Dir) _readDir() error {
	when := time.Now()
	if age, stale := d._age(when); stale {
		if age != 0 {
			fs.Debugf(d.path, "Re-reading directory (%v old)", age)
		}
	} else {
		return nil
	}
	entries, err := list.DirSorted(context.TODO(), d.f, false, d.path)
	if err == fs.ErrorDirNotFound {
		// We treat directory not found as empty because we
		// create directories on the fly
	} else if err != nil {
		return err
	}

	if d.vfs.Opt.BlockNormDupes { // do this only if requested, as it will have a performance hit
		ci := fs.GetConfig(context.TODO())

		// sort entries such that NFD comes before NFC of same name
		sort.Slice(entries, func(i, j int) bool {
			if entries[i] != entries[j] && fs.DirEntryType(entries[i]) == fs.DirEntryType(entries[j]) && norm.NFC.String(entries[i].Remote()) == norm.NFC.String(entries[j].Remote()) {
				if norm.NFD.IsNormalString(entries[i].Remote()) && !norm.NFD.IsNormalString(entries[j].Remote()) {
					return true
				}
			}
			return entries.Less(i, j)
		})

		// detect dupes, remove them from the list and log an error
		normalizedNames := make(map[string]struct{}, entries.Len())
		filteredEntries := make(fs.DirEntries, 0)
		for _, e := range entries {
			normName := fmt.Sprintf("%s-%T", operations.ToNormal(e.Remote(), !ci.NoUnicodeNormalization, (ci.IgnoreCaseSync || d.vfs.Opt.CaseInsensitive)), e) // include type to track objects and dirs separately
			_, found := normalizedNames[normName]
			if found {
				fs.Errorf(e.Remote(), "duplicate normalized names detected - skipping")
				continue
			}
			normalizedNames[normName] = struct{}{}
			filteredEntries = append(filteredEntries, e)
		}
		entries = filteredEntries
	}

	err = d._readDirFromEntries(entries, nil, time.Time{})
	if err != nil {