// GetFileWithOptions gets a file and observes the options specified // in opt. If fs implements FileGetter, fs.GetFileWithOptions is // called; otherwise the options are applied on the client side after // fetching the whole file. func GetFileWithOptions(fs vfs.FileSystem, path string, opt GetFileOptions) (*FileWithRange, error) { if fg, ok := fs.(FileGetter); ok { return fg.GetFileWithOptions(path, opt) } fi, err := fs.Lstat(path) if err != nil { return nil, err } e := newTreeEntry(fi) fwr := FileWithRange{TreeEntry: e} if fi.Mode().IsDir() { entries, err := fs.ReadDir(path) if err != nil { return nil, err } e.Entries = make([]*TreeEntry, len(entries)) for i, fi := range entries { e.Entries[i] = newTreeEntry(fi) } sort.Sort(TreeEntriesByTypeByName(e.Entries)) } else if fi.Mode().IsRegular() { f, err := fs.Open(path) if err != nil { return nil, err } defer f.Close() contents, err := ioutil.ReadAll(f) if err != nil { return nil, err } e.Contents = contents if empty := (GetFileOptions{}); opt != empty { fr, _, err := ComputeFileRange(contents, opt) if err != nil { return nil, err } // Trim to only requested range. e.Contents = e.Contents[fr.StartByte:fr.EndByte] fwr.FileRange = *fr } } return &fwr, nil }