Description: add appimage command 
 docker-ce (5:20.10.3-8) buster; urgency=low
 .
   * Version: 20.10.3-8
   * add appimage command
Author: wanghuaiqing <wanghuaiqing@loongson.com>

---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: <vendor|upstream|other>, <url of original patch>
Bug: <url in upstream bugtracker>
Bug-Debian: https://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>
Last-Update: 2021-12-01

--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/cli/cli/command/commands/commands.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/commands/commands.go
@@ -122,6 +122,8 @@ func AddCommands(cmd *cobra.Command, doc
 		hide(image.NewRemoveCommand(dockerCli)),
 		hide(image.NewSaveCommand(dockerCli)),
 		hide(image.NewTagCommand(dockerCli)),
+		hide(image.NewLoadAppCommand(dockerCli)),
+		hide(image.NewSaveAppCommand(dockerCli)),
 	)
 }
 
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/cli/cli/command/image/cmd.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/image/cmd.go
@@ -20,9 +20,11 @@ func NewImageCommand(dockerCli command.C
 		NewHistoryCommand(dockerCli),
 		NewImportCommand(dockerCli),
 		NewLoadCommand(dockerCli),
+		NewLoadAppCommand(dockerCli),
 		NewPullCommand(dockerCli),
 		NewPushCommand(dockerCli),
 		NewSaveCommand(dockerCli),
+		NewSaveAppCommand(dockerCli),
 		NewTagCommand(dockerCli),
 		newListCommand(dockerCli),
 		newRemoveCommand(dockerCli),
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/image/loadapp.go
@@ -0,0 +1,76 @@
+package image
+
+import (
+	"context"
+	"io"
+
+	"github.com/docker/cli/cli"
+	"github.com/docker/cli/cli/command"
+	"github.com/docker/docker/pkg/jsonmessage"
+	"github.com/docker/docker/pkg/system"
+	"github.com/pkg/errors"
+	"github.com/spf13/cobra"
+)
+
+type loadAppOptions struct {
+	input string
+	quiet bool
+}
+
+// NewLoadCommand creates a new `docker load` command
+func NewLoadAppCommand(dockerCli command.Cli) *cobra.Command {
+	var opts loadAppOptions
+
+	cmd := &cobra.Command{
+		Use:   "loadapp [OPTIONS]",
+		Short: "Load an appimage from a tar archive or STDIN",
+		Args:  cli.NoArgs,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return runLoadApp(dockerCli, opts)
+		},
+	}
+
+	flags := cmd.Flags()
+
+	flags.StringVarP(&opts.input, "input", "i", "", "Read from tar archive file, instead of STDIN")
+	flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress the load output")
+
+	return cmd
+}
+
+func runLoadApp(dockerCli command.Cli, opts loadAppOptions) error {
+
+	var input io.Reader = dockerCli.In()
+	if opts.input != "" {
+		// We use system.OpenSequential to use sequential file access on Windows, avoiding
+		// depleting the standby list un-necessarily. On Linux, this equates to a regular os.Open.
+		file, err := system.OpenSequential(opts.input)
+		if err != nil {
+			return err
+		}
+		defer file.Close()
+		input = file
+	}
+
+	// To avoid getting stuck, verify that a tar file is given either in
+	// the input flag or through stdin and if not display an error message and exit.
+	if opts.input == "" && dockerCli.In().IsTerminal() {
+		return errors.Errorf("requested load from stdin, but stdin is empty")
+	}
+
+	if !dockerCli.Out().IsTerminal() {
+		opts.quiet = true
+	}
+	response, err := dockerCli.Client().AppImageLoad(context.Background(), input, opts.quiet)
+	if err != nil {
+		return err
+	}
+	defer response.Body.Close()
+
+	if response.Body != nil && response.JSON {
+		return jsonmessage.DisplayJSONMessagesToStream(response.Body, dockerCli.Out(), nil)
+	}
+
+	_, err = io.Copy(dockerCli.Out(), response.Body)
+	return err
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/image/saveapp.go
@@ -0,0 +1,71 @@
+package image
+
+import (
+	"context"
+	"io"
+
+	"github.com/docker/cli/cli"
+	"github.com/docker/cli/cli/command"
+	"github.com/pkg/errors"
+	"github.com/spf13/cobra"
+)
+
+type saveAppOptions struct {
+	output string
+	appimage string
+	baseimage string
+}
+
+// NewSaveCommand creates a new `docker save` command
+func NewSaveAppCommand(dockerCli command.Cli) *cobra.Command {
+	var opts saveAppOptions
+
+	cmd := &cobra.Command{
+		Use:   "saveapp [OPTIONS] IMAGE [IMAGE...]",
+		Short: "Save one appimage to a tar archive (streamed to STDOUT by default)",
+		Args:  cli.NoArgs,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return RunSaveApp(dockerCli, opts)
+		},
+	}
+
+	flags := cmd.Flags()
+
+	flags.StringVarP(&opts.output, "output", "o", "", "Write to a file, instead of STDOUT")
+	flags.StringVarP(&opts.appimage, "appimage", "a", "", "the app image to save")
+	flags.StringVarP(&opts.baseimage, "baseimage", "b", "", "base image of the app image")
+
+	return cmd
+}
+
+// RunSave performs a save against the engine based on the specified options
+func RunSaveApp(dockerCli command.Cli, opts saveAppOptions) error {
+	if opts.output == "" && dockerCli.Out().IsTerminal() {
+		return errors.New("cowardly refusing to save to a terminal. Use the -o flag or redirect")
+	}
+
+	if opts.baseimage == "" {
+		return errors.New("please specify a baseimage")
+	}
+
+	if opts.appimage == "" {
+		return errors.New("please specify a appimage")
+	}
+
+	if err := command.ValidateOutputPath(opts.output); err != nil {
+		return errors.Wrap(err, "failed to save image")
+	}
+
+	responseBody, err := dockerCli.Client().AppImageSave(context.Background(), opts.baseimage, opts.appimage)
+	if err != nil {
+		return err
+	}
+	defer responseBody.Close()
+
+	if opts.output == "" {
+		_, err := io.Copy(dockerCli.Out(), responseBody)
+		return err
+	}
+
+	return command.CopyToFile(opts.output, responseBody)
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/vendor/github.com/docker/docker/client/appimage_load.go
@@ -0,0 +1,29 @@
+package client // import "github.com/docker/docker/client"
+
+import (
+	"context"
+	"io"
+	"net/url"
+
+	"github.com/docker/docker/api/types"
+)
+
+// ImageLoad loads an image in the docker host from the client host.
+// It's up to the caller to close the io.ReadCloser in the
+// ImageLoadResponse returned by this function.
+func (cli *Client) AppImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) {
+	v := url.Values{}
+	v.Set("quiet", "0")
+	if quiet {
+		v.Set("quiet", "1")
+	}
+	headers := map[string][]string{"Content-Type": {"application/x-tar"}}
+	resp, err := cli.postRaw(ctx, "/images/loadapp", v, input, headers)
+	if err != nil {
+		return types.ImageLoadResponse{}, err
+	}
+	return types.ImageLoadResponse{
+		Body: resp.body,
+		JSON: resp.header.Get("Content-Type") == "application/json",
+	}, nil
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/vendor/github.com/docker/docker/client/appimage_save.go
@@ -0,0 +1,24 @@
+package client // import "github.com/docker/docker/client"
+
+import (
+	"context"
+	"io"
+	"net/url"
+)
+
+// AppImageSave retrieves one or more images from the docker host as an io.ReadCloser.
+// It's up to the caller to store the images and close the stream.
+func (cli *Client) AppImageSave(ctx context.Context, baseimage string, appimage string) (io.ReadCloser, error) {
+	query := url.Values{}
+	if baseimage != "" {
+		query.Set("baseimage", baseimage)
+	}
+	if appimage != "" {
+		query.Set("appimage", appimage)
+	}
+	resp, err := cli.get(ctx, "/images/getapp", query, nil)
+	if err != nil {
+		return nil, err
+	}
+	return resp.body, nil
+}
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/cli/vendor/github.com/docker/docker/client/interface.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/vendor/github.com/docker/docker/client/interface.go
@@ -96,11 +96,13 @@ type ImageAPIClient interface {
 	ImageInspectWithRaw(ctx context.Context, image string) (types.ImageInspect, []byte, error)
 	ImageList(ctx context.Context, options types.ImageListOptions) ([]types.ImageSummary, error)
 	ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error)
+	AppImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error)
 	ImagePull(ctx context.Context, ref string, options types.ImagePullOptions) (io.ReadCloser, error)
 	ImagePush(ctx context.Context, ref string, options types.ImagePushOptions) (io.ReadCloser, error)
 	ImageRemove(ctx context.Context, image string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error)
 	ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error)
 	ImageSave(ctx context.Context, images []string) (io.ReadCloser, error)
