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: walk.go
    path of file: ./repos/kubeedge/vendor/github.com/karrick/godirwalk
    
    the code of the file until where you have to start completion: package godirwalk

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
)

// Options provide parameters for how the Walk function operates.
type Options struct {
	// ErrorCallback specifies a function to be invoked in the case of an error
	// that could potentially be ignored while walking a file system
	// hierarchy. When set to nil or left as its zero-value, any error condition
	// causes Walk to immediately return the error describing what took
	// place. When non-nil, this user supplied function is invoked with the OS
	// pathname of the file system object that caused the error along with the
	// error that took place. The return value of the supplied ErrorCallback
	// function determines whether the error will cause Walk to halt immediately
	// as it would were no ErrorCallback value provided, or skip this file
	// system node yet continue on with the remaining nodes in the file system
	// hierarchy.
	//
	// ErrorCallback is invoked both for errors that are returned by the
	// runtime, and for errors returned by other user supplied callback
	// functions.
	ErrorCallback func(string, error) ErrorAction

	// FollowSymbolicLinks specifies whether Walk will follow symbolic links
	// that refer to directories. When set to false or left as its zero-value,
	// Walk will still invoke the callback function with symbolic link nodes,
	// but if the symbolic link refers to a directory, it will not recurse on
	// that directory. When set to true, Walk will recurse on symbolic links
	// that refer to a directory.
	FollowSymbolicLinks bool

	// Unsorted controls whether or not Walk will sort the immediate descendants
	// of a directory by their relative names prior to visiting each of those
	// entries.
	//
	// When set to false or left at its zero-value, Walk will get the list of
	// immediate descendants of a particular directory, sort that list by
	// lexical order of their names, and then visit each node in the list in
	// sorted order. This will cause Walk to always traverse the same directory
	// tree in the same order, however may be inefficient for directories with
	// many immediate descendants.
	//
	// When set to true, Walk skips sorting the list of immediate descendants
	// for a directory, and simply visits each node in the order the operating
	// system e
    
func walk(osPathname string, dirent *Dirent, options *Options) error {
	err := options.Callback(osPathname, dirent)
	if err != nil {
		if err == SkipThis || err == filepath.SkipDir {
			return err
		}
		if action := options.ErrorCallback(osPathname, err); action == SkipNode {
			return nil
		}
		return err
	}

	if dirent.IsSymlink() {
		if !options.FollowSymbolicLinks {
			return nil
		}
		// Does this symlink point to a directory?
		info, err := os.Stat(osPathname)
		if err != nil {
			if action := options.ErrorCallback(osPathname, err); action == SkipNode {
				return nil
			}
			return err
		}
		if !info.IsDir() {
			return nil
		}
	} else if !dirent.IsDir() {
		return nil
	}

	// If get here, then specified pathname refers to a directory or a
	// symbolic link to a directory.

	var ds scanner

	if options.Unsorted {
		// When upstream does not request a sorted iteration, it's more memory
		// efficient to read a single child at a time from the file system.
		ds, err = NewScanner(osPathname)
	} else {
		// When upstream wants a sorted iteration, we must read the entire
		// directory and sort through the child names, and then iterate on each
		// child.
		ds, err = newSortedScanner(osPathname, options.ScratchBuffer)
	}
	if err != nil {
		if action := options.ErrorCallback(osPathname, err); action == SkipNode {
			return nil
		}
		return err
	}

	for ds.Scan() {
		deChild, err := ds.Dirent()
		osChildname := filepath.Join(osPathname, deChild.name)
		if err != nil {
			if action := options.ErrorCallback(osChildname, err); action == SkipNode {
				return nil
			}
			return err
		}
		err = walk(osChildname, deChild, options)
		debug("osChildname: %q; error: %v\n", osChildname, err)
		if err == nil || err == SkipThis {
			continue
		}
		if err != filepath.SkipDir {
			return err
		}
		// When received SkipDir on a directory or a symbolic link to a
		// directory, stop processing that directory but continue processing
		// siblings.  When received on a non-directory, stop processing
		// remaining siblings.
		isDir, err := deChild.IsDirOrSymlinkToDir()
		if err != nil {
			if action := options.ErrorCallback(osChildname, err); action == SkipNode {
				continue // ignore and continue with next sibling
			}
			return err // caller does not approve of this error
		}
		if !isDir {
			break // stop processing remaining siblings, but allow post children callback
		}
		// continue processing remaining siblings
	}
	if err = ds.Err(); err != nil {
		return err
	}

	if options.PostChildrenCallback == nil {
		return nil
	}

	err = options.PostChildrenCallback(osPathname, dirent)
	if err == nil || err == filepath.SkipDir {
		return err
	}

	if action := options.ErrorCallback(osPathname, err); action == SkipNode {
		return nil
	}
	return err
}