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: query.go
    path of file: ./repos/ebpf/link
    
    the code of the file until where you have to start completion: package link

import (
	"fmt"
	"unsafe"

	"github.com/cilium/ebpf"
	"github.com/cilium/ebpf/internal/sys"
)

// QueryOptions defines additional parameters when querying for programs.
type QueryOptions struct {
	// Target to query. This is usually a file descriptor but may refer to
	// something else based on the attach type.
	Target int
	// Attach specifies the AttachType of the programs queried for
	Attach ebpf.AttachType
	// QueryFlags are flags for BPF_PROG_QUERY, e.g. BPF_F_QUERY_EFFECTIVE
	QueryFla
    
func QueryPrograms(opts QueryOptions) (*QueryResult, error) {
	// query the number of programs to allocate correct slice size
	attr := sys.ProgQueryAttr{
		TargetFdOrIfindex: uint32(opts.Target),
		AttachType:        sys.AttachType(opts.Attach),
		QueryFlags:        opts.QueryFlags,
	}
	err := sys.ProgQuery(&attr)
	if err != nil {
		if haveFeatErr := haveProgQuery(); haveFeatErr != nil {
			return nil, fmt.Errorf("query programs: %w", haveFeatErr)
		}
		return nil, fmt.Errorf("query programs: %w", err)
	}
	if attr.Count == 0 {
		return &QueryResult{Revision: attr.Revision}, nil
	}

	// The minimum bpf_mprog revision is 1, so we can use the field to detect
	// whether the attach type supports link ids.
	haveLinkIDs := attr.Revision != 0

	count := attr.Count
	progIds := make([]ebpf.ProgramID, count)
	attr = sys.ProgQueryAttr{
		TargetFdOrIfindex: uint32(opts.Target),
		AttachType:        sys.AttachType(opts.Attach),
		QueryFlags:        opts.QueryFlags,
		Count:             count,
		ProgIds:           sys.NewPointer(unsafe.Pointer(&progIds[0])),
	}

	var linkIds []ID
	if haveLinkIDs {
		linkIds = make([]ID, count)
		attr.LinkIds = sys.NewPointer(unsafe.Pointer(&linkIds[0]))
	}

	if err := sys.ProgQuery(&attr); err != nil {
		return nil, fmt.Errorf("query programs: %w", err)
	}

	// NB: attr.Count might have changed between the two syscalls.
	var programs []AttachedProgram
	for i, id := range progIds[:attr.Count] {
		ap := AttachedProgram{ID: id}
		if haveLinkIDs {
			ap.linkID = linkIds[i]
		}
		programs = append(programs, ap)
	}

	return &QueryResult{programs, attr.Revision}, nil
}