+	AppImageSave(ctx context.Context, baseimage string, appimage string) (io.ReadCloser, error)
 	ImageTag(ctx context.Context, image, ref string) error
 	ImagesPrune(ctx context.Context, pruneFilter filters.Args) (types.ImagesPruneReport, error)
 }
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/api/server/router/image/backend.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/api/server/router/image/backend.go
@@ -32,6 +32,8 @@ type importExportBackend interface {
 	LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error
 	ImportImage(src string, repository, platform string, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error
 	ExportImage(names []string, outStream io.Writer) error
+	LoadApp(inTar io.ReadCloser, outStream io.Writer, quiet bool) error
+	ExportApp(baseimage string, appimage string, outStream io.Writer) error
 }
 
 type registryBackend interface {
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/api/server/router/image/image.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/api/server/router/image/image.go
@@ -32,12 +32,14 @@ func (r *imageRouter) initRoutes() {
 		router.NewGetRoute("/images/{name:.*}/get", r.getImagesGet),
 		router.NewGetRoute("/images/{name:.*}/history", r.getImagesHistory),
 		router.NewGetRoute("/images/{name:.*}/json", r.getImagesByName),
+		router.NewGetRoute("/images/getapp", r.getAppImageGet),
 		// POST
 		router.NewPostRoute("/images/load", r.postImagesLoad),
 		router.NewPostRoute("/images/create", r.postImagesCreate),
 		router.NewPostRoute("/images/{name:.*}/push", r.postImagesPush),
 		router.NewPostRoute("/images/{name:.*}/tag", r.postImagesTag),
 		router.NewPostRoute("/images/prune", r.postImagesPrune),
+		router.NewPostRoute("/images/loadapp", r.postAppImageLoad),
 		// DELETE
 		router.NewDeleteRoute("/images/{name:.*}", r.deleteImages),
 	}
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/api/server/router/image/image_routes.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/api/server/router/image/image_routes.go
@@ -166,6 +166,7 @@ func (s *imageRouter) getImagesGet(ctx c
 	return nil
 }
 
+
 func (s *imageRouter) postImagesLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
@@ -180,6 +181,46 @@ func (s *imageRouter) postImagesLoad(ctx
 		_, _ = output.Write(streamformatter.FormatError(err))
 	}
 	return nil
+}
+
+func (s *imageRouter) getAppImageGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := httputils.ParseForm(r); err != nil {
+		return err
+	}
+
+	w.Header().Set("Content-Type", "application/x-tar")
+
+	output := ioutils.NewWriteFlusher(w)
+	defer output.Close()
+	var basenames []string
+	var appnames []string
+
+	basenames = r.Form["baseimage"]
+	appnames = r.Form["appimage"]
+
+	if err := s.backend.ExportApp(basenames[0], appnames[0], output); err != nil {
+		if !output.Flushed() {
+			return err
+		}
+		_, _ = output.Write(streamformatter.FormatError(err))
+	}
+	return nil
+}
+
+func (s *imageRouter) postAppImageLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := httputils.ParseForm(r); err != nil {
+		return err
+	}
+	quiet := httputils.BoolValueOrDefault(r, "quiet", true)
+
+	w.Header().Set("Content-Type", "application/json")
+
+	output := ioutils.NewWriteFlusher(w)
+	defer output.Close()
+	if err := s.backend.LoadApp(r.Body, output, quiet); err != nil {
+		_, _ = output.Write(streamformatter.FormatError(err))
+	}
+	return nil
 }
 
 type missingImageError struct{}
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/daemon/images/image_exporter.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/images/image_exporter.go
@@ -23,3 +23,13 @@ func (i *ImageService) LoadImage(inTar i
 	imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStores, i.referenceStore, i)
 	return imageExporter.Load(inTar, outStream, quiet)
 }
