func (g *guestTools) doListFolder(ID, path string) { g.log.Info("Listing path: ", path) files := []string{} err := filepath.Walk(path, func(p string, info os.FileInfo, err error) error { // Stop iteration and send an error to metaservice, if there is an error // with the path we were asked to iterate over. if p == path && err != nil { return err } // We ignore errors, directories and anything that isn't plain files if info != nil && err == nil && ioext.IsPlainFileInfo(info) { files = append(files, p) } return nil // Ignore other errors }) notFound := err != nil // Create reply request... We use got here, this means that we get retries... // There is no harm in retries, server will just ignore them. req := g.got.Post(g.url("engine/v1/reply?id="+ID), nil) err = req.JSON(metaservice.Files{ Files: files, NotFound: notFound, }) if err != nil { g.log.Panic("Failed to serialize JSON payload, error: ", err) } // Send the reply res, err := req.Send() if err != nil { g.log.Error("Reply with list-folder for path: ", path, " failed error: ", err) return } if res.StatusCode != http.StatusOK { g.log.Error("Reply with list-folder for path: ", path, " got status: ", res.StatusCode) } }
func (r *resultSet) ExtractFile(path string) (ioext.ReadSeekCloser, error) { // Evaluate symlinks p, err := filepath.EvalSymlinks(filepath.Join(r.homeFolder.Path(), path)) if err != nil { if _, ok := err.(*os.PathError); ok { return nil, engines.ErrResourceNotFound } return nil, engines.NewMalformedPayloadError( "Unable to evaluate path: ", path, ) } // Cleanup the path p = filepath.Clean(p) // Check that p is inside homeFolder if !strings.HasPrefix(p, r.homeFolder.Path()+string(filepath.Separator)) { return nil, engines.ErrResourceNotFound } // Stat the file to make sure it's a file info, err := os.Lstat(p) if err != nil { return nil, engines.ErrResourceNotFound } // Don't allow anything that isn't a plain file if !ioext.IsPlainFileInfo(info) { return nil, engines.ErrResourceNotFound } // Open file f, err := os.Open(p) if err != nil { return nil, engines.ErrResourceNotFound } return f, nil }
func (r *resultSet) ExtractFolder(path string, handler engines.FileHandler) error { // Evaluate symlinks p, err := filepath.EvalSymlinks(filepath.Join(r.homeFolder.Path(), path)) if err != nil { if _, ok := err.(*os.PathError); ok { return engines.ErrResourceNotFound } return engines.NewMalformedPayloadError( "Unable to evaluate path: ", path, ) } // Cleanup the path p = filepath.Clean(p) // Check that p is inside homeFolder if !strings.HasPrefix(p, r.homeFolder.Path()+string(filepath.Separator)) { return engines.ErrResourceNotFound } first := true return filepath.Walk(p, func(abspath string, info os.FileInfo, err error) error { // If there is a path error, on the first call then the folder is missing if _, ok := err.(*os.PathError); ok && first { return engines.ErrResourceNotFound } first = false // Ignore folder we can't walk (probably a permission issues) if err != nil { return nil } // Skip anything that isn't a plain file if !ioext.IsPlainFileInfo(info) { return nil } // If we can't construct relative file path this internal error, we'll skip relpath, err := filepath.Rel(p, abspath) if err != nil { // TODO: Send error to sentry r.log.Errorf( "ExtractFolder from %s, filepath.Rel('%s', '%s') returns error: %s", path, p, abspath, err, ) return nil } f, err := os.Open(abspath) if err != nil { // file must have been deleted as we tried to open it // that makes no sense, but who knows... return nil } // If handler returns an error we return ErrHandlerInterrupt if handler(filepath.ToSlash(relpath), f) != nil { return engines.ErrHandlerInterrupt } return nil }) }