func getMetadata(path string, rootDir string) (*mpb.FileMetadata, error) {
	s, err := os.Stat(path)
	if err != nil {
		return nil, err
	}
	sys := s.Sys()
	if sys == nil {
		return nil, errors.New("cannot access OS-specific metadata")
	}
	m := &mpb.FileMetadata{Path: removeRoot(path, rootDir)}
	m.OwnerUid = int32(sys.(*syscall.Stat_t).Uid)
	m.OwnerGid = int32(sys.(*syscall.Stat_t).Gid)
	m.Permissions = uint32(s.Mode())
	m.Size = s.Size()
	return m, nil
}
getMetadata is heavily linux skewed, but so is minions right now.
It's fairly easy to port to windows by adding the appropriate data
structure, but not planned for now.
package goblins
import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"
	"time"
	"github.com/google/minions/go/interests"
	mpb "github.com/google/minions/proto/minions"
	pb "github.com/google/minions/proto/overlord"
)
func loadFiles(intrs []*mpb.Interest, maxKb int, maxFiles int, root string) ([][]*pb.File, error) {
	intrs = interests.Minify(intrs)
	paths := make(map[string]mpb.Interest_DataType)
	err := filepath.Walk(root, func(path string, f os.FileInfo, e error) error {
		if e != nil {
			if os.IsPermission(e) {
				return filepath.SkipDir
			}
			if os.IsNotExist(e) {
				return filepath.SkipDir
			}
			log.Printf("prevent panic by handling failure accessing a path %q: %v\n", path, e)
			return e
		}
		if !f.IsDir() {
			for _, i := range intrs {
				r, err := regexp.MatchString(i.GetPathRegexp(), removeRoot(path, root))
				if err == nil && r {
					log.Printf("Great, %s matched %s\n", path, i.GetPathRegexp())
					paths[path] = i.GetDataType()
				}
			}
		}
		return nil
	})
	if err != nil {
		return nil, fmt.Errorf("Failed Walk: %v", err)
	}
	var files [][]*pb.File
	var fs []*pb.File
	for path, dataType := range paths {
		metadata, err := getMetadata(path, root)
		if err != nil {
			log.Printf("Cannot create Metadata for %s. %v", path, err)
			continue
		}
		f := &pb.File{Metadata: metadata, DataChunks: nil}
		switch dataType {
		case mpb.Interest_METADATA:
			break
		case mpb.Interest_METADATA_AND_DATA:
			chunks, err := getDataChunks(path)
			if err != nil {
				if os.IsPermission(err) {
					log.Printf("Cannot send %s. Permission denied. Skipping.", path)
					continue
				} else {
					return nil, err
				}
			}
			f.DataChunks = chunks
			break
		default:
			return nil, errors.New("Unknown interest type")
		}
		fs = append(fs, f)
	}
	files = append(files, fs)
	return files, nil
}