+
+func (i *ImageService) LoadApp(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
+	imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStores, i.referenceStore, i)
+	return imageExporter.LoadApp(inTar, outStream, quiet)
+}
+
+func (i *ImageService) ExportApp(baseimage string, appimage string, outStream io.Writer) error {
+	imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStores, i.referenceStore, i)
+	return imageExporter.SaveApp(baseimage, appimage, outStream)
+}
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/image/image.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/image.go
@@ -223,6 +223,8 @@ type Exporter interface {
 	Load(io.ReadCloser, io.Writer, bool) error
 	// TODO: Load(net.Context, io.ReadCloser, <- chan StatusMessage) error
 	Save([]string, io.Writer) error
+	LoadApp(io.ReadCloser, io.Writer, bool) error
+	SaveApp(string, string, io.Writer) error
 }
 
 // NewFromJSON creates an Image configuration from json.
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/image/tarexport/load.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/tarexport/load.go
@@ -28,6 +28,184 @@ import (
 	"github.com/sirupsen/logrus"
 )
 
+func (l *tarexporter) checkifbaseInApp(appimg *image.Image, baseimg *image.Image) bool {
+	baseID := baseimg.RootFS.ChainID()
+	for i := range appimg.RootFS.DiffIDs {
+                rootFS := *appimg.RootFS
+                rootFS.DiffIDs = rootFS.DiffIDs[:i+1]
+                if baseID == rootFS.ChainID() {
+                        l.index = i
+			return true
+                }
+        }
+	return false
+}
+
+func (l *tarexporter) LoadApp(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
+	var progressOutput progress.Output
+	if !quiet {
+		progressOutput = streamformatter.NewJSONProgressOutput(outStream, false)
+	}
+	outStream = streamformatter.NewStdoutWriter(outStream)
+
+	tmpDir, err := ioutil.TempDir("", "docker-import-")
+	if err != nil {
+		return err
+	}
+	defer os.RemoveAll(tmpDir)
+
+	if err := chrootarchive.Untar(inTar, tmpDir, nil); err != nil {
+		return err
+	}
+	baseconfPath, err := safePath(tmpDir, baseconfFileName)
+	if err != nil {
+		return err
+	}
+	baseconfig, err := ioutil.ReadFile(baseconfPath)
+	if err != nil {
+		return err
+	}
+	baseimg, err := image.NewFromJSON(baseconfig)
+	if err != nil {
+		return err
+	}
+	if err := checkCompatibleOS(baseimg.OS); err != nil {
+		return err
+	}
+	dgst := digest.FromBytes(baseconfig)
+	baseID := image.IDFromDigest(dgst)
+	if _, err := l.is.Get(baseID); err != nil {
+		return fmt.Errorf("can not find baseimage, please load ID:%s", baseID)
+	}
+
+	// read manifest, if no file then load in legacy mode
+	manifestPath, err := safePath(tmpDir, manifestFileName)
+	if err != nil {
+		return err
+	}
+	manifestFile, err := os.Open(manifestPath)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return l.legacyLoad(tmpDir, outStream, progressOutput)
+		}
+		return err
+	}
+	defer manifestFile.Close()
+
+	var manifest []manifestItem
+	if err := json.NewDecoder(manifestFile).Decode(&manifest); err != nil {
+		return err
+	}
+
+	var parentLinks []parentLink
+	var imageIDsStr string
+	var imageRefCount int
+
+	for _, m := range manifest {
+		configPath, err := safePath(tmpDir, m.Config)
+		if err != nil {
+			return err
+		}
+		config, err := ioutil.ReadFile(configPath)
+		if err != nil {
+			return err
+		}
+		img, err := image.NewFromJSON(config)
+		if err != nil {
+			return err
+		}
+		if err := checkCompatibleOS(img.OS); err != nil {
+			return err
+		}
+		if have := l.checkifbaseInApp(img, baseimg);have == false {
+			return fmt.Errorf("baseimage is included in appimage, please check it")
+		}
+		rootFS := *img.RootFS
+		rootFS.DiffIDs = nil
+		/*	
+		if expected, actual := len(m.Layers), len(img.RootFS.DiffIDs); expected != actual {
+			return fmt.Errorf("invalid manifest, layers length mismatch: expected %d, got %d", expected, actual)
+		}
+		*/
+
+		// On Windows, validate the platform, defaulting to windows if not present.
+		os := img.OS
+		if os == "" {
+			os = runtime.GOOS
+		}
+		if runtime.GOOS == "windows" {
+			if (os != "windows") && (os != "linux") {
+				return fmt.Errorf("configuration for this image has an unsupported operating system: %s", os)
+			}
+		}
+
+		for i, diffID := range img.RootFS.DiffIDs {
+			if i <= l.index {
+				rootFS.Append(diffID)
+				continue
+			}
+
+
+			layerPath, err := safePath(tmpDir, m.Layers[i-l.index-1])
+			if err != nil {
+				return err
+			}
+			r := rootFS
+			r.Append(diffID)
+			newLayer, err := l.lss[os].Get(r.ChainID())
+			if err != nil {
+				newLayer, err = l.loadLayer(layerPath, rootFS, diffID.String(), os, m.LayerSources[diffID], progressOutput)
+				if err != nil {
+					return err
+				}
+			}
+			defer layer.ReleaseAndLog(l.lss[os], newLayer)
+			if expected, actual := diffID, newLayer.DiffID(); expected != actual {
+				return fmt.Errorf("invalid diffID for layer %d: expected %q, got %q", i, expected, actual)
+			}
+			rootFS.Append(diffID)
+		}
+
+		imgID, err := l.is.Create(config)
+		if err != nil {
+			return err
+		}
+		imageIDsStr += fmt.Sprintf("Loaded image ID: %s\n", imgID)
+
+		imageRefCount = 0
+		for _, repoTag := range m.RepoTags {
+			named, err := reference.ParseNormalizedNamed(repoTag)
+			if err != nil {
+				return err
+			}
+			ref, ok := named.(reference.NamedTagged)
+			if !ok {
+				return fmt.Errorf("invalid tag %q", repoTag)
+			}
+			l.setLoadedTag(ref, imgID.Digest(), outStream)
+			outStream.Write([]byte(fmt.Sprintf("Loaded image: %s\n", reference.FamiliarString(ref))))
+			imageRefCount++
+		}
+
+		parentLinks = append(parentLinks, parentLink{imgID, m.Parent})
+		l.loggerImgEvent.LogImageEvent(imgID.String(), imgID.String(), "load")
+	}
+
+	for _, p := range validatedParentLinks(parentLinks) {
+		if p.parentID != "" {
+			if err := l.setParentID(p.id, p.parentID); err != nil {
+				return err
+			}
+		}
+	}
+
+	if imageRefCount == 0 {
+		outStream.Write([]byte(imageIDsStr))
+	}
+
+	return nil
+}
+
 func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
 	var progressOutput progress.Output
 	if !quiet {
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/image/tarexport/save.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/tarexport/save.go
@@ -35,6 +35,63 @@ type saveSession struct {
 	images      map[image.ID]*imageDescriptor
 	savedLayers map[string]struct{}
 	diffIDPaths map[layer.DiffID]string // cache every diffID blob to avoid duplicates
+	baseID      image.ID
+	appID       image.ID
+	baseChainID layer.ChainID
+	index       int
+}
+
+type saveAppSession struct {
+	*tarexporter
+	outDir      string
+	baseimgDescr *imageDescriptor
+	appimgDescr *imageDescriptor
+	savedLayers map[string]struct{}
+	diffIDPaths map[layer.DiffID]string // cache every diffID blob to avoid duplicates
+	baseID      image.ID
+	appID       image.ID
+	baseChainID layer.ChainID
+	index       int
+}
+
+func (l *tarexporter) SaveApp(basename string, appname string, outStream io.Writer) error {
+	var pbase *imageDescriptor
+	var papp  *imageDescriptor
+	var baseID image.ID
+	var appID  image.ID
+
+	baseimages, err := l.parseNames([]string{basename})
+	if err != nil {
+		return err
+	}
+
+	defer l.releaseLayerReferences(baseimages)
+	appimages, err := l.parseNames([]string{appname})
+	if err != nil {
+		return err
+	}
+	defer l.releaseLayerReferences(appimages)
+
+	for k, v := range baseimages {
+		baseID = k
+		pbase = v
+		break
+	}
+
+	for k, v := range appimages {
+		appID = k
+		papp = v
+		break
+	}
+	session1 := &saveAppSession{tarexporter:l, baseimgDescr: pbase, appimgDescr: papp, appID:appID, baseID:baseID}
+
+	have := session1.checkAppIncludebase(pbase, papp)
+
+	if have == false {
+		return errors.Errorf("baseImage is not included in appImage")
+	}
+
+	return session1.saveApp(outStream)
 }
 
 func (l *tarexporter) Save(names []string, outStream io.Writer) error {
@@ -48,6 +105,205 @@ func (l *tarexporter) Save(names []strin
 	return (&saveSession{tarexporter: l, images: images}).save(outStream)
 }
 
+func (s *saveAppSession) checkAppIncludebase(pbase *imageDescriptor, papp *imageDescriptor) bool {
+	appimg := papp.image
+	baseimg := pbase.image
+	appChainID := appimg.RootFS.ChainID()
+	baseChainID := baseimg.RootFS.ChainID()
+	s.baseChainID = baseChainID
+	if  appChainID == baseChainID {
+		return false
+	}
+
+	for i := range appimg.RootFS.DiffIDs {
+		rootFS := *appimg.RootFS
+		rootFS.DiffIDs = rootFS.DiffIDs[:i+1]
+		if baseChainID == rootFS.ChainID() {
+			s.index = i
+			return true
+		}
+	}
+	return false
+}
+
+func (s *saveAppSession) saveApp(outStream io.Writer) error {
+	s.savedLayers = make(map[string]struct{})
+	s.diffIDPaths = make(map[layer.DiffID]string)
+
+	// get image json
+	tempDir, err := ioutil.TempDir("", "docker-export-")
+	if err != nil {
+		return err
+	}
+	defer os.RemoveAll(tempDir)
+
+	s.outDir = tempDir
+	reposLegacy := make(map[string]map[string]string)
+
+	var manifest []manifestItem
+	var parentLinks []parentLink
+
+	id := s.appID
+	imageDescr := s.appimgDescr
+
+	foreignSrcs, err := s.saveAppimage(id, s.baseChainID)
+	if err != nil {
+		return err
+	}
+
+	var repoTags []string
+	var layers []string
+
+	for _, ref := range imageDescr.refs {
+		familiarName := reference.FamiliarName(ref)
+		if _, ok := reposLegacy[familiarName]; !ok {
+			reposLegacy[familiarName] = make(map[string]string)
+		}
+		reposLegacy[familiarName][ref.Tag()] = imageDescr.layers[len(imageDescr.layers)-1]
+		repoTags = append(repoTags, reference.FamiliarString(ref))
+	}
+
+	for _, l := range imageDescr.layers {
+		// IMPORTANT: We use path, not filepath here to ensure the layers
+		// in the manifest use Unix-style forward-slashes. Otherwise, a
+		// Linux image saved from LCOW won't be able to be imported on
+		// LCOL.
+		layers = append(layers, path.Join(l, legacyLayerFileName))
+	}
+
+	manifest = append(manifest, manifestItem{
+		Config:       id.Digest().Hex() + ".json",
+		RepoTags:     repoTags,
+		Layers:       layers,
+		LayerSources: foreignSrcs,
+	})
+
+	parentID, _ := s.is.GetParent(id)
+	parentLinks = append(parentLinks, parentLink{id, parentID})
+	s.tarexporter.loggerImgEvent.LogImageEvent(id.String(), id.String(), "save")
+
+	for i, p := range validatedParentLinks(parentLinks) {
+		if p.parentID != "" {
+			manifest[i].Parent = p.parentID
+		}
+	}
+
+	if len(reposLegacy) > 0 {
+		reposFile := filepath.Join(tempDir, legacyRepositoriesFileName)
+		rf, err := os.OpenFile(reposFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
+		if err != nil {
+			return err
+		}
+
+		if err := json.NewEncoder(rf).Encode(reposLegacy); err != nil {
+			rf.Close()
+			return err
+		}
+
+		rf.Close()
+
+		if err := system.Chtimes(reposFile, time.Unix(0, 0), time.Unix(0, 0)); err != nil {
+			return err
+		}
+	}
+
+	manifestFileName := filepath.Join(tempDir, manifestFileName)
+	f, err := os.OpenFile(manifestFileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
+	if err != nil {
+		return err
+	}
+
+	if err := json.NewEncoder(f).Encode(manifest); err != nil {
+		f.Close()
+		return err
+	}
+
+	f.Close()
+
+	img := s.baseimgDescr.image
+	baseconfFileName := filepath.Join(tempDir, baseconfFileName)
+	if err := ioutil.WriteFile(baseconfFileName, img.RawJSON(), 0644); err != nil {
+                return err
+        }
+
+	if err := system.Chtimes(manifestFileName, time.Unix(0, 0), time.Unix(0, 0)); err != nil {
+		return err
+	}
+
+	if err := system.Chtimes(baseconfFileName, time.Unix(0, 0), time.Unix(0, 0)); err != nil {
+		return err
+	}
+
+	fs, err := archive.Tar(tempDir, archive.Uncompressed)
+	if err != nil {
+		return err
+	}
+	defer fs.Close()
+
+	_, err = io.Copy(outStream, fs)
+	return err
+}
+
+func (s *saveAppSession) saveAppimage(id image.ID, layerID layer.ChainID) (map[layer.DiffID]distribution.Descriptor, error) {
+
+	appimg := s.appimgDescr.image
+	if len(appimg.RootFS.DiffIDs) == 0 {
+		return nil, fmt.Errorf("empty export - not implemented")
+	}
+
+	var parent digest.Digest
+	var layers []string
+	var foreignSrcs map[layer.DiffID]distribution.Descriptor
+	for i := range appimg.RootFS.DiffIDs {
+		if i <= s.index  {
+			continue
+		}
+		v1Img := image.V1Image{
+			// This is for backward compatibility used for
+			// pre v1.9 docker.
+			Created: time.Unix(0, 0),
+		}
+		if i == len(appimg.RootFS.DiffIDs)-1 {
+			v1Img = appimg.V1Image
+		}
+		rootFS := *appimg.RootFS
+		rootFS.DiffIDs = rootFS.DiffIDs[:i+1]
+		v1ID, err := v1.CreateID(v1Img, rootFS.ChainID(), parent)
+		if err != nil {
+			return nil, err
+		}
+
+		v1Img.ID = v1ID.Hex()
+		if parent != "" {
+			v1Img.Parent = parent.Hex()
+		}
+
+		v1Img.OS = appimg.OS
+		src, err := s.saveLayer(rootFS.ChainID(), v1Img, appimg.Created)
+		if err != nil {
+			return nil, err
+		}
+		layers = append(layers, v1Img.ID)
+		parent = v1ID
+		if src.Digest != "" {
+			if foreignSrcs == nil {
+				foreignSrcs = make(map[layer.DiffID]distribution.Descriptor)
+			}
+			foreignSrcs[appimg.RootFS.DiffIDs[i]] = src
+		}
+	}
+
+	configFile := filepath.Join(s.outDir, id.Digest().Hex()+".json")
+	if err := ioutil.WriteFile(configFile, appimg.RawJSON(), 0644); err != nil {
+		return nil, err
+	}
+	if err := system.Chtimes(configFile, appimg.Created, appimg.Created); err != nil {
+		return nil, err
+	}
+	s.appimgDescr.layers = layers
+	return foreignSrcs, nil
+}
+
 // parseNames will parse the image names to a map which contains image.ID to *imageDescriptor.
 // Each imageDescriptor holds an image top layer reference named 'layerRef'. It is taken here, should be released later.
 func (l *tarexporter) parseNames(names []string) (desc map[image.ID]*imageDescriptor, rErr error) {
@@ -352,6 +608,88 @@ func (s *saveSession) saveLayer(id layer
 	if _, exists := s.savedLayers[legacyImg.ID]; exists {
 		return distribution.Descriptor{}, nil
 	}
+
+	outDir := filepath.Join(s.outDir, legacyImg.ID)
+	if err := os.Mkdir(outDir, 0755); err != nil {
+		return distribution.Descriptor{}, err
+	}
+
+	// todo: why is this version file here?
+	if err := ioutil.WriteFile(filepath.Join(outDir, legacyVersionFileName), []byte("1.0"), 0644); err != nil {
+		return distribution.Descriptor{}, err
+	}
+
+	imageConfig, err := json.Marshal(legacyImg)
+	if err != nil {
+		return distribution.Descriptor{}, err
+	}
+
+	if err := ioutil.WriteFile(filepath.Join(outDir, legacyConfigFileName), imageConfig, 0644); err != nil {
+		return distribution.Descriptor{}, err
+	}
+
+	// serialize filesystem
+	layerPath := filepath.Join(outDir, legacyLayerFileName)
+	operatingSystem := legacyImg.OS
+	if operatingSystem == "" {
+		operatingSystem = runtime.GOOS
+	}
+	l, err := s.lss[operatingSystem].Get(id)
+	if err != nil {
+		return distribution.Descriptor{}, err
+	}
+	defer layer.ReleaseAndLog(s.lss[operatingSystem], l)
+
+	if oldPath, exists := s.diffIDPaths[l.DiffID()]; exists {
+		relPath, err := filepath.Rel(outDir, oldPath)
+		if err != nil {
+			return distribution.Descriptor{}, err
+		}
+		if err := os.Symlink(relPath, layerPath); err != nil {
+			return distribution.Descriptor{}, errors.Wrap(err, "error creating symlink while saving layer")
+		}
+	} else {
+		// Use system.CreateSequential rather than os.Create. This ensures sequential
+		// file access on Windows to avoid eating into MM standby list.
+		// On Linux, this equates to a regular os.Create.
+		tarFile, err := system.CreateSequential(layerPath)
+		if err != nil {
+			return distribution.Descriptor{}, err
+		}
+		defer tarFile.Close()
+
+		arch, err := l.TarStream()
+		if err != nil {
+			return distribution.Descriptor{}, err
+		}
+		defer arch.Close()
+
+		if _, err := io.Copy(tarFile, arch); err != nil {
+			return distribution.Descriptor{}, err
+		}
+
+		for _, fname := range []string{"", legacyVersionFileName, legacyConfigFileName, legacyLayerFileName} {
+			// todo: maybe save layer created timestamp?
+			if err := system.Chtimes(filepath.Join(outDir, fname), createdTime, createdTime); err != nil {
+				return distribution.Descriptor{}, err
+			}
+		}
+
+		s.diffIDPaths[l.DiffID()] = layerPath
+	}
+	s.savedLayers[legacyImg.ID] = struct{}{}
+
+	var src distribution.Descriptor
+	if fs, ok := l.(distribution.Describable); ok {
+		src = fs.Descriptor()
+	}
+	return src, nil
+}
+
+func (s *saveAppSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, createdTime time.Time) (distribution.Descriptor, error) {
+	if _, exists := s.savedLayers[legacyImg.ID]; exists {
+		return distribution.Descriptor{}, nil
+	}
 
 	outDir := filepath.Join(s.outDir, legacyImg.ID)
 	if err := os.Mkdir(outDir, 0755); err != nil {
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/image/tarexport/tarexport.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/tarexport/tarexport.go
@@ -13,6 +13,7 @@ const (
 	legacyConfigFileName       = "json"
 	legacyVersionFileName      = "VERSION"
 	legacyRepositoriesFileName = "repositories"
+	baseconfFileName           = "baseimg.conf"
 )
 
 type manifestItem struct {
@@ -28,6 +29,7 @@ type tarexporter struct {
 	lss            map[string]layer.Store
 	rs             refstore.Store
 	loggerImgEvent LogImageEvent
+	index          int
 }
 
 // LogImageEvent defines interface for event generation related to image tar(load and save) operations
