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

Code before:
	if err := osutil.TraversesSymlink(f.mtimefs, parent); err != nil {
		f.newPullError(file, fmt.Errorf("checking parent dirs: %w", err))
		return false
	}

	// issues #114 and #4475: This works around a race condition
	// between two devices, when one device removes a directory and the
	// other creates a file in it. However that happens, we end up with
	// a directory for "foo" with the delete bit, but a file "foo/bar"
	// that we want to sync. We never create the directory, and hence
	// fail to create the file and end up looping forever on it. This
	// breaks that by creating the directory and scheduling a scan,
	// where it will be found and the delete bit on it removed. The
	// user can then clean up as they like...
	// This can also occur if an entire tree structure was deleted, but only
	// a leave has been scanned.
	//
	// And if this is an encrypted folder:
	// Encrypted files have made-up filenames with two synthetic parent
	// directories which don't have any meaning. Create those if necessary.
	if _, err := f.mtimefs.Lstat(parent); !fs.IsNotExist(err) {
		l.Debugf("%v parent not missing %v", f, file)
		return true
	}
	l.Debugf("%v creating parent directory of %v", f, file)
	if err := f.mtimefs.MkdirAll(parent, 0755); err != nil {
		f.newPullError(file, fmt.Errorf("creating parent dir: %w", err))
		return false
	}
	if f.Type != config.FolderTypeReceiveEncrypted {
		scanChan <- parent
	}
	return true
}

// handleSymlink creates or updates the given symlink
func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo, snap *db.Snapshot, dbUpdateChan chan<- dbUpdateJob, scanChan chan<- string) {
	// Used in the defer closure below, updated by the function body. Take
	// care not declare another err.
	var err error

	f.evLogger.Log(events.ItemStarted, map[string]string{
		"folder": f.folderID,
		"item":   file.Name,
		"type":   "symlink",
		"action": "update",
	})

	defer func() {
		f.evLogger.Log(events.ItemFinished, map[string]interface{}{
			"folder": f.folderID,

Review comment (suggestion):
```suggestion
		f.newPullError(file, fmt.Errorf("create parent dir: %w", err))
```

Code after:
		f.newPullError(file, fmt.Errorf("checking parent dirs: %w", err))
		return false
	}

	// issues #114 and #4475: This works around a race condition
	// between two devices, when one device removes a directory and the
	// other creates a file in it. However that happens, we end up with
	// a directory for "foo" with the delete bit, but a file "foo/bar"
	// that we want to sync. We never create the directory, and hence
	// fail to create the file and end up looping forever on it. This
	// breaks that by creating the directory and scheduling a scan,
	// where it will be found and the delete bit on it removed. The
	// user can then clean up as they like...
	// This can also occur if an entire tree structure was deleted, but only
	// a leave has been scanned.
	//
	// And if this is an encrypted folder:
	// Encrypted files have made-up filenames with two synthetic parent
	// directories which don't have any meaning. Create those if necessary.
	if _, err := f.mtimefs.Lstat(parent); !fs.IsNotExist(err) {
		l.Debugf("%v parent not missing %v", f, file)
		return true
	}
	l.Debugf("%v creating parent directory of %v", f, file)
	if err := f.mtimefs.MkdirAll(parent, 0755); err != nil {
		f.newPullError(file, fmt.Errorf("creating parent dir: %w", err))
		return false
	}
	if f.Type != config.FolderTypeReceiveEncrypted {
		scanChan <- parent
	}
	return true
}

// handleSymlink creates or updates the given symlink
func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo, snap *db.Snapshot, dbUpdateChan chan<- dbUpdateJob, scanChan chan<- string) {
	// Used in the defer closure below, updated by the function body. Take
	// care not declare another err.
	var err error

	f.evLogger.Log(events.ItemStarted, map[string]string{
		"folder": f.folderID,
		"item":   file.Name,
		"type":   "symlink",
		"action": "update",
	})

	defer func() {
		f.evLogger.Log(events.ItemFinished, map[string]interface{}{
			"folder": f.folderID,
			"item":   file.Name,