You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: dsync.go
    path of file: ./repos/bud/internal/dsync
    
    the code of the file until where you have to start completion: package dsync

import (
	"errors"
	"io/fs"
	"path/filepath"
	"sort"
	"strconv"
	"time"

	"github.com/livebud/bud/package/log"
	"github.com/livebud/bud/package/vfs"
)

type skipFunc = func(name string, isDir bool) bool

type option struct {
	Skip skipFunc
	log  log.Log
	rel  func(spath string) (string, error)
}

type Opti
    
func diff(opt *option, sfs fs.FS, sdir string, tfs vfs.ReadWritable, tdir string) (ops []Op, err error) {
	log := opt.log.Field("fn", "diff")
	sourceEntries, err := fs.ReadDir(sfs, sdir)
	if err != nil {
		return nil, err
	}
	targetEntries, err := fs.ReadDir(tfs, tdir)
	if err != nil && !errors.Is(err, fs.ErrNotExist) {
		return nil, err
	}
	// Create the source set from the source entries
	sourceSet := newSet(sourceEntries)
	// Create a target set from the target entries
	targetSet := newSet(targetEntries)
	// Compute the operations
	creates := sourceSet.Difference(targetSet)
	deletes := targetSet.Difference(sourceSet)
	updates := sourceSet.Intersection(targetSet)
	createOps, err := createOps(opt, sfs, sdir, creates)
	if err != nil {
		return nil, err
	}
	deleteOps, err := deleteOps(opt, sdir, deletes)
	if err != nil {
		return nil, err
	}
	childOps, err := updateOps(opt, sfs, sdir, tfs, tdir, updates)
	if err != nil {
		return nil, err
	}
	ops = append(ops, createOps...)
	ops = append(ops, deleteOps...)
	ops = append(ops, childOps...)
	for _, op := range ops {
		log.Debug("op:", op.Type, op.Path)
	}
	return ops, nil
}