Repository: syncthing/syncthing
File: lib/model/model.go (Go)

Code before:
	if ok {
		runner.BringToFront(file)
	}
}

func (m *model) ResetFolder(folder string) {
	l.Infof("Cleaning metadata for reset folder %q", folder)
	m.fmut.RLock()
	token, ok := m.folderRunnerToken[folder]
	fcfg := m.folderCfgs[folder]
	if !ok {
		// Do it under lock to prevent the folder being started at the same time
		db.DropFolder(m.db, folder)
	}
	m.fmut.RUnlock()
	if !ok {
		return
	}

	// Stop the folder holding restart mutex to prevent any other concurrent
	// changes from interfering.
	restartMut := m.folderRestartMuts.Get(folder)
	restartMut.Lock()
	defer restartMut.Unlock()

	m.RemoveAndWait(token, 0)

	db.DropFolder(m.db, folder)

	m.fmut.Lock()
	defer m.fmut.Unlock()

	m.cleanupFolderLocked(fcfg)
	fset, err := db.NewFileSet(folder, fcfg.Filesystem(), m.db)
	if err != nil {
		m.fatal(err)
	}
	m.addAndStartFolderLocked(fcfg, fset, m.cfg.Options().CacheIgnoredFiles)
}

func (m *model) String() string {
	return fmt.Sprintf("model@%p", m)
}

func (m *model) VerifyConfiguration(from, to config.Configuration) error {
	toFolders := to.FolderMap()
	for _, from := range from.Folders {
		to, ok := toFolders[from.ID]
		if ok && from.Type != to.Type && (from.Type == config.FolderTypeReceiveEncrypted || to.Type == config.FolderTypeReceiveEncrypted) {
			return errors.New("folder type must not be changed from/to receive-encrypted")
		}

Review comment (suggestion):
This seems in principle unsafe, I see no reason that the folder isn't already restarted or reconfigured or removed after we release fmut and before we reach this point. Do we need to allow resetting a running folder at all? It seems to me like we could do all this under fmut, and return an error in case the folder is running...

Code after:
	if ok {
		runner.BringToFront(file)
	}
}

func (m *model) ResetFolder(folder string) error {
	m.fmut.RLock()
	defer m.fmut.RUnlock()
	_, ok := m.folderRunners[folder]
	if ok {
		return errors.New("folder must be paused when resetting")
	}
	l.Infof("Cleaning metadata for reset folder %q", folder)
	db.DropFolder(m.db, folder)
	return nil
}

func (m *model) String() string {
	return fmt.Sprintf("model@%p", m)
}

func (m *model) VerifyConfiguration(from, to config.Configuration) error {
	toFolders := to.FolderMap()
	for _, from := range from.Folders {
		to, ok := toFolders[from.ID]
		if ok && from.Type != to.Type && (from.Type == config.FolderTypeReceiveEncrypted || to.Type == config.FolderTypeReceiveEncrypted) {
			return errors.New("folder type must not be changed from/to receive-encrypted")
		}
	}
	return nil
}

func (m *model) CommitConfiguration(from, to config.Configuration) bool {
	// TODO: This should not use reflect, and should take more care to try to handle stuff without restart.

	// Delay processing config changes until after the initial setup
	<-m.started

	// Go through the folder configs and figure out if we need to restart or not.

	// Tracks devices affected by any configuration change to resend ClusterConfig.
	clusterConfigDevices := make(deviceIDSet, len(from.Devices)+len(to.Devices))
	closeDevices := make([]protocol.DeviceID, 0, len(to.Devices))

	fromFolders := mapFolders(from.Folders)
	toFolders := mapFolders(to.Folders)
	for folderID, cfg := range toFolders {
		if _, ok := fromFolders[folderID]; !ok {
			// A folder was added.
			if cfg.Paused {
				l.Infoln("Paused folder", cfg.Description())