Description: add applayer to docker 
 docker-ce (5:20.10.3-11) buster; urgency=low
 .
   * Version: 20.10.3-11
   * add applayer to docker 
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: 2022-05-06

--- 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
@@ -115,6 +115,7 @@ func AddCommands(cmd *cobra.Command, doc
 		hide(container.NewWaitCommand(dockerCli)),
 		hide(image.NewHistoryCommand(dockerCli)),
 		hide(image.NewImagesCommand(dockerCli)),
+		hide(image.NewApplayersCommand(dockerCli)),
 		hide(image.NewImportCommand(dockerCli)),
 		hide(image.NewLoadCommand(dockerCli)),
 		hide(image.NewPullCommand(dockerCli)),
@@ -122,6 +123,12 @@ func AddCommands(cmd *cobra.Command, doc
 		hide(image.NewRemoveCommand(dockerCli)),
 		hide(image.NewSaveCommand(dockerCli)),
 		hide(image.NewTagCommand(dockerCli)),
+		hide(image.NewLoadUpgradeCommand(dockerCli)),
+		hide(image.NewSaveUpgradeCommand(dockerCli)),
+		hide(image.NewGenCommand(dockerCli)),
+		hide(image.NewRemoveApplayerCommand(dockerCli)),
+		hide(image.NewRemoveApplayerCommand(dockerCli)),
+		hide(image.NewAppComposeCommand(dockerCli)),
 		hide(image.NewLoadAppCommand(dockerCli)),
 		hide(image.NewSaveAppCommand(dockerCli)),
 	)
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/formatter/applayer.go
@@ -0,0 +1,115 @@
+package formatter
+
+import (
+	"fmt"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/pkg/stringid"
+	"github.com/docker/go-units"
+)
+
+const (
+	defaultApplayerTableFormat = "table {{.ID}}\t{{.Name}}\t{{.DiffID}}\t{{.Size}}\t{{.DepCount}}\t{{.RefImageCount}}"
+	idHeader         = "APPLAYERID"
+	nameHeader      = "NAME"
+	diffidHeader     = "DIFFID"
+	sizeHeader	 = "SIZE"
+	depCountHeader   = "DEPCOUNT"
+	refImageHeader   = "REFIMAGECOUNT"
+)
+
+// NewApplayerFormat returns a Format for rendering using a Context
+func NewApplayerFormat(source string, quiet bool) Format {
+	switch source {
+	case TableFormatKey:
+		if quiet {
+			return DefaultQuietFormat
+		}
+		format := defaultApplayerTableFormat
+		return Format(format)
+	case RawFormatKey:
+		if quiet {
+			return `applayer_id: {{.ID}}`
+		}
+		format := `applayer_id: {{.ID}}
+name: {{.Name}}
+diffid: {{.DiffID}}
+size: {{.Size}}
+depCount: {{.DepCount}}
+refImageCount: {{.RefImageCount}}
+`
+		return Format(format)
+	}
+	return Format(source)
+}
+
+// ApplayerWrite renders the context for a list of containers
+func ApplayerWrite(ctx Context, applayers []types.AppLayer) error {
+	render := func(format func(subContext SubContext) error) error {
+		for _, applayer := range applayers {
+			err := format(&ApplayerContext{trunc: ctx.Trunc, a: applayer})
+			if err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+	return ctx.Write(NewApplayerContext(), render)
+}
+
+// ApplayerContext is a struct used for rendering a list of applayers in a Go template.
+type ApplayerContext struct {
+	HeaderContext
+	trunc bool
+	a     types.AppLayer
+}
+
+// NewApplayerContext creates a new context for rendering applayers 
+func NewApplayerContext() *ApplayerContext {
+	applayerCtx := ApplayerContext{}
+	applayerCtx.Header = SubHeaderContext{
+		"ID":			idHeader,
+		"Name":			nameHeader,
+		"DiffID":		diffidHeader,
+		"Size":			sizeHeader,
+		"DepCount":		depCountHeader,
+		"RefImageCount":	refImageHeader,
+	}
+	return &applayerCtx
+}
+
+// MarshalJSON makes ContainerContext implement json.Marshaler
+func (a *ApplayerContext) MarshalJSON() ([]byte, error) {
+	return MarshalJSON(a)
+}
+
+// ID returns the applayer's ID as a string. Depending on the `--no-trunc`
+// option being set, the full or truncated ID is returned.
+func (a *ApplayerContext) ID() string {
+	if a.trunc {
+		return stringid.TruncateID(a.a.ID)
+	}
+	return a.a.ID
+}
+
+func (a *ApplayerContext) Name() string {
+	return a.a.Name
+}
+
+func (a *ApplayerContext) DiffID() string {
+	return a.a.DiffId
+}
+
+func (a *ApplayerContext) Size() string {
+	sz := units.HumanSizeWithPrecision(float64(a.a.Size), 3)
+	return sz
+}
+
+func (a *ApplayerContext) DepCount() string {
+	sf := fmt.Sprintf("%d", a.a.DepCount)
+	return sf
+}
+
+func (a *ApplayerContext) RefImageCount() string {
+	sf := fmt.Sprintf("%d", a.a.RefImageCount)
+	return sf
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/image/appcompose.go
@@ -0,0 +1,33 @@
+package image
+
+import (
+	"context"
+
+	"github.com/docker/cli/cli"
+	"github.com/docker/cli/cli/command"
+	"github.com/spf13/cobra"
+)
+
+
+func NewAppComposeCommand(dockerCli command.Cli) *cobra.Command {
+
+	cmd := &cobra.Command{
+		Use:   "appcompose",
+		Short: "try to compose all images and all applayers",
+		Args:  cli.ExactArgs(0),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return runAppcompose(dockerCli)
+		},
+	}
+
+	flags := cmd.Flags()
+	flags.SetInterspersed(false)
+
+	return cmd
+}
+
+func runAppcompose(dockerCli command.Cli) error {
+	ctx := context.Background()
+
+	return dockerCli.Client().Appcompose(ctx)
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/image/applayer_list.go
@@ -0,0 +1,66 @@
+package image
+
+import (
+	"context"
+
+	"github.com/docker/cli/cli"
+	"github.com/docker/cli/cli/command"
+	"github.com/docker/cli/cli/command/formatter"
+	"github.com/docker/cli/opts"
+	"github.com/docker/docker/api/types"
+	"github.com/spf13/cobra"
+)
+
+type applayersOptions struct {
+	quiet       bool
+	noTrunc     bool
+	format      string
+	filter      opts.FilterOpt
+}
+
+// NewApplayersCommand creates a new `docker applayers` command
+func NewApplayersCommand(dockerCli command.Cli) *cobra.Command {
+	options := applayersOptions{filter: opts.NewFilterOpt()}
+
+	cmd := &cobra.Command{
+		Use:   "applayers [OPTIONS]",
+		Short: "List applayers",
+		Args:  cli.NoArgs,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return runApplayers(dockerCli, &options)
+		},
+	}
+
+	flags := cmd.Flags()
+
+	flags.BoolVarP(&options.quiet, "quiet", "q", false, "Only show applayer IDs")
+	flags.BoolVar(&options.noTrunc, "no-trunc", false, "Don't truncate output")
+	flags.StringVar(&options.format, "format", "", "Pretty-print applayers using a Go template")
+	flags.VarP(&options.filter, "filter", "f", "Filter output based on conditions provided")
+
+	return cmd
+}
+
+func runApplayers(dockerCli command.Cli, options *applayersOptions) error {
+	ctx := context.Background()
+
+	filters := options.filter.Value()
+
+	listOptions := types.AppLayerListOptions{
+		Filters: filters,
+	}
+
+	applayers, err := dockerCli.Client().AppLayerList(ctx, listOptions)
+	if err != nil {
+		return err
+	}
+
+	format := formatter.TableFormatKey
+
+	applayerCtx := formatter.Context {
+			Output: dockerCli.Out(),
+			Format: formatter.NewApplayerFormat(format, options.quiet),
+			Trunc:  !options.noTrunc,
+		}
+	return formatter.ApplayerWrite(applayerCtx, applayers)
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/image/applayer_remove.go
@@ -0,0 +1,46 @@
+package image
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/docker/cli/cli"
+	"github.com/docker/cli/cli/command"
+	apiclient "github.com/docker/docker/client"
+	"github.com/spf13/cobra"
+)
+
+func NewRemoveApplayerCommand(dockerCli command.Cli) *cobra.Command {
+
+	cmd := &cobra.Command{
+		Use:   "rma [OPTIONS] AppLayer",
+		Short: "Remove one applayer",
+		Args:  cli.RequiresMinArgs(1),
+		RunE: func(cmd *cobra.Command, arg []string) error {
+			return runRemoveApplayer(dockerCli, arg[0])
+		},
+	}
+
+	return cmd
+}
+
+func runRemoveApplayer(dockerCli command.Cli, applayer string) error {
+	client := dockerCli.Client()
+	ctx := context.Background()
+
+	var fatalErr = false
+	del, err := client.ApplayerRemove(ctx, applayer)
+	if err != nil {
+		if !apiclient.IsErrNotFound(err) {
+			fatalErr = true
+		}
+	} else {
+		fmt.Fprintf(dockerCli.Out(), "Deleted: %s\n", del.ID)
+		return nil
+	}
+	if fatalErr {
+		return err
+	}
+	fmt.Fprintln(dockerCli.Err(), err)
+	return nil
+}
--- 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,16 +20,18 @@ func NewImageCommand(dockerCli command.C
 		NewHistoryCommand(dockerCli),
 		NewImportCommand(dockerCli),
 		NewLoadCommand(dockerCli),
-		NewLoadAppCommand(dockerCli),
+		NewLoadUpgradeCommand(dockerCli),
 		NewPullCommand(dockerCli),
 		NewPushCommand(dockerCli),
 		NewSaveCommand(dockerCli),
-		NewSaveAppCommand(dockerCli),
+		NewSaveUpgradeCommand(dockerCli),
 		NewTagCommand(dockerCli),
 		newListCommand(dockerCli),
 		newRemoveCommand(dockerCli),
 		newInspectCommand(dockerCli),
 		NewPruneCommand(dockerCli),
+		NewGenCommand(dockerCli),
+		NewAppComposeCommand(dockerCli),
 	)
 	return cmd
 }
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/image/genapplayer.go
@@ -0,0 +1,48 @@
+package image
+
+import (
+	"context"
+	"fmt"
+	"github.com/docker/cli/cli"
+	"github.com/docker/cli/cli/command"
+	"github.com/docker/docker/api/types"
+	"github.com/spf13/cobra"
+)
+
+type genOptions struct {
+	image string
+	name  string
+}
+
+// NewTagCommand creates a new `docker gen` command
+func NewGenCommand(dockerCli command.Cli) *cobra.Command {
+	var opts genOptions
+
+	cmd := &cobra.Command{
+		Use:   "gen IMAGE APPLAYERNAME",
+		Short: "gen applayer for the toplayer of the image",
+		Args:  cli.ExactArgs(2),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			opts.image = args[0]
+			opts.name = args[1]
+			return runGen(dockerCli, opts)
+		},
+	}
+
+	flags := cmd.Flags()
+	flags.SetInterspersed(false)
+
+	return cmd
+}
+
+func runGen(dockerCli command.Cli, opts genOptions) error {
+	ctx := context.Background()
+	var applayer types.ImageGenApplayerBody
+
+	applayer, err := dockerCli.Client().ImageGenApplayer(ctx, opts.image, opts.name)
+	if err != nil {
+		return err
+	}
+	fmt.Fprintln(dockerCli.Out(), "gen Applayer ", applayer.ID)
+	return nil
+}
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/cli/cli/command/image/loadapp.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/image/loadapp.go
@@ -23,7 +23,7 @@ func NewLoadAppCommand(dockerCli command
 
 	cmd := &cobra.Command{
 		Use:   "loadapp [OPTIONS]",
-		Short: "Load an appimage from a tar archive or STDIN",
+		Short: "Load an applayer from a tar archive or STDIN",
 		Args:  cli.NoArgs,
 		RunE: func(cmd *cobra.Command, args []string) error {
 			return runLoadApp(dockerCli, opts)
@@ -61,7 +61,7 @@ func runLoadApp(dockerCli command.Cli, o
 	if !dockerCli.Out().IsTerminal() {
 		opts.quiet = true
 	}
-	response, err := dockerCli.Client().AppImageLoad(context.Background(), input, opts.quiet)
+	response, err := dockerCli.Client().AppLoad(context.Background(), input, opts.quiet)
 	if err != nil {
 		return err
 	}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/image/loadupgrade.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 loadUpgradeOptions struct {
+	input string
+	quiet bool
+}
+
+// NewLoadCommand creates a new `docker load` command
+func NewLoadUpgradeCommand(dockerCli command.Cli) *cobra.Command {
+	var opts loadUpgradeOptions
+
+	cmd := &cobra.Command{
+		Use:   "loadupgrade [OPTIONS]",
+		Short: "Load an upgradeimage from a tar archive or STDIN",
+		Args:  cli.NoArgs,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return runLoadUpgrade(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 runLoadUpgrade(dockerCli command.Cli, opts loadUpgradeOptions) 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().UpgradeImageLoad(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
+}
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/cli/cli/command/image/saveapp.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/image/saveapp.go
@@ -12,17 +12,16 @@ import (
 
 type saveAppOptions struct {
 	output string
-	appimage string
-	baseimage string
+	applayer string
 }
 
-// NewSaveCommand creates a new `docker save` command
+// NewSaveAppCommand creates a new `docker saveapp` 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)",
+		Use:   "saveapp [OPTIONS] applayer",
+		Short: "Save one applayer to a tar archive (streamed to STDOUT by default)",
 		Args:  cli.NoArgs,
 		RunE: func(cmd *cobra.Command, args []string) error {
 			return RunSaveApp(dockerCli, opts)
@@ -32,8 +31,7 @@ func NewSaveAppCommand(dockerCli command
 	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")
+	flags.StringVarP(&opts.applayer, "applayer", "a", "", "applayerid or applayername to save")
 
 	return cmd
 }
@@ -44,19 +42,15 @@ func RunSaveApp(dockerCli command.Cli, o
 		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 opts.applayer == "" {
+		return errors.New("please specify id or name of a applayer")
 	}
 
 	if err := command.ValidateOutputPath(opts.output); err != nil {
-		return errors.Wrap(err, "failed to save image")
+		return errors.Wrap(err, "failed to save applayer")
 	}
 
-	responseBody, err := dockerCli.Client().AppImageSave(context.Background(), opts.baseimage, opts.appimage)
+	responseBody, err := dockerCli.Client().AppSave(context.Background(), opts.applayer)
 	if err != nil {
 		return err
 	}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/cli/command/image/saveupgrade.go
@@ -0,0 +1,77 @@
+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 saveUpgradeOptions struct {
+	output string
+	upgradeimage string
+	baseimage string
+	target string
+}
+
+// NewSaveCommand creates a new `docker save` command
+func NewSaveUpgradeCommand(dockerCli command.Cli) *cobra.Command {
+	var opts saveUpgradeOptions
+
+	cmd := &cobra.Command{
+		Use:   "saveupgrade [OPTIONS] IMAGE [IMAGE...]",
+		Short: "Save one upgradeimage to a tar archive (streamed to STDOUT by default)",
+		Args:  cli.NoArgs,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return RunSaveUpgrade(dockerCli, opts)
+		},
+	}
+
+	flags := cmd.Flags()
+
+	flags.StringVarP(&opts.output, "output", "o", "", "Write to a file, instead of STDOUT")
+	flags.StringVarP(&opts.upgradeimage, "upgradeimage", "a", "", "the upgrade image to save")
+	flags.StringVarP(&opts.baseimage, "baseimage", "b", "", "base image of the upgrade image")
+	flags.StringVarP(&opts.target, "target", "t", "", "name of the target image")
+
+	return cmd
+}
+
+// RunSave performs a save against the engine based on the specified options
+func RunSaveUpgrade(dockerCli command.Cli, opts saveUpgradeOptions) 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.upgradeimage == "" {
+		return errors.New("please specify a upgradeimage")
+	}
+
+	if opts.target == "" {
+		return errors.New("please specify a target")
+	}
+
+	if err := command.ValidateOutputPath(opts.output); err != nil {
+		return errors.Wrap(err, "failed to save image")
+	}
+
+	responseBody, err := dockerCli.Client().UpgradeImageSave(context.Background(), opts.baseimage, opts.upgradeimage, opts.target)
+	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/api/types/image_genapplayer_response.go
@@ -0,0 +1,11 @@
+package types // import "github.com/docker/docker/api/types"
+
+
+type ImageGenApplayerBody struct {
+
+	// The ID of applayer 
+	// Required: true
+	ID string `json:"Id"`
+
+	Warnings []string `json:"Warnings"`
+}
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/cli/vendor/github.com/docker/docker/api/types/types.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/vendor/github.com/docker/docker/api/types/types.go
@@ -76,6 +76,17 @@ type Container struct {
 	Mounts          []MountPoint
 }
 
+// AppLayer contains response of Engine API:
+// GET "/applayers/json"
+type AppLayer struct {
+	ID		string `json:"Id"`
+	Name		string
+	DiffId		string
+	Size		int64
+	DepCount	int
+	RefImageCount	int
+}
+
 // CopyConfig contains request body of Engine API:
 // POST "/containers/"+containerID+"/copy"
 type CopyConfig struct {
@@ -599,6 +610,14 @@ type ConfigListOptions struct {
 	Filters filters.Args
 }
 
+type AppLayerListOptions struct {
+	Filters filters.Args
+}
+
+type AppLayerDeleteResponse struct {
+	// ID is the id of the created secret.
+	ID string
+}
 // PushResult contains the tag, manifest digest, and manifest size from the
 // push. It's used to signal this information to the trust code in the client
 // so it can sign the manifest if necessary.
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/vendor/github.com/docker/docker/client/app_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 applayer 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) AppLoad(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, "/applayers/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/app_save.go
@@ -0,0 +1,22 @@
+package client // import "github.com/docker/docker/client"
+
+import (
+	"context"
+	"io"
+	"net/url"
+)
+
+// AppSave retrieves one applayer from the docker host as an io.ReadCloser.
+// It's up to the caller to store the applayer and close the stream.
+func (cli *Client) AppSave(ctx context.Context, idorName string) (io.ReadCloser, error) {
+	query := url.Values{}
+	if idorName != "" {
+		query.Set("name", idorName)
+	}
+
+	resp, err := cli.get(ctx, "/applayers/getapp", query, nil)
+	if err != nil {
+		return nil, err
+	}
+	return resp.body, nil
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/vendor/github.com/docker/docker/client/appcompose.go
@@ -0,0 +1,11 @@
+package client // import "github.com/docker/docker/client"
+
+import (
+	"context"
+)
+
+func (cli *Client) Appcompose(ctx context.Context) error {
+	resp, err := cli.post(ctx, "/images/appcompose", nil, nil, nil)
+	ensureReaderClosed(resp)
+	return err
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/vendor/github.com/docker/docker/client/applayer_list.go
@@ -0,0 +1,35 @@
+package client // import "github.com/docker/docker/client"
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/filters"
+)
+
+// ContainerList returns the list of containers in the docker host.
+func (cli *Client) AppLayerList(ctx context.Context, options types.AppLayerListOptions) ([]types.AppLayer, error) {
+	query := url.Values{}
+
+	if options.Filters.Len() > 0 {
+		//nolint:staticcheck // ignore SA1019 for old code
+		filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filters)
+
+		if err != nil {
+			return nil, err
+		}
+
+		query.Set("filters", filterJSON)
+	}
+
+	resp, err := cli.get(ctx, "/applayers/json", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return nil, err
+	}
+
+	var applayers []types.AppLayer
+	err = json.NewDecoder(resp.body).Decode(&applayers)
+	return applayers, err
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/vendor/github.com/docker/docker/client/applayer_remove.go
@@ -0,0 +1,22 @@
+package client // import "github.com/docker/docker/client"
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/docker/docker/api/types"
+)
+
+// ApplayerRemove removes an applayer from the docker host.
+func (cli *Client) ApplayerRemove(ctx context.Context,  idorName string) (types.AppLayerDeleteResponse, error) {
+
+	var del types.AppLayerDeleteResponse
+	resp, err := cli.delete(ctx, "/applayers/"+idorName, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return del, wrapResponseError(err, resp, "applayer", idorName)
+	}
+
+	err = json.NewDecoder(resp.body).Decode(&del)
+	return del, err
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/vendor/github.com/docker/docker/client/image_gen.go
@@ -0,0 +1,24 @@
+package client // import "github.com/docker/docker/client"
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/docker/docker/api/types"
+)
+
+func (cli *Client) ImageGenApplayer(ctx context.Context, imageID string, target string) (types.ImageGenApplayerBody, error) {
+	query := url.Values{}
+	query.Set("applayername", target)
+
+	var applayer types.ImageGenApplayerBody
+	resp, err := cli.post(ctx, "/images/"+imageID+"/genapplayer", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return applayer, wrapResponseError(err, resp, "image", imageID)
+	}
+
+	err = json.NewDecoder(resp.body).Decode(&applayer)
+	return applayer, err
+}
--- 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,15 +96,21 @@ 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)
+	UpgradeImageLoad(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)
+	UpgradeImageSave(ctx context.Context, baseimage string, upgradeimage string, target string) (io.ReadCloser, error)
 	ImageTag(ctx context.Context, image, ref string) error
 	ImagesPrune(ctx context.Context, pruneFilter filters.Args) (types.ImagesPruneReport, error)
+	ImageGenApplayer(ctx context.Context, imageID string, target string) (types.ImageGenApplayerBody, error)
+	AppLayerList(ctx context.Context, options types.AppLayerListOptions) ([]types.AppLayer, error)
+	ApplayerRemove(ctx context.Context,  idorName string) (types.AppLayerDeleteResponse, error)
+	Appcompose(ctx context.Context) error
+	AppSave(ctx context.Context, idorName string) (io.ReadCloser, error)
+	AppLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error)
 }
 
 // NetworkAPIClient defines API client methods for the networks
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/cli/vendor/github.com/docker/docker/client/upgradeimage_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) UpgradeImageLoad(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/loadupgrade", 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/upgradeimage_save.go
@@ -0,0 +1,40 @@
+package client // import "github.com/docker/docker/client"
+
+import (
+	"context"
+	"io"
+	"net/url"
+	"github.com/docker/distribution/reference"
+	"github.com/pkg/errors"
+)
+
+// UpgradeImageSave 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) UpgradeImageSave(ctx context.Context, baseimage string, upgradeimage string, target string) (io.ReadCloser, error) {
+	query := url.Values{}
+	if baseimage != "" {
+		query.Set("baseimage", baseimage)
+	}
+	if upgradeimage != "" {
+		query.Set("upgradeimage", upgradeimage)
+	}
+	ref, err := reference.ParseNormalizedNamed(target)
+	if err != nil {
+		return nil, errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", target)
+	}
+
+	if _, isCanonical := ref.(reference.Canonical); isCanonical {
+		return nil, errors.New("refusing to create a tag with a digest reference")
+	}
+
+	ref = reference.TagNameOnly(ref)
+	query.Set("repo", reference.FamiliarName(ref))
+	if tagged, ok := ref.(reference.Tagged); ok {
+		query.Set("tag", tagged.Tag())
+	}
+	resp, err := cli.get(ctx, "/images/getupgrade", 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/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
@@ -23,17 +23,23 @@ type imageBackend interface {
 	ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error)
 	ImageHistory(imageName string) ([]*image.HistoryResponseItem, error)
 	Images(imageFilters filters.Args, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error)
+	Applayers(imageFilters filters.Args) ([]*types.AppLayer, error)
 	LookupImage(name string) (*types.ImageInspect, error)
 	TagImage(imageName, repository, tag string) (string, error)
 	ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error)
+	ImageGenApplayer(imageRef string, appname string) (*types.ImageGenApplayerBody, error)
+	ApplayerDelete(idorName string) (*types.AppLayerDeleteResponse, error)
+	Appcompose() error
 }
 
 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
+	LoadUpgrade(inTar io.ReadCloser, outStream io.Writer, quiet bool) error
+	ExportUpgrade(baseimage string, upgradeimage string, repo string, tag string, outStream io.Writer) error
 	LoadApp(inTar io.ReadCloser, outStream io.Writer, quiet bool) error
-	ExportApp(baseimage string, appimage string, outStream io.Writer) error
+	ExportApp(idorName 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
@@ -27,20 +27,26 @@ func (r *imageRouter) initRoutes() {
 	r.routes = []router.Route{
 		// GET
 		router.NewGetRoute("/images/json", r.getImagesJSON),
+		router.NewGetRoute("/applayers/json", r.getAppLayersJSON),
 		router.NewGetRoute("/images/search", r.getImagesSearch),
 		router.NewGetRoute("/images/get", r.getImagesGet),
 		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),
+		router.NewGetRoute("/images/getupgrade", r.getUpgradeImageGet),
+		router.NewGetRoute("/applayers/getapp", r.getAppGet),
 		// 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/{name:.*}/genapplayer", r.genApplayer),
 		router.NewPostRoute("/images/prune", r.postImagesPrune),
-		router.NewPostRoute("/images/loadapp", r.postAppImageLoad),
+		router.NewPostRoute("/images/loadupgrade", r.postUpgradeImageLoad),
+		router.NewPostRoute("/images/appcompose", r.postAppcompose),
+		router.NewPostRoute("/applayers/loadapp", r.postAppLoad),
 		// DELETE
 		router.NewDeleteRoute("/images/{name:.*}", r.deleteImages),
+		router.NewDeleteRoute("/applayers/{name:.*}", r.deleteApplayer),
 	}
 }
--- 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,26 @@ func (s *imageRouter) getImagesGet(ctx c
 	return nil
 }
 
+func (s *imageRouter) getAppGet(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 names []string
+	names = r.Form["name"]
+
+	if err := s.backend.ExportApp(names[0], output); err != nil {
+		if !output.Flushed() {
+			return err
+		}
+		_, _ = output.Write(streamformatter.FormatError(err))
+	}
+	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 {
@@ -183,7 +203,23 @@ func (s *imageRouter) postImagesLoad(ctx
 	return nil
 }
 
-func (s *imageRouter) getAppImageGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *imageRouter) postAppLoad(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
+}
+
+func (s *imageRouter) getUpgradeImageGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 	}
@@ -193,12 +229,16 @@ func (s *imageRouter) getAppImageGet(ctx
 	output := ioutils.NewWriteFlusher(w)
 	defer output.Close()
 	var basenames []string
-	var appnames []string
+	var upgradenames []string
+	var repos []string
+	var tags []string
 
 	basenames = r.Form["baseimage"]
-	appnames = r.Form["appimage"]
+	upgradenames = r.Form["upgradeimage"]
+	repos = r.Form["repo"]
+	tags = r.Form["tag"]
 
-	if err := s.backend.ExportApp(basenames[0], appnames[0], output); err != nil {
+	if err := s.backend.ExportUpgrade(basenames[0], upgradenames[0], repos[0], tags[0], output); err != nil {
 		if !output.Flushed() {
 			return err
 		}
@@ -207,7 +247,7 @@ func (s *imageRouter) getAppImageGet(ctx
 	return nil
 }
 
-func (s *imageRouter) postAppImageLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (s *imageRouter) postUpgradeImageLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 	}
@@ -217,7 +257,7 @@ func (s *imageRouter) postAppImageLoad(c
 
 	output := ioutils.NewWriteFlusher(w)
 	defer output.Close()
-	if err := s.backend.LoadApp(r.Body, output, quiet); err != nil {
+	if err := s.backend.LoadUpgrade(r.Body, output, quiet); err != nil {
 		_, _ = output.Write(streamformatter.FormatError(err))
 	}
 	return nil
@@ -228,9 +268,15 @@ type missingImageError struct{}
 func (missingImageError) Error() string {
 	return "image name cannot be blank"
 }
-
 func (missingImageError) InvalidParameter() {}
 
+type missingApplayerError struct{}
+
+func (missingApplayerError) Error() string {
+	return "applayer name cannot be blank"
+}
+
+
 func (s *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := httputils.ParseForm(r); err != nil {
 		return err
@@ -253,6 +299,46 @@ func (s *imageRouter) deleteImages(ctx c
 	return httputils.WriteJSON(w, http.StatusOK, list)
 }
 
+func (s *imageRouter) deleteApplayer(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := httputils.ParseForm(r); err != nil {
+		return err
+	}
+
+	name := vars["name"]
+
+	if strings.TrimSpace(name) == "" {
+		return missingApplayerError{}
+	}
+
+	resp, err := s.backend.ApplayerDelete(name)
+	if err != nil {
+		return err
+	}
+
+	return httputils.WriteJSON(w, http.StatusOK, resp)
+}
+
+
+func (s *imageRouter) genApplayer(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := httputils.ParseForm(r); err != nil {
+		return err
+	}
+
+	applayername := r.Form.Get("applayername")
+	name := vars["name"]
+
+	if strings.TrimSpace(name) == "" {
+		return missingImageError{}
+	}
+
+	response, err := s.backend.ImageGenApplayer(name, applayername)
+	if err != nil {
+		return err
+	}
+
+	return httputils.WriteJSON(w, http.StatusOK, response)
+}
+
 func (s *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	imageInspect, err := s.backend.LookupImage(vars["name"])
 	if err != nil {
@@ -288,6 +374,24 @@ func (s *imageRouter) getImagesJSON(ctx
 	return httputils.WriteJSON(w, http.StatusOK, images)
 }
 
+func (s *imageRouter) getAppLayersJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := httputils.ParseForm(r); err != nil {
+		return err
+	}
+
+	filters, err := filters.FromJSON(r.Form.Get("filters"))
+	if err != nil {
+		return err
+	}
+
+	applayers, err := s.backend.Applayers(filters)
+	if err != nil {
+		return err
+	}
+
+	return httputils.WriteJSON(w, http.StatusOK, applayers)
+}
+
 func (s *imageRouter) getImagesHistory(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	name := vars["name"]
 	history, err := s.backend.ImageHistory(name)
@@ -306,6 +410,14 @@ func (s *imageRouter) postImagesTag(ctx
 		return err
 	}
 	w.WriteHeader(http.StatusCreated)
+	return nil
+}
+
+func (s *imageRouter) postAppcompose(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := s.backend.Appcompose(); err != nil {
+		return err
+	}
+	w.WriteHeader(http.StatusCreated)
 	return nil
 }
 
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/api/types/image_genapplayer_response.go
@@ -0,0 +1,11 @@
+package types // import "github.com/docker/docker/api/types"
+
+
+type ImageGenApplayerBody struct {
+
+	// The ID of applayer 
+	// Required: true
+	ID string `json:"Id"`
+
+	Warnings []string `json:"Warnings"`
+}
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/api/types/types.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/api/types/types.go
@@ -76,6 +76,17 @@ type Container struct {
 	Mounts          []MountPoint
 }
 
+// AppLayer contains response of Engine API:
+// GET "/applayers/json"
+type AppLayer struct {
+	ID		string `json:"Id"`
+	Name		string
+	DiffId		string
+	Size		int64
+	DepCount	int
+	RefImageCount	int
+}
+
 // CopyConfig contains request body of Engine API:
 // POST "/containers/"+containerID+"/copy"
 type CopyConfig struct {
@@ -599,6 +610,15 @@ type ConfigListOptions struct {
 	Filters filters.Args
 }
 
+type AppLayerListOptions struct {
+	Filters filters.Args
+}
+
+type AppLayerDeleteResponse struct {
+	// ID is the id of the created secret.
+	ID string
+}
+
 // PushResult contains the tag, manifest digest, and manifest size from the
 // push. It's used to signal this information to the trust code in the client
 // so it can sign the manifest if necessary.
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/builder/dockerfile/internals.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/builder/dockerfile/internals.go
@@ -347,6 +347,15 @@ func withEnv(env []string) runConfigModi
 	}
 }
 
+func withAppLayerID(applayerid string) runConfigModifier {
+	return func(runConfig *container.Config) {
+		if runConfig.Labels == nil {
+			runConfig.Labels = make(map[string]string)
+		}
+		runConfig.Labels["applayerid"] = applayerid
+	}
+}
+
 // withEntrypointOverride sets an entrypoint on runConfig if the command is
 // not empty. The entrypoint is left unmodified if command is empty.
 //
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/daemon/daemon.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/daemon.go
@@ -1029,6 +1029,14 @@ func NewDaemon(ctx context.Context, conf
 	if err != nil {
 		return nil, err
 	}
+	applayerRoot := filepath.Join(config.Root, "applayer", d.graphDrivers[runtime.GOOS])
+	afs, err := image.NewAppLayerFSStoreBackend(filepath.Join(applayerRoot, "applayerdb"))
+	applayerStore, err := image.NewApplayerStore(afs, imageStore, image.AsOptions{
+		IDMapping:	idMapping,
+	})
+	if err != nil {
+		return nil, err
+	}
 
 	d.volumes, err = volumesservice.NewVolumeService(config.Root, d.PluginStore, rootIDs, d)
 	if err != nil {
@@ -1103,6 +1111,7 @@ func NewDaemon(ctx context.Context, conf
 		DistributionMetadataStore: distributionMetadataStore,
 		EventsService:             d.EventsService,
 		ImageStore:                imageStore,
+		ApplayerStore:             applayerStore,
 		LayerStores:               layerStores,
 		MaxConcurrentDownloads:    *config.MaxConcurrentDownloads,
 		MaxConcurrentUploads:      *config.MaxConcurrentUploads,
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/images/appcompose.go
@@ -0,0 +1,11 @@
+package images // import "github.com/docker/docker/daemon/images"
+
+import (
+	"github.com/docker/docker/image/appcompose"
+)
+
+func (i *ImageService) Appcompose() error {
+	ac := appcompose.NewAppComposer(i.imageStore, i.layerStores, i.referenceStore, i.applayerStore, i)
+	err := ac.GenImg()
+	return  err
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/images/applayer_delete.go
@@ -0,0 +1,27 @@
+package images // import "github.com/docker/docker/daemon/images"
+
+import (
+
+	"github.com/docker/docker/api/types"
+)
+
+
+func (i *ImageService) ApplayerDelete(idorName string) (*types.AppLayerDeleteResponse, error) {
+	var resp types.AppLayerDeleteResponse
+
+	id, err := i.applayerStore.Search(idorName)
+	if err != nil {
+		id, err = i.applayerStore.GetByName(idorName)
+		if err != nil {
+			return nil, err
+		}
+	}
+	err = i.applayerStore.Delete(id)
+	if err != nil {
+		return nil, err
+	}
+	resp.ID = id.String()
+	return &resp, nil
+}
+
+
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/images/applayers.go
@@ -0,0 +1,51 @@
+package images // import "github.com/docker/docker/daemon/images"
+
+import (
+	"sort"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/filters"
+	"github.com/docker/docker/image"
+	"github.com/docker/docker/pkg/system"
+)
+
+
+// byCreated is a temporary type used to sort a list of images by creation
+// time.
+type byName []*types.AppLayer
+
+func (r byName) Len() int           { return len(r) }
+func (r byName) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
+func (r byName) Less(i, j int) bool { return r[i].Name < r[j].Name }
+
+func (i *ImageService) Applayers(filters filters.Args) ([]*types.AppLayer, error) {
+	var (
+		all	map[image.ID]image.AppLayer
+	)
+	all = i.applayerStore.Map()
+
+	applayers := []*types.AppLayer{}
+	for _, applayer := range all {
+
+		if !system.IsOSSupported(applayer.OS()) {
+			continue
+		}
+		newal := newAppLayer(applayer)
+		applayers = append(applayers, newal)
+	}
+
+	sort.Sort(sort.Reverse(byName(applayers)))
+
+	return applayers, nil
+}
+
+func newAppLayer(applayer image.AppLayer) *types.AppLayer {
+	newApplayer := new(types.AppLayer)
+	newApplayer.ID = applayer.AppLayerID().String()
+	newApplayer.Name = applayer.Name()
+	newApplayer.DiffId = applayer.DiffID().String()
+	newApplayer.Size = applayer.Size()
+	newApplayer.DepCount = applayer.Depslen()
+	newApplayer.RefImageCount = applayer.RefsCount()
+	return newApplayer
+}
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/daemon/images/image_builder.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/images/image_builder.go
@@ -10,6 +10,7 @@ import (
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/builder"
 	"github.com/docker/docker/image"
+	"github.com/docker/docker/image/appcompose"
 	"github.com/docker/docker/layer"
 	"github.com/docker/docker/pkg/containerfs"
 	"github.com/docker/docker/pkg/stringid"
@@ -223,6 +224,7 @@ func (i *ImageService) CreateImage(confi
 			return nil, errors.Wrapf(err, "failed to set parent %s", parent)
 		}
 	}
-
+	ac := appcompose.NewAppComposer(i.imageStore, i.layerStores, i.referenceStore, i.applayerStore, i)
+	ac.GenImgByImageID(id)
 	return i.imageStore.Get(id)
 }
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/daemon/images/image_commit.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/images/image_commit.go
@@ -6,6 +6,7 @@ import (
 
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/image"
+	"github.com/docker/docker/image/appcompose"
 	"github.com/docker/docker/layer"
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/pkg/system"
@@ -68,6 +69,8 @@ func (i *ImageService) CommitImage(c bac
 			return "", err
 		}
 	}
+	ac := appcompose.NewAppComposer(i.imageStore, i.layerStores, i.referenceStore, i.applayerStore, i)
+	ac.GenImgByImageID(id)
 	return id, nil
 }
 
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/daemon/images/image_delete.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/images/image_delete.go
@@ -13,6 +13,7 @@ import (
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/pkg/system"
 	"github.com/pkg/errors"
+	digest "github.com/opencontainers/go-digest"
 )
 
 type conflictType int
@@ -327,11 +328,32 @@ func (i *ImageService) imageDeleteHelper
 		return err
 	}
 
+	img, err := i.imageStore.Get(imgID)
+	if err != nil {
+		return err
+	}
+	id, err := img.GetAppLayerID()
+	if err != nil {
+		return err
+	}
+
 	removedLayers, err := i.imageStore.Delete(imgID)
 	if err != nil {
 		return err
 	}
 
+	if id != "" {
+		dgst, err := digest.Parse(strings.TrimSpace(id))
+		if err != nil {
+			return err
+		}
+		applayerid := image.ID(dgst)
+		err = i.applayerStore.DeleteImgID(applayerid, imgID)
+		if err != nil {
+			return err
+		}
+	}
+
 	i.LogImageEvent(imgID.String(), imgID.String(), "delete")
 	*records = append(*records, types.ImageDeleteResponseItem{Deleted: imgID.String()})
 	for _, removedLayer := range removedLayers {
--- 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
@@ -3,6 +3,7 @@ package images // import "github.com/doc
 import (
 	"io"
 
+	"github.com/docker/docker/image/apptarexport"
 	"github.com/docker/docker/image/tarexport"
 )
 
@@ -12,7 +13,7 @@ import (
 // the same tag are exported. names is the set of tags to export, and
 // outStream is the writer which the images are written to.
 func (i *ImageService) ExportImage(names []string, outStream io.Writer) error {
-	imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStores, i.referenceStore, i)
+	imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStores, i.referenceStore, i.applayerStore, i)
 	return imageExporter.Save(names, outStream)
 }
 
@@ -20,16 +21,26 @@ func (i *ImageService) ExportImage(names
 // complement of ImageExport.  The input stream is an uncompressed tar
 // ball containing images and metadata.
 func (i *ImageService) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
-	imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStores, i.referenceStore, i)
+	imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStores, i.referenceStore, i.applayerStore, i)
 	return imageExporter.Load(inTar, outStream, quiet)
 }
 
+func (i *ImageService) LoadUpgrade(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
+	imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStores, i.referenceStore, i.applayerStore, i)
+	return imageExporter.LoadUpgrade(inTar, outStream, quiet)
+}
+
+func (i *ImageService) ExportUpgrade(baseimage string, upgradeimage string, repo string, tag string, outStream io.Writer) error {
+	imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStores, i.referenceStore, i.applayerStore, i)
+	return imageExporter.SaveUpgrade(baseimage, upgradeimage, repo, tag, outStream)
+}
+
 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)
+	appExporter := apptarexport.NewAppTarExporter(i.imageStore, i.layerStores, i.applayerStore, i.referenceStore, i)
+	return appExporter.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)
+func (i *ImageService) ExportApp(idorName string, outStream io.Writer) error {
+	appExporter := apptarexport.NewAppTarExporter(i.imageStore, i.layerStores, i.applayerStore, i.referenceStore, i)
+	return appExporter.SaveApp(idorName, outStream)
 }
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/images/image_genapplayer.go
@@ -0,0 +1,71 @@
+package images // import "github.com/docker/docker/daemon/images"
+
+import (
+	"runtime"
+	"encoding/json"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/layer"
+	"github.com/docker/docker/image"
+	"github.com/docker/docker/pkg/system"
+	"github.com/docker/docker/image/appcompose"
+	"github.com/pkg/errors"
+	digest "github.com/opencontainers/go-digest"
+)
+
+func (i *ImageService) ImageGenApplayer(imageRef string, appname string) (*types.ImageGenApplayerBody, error) {
+
+	id, err := i.applayerStore.GetByName(appname)
+	if err == nil {
+		return  nil, errors.Errorf("name %s already exists", appname)
+	}
+	var resp types.ImageGenApplayerBody
+	img, err := i.GetImage(imageRef, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if !system.IsOSSupported(img.OperatingSystem()) {
+		return	nil, errors.Errorf("unable to gen applayer: %q", system.ErrNotSupportedOperatingSystem)
+	}
+	if img.DiffLen() <= 1 {
+		return  nil, errors.Errorf("image layers count is not more than 1, please check it")
+	}
+	os := img.OS
+	if os == "" {
+		os = runtime.GOOS
+	}
+	if os != "linux" {
+		return	nil, errors.Errorf("please check image os, make sure it is linux")
+	}
+	appimg := image.NewApplayerImage(img)
+	config, err := json.Marshal(appimg)
+	if err != nil {
+		return nil, err
+	}
+	dgst := digest.FromBytes(config)
+	id = image.IDFromDigest(dgst)
+	_, err = i.applayerStore.Get(id)
+	if err == nil {
+		return nil, errors.Errorf("applayerid %v already exsit", id)
+	}
+	chainID := img.RootFS.ChainID()
+	newLayer, err := i.layerStores[os].Get(chainID)
+	if err != nil {
+		return nil, err
+	}
+	defer layer.ReleaseAndLog(i.layerStores[os], newLayer)
+	tar, err := newLayer.TarStream()
+	if err != nil {
+		return nil, err
+	}
+	defer tar.Close()
+
+	id, err = i.applayerStore.Create(tar, appname, config)
+	if err != nil {
+		return nil, err
+	}
+	ac := appcompose.NewAppComposer(i.imageStore, i.layerStores, i.referenceStore, i.applayerStore, i)
+	ac.GenImgByApplayerID(id)
+	resp.ID = id.String()
+	return &resp, nil
+}
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/daemon/images/image_import.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/images/image_import.go
@@ -16,6 +16,7 @@ import (
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/image"
+	"github.com/docker/docker/image/appcompose"
 	"github.com/docker/docker/layer"
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/progress"
@@ -131,7 +132,8 @@ func (i *ImageService) ImportImage(src s
 			return err
 		}
 	}
-
+	ac := appcompose.NewAppComposer(i.imageStore, i.layerStores, i.referenceStore, i.applayerStore, i)
+	ac.GenImgByImageID(id)
 	i.LogImageEvent(id.String(), id.String(), "import")
 	outStream.Write(streamformatter.FormatStatus("", id.String()))
 	return nil
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/daemon/images/images.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/images/images.go
@@ -13,6 +13,7 @@ import (
 	"github.com/docker/docker/api/types/filters"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/image"
+	"github.com/docker/docker/image/appcompose"
 	"github.com/docker/docker/layer"
 	"github.com/docker/docker/pkg/system"
 )
@@ -340,6 +341,8 @@ func (i *ImageService) SquashImage(id, p
 	if err != nil {
 		return "", errors.Wrap(err, "error creating new image after squash")
 	}
+	ac := appcompose.NewAppComposer(i.imageStore, i.layerStores, i.referenceStore, i.applayerStore, i)
+	ac.GenImgByImageID(image.ID(id))
 	return string(newImgID), nil
 }
 
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/daemon/images/service.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/daemon/images/service.go
@@ -37,6 +37,7 @@ type ImageServiceConfig struct {
 	DistributionMetadataStore metadata.Store
 	EventsService             *daemonevents.Events
 	ImageStore                image.Store
+	ApplayerStore             image.ApplayerStore
 	LayerStores               map[string]layer.Store
 	MaxConcurrentDownloads    int
 	MaxConcurrentUploads      int
@@ -60,6 +61,7 @@ func NewImageService(config ImageService
 		downloadManager:           xfer.NewLayerDownloadManager(config.LayerStores, config.MaxConcurrentDownloads, xfer.WithMaxDownloadAttempts(config.MaxDownloadAttempts)),
 		eventsService:             config.EventsService,
 		imageStore:                &imageStoreWithLease{Store: config.ImageStore, leases: config.Leases, ns: config.ContentNamespace},
+		applayerStore:             config.ApplayerStore,
 		layerStores:               config.LayerStores,
 		referenceStore:            config.ReferenceStore,
 		registryService:           config.RegistryService,
@@ -75,6 +77,7 @@ func NewImageService(config ImageService
 type ImageService struct {
 	containers                containerStore
 	distributionMetadataStore metadata.Store
+	applayerStore             image.ApplayerStore
 	downloadManager           *xfer.LayerDownloadManager
 	eventsService             *daemonevents.Events
 	imageStore                image.Store
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/applayer.go
@@ -0,0 +1,112 @@
+package image  // import "github.com/docker/docker/image"
+
+import (
+	"github.com/docker/docker/layer"
+)
+
+type AppLayer interface {
+	AppLayerID() ID
+        // Name of Applayer layer
+        Name() string
+        // return dependence of the applayer
+        Deps () []layer.DiffID
+	// return len of deps
+	Depslen () int
+        // return size of the applayer
+        Size() int64
+
+	DiffID() layer.DiffID
+	OS() string
+	RefsCount() int
+	AddRefImage(id ID) error
+	DelRefImage(id ID) error
+}
+/*
+The content of the appLayer contains two parts.
+One part is the image config that is related to applayer.
+One part is the layer data.
+*/
+type appLayer struct {
+	size   int64
+	diffid layer.DiffID
+	name   string
+	os     string
+        // computedID is the ID computed from the hash of the image config.
+	applayerid ID
+        deps []layer.DiffID
+	refImages map[ID]struct{}
+}
+
+func copyDiffIDSlice(orig []layer.DiffID) []layer.DiffID {
+	if orig == nil {
+		return nil
+	}
+	return append([]layer.DiffID{}, orig...)
+}
+
+func copyIDSlice(orig []ID) []ID {
+	if orig == nil {
+		return nil
+	}
+	return append([]ID{}, orig...)
+}
+
+func (al *appLayer) copyAppLayer() AppLayer {
+	var copy appLayer
+
+	copy = *al
+	copy.deps = copyDiffIDSlice(al.deps)
+
+	if copy.refImages != nil {
+		copy.refImages = make(map[ID]struct{}, len(al.refImages))
+		for k, _ := range al.refImages {
+			copy.refImages[k] = struct{}{}
+		}
+	}
+
+	return &copy
+}
+
+
+func (al *appLayer) AppLayerID() ID {
+	return al.applayerid
+}
+
+func (al *appLayer) DiffID() layer.DiffID {
+        return al.diffid
+}
+
+func (al *appLayer) Name() string {
+        return al.name
+}
+
+func (al *appLayer) Size() int64 {
+        return al.size
+}
+
+func (al *appLayer) Deps() []layer.DiffID {
+        return al.deps
+}
+
+func (al *appLayer) Depslen() int {
+	return len(al.deps)
+}
+
+func (al *appLayer) RefsCount() int {
+	return len(al.refImages)
+}
+
+func (al *appLayer) OS() string {
+	return al.os
+}
+
+func (al *appLayer) AddRefImage(id ID) error {
+	al.refImages[id]=struct{}{}
+	return nil
+}
+
+func (al *appLayer) DelRefImage(id ID) error {
+	delete(al.refImages, id)
+	return nil
+}
+
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/applayer_fs.go
@@ -0,0 +1,424 @@
+package image // import "github.com/docker/docker/image"
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"io"
+	"path/filepath"
+	"sync"
+	"strconv"
+	"strings"
+	"github.com/docker/docker/layer"
+	"github.com/docker/docker/pkg/ioutils"
+	"github.com/docker/docker/pkg/archive"
+	digest "github.com/opencontainers/go-digest"
+	"github.com/pkg/errors"
+	"github.com/sirupsen/logrus"
+	"github.com/vbatts/tar-split/tar/storage"
+	"github.com/vbatts/tar-split/tar/asm"
+	"compress/gzip"
+)
+
+// StoreBackend provides interface for image.Store persistence
+type ApplayerStoreBackend interface {
+	LayerContentDir(dgst digest.Digest) string
+	SetLayerContent(ts io.Reader, dgst digest.Digest) (layer.DiffID, error)
+	Walk(f DigestWalkFunc) error
+	GetConfig(id digest.Digest) ([]byte, error)
+	SetConfig(data []byte) (digest.Digest, error)
+	Delete(id digest.Digest) error
+	GetSize(dgst digest.Digest) (int64, error)
+	SetSize(dgst digest.Digest, size int64) error
+	GetDiffid(dgst digest.Digest) (layer.DiffID, error)
+	SetDiffid(dgst digest.Digest, diffid layer.DiffID) error
+	GetName(dgst digest.Digest) (string, error)
+	SetName(dgst digest.Digest, name string) error
+	GetApplayerid(dgst digest.Digest) (ID, error)
+	SetApplayerid(dgst digest.Digest, id ID) error
+	DeleteMetadata(id digest.Digest, key string) error
+	GetLayerDataRoot() string
+	AppendImageID(dgst digest.Digest, id ID) error
+	RemoveImageID(dgst digest.Digest, id ID) error
+	GetImageRefs(dgst digest.Digest) (refs []string, err error)
+	AssembleTarTo(dgst digest.Digest, metadata io.ReadCloser, w io.Writer) error
+	TarSplitReader(dgst digest.Digest) (io.ReadCloser, error)
+}
+
+// fs implements StoreBackend using the filesystem.
+type applayerfs struct {
+	sync.RWMutex
+	root string
+}
+
+const (
+	applayerContentDirName  = "applayercontent"
+	applayerConfigDirName  = "applayerconfig"
+	applayerMetaDirName = "applayermeta"
+)
+
+// NewFSStoreBackend returns new filesystem based backend for image.Store
+func NewAppLayerFSStoreBackend(root string) (ApplayerStoreBackend, error) {
+	return newApplayerFSStore(root)
+}
+
+func newApplayerFSStore(root string) (*applayerfs, error) {
+	s := &applayerfs{
+		root: root,
+	}
+	if err := os.MkdirAll(filepath.Join(root, applayerConfigDirName, string(digest.Canonical)), 0700); err != nil {
+		return nil, errors.Wrap(err, "failed to create storage backend")
+	}
+	if err := os.MkdirAll(filepath.Join(root, applayerContentDirName, string(digest.Canonical)), 0700); err != nil {
+		return nil, errors.Wrap(err, "failed to create storage backend")
+	}
+	if err := os.MkdirAll(filepath.Join(root, applayerMetaDirName, string(digest.Canonical)), 0700); err != nil {
+		return nil, errors.Wrap(err, "failed to create storage backend")
+	}
+	return s, nil
+}
+
+func (s *applayerfs) getAllFiles(dirPth string) (files []string, err error) {
+	s.RLock()
+	dir, err := ioutil.ReadDir(dirPth)
+	s.RUnlock()
+	if err != nil {
+		return nil, err
+	}
+
+	for _, fi := range dir {
+		if fi.IsDir() {
+			continue
+		} else {
+			ok := strings.HasPrefix(fi.Name(), "sha256")
+			if ok {
+				files = append(files, fi.Name())
+			}
+		}
+	}
+	return files, nil
+}
+
+func (s *applayerfs) SetLayerContent(ts io.Reader, dgst digest.Digest) (layer.DiffID, error) {
+
+	layerdir := s.layerContentDir(dgst)
+	digester := digest.Canonical.Digester()
+	tr := io.TeeReader(ts, digester.Hash())
+	tsw, err := s.tarSplitWriter(dgst, true)
+	if err != nil {
+		return "", err
+	}
+	metaPacker := storage.NewJSONPacker(tsw)
+	defer tsw.Close()
+
+	// we're passing nil here for the file putter, because the ApplyDiff will
+	// handle the extraction of the archive
+	rdr, err := asm.NewInputTarStream(tr, metaPacker, nil)
+	if err != nil {
+		return "", err
+	}
+        err = untar(rdr, layerdir, &archive.TarOptions{WhiteoutFormat: archive.OverlayWhiteoutFormat,})
+	io.Copy(ioutil.Discard, rdr)
+	if err != nil {
+		return "", err
+	}
+	return layer.DiffID(digester.Digest()), nil
+}
+
+func (s *applayerfs) AssembleTarTo(dgst digest.Digest, metadata io.ReadCloser, w io.Writer) error {
+	defer metadata.Close()
+
+	path :=	s.layerContentDir(dgst)
+	fileGetter := storage.NewPathFileGetter(path)
+	metaUnpacker := storage.NewJSONUnpacker(metadata)
+	return asm.WriteOutputTarStream(fileGetter, metaUnpacker, w)
+}
+
+func (s *applayerfs) configContentFile(dgst digest.Digest) string {
+	return filepath.Join(s.root, applayerConfigDirName, string(dgst.Algorithm()), dgst.Hex())
+}
+
+func (s *applayerfs) layerContentDir(dgst digest.Digest) string {
+	return filepath.Join(s.root, applayerContentDirName, string(dgst.Algorithm()), dgst.Hex())
+}
+
+func (s *applayerfs) LayerContentDir(dgst digest.Digest) string {
+	return s.layerContentDir(dgst)
+}
+
+func (s *applayerfs) metadataDir(dgst digest.Digest) string {
+	return filepath.Join(s.root, applayerMetaDirName, string(dgst.Algorithm()), dgst.Hex())
+}
+
+func (s *applayerfs) GetImageRefs(dgst digest.Digest) (refs []string, err error) {
+	dir := s.metadataDir(dgst)
+	return s.getAllFiles(filepath.Join(dir, "ImageRefs"))
+}
+
+// Walk calls the supplied callback for each image ID in the storage backend.
+func (s *applayerfs) Walk(f DigestWalkFunc) error {
+	// Only Canonical digest (sha256) is currently supported
+	s.RLock()
+	dir, err := ioutil.ReadDir(filepath.Join(s.root, applayerConfigDirName, string(digest.Canonical)))
+	s.RUnlock()
+	if err != nil {
+		return err
+	}
+	for _, v := range dir {
+		dgst := digest.NewDigestFromHex(string(digest.Canonical), v.Name())
+		if err := dgst.Validate(); err != nil {
+			logrus.Debugf("skipping invalid digest %s: %s", dgst, err)
+			continue
+		}
+		if err := f(dgst); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// Get returns the content stored under a given digest.
+func (s *applayerfs) GetConfig(dgst digest.Digest) ([]byte, error) {
+	s.RLock()
+	defer s.RUnlock()
+
+	return s.getConfig(dgst)
+}
+
+func (s *applayerfs) getConfig(dgst digest.Digest) ([]byte, error) {
+	content, err := ioutil.ReadFile(s.configContentFile(dgst))
+	if err != nil {
+		return nil, errors.Wrapf(err, "failed to get digest %s", dgst)
+	}
+
+	// todo: maybe optional
+	if digest.FromBytes(content) != dgst {
+		return nil, fmt.Errorf("failed to verify: %v", dgst)
+	}
+
+	return content, nil
+}
+
+// Set stores content by checksum.
+func (s *applayerfs) SetConfig(data []byte) (digest.Digest, error) {
+	s.Lock()
+	defer s.Unlock()
+
+	if len(data) == 0 {
+		return "", fmt.Errorf("invalid empty data")
+	}
+
+	dgst := digest.FromBytes(data)
+	if err := ioutils.AtomicWriteFile(s.configContentFile(dgst), data, 0600); err != nil {
+		return "", errors.Wrap(err, "failed to write digest data")
+	}
+
+	return dgst, nil
+}
+
+// Delete removes content and metadata files associated with the digest.
+func (s *applayerfs) Delete(dgst digest.Digest) error {
+	s.Lock()
+	defer s.Unlock()
+
+	if err := os.RemoveAll(s.metadataDir(dgst)); err != nil {
+		return err
+	}
+	if err := os.RemoveAll(s.layerContentDir(dgst)); err != nil {
+		return err
+	}
+	return os.Remove(s.configContentFile(dgst))
+}
+
+func (s *applayerfs) GetLayerDataRoot() string {
+	return filepath.Join(s.root, applayerContentDirName)
+}
+
+// SetMetadata sets metadata for a given ID. It fails if there's no base file.
+func (s *applayerfs) setMetadata(dgst digest.Digest, key string, data []byte) error {
+	s.Lock()
+	defer s.Unlock()
+	if _, err := s.getConfig(dgst); err != nil {
+		return err
+	}
+
+	baseDir := filepath.Join(s.metadataDir(dgst))
+	if err := os.MkdirAll(baseDir, 0700); err != nil {
+		return err
+	}
+	return ioutils.AtomicWriteFile(filepath.Join(s.metadataDir(dgst), key), data, 0600)
+}
+
+type syncFileCloser struct {
+	*os.File
+}
+
+func (w syncFileCloser) Close() error {
+	err := w.File.Sync()
+	if err1 := w.File.Close(); err == nil {
+		err = err1
+	}
+	return err
+}
+
+func (s *applayerfs) tarSplitWriter(dgst digest.Digest, compressInput bool) (io.WriteCloser, error) {
+	if _, err := s.getConfig(dgst); err != nil {
+		return nil, err
+	}
+
+	baseDir := filepath.Join(s.metadataDir(dgst))
+	if err := os.MkdirAll(baseDir, 0700); err != nil {
+		return nil, err
+	}
+	f, err := os.OpenFile(filepath.Join(baseDir, "app-tar-split.json.gz"), os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
+	if err != nil {
+		return nil, err
+	}
+	sf := syncFileCloser{f}
+	var wc io.WriteCloser
+	if compressInput {
+		wc = gzip.NewWriter(sf)
+	} else {
+		wc = sf
+	}
+
+	return ioutils.NewWriteCloserWrapper(wc, func() error {
+		wc.Close()
+		return sf.Close()
+	}), nil
+}
+
+func (s *applayerfs) TarSplitReader(dgst digest.Digest) (io.ReadCloser, error) {
+	if _, err := s.getConfig(dgst); err != nil {
+		return nil, err
+	}
+	baseDir := filepath.Join(s.metadataDir(dgst))
+	if err := os.MkdirAll(baseDir, 0700); err != nil {
+		return nil, err
+	}
+	fp := filepath.Join(baseDir, "app-tar-split.json.gz")
+	fz, err := os.Open(fp)
+	if err != nil {
+		return nil, err
+	}
+	f, err := gzip.NewReader(fz)
+	if err != nil {
+		fz.Close()
+		return nil, err
+	}
+
+	return ioutils.NewReadCloserWrapper(f, func() error {
+		f.Close()
+		return fz.Close()
+	}), nil
+}
+
+func (s *applayerfs) AppendImageID(dgst digest.Digest, id ID) error {
+	s.Lock()
+	defer s.Unlock()
+	if _, err := s.getConfig(dgst); err != nil {
+		return err
+	}
+
+	baseDir := filepath.Join(s.metadataDir(dgst), "ImageRefs")
+	if err := os.MkdirAll(baseDir, 0700); err != nil {
+		return err
+	}
+	return ioutils.AtomicWriteFile(filepath.Join(baseDir, id.String()), []byte(""), 0600)
+}
+
+func (s *applayerfs) RemoveImageID(dgst digest.Digest, id ID) error {
+	s.Lock()
+	defer s.Unlock()
+	if _, err := s.getConfig(dgst); err != nil {
+		return err
+	}
+
+	baseDir := filepath.Join(s.metadataDir(dgst), "ImageRefs")
+	return os.Remove(filepath.Join(baseDir, id.String()))
+}
+
+// GetMetadata returns metadata for a given digest.
+func (s *applayerfs) getMetadata(dgst digest.Digest, key string) ([]byte, error) {
+	s.RLock()
+	defer s.RUnlock()
+
+	if _, err := s.getConfig(dgst); err != nil {
+		return nil, err
+	}
+	bytes, err := ioutil.ReadFile(filepath.Join(s.metadataDir(dgst), key))
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to read metadata")
+	}
+	return bytes, nil
+}
+
+func (s *applayerfs) GetSize(dgst digest.Digest) (int64, error) {
+
+	bytes, err := s.getMetadata(dgst, "size")
+	if err != nil {
+		return 0, err
+	}
+	size, err := strconv.ParseInt(string(bytes), 10, 64)
+	if err != nil {
+		return 0, err
+	}
+	return size, nil
+}
+
+func (s *applayerfs) SetSize(dgst digest.Digest, size int64) error {
+	content := fmt.Sprintf("%d", size)
+	return s.setMetadata(dgst, "size", []byte(content))
+}
+
+
+func (s *applayerfs) GetDiffid(dgst digest.Digest) (layer.DiffID, error) {
+	bytes, err := s.getMetadata(dgst, "diffid")
+	if err != nil {
+		return "", err
+	}
+	dgst1, err := digest.Parse(strings.TrimSpace(string(bytes)))
+	if err != nil {
+		return "", err
+	}
+	return layer.DiffID(dgst1), nil
+}
+
+func (s *applayerfs) SetDiffid(dgst digest.Digest, diffid layer.DiffID) error {
+	return s.setMetadata(dgst, "diffid", []byte(diffid.String()));
+}
+
+func (s *applayerfs) GetName(dgst digest.Digest) (string, error) {
+	bytes, err := s.getMetadata(dgst, "name")
+	if err != nil {
+		return "", err
+	}
+	return string(bytes), nil
+}
+
+func (s *applayerfs) SetName(dgst digest.Digest, name string) error {
+	return s.setMetadata(dgst, "name", []byte(name))
+}
+
+func (s *applayerfs) GetApplayerid(dgst digest.Digest) (ID, error) {
+	bytes, err := s.getMetadata(dgst, "applayerid")
+	if err != nil {
+		return "", err
+	}
+	dgst1, err := digest.Parse(strings.TrimSpace(string(bytes)))
+	if err != nil {
+		return "", err
+	}
+	return ID(dgst1), nil
+}
+
+func (s *applayerfs) SetApplayerid(dgst digest.Digest, id ID) error {
+	return s.setMetadata(dgst, "applayerid", []byte(id.String()))
+}
+// DeleteMetadata removes the metadata associated with a digest.
+func (s *applayerfs) DeleteMetadata(dgst digest.Digest, key string) error {
+	s.Lock()
+	defer s.Unlock()
+
+	return os.RemoveAll(filepath.Join(s.metadataDir(dgst), key))
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/applayer_store.go
@@ -0,0 +1,479 @@
+package image // import "github.com/docker/docker/image"
+
+import (
+	"encoding/json"
+	"context"
+	"strings"
+	"fmt"
+	"sync"
+	"io"
+	"io/ioutil"
+	"path/filepath"
+	"os"
+	"github.com/docker/distribution/digestset"
+	"github.com/docker/docker/layer"
+	"github.com/docker/docker/pkg/system"
+	"github.com/docker/docker/pkg/chrootarchive"
+	"github.com/docker/docker/pkg/directory"
+	digest "github.com/opencontainers/go-digest"
+	"github.com/pkg/errors"
+	"github.com/sirupsen/logrus"
+	"github.com/docker/docker/pkg/stringid"
+	"github.com/moby/locker"
+	"github.com/docker/docker/pkg/idtools"
+)
+
+var (
+        // untar defines the untar method
+        untar = chrootarchive.UntarUncompressed
+)
+
+const (
+	ApplayerFileName        = "applayer.tar"
+	NameFileName		= "applayername"
+	ConfFileName		= "applayer.conf"
+)
+
+// Store is an interface for creating and accessing images
+type ApplayerStore interface {
+	SaveAppLayer(id ID, outDir string) error
+	GetAppLayerDataDir(id ID) string
+	AppendImgID(applayerid ID, imageID ID) error
+	DeleteImgID(applayerid ID, imageID ID) error
+	Create(ts io.Reader, name string, config []byte) (ID, error)
+	GetConfig(id ID) (*Image, error)
+	Get(id ID) (AppLayer, error)
+	GetByName(name string) (ID, error)
+	Delete(id ID) error
+	Search(partialID string) (ID, error)
+	Map() map[ID]AppLayer
+	Len() int
+	LockId(id string)
+	UnlockId(id string)
+}
+
+type AsOptions struct {
+	IDMapping	*idtools.IdentityMapping
+}
+
+
+type applayerstore struct {
+	sync.RWMutex
+	applayers    map[ID]*appLayer
+	fs        ApplayerStoreBackend
+	digestSet *digestset.Set
+	nameSet    map[string]ID
+	locker    *locker.Locker
+	uidMaps       []idtools.IDMap
+	gidMaps       []idtools.IDMap
+}
+
+// NewApplayerStore returns new store object for given set of layer stores
+func NewApplayerStore(fs ApplayerStoreBackend, imageStore Store, options AsOptions) (ApplayerStore, error) {
+	as := &applayerstore{
+		applayers:    make(map[ID]*appLayer),
+		fs:        fs,
+		digestSet: digestset.NewSet(),
+		nameSet:	make(map[string]ID),
+		locker:    locker.New(),
+		uidMaps:   options.IDMapping.UIDs(),
+		gidMaps:   options.IDMapping.GIDs(),
+	}
+
+	// load all current applayers 
+	if err := as.restore(imageStore); err != nil {
+		return nil, err
+	}
+
+	return as, nil
+
+}
+
+func (as *applayerstore) restore(imageStore Store) error {
+	err := as.fs.Walk(func(dgst digest.Digest) error {
+		appimg, err := as.GetConfig(IDFromDigest(dgst))
+		if err != nil {
+			logrus.Errorf("invalid applayer %v, %v", dgst, err)
+			return nil
+		}
+		if !system.IsOSSupported(appimg.OperatingSystem()) {
+			logrus.Errorf("not restoring applayer with unsupported operating system %v, %s", dgst, appimg.OperatingSystem())
+			return nil
+		}
+
+		flag, err := appimg.GetAppImageflag()
+		if err != nil {
+			logrus.Errorf("invalid applayer %v, %v", dgst, err)
+			return nil
+		}
+		if flag != "true" {
+			logrus.Errorf("not restoring applayer %v without appImageflag", dgst)
+			return nil
+		}
+
+		var al appLayer
+		al.os = appimg.OperatingSystem()
+		al.size, err = as.fs.GetSize(dgst)
+		if err != nil {
+			logrus.Errorf("not restoring applayer %v without size", dgst)
+			return nil;
+		}
+		al.diffid, err = as.fs.GetDiffid(dgst)
+		if err != nil {
+			logrus.Errorf("not restoring applayer %v without diffid", dgst)
+			return nil;
+		}
+		al.name, err = as.fs.GetName(dgst)
+		if err != nil {
+			logrus.Errorf("not restoring applayer %v without name", dgst)
+			return nil;
+		}
+		al.applayerid, err = as.fs.GetApplayerid(dgst)
+		if err != nil {
+			logrus.Errorf("not restoring applayer %v without applayerid", dgst)
+			return nil;
+		}
+		deplen, err := appimg.Getdeplen()
+		if err != nil  {
+			logrus.Errorf("not restoring applayer %v for invalid deplen", dgst)
+			return nil
+		}
+		for i := 0; i < deplen; i++ {
+			diffIdStr, err := appimg.Getdepdiff(i);
+			if err != nil {
+				logrus.Errorf("not restoring applayer %v for invalid depdiff", dgst)
+				return nil
+			}
+			dgst1, err := digest.Parse(diffIdStr)
+			if err != nil {
+				return err
+			}
+			al.deps = append(al.deps, layer.DiffID(dgst1))
+		}
+		refs, err := as.fs.GetImageRefs(dgst)
+		if err != nil {
+			return err
+		}
+		al.refImages = make(map[ID]struct{})
+		for _, ref := range refs {
+			dgst1, err := digest.Parse(strings.TrimSpace(string(ref)))
+			if err != nil {
+				return err
+			}
+			id := IDFromDigest(dgst1)
+			_, err = imageStore.Search(id.String())
+			if err == nil {
+				al.refImages[id] = struct{}{}
+			} else {
+				if err := as.fs.RemoveImageID(dgst, id); err != nil {
+					return err
+				}
+			}
+		}
+		if err := as.digestSet.Add(dgst); err != nil {
+			return err
+		}
+		as.applayers[IDFromDigest(dgst)] = &al
+		as.nameSet[al.name]=al.applayerid
+		return nil
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (as *applayerstore) GetAppLayerDataDir(id ID) string {
+	return as.fs.LayerContentDir(id.Digest())
+}
+
+
+func (as *applayerstore) AppendImgID(applayerid ID, imageID ID) error {
+	as.Lock()
+	defer as.Unlock()
+	al := as.applayers[applayerid]
+	if nil == al {
+		return fmt.Errorf("func AppendImgID failed to get applayer: %v", applayerid)
+	}
+	al.AddRefImage(imageID)
+	return as.fs.AppendImageID(applayerid.Digest(), imageID)
+}
+
+func (as *applayerstore) DeleteImgID(applayerid ID, imageID ID) error {
+	as.Lock()
+	defer as.Unlock()
+	al := as.applayers[applayerid]
+	if nil == al {
+		return fmt.Errorf("func DeleteImgID failed to get applayer: %v", applayerid)
+	}
+	al.DelRefImage(imageID)
+	return as.fs.RemoveImageID(applayerid.Digest(), imageID)
+}
+
+
+func (as *applayerstore) Create(ts io.Reader, name string, config []byte) (ID, error) {
+	var appimg Image
+	err := json.Unmarshal(config, &appimg)
+	if err != nil {
+		return "", err
+	}
+	var layerCount = 0
+
+	// Must reject any config that references diffIDs from the history
+	// which aren't among the rootfs layers.
+	var diffID layer.DiffID
+	for _, diffID = range appimg.RootFS.DiffIDs {
+		layerCount++
+	}
+	if layerCount > 1 {
+		return "", errors.Wrapf(err, "too many layers in config file")
+	}
+
+	flag, err := appimg.GetAppImageflag()
+	if err != nil {
+		return "",  err
+	}
+	if flag != "true" {
+		return "", errors.Wrapf(err, "can not find appImageflag label in config file")
+	}
+	deplen, err := appimg.Getdeplen()
+	if err != nil  {
+		return "", errors.Wrapf(err, "can not find deplen in config file")
+	}
+	var al appLayer
+	for i := 0 ; i < deplen ; i++ {
+		diffIdStr, err := appimg.Getdepdiff(i);
+		if err != nil {
+			return "", nil
+		}
+		dgst1, err := digest.Parse(strings.TrimSpace(diffIdStr))
+		if err != nil {
+			return "", err
+		}
+		al.deps = append(al.deps, layer.DiffID(dgst1))
+	}
+
+	dgst, err := as.fs.SetConfig(config)
+	if err != nil {
+		return "", err
+	}
+	applayerid := IDFromDigest(dgst)
+	as.locker.Lock(applayerid.String())
+	defer as.locker.Unlock(applayerid.String())
+
+	as.Lock()
+	defer as.Unlock()
+	if _, exists := as.applayers[applayerid]; exists {
+		return applayerid, nil
+	}
+	diffid,	err := as.fs.SetLayerContent(ts, dgst)
+	if err != nil {
+		as.fs.Delete(dgst)
+		return "", err
+	}
+	if diffid != diffID {
+		as.fs.Delete(dgst)
+		return "", errors.Wrapf(err, "applayer content can not pass verification")
+	}
+	applyDir := as.fs.LayerContentDir(dgst)
+	al.size, _ = directory.Size(context.TODO(), applyDir)
+	al.diffid = diffid
+	al.name = name
+	al.os = appimg.OperatingSystem()
+	al.applayerid = applayerid
+	al.refImages = make(map[ID]struct{})
+	as.fs.SetSize(dgst, al.size)
+	as.fs.SetDiffid(dgst, al.diffid)
+	as.fs.SetName(dgst, al.name)
+	as.fs.SetApplayerid(dgst, al.applayerid)
+
+	as.applayers[applayerid] = &al
+	if err := as.digestSet.Add(applayerid.Digest()); err != nil {
+		as.fs.Delete(dgst)
+		delete(as.applayers, applayerid)
+		return "", err
+	}
+	as.nameSet[name]=applayerid
+
+	return applayerid, nil
+}
+
+type applayerNotFoundError string
+
+func (e applayerNotFoundError) Error() string {
+	return "No such image: " + string(e)
+}
+
+func (applayerNotFoundError) NotFound() {}
+
+func (as *applayerstore) Search(term string) (ID, error) {
+	as.RLock()
+	defer as.RUnlock()
+	dgst, err := as.digestSet.Lookup(term)
+	if err != nil {
+		if err == digestset.ErrDigestNotFound {
+			err = applayerNotFoundError(term)
+		}
+		return "", errors.WithStack(err)
+	}
+	return IDFromDigest(dgst), nil
+}
+
+func (as *applayerstore) GetConfig(id ID) (*Image, error) {
+	// todo: Check if image is in images
+	// todo: Detect manual insertions and start using them
+	config, err := as.fs.GetConfig(id.Digest())
+	if err != nil {
+		return nil, err
+	}
+
+	img, err := NewFromJSON(config)
+	if err != nil {
+		return nil, err
+	}
+	img.computedID = id
+
+	return (*Image)(img), nil
+}
+
+
+func (as *applayerstore) Get(id ID) (AppLayer, error) {
+	as.RLock()
+	defer as.RUnlock()
+	al := as.applayers[id]
+	if nil == al {
+		return nil, fmt.Errorf("func Get failed to get applayer: %v", id)
+	}
+	return al.copyAppLayer(), nil
+}
+
+func (as *applayerstore) SaveAppLayer(id ID, outDir string) error {
+	as.LockId(id.String())
+	defer as.UnlockId(id.String())
+
+	as.RLock()
+	al := as.applayers[id]
+	as.RUnlock()
+	if nil == al {
+		return fmt.Errorf("func SaveAppLayer failed to get applayer: %v", id)
+	}
+	fileinfo, err := os.Stat(outDir)
+	if err != nil {
+		return err
+	}
+	isDir := fileinfo.IsDir()
+	if isDir == false {
+		return fmt.Errorf("%s is not dir", outDir)
+	}
+	config, err := as.fs.GetConfig(id.Digest())
+	if err != nil {
+		return err
+	}
+	confPath := filepath.Join(outDir, ConfFileName)
+	if err := ioutil.WriteFile(confPath, config, 0644); err != nil {
+		return err
+	}
+	namePath := filepath.Join(outDir, NameFileName)
+	if err := ioutil.WriteFile(namePath, []byte(al.Name()), 0644); err != nil {
+		return err
+	}
+	r, err := as.fs.TarSplitReader(id.Digest())
+	if err != nil {
+		return err
+	}
+
+	pr, pw := io.Pipe()
+	defer pr.Close()
+
+	go func() {
+		err := as.fs.AssembleTarTo(id.Digest(), r, pw)
+		if err != nil {
+			pw.CloseWithError(err)
+		} else {
+			pw.Close()
+		}
+	}()
+
+	layerPath := filepath.Join(outDir, ApplayerFileName)
+	tarFile, err := system.CreateSequential(layerPath)
+	if err != nil {
+		return err
+	}
+	defer tarFile.Close()
+	if _, err := io.Copy(tarFile, pr); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (as *applayerstore) GetByName(name string) (ID, error) {
+	as.RLock()
+	defer as.RUnlock()
+	id := as.nameSet[name]
+	if "" == id {
+		return "", fmt.Errorf("func GetByName failed to get applayer: %s", name)
+	}
+	return id, nil
+}
+
+type applayerDeleteConflict struct {
+	refcount     int
+	applayerID   ID
+}
+
+func (adc *applayerDeleteConflict) Error() string {
+
+	return fmt.Sprintf("conflict: unable to delete %s (is used by other %d images)", stringid.TruncateID(adc.applayerID.String()), adc.refcount)
+}
+
+func (adc *applayerDeleteConflict) Conflict() {}
+
+func (as *applayerstore) Delete(id ID) error {
+	as.locker.Lock(id.String())
+	defer as.locker.Unlock(id.String())
+	as.Lock()
+	defer as.Unlock()
+	al := as.applayers[id]
+	if nil == al {
+		return fmt.Errorf("func Delete failed to get applayer: %v", id)
+	}
+	if al.RefsCount() > 0 {
+		return &applayerDeleteConflict{
+			applayerID:   id,
+			refcount: al.RefsCount(),
+		}
+	}
+	as.fs.Delete(id.Digest())
+	if err := as.digestSet.Remove(id.Digest()); err != nil {
+		logrus.Errorf("error removing %s from digest set: %q", id, err)
+	}
+	delete(as.applayers, id)
+	delete(as.nameSet, al.name)
+	return nil
+}
+
+func (as *applayerstore) LockId(id string) {
+	as.locker.Lock(id)
+}
+
+func (as *applayerstore) UnlockId(id string) {
+	as.locker.Unlock(id)
+}
+
+func (as *applayerstore) Map() map[ID]AppLayer {
+	as.RLock()
+	defer as.RUnlock()
+
+	applayers := make(map[ID]AppLayer)
+
+	for id, applayer := range as.applayers {
+		applayers[id] = applayer.copyAppLayer()
+	}
+	return applayers
+}
+
+func (as *applayerstore) Len() int {
+	as.RLock()
+	defer as.RUnlock()
+	return len(as.applayers)
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/apptarexport/appload.go
@@ -0,0 +1,92 @@
+package apptarexport // import "github.com/docker/docker/image/apptarexport"
+
+import (
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+
+	"github.com/docker/docker/image"
+	"github.com/docker/docker/image/appcompose"
+	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/pkg/chrootarchive"
+	"github.com/docker/docker/pkg/progress"
+	"github.com/docker/docker/pkg/streamformatter"
+	"github.com/docker/docker/pkg/system"
+	"github.com/moby/sys/symlink"
+	"github.com/sirupsen/logrus"
+)
+
+func (l *apptarexporter) 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-app-import-")
+	if err != nil {
+		return err
+	}
+	defer os.RemoveAll(tmpDir)
+
+	if err := chrootarchive.Untar(inTar, tmpDir, nil); err != nil {
+		return err
+	}
+
+	confPath, err := safePath(tmpDir, image.ConfFileName)
+	if err != nil {
+		return err
+	}
+	config, err := ioutil.ReadFile(confPath)
+	if err != nil {
+		return err
+	}
+	namePath, err := safePath(tmpDir, image.NameFileName)
+	if err != nil {
+		return err
+	}
+	name, err := ioutil.ReadFile(namePath)
+	if err != nil {
+		return err
+	}
+	tarPath, err := safePath(tmpDir, image.ApplayerFileName)
+	rawTar, err := system.OpenSequential(tarPath)
+	if err != nil {
+		return err
+	}
+	defer rawTar.Close()
+
+	var r io.Reader
+	if progressOutput != nil {
+		fileInfo, err := rawTar.Stat()
+		if err != nil {
+			logrus.Debugf("Error statting file: %v", err)
+			return err
+		}
+
+		r = progress.NewProgressReader(rawTar, progressOutput, fileInfo.Size(), string(name), "Loading applayer")
+	} else {
+		r = rawTar
+	}
+
+	inflatedLayerData, err := archive.DecompressStream(r)
+	if err != nil {
+		return err
+	}
+	defer inflatedLayerData.Close()
+	id, err := l.as.Create(inflatedLayerData, string(name), config)
+	if err != nil {
+		return err
+	}
+	logrus.Debugf("In func LoadApp call NewAppComposer")
+	ac := appcompose.NewAppComposer(l.is, l.lss, l.rs, l.as, l.loggerImgEvent)
+	err = ac.GenImgByApplayerID(id)
+
+	return err
+}
+
+
+func safePath(base, path string) (string, error) {
+	return symlink.FollowSymlinkInScope(filepath.Join(base, path), base)
+}
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/apptarexport/appsave.go
@@ -0,0 +1,38 @@
+package apptarexport // import "github.com/docker/docker/image/apptarexport"
+
+import (
+	"io"
+	"io/ioutil"
+	"os"
+
+	"github.com/docker/docker/pkg/archive"
+)
+
+func (l *apptarexporter) SaveApp(idorName string, outStream io.Writer) error {
+
+	id, err := l.as.Search(idorName)
+	if err != nil {
+		id, err = l.as.GetByName(idorName)
+		if err != nil {
+			return err
+		}
+	}
+
+	tempDir, err := ioutil.TempDir("", "docker-app-export-")
+	if err != nil {
+		return err
+	}
+	defer os.RemoveAll(tempDir)
+	err = l.as.SaveAppLayer(id, tempDir)
+	if 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
+}
+
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/apptarexport/apptarexport.go
@@ -0,0 +1,27 @@
+package apptarexport // import "github.com/docker/docker/image/apptarexport"
+
+import (
+	"github.com/docker/docker/image"
+	"github.com/docker/docker/layer"
+	refstore "github.com/docker/docker/reference"
+)
+
+
+type apptarexporter struct {
+	is             image.Store
+	lss            map[string]layer.Store
+	rs             refstore.Store
+	as	       image.ApplayerStore
+	loggerImgEvent image.LogImageEvent
+}
+
+// NewTarExporter returns new Exporter for tar packages
+func NewAppTarExporter(is image.Store, lss map[string]layer.Store, as image.ApplayerStore, rs refstore.Store, loggerImgEvent image.LogImageEvent) image.AppExporter {
+	return &apptarexporter{
+		is:             is,
+		lss:            lss,
+		as:             as,
+		rs:             rs,
+		loggerImgEvent: loggerImgEvent,
+	}
+}
--- 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
@@ -3,6 +3,7 @@ package image // import "github.com/dock
 import (
 	"encoding/json"
 	"errors"
+	"strconv"
 	"io"
 	"runtime"
 	"strings"
@@ -11,9 +12,17 @@ import (
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/layer"
+	"github.com/docker/go-connections/nat"
 	digest "github.com/opencontainers/go-digest"
 )
 
+type LogImageEvent interface {
+	// LogImageEvent generates an event related to an image operation
+	LogImageEvent(imageID, refName, action string)
+}
+
+type runConfigModifier func(*container.Config)
+
 // ID is the content-addressable ID of an image.
 type ID digest.Digest
 
@@ -61,6 +70,7 @@ type V1Image struct {
 	Size int64 `json:",omitempty"`
 }
 
+
 // Image stores the image configuration
 type Image struct {
 	V1Image
@@ -98,6 +108,10 @@ func (img *Image) RunConfig() *container
 	return img.Config
 }
 
+func (img *Image) RunContainerConfig() *container.Config {
+	return &img.ContainerConfig
+}
+
 // BaseImgArch returns the image's architecture. If not populated, defaults to the host runtime arch.
 func (img *Image) BaseImgArch() string {
 	arch := img.Architecture
@@ -107,6 +121,21 @@ func (img *Image) BaseImgArch() string {
 	return arch
 }
 
+func (img *Image) DiffLen() int {
+	if img.RootFS == nil {
+		return 0
+	}
+	return len(img.RootFS.DiffIDs)
+}
+
+func (img *Image) Diff() []layer.DiffID {
+	if img.RootFS == nil {
+		return nil
+	}
+	return img.RootFS.DiffIDs
+}
+
+
 // BaseImgVariant returns the image's variant, whether populated or not.
 // This avoids creating an inconsistency where the stored image variant
 // is "greater than" (i.e. v8 vs v6) the actual image variant.
@@ -123,6 +152,86 @@ func (img *Image) OperatingSystem() stri
 	return os
 }
 
+func (img *Image) Getdeplen() (int, error) {
+	if img.Config == nil {
+		return 0, errors.New("container config of the image is empty")
+	}
+	tmp := img.Config.Labels["deplen"]
+	if tmp != "" {
+		return strconv.Atoi(tmp)
+	}
+	return 0, errors.New("Not exsit label deplen")
+}
+
+func (img *Image) Getdepdiff(index int) (string, error) {
+	if img.Config == nil {
+		return "", errors.New("container config of the image is empty")
+	}
+	tmp := img.Config.Labels["depdiff"+strconv.Itoa(index)]
+	if tmp != "" {
+		return tmp, nil
+	}
+	return "", errors.New("Not exsit label depdiff")
+}
+
+func (img *Image) setdepdiff(index int, id layer.DiffID) error {
+	if index < 0 {
+		return errors.New("invalid index")
+	}
+	if img.Config == nil {
+		return errors.New("container config of the image is empty")
+	}
+	img.Config.Labels["depdiff"+strconv.Itoa(index)] = id.String()
+	return nil
+}
+
+func (img *Image) setdeplen(deplen int) error {
+	if deplen <= 0 {
+		return errors.New("invalid deplen")
+	}
+	if img.Config == nil {
+		return errors.New("container config of the image is empty")
+	}
+	img.Config.Labels["deplen"]=strconv.Itoa(deplen);
+	return nil
+}
+
+func (img *Image) SetLayerDiff(diffid layer.DiffID) error {
+	if img.Config == nil {
+		return errors.New("container config of the image is empty")
+	}
+	img.Config.Labels["upgradelayer"+diffid.String()] = "true";
+	return nil
+}
+
+func (img *Image) GetLayerDiff(diffid layer.DiffID) (string, error) {
+	if img.Config == nil {
+		return "", errors.New("container config of the image is empty")
+	}
+	return img.Config.Labels["upgradelayer"+diffid.String()], nil
+}
+
+func (img *Image) setAppImageflag() error {
+	if img.Config == nil {
+		return errors.New("container config of the image is empty")
+	}
+	img.Config.Labels["appimage"]="true"
+	return nil
+}
+
+func (img *Image) GetAppImageflag() (string, error) {
+	if img.Config == nil {
+		return "", errors.New("container config of the image is empty")
+	}
+	return img.Config.Labels["appimage"], nil
+}
+
+func (img *Image) GetAppLayerID() (string, error) {
+	if img.Config == nil {
+		return "", errors.New("container config of the image is empty")
+	}
+	return img.Config.Labels["applayerid"], nil
+}
 // MarshalJSON serializes the image to JSON. It sorts the top-level keys so
 // that JSON that's been manipulated by a push/pull cycle with a legacy
 // registry won't end up with a different key order.
@@ -190,6 +299,181 @@ func NewChildImage(img *Image, child Chi
 	}
 }
 
+func withAppLayerID(applayerid string) runConfigModifier {
+	return func(runConfig *container.Config) {
+		if runConfig.Labels == nil {
+			runConfig.Labels = make(map[string]string)
+		}
+		runConfig.Labels["applayerid"] = applayerid
+	}
+}
+
+func copyRunConfig(runConfig *container.Config, modifiers ...runConfigModifier) *container.Config {
+	copy := *runConfig
+	copy.Cmd = copyStringSlice(runConfig.Cmd)
+	copy.Env = copyStringSlice(runConfig.Env)
+	copy.Entrypoint = copyStringSlice(runConfig.Entrypoint)
+	copy.OnBuild = copyStringSlice(runConfig.OnBuild)
+	copy.Shell = copyStringSlice(runConfig.Shell)
+
+	if copy.Volumes != nil {
+		copy.Volumes = make(map[string]struct{}, len(runConfig.Volumes))
+		for k, v := range runConfig.Volumes {
+			copy.Volumes[k] = v
+		}
+	}
+
+	if copy.ExposedPorts != nil {
+		copy.ExposedPorts = make(nat.PortSet, len(runConfig.ExposedPorts))
+		for k, v := range runConfig.ExposedPorts {
+			copy.ExposedPorts[k] = v
+		}
+	}
+
+	if copy.Labels != nil {
+		copy.Labels = make(map[string]string, len(runConfig.Labels))
+		for k, v := range runConfig.Labels {
+			copy.Labels[k] = v
+		}
+	}
+
+	for _, modifier := range modifiers {
+		modifier(&copy)
+	}
+	return &copy
+}
+
+func copyStringSlice(orig []string) []string {
+	if orig == nil {
+		return nil
+	}
+	return append([]string{}, orig...)
+}
+
+func NewMergeImage(img *Image, topimg *Image) (*Image, error) {
+	var rootFS *RootFS
+	if img.RootFS != nil {
+		rootFS = img.RootFS.Clone()
+	} else {
+		rootFS = NewRootFS()
+	}
+	diffs := topimg.Diff()
+	diff := diffs[len(diffs)-1]
+	rootFS.Append(diff)
+	config, err := json.Marshal(topimg)
+	if err != nil {
+		return nil, err
+	}
+	dgst := digest.FromBytes(config)
+	applayerid := IDFromDigest(dgst)
+
+	return &Image{
+		V1Image: V1Image{
+			DockerVersion:   dockerversion.Version,
+			Config:          copyRunConfig(topimg.RunConfig(), withAppLayerID(applayerid.String())),
+			// set ContainerConfig to zero, because we do not want to make multi 
+			// different images have same commited container
+			Architecture:    img.BaseImgArch(),
+			Variant:         img.BaseImgVariant(),
+			OS:              img.OperatingSystem(),
+			Author:          topimg.Author,
+			Created:         time.Now().UTC(),
+		},
+		RootFS:     rootFS,
+		History:    img.History,
+		OSFeatures: img.OSFeatures,
+		OSVersion:  img.OSVersion,
+	}, nil
+}
+
+func NewApplayerImage(img *Image) *Image {
+	var rootFS *RootFS
+	rootFS = NewRootFS()
+	diffs := img.Diff()
+	diff := diffs[len(diffs)-1]
+	rootFS.Append(diff)
+
+	appimg := &Image{
+		V1Image: V1Image{
+			DockerVersion:   dockerversion.Version,
+			Config:          copyRunConfig(img.RunConfig()),
+			Architecture:    img.BaseImgArch(),
+			Variant:         img.BaseImgVariant(),
+			OS:              img.OperatingSystem(),
+			//Container:       img.Container,
+			//ContainerConfig: *copyRunConfig(img.RunContainerConfig()),
+			Author:          img.Author,
+			Created:         time.Now().UTC(),
+		},
+		RootFS:     rootFS,
+		History:    nil,
+		OSFeatures: img.OSFeatures,
+		OSVersion:  img.OSVersion,
+	}
+	deplen := len(diffs)-1
+	for i := 0; i < deplen; i++ {
+		appimg.setdepdiff(i, diffs[i])
+	}
+	appimg.setdeplen(deplen)
+	appimg.setAppImageflag()
+	return appimg
+}
+
+func NewUpgradeImage(img *Image, diffs []layer.DiffID) *Image {
+	var rootFS *RootFS
+	if img.RootFS != nil {
+		rootFS = img.RootFS.Clone()
+	} else {
+		rootFS = NewRootFS()
+	}
+	upgradeimg := &Image{
+		V1Image: V1Image{
+			DockerVersion:   dockerversion.Version,
+			Config:          copyRunConfig(img.RunConfig()),
+			Architecture:    img.BaseImgArch(),
+			Variant:         img.BaseImgVariant(),
+			OS:              img.OperatingSystem(),
+			//Container:       img.Container,
+			//ContainerConfig: *copyRunConfig(img.RunContainerConfig()),
+			Author:          img.Author,
+			Created:         img.V1Image.Created,
+		},
+		RootFS:     rootFS,
+		History:    img.History ,
+		OSFeatures: img.OSFeatures,
+		OSVersion:  img.OSVersion,
+	}
+	for _, diff := range diffs {
+		upgradeimg.SetLayerDiff(diff)
+	}
+	return upgradeimg
+}
+
+func NewImageWithoutCreated(img *Image) *Image {
+	var rootFS *RootFS
+	if img.RootFS != nil {
+		rootFS = img.RootFS.Clone()
+	} else {
+		rootFS = NewRootFS()
+	}
+	upgradeimg := &Image{
+		V1Image: V1Image{
+			DockerVersion:   dockerversion.Version,
+			Config:          copyRunConfig(img.RunConfig()),
+			Architecture:    img.BaseImgArch(),
+			Variant:         img.BaseImgVariant(),
+			OS:              img.OperatingSystem(),
+			//Container:       img.Container,
+			//ContainerConfig: *copyRunConfig(img.RunContainerConfig()),
+			Author:          img.Author,
+		},
+		RootFS:     rootFS,
+		History:    img.History ,
+		OSFeatures: img.OSFeatures,
+		OSVersion:  img.OSVersion,
+	}
+	return upgradeimg
+}
 // History stores build commands that were used to create an image
 type History struct {
 	// Created is the timestamp at which the image was created
@@ -223,8 +507,14 @@ 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
+	LoadUpgrade(io.ReadCloser, io.Writer, bool) error
+	SaveUpgrade(string, string, string, string, io.Writer) error
+}
+
+// AppExporter provides interface for loading and saving images
+type AppExporter interface {
+	LoadApp(inTar io.ReadCloser, outStream io.Writer, quiet bool) error
+	SaveApp(idorName string, outStream io.Writer) error
 }
 
 // NewFromJSON creates an Image configuration from json.
--- /dev/null
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/image/appcompose.go
@@ -0,0 +1,181 @@
+package appcompose // import "github.com/docker/docker/image/appcompose"
+
+import (
+	"encoding/json"
+	"github.com/docker/docker/image"
+	"github.com/docker/docker/layer"
+	"github.com/sirupsen/logrus"
+	"github.com/docker/docker/pkg/stringid"
+	refstore "github.com/docker/docker/reference"
+	"github.com/docker/distribution/reference"
+)
+
+
+type appcomposer struct {
+	is             image.Store
+	lss            map[string]layer.Store
+	as	       image.ApplayerStore
+	rs             refstore.Store
+	loggerImgEvent image.LogImageEvent
+}
+type appComposer interface {
+	GenImgByApplayerID(applayerID image.ID) error
+	GenImgByImageID(ImageID image.ID) error
+	GenImg() error
+}
+
+// NewAppComposer returns new AppComposer for composing app images
+func NewAppComposer(is image.Store, lss map[string]layer.Store, rs refstore.Store, as image.ApplayerStore, loggerImgEvent image.LogImageEvent) appComposer {
+	return &appcomposer{
+		is:             is,
+		lss:            lss,
+		rs:             rs,
+		as:		as,
+		loggerImgEvent: loggerImgEvent,
+	}
+}
+
+
+func (ac *appcomposer) appcompose(imgid image.ID, baseimg *image.Image, al image.AppLayer) (err error) {
+	defer func() {
+		if err != nil {
+			logrus.Error("Error compose appimg between applayer: %v and img: %v for %v", al.AppLayerID(), baseimg.ID(), err)
+		}
+	}()
+	id := imgid.String()
+	applayerid := al.AppLayerID().String()
+	ac.is.LockId(id)
+	defer ac.is.UnlockId(id)
+	ac.as.LockId(applayerid)
+	defer ac.as.UnlockId(applayerid)
+	_, err = ac.is.Search(id)
+	if err != nil {
+		return nil
+	}
+	_, err = ac.as.Search(applayerid)
+	if err != nil {
+		return nil
+	}
+	deplen := al.Depslen()
+	deps := al.Deps()
+	if deplen > baseimg.DiffLen() {
+		logrus.Debugf("In func appcompose image %v have too few layer")
+		return nil
+	}
+	diffs := baseimg.Diff()
+	difflen := baseimg.DiffLen()
+	for i :=0; i < deplen; i++ {
+		if deps[i] != diffs[i] {
+			logrus.Debugf("In func appcompose diffID not match")
+			return nil
+		}
+	}
+	if deplen < difflen {
+		for i := deplen; i < difflen; i++ {
+			flag, err := baseimg.GetLayerDiff(diffs[i])
+			if err != nil {
+				return err
+			}
+			if flag != "true" {
+				return nil
+			}
+		}
+	}
+	chainid := baseimg.RootFS.ChainID()
+	datadir := ac.as.GetAppLayerDataDir(al.AppLayerID())
+	_, err = ac.lss[baseimg.OperatingSystem()].RegisterDir(datadir, al.DiffID(), al.Size(), chainid)
+	if err != nil {
+		return
+	}
+	topimg, err := ac.as.GetConfig(al.AppLayerID())
+	if err != nil {
+		return
+	}
+	mergeImage, err := image.NewMergeImage(baseimg, topimg)
+	if err != nil {
+		return
+	}
+	have, err := ac.is.GetAppImage(mergeImage)
+	if err != nil {
+		return
+	}
+	if true == have {
+		return  nil
+	}
+	config, err := json.Marshal(mergeImage)
+	if err != nil {
+		return
+	}
+	imgID, err := ac.is.Create(config)
+	if err != nil {
+		return
+	}
+	err = ac.as.AppendImgID(al.AppLayerID(), imgID)
+	if err != nil {
+		return
+	}
+	ac.loggerImgEvent.LogImageEvent(imgID.String(), imgID.String(), "Compose")
+	err = ac.is.AddAppImage(mergeImage)
+	if err != nil {
+		return
+	}
+	newTag, err := reference.ParseNormalizedNamed(al.Name())
+	if err != nil {
+		return
+	}
+	var baseID image.ID
+	baseID = baseimg.ID()
+	if newTag, err = reference.WithTag(reference.TrimNamed(newTag), stringid.TruncateID(baseID.String())); err != nil {
+		return
+	}
+	if err = ac.rs.AddTag(newTag, imgID.Digest(), true); err != nil {
+		return
+	}
+
+	if err = ac.is.SetLastUpdated(imgID); err != nil {
+		return
+	}
+	return
+}
+
+func (ac *appcomposer) GenImgByApplayerID(applayerID image.ID) error {
+	al, err := ac.as.Get(applayerID)
+	if err != nil {
+		return err
+	}
+
+	basemap := make(map[image.ID]*image.Image)
+	basemap = ac.is.Map()
+	for id, img := range basemap {
+		err = ac.appcompose(id, img, al)
+	}
+	return err
+}
+
+func (ac *appcomposer) GenImgByImageID(ImageID image.ID) error {
+	img, err := ac.is.Get(ImageID)
+	if err != nil {
+		return err
+	}
+	almap := make(map[image.ID]image.AppLayer)
+	almap = ac.as.Map()
+	for _, al := range almap {
+		err = ac.appcompose(ImageID, img, al)
+	}
+	return err
+}
+
+func (ac *appcomposer) GenImg() error {
+
+	basemap := make(map[image.ID]*image.Image)
+	almap := make(map[image.ID]image.AppLayer)
+	basemap = ac.is.Map()
+	almap = ac.as.Map()
+	var err error
+	for _, al := range almap {
+		for id, img := range basemap {
+			err = ac.appcompose(id, img, al)
+		}
+	}
+	return err
+}
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/image/store.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/image/store.go
@@ -12,10 +12,13 @@ import (
 	digest "github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
+	"github.com/moby/locker"
 )
 
 // Store is an interface for creating and accessing images
 type Store interface {
+	GetAppImage(img *Image) (bool, error)
+	AddAppImage(img *Image) error
 	Create(config []byte) (ID, error)
 	Get(id ID) (*Image, error)
 	Delete(id ID) ([]layer.Metadata, error)
@@ -28,6 +31,8 @@ type Store interface {
 	Map() map[ID]*Image
 	Heads() map[ID]*Image
 	Len() int
+	LockId(id string)
+	UnlockId(id string)
 }
 
 // LayerGetReleaser is a minimal interface for getting and releasing images.
@@ -45,8 +50,11 @@ type store struct {
 	sync.RWMutex
 	lss       map[string]LayerGetReleaser
 	images    map[ID]*imageMeta
+	applock sync.RWMutex
+	appimages map[ID]struct{}
 	fs        StoreBackend
 	digestSet *digestset.Set
+	locker *locker.Locker
 }
 
 // NewImageStore returns new store object for given set of layer stores
@@ -54,8 +62,10 @@ func NewImageStore(fs StoreBackend, lss
 	is := &store{
 		lss:       lss,
 		images:    make(map[ID]*imageMeta),
+		appimages: make(map[ID]struct{}),
 		fs:        fs,
 		digestSet: digestset.NewSet(),
+		locker:    locker.New(),
 	}
 
 	// load all current images and retain layers
@@ -92,13 +102,16 @@ func (is *store) restore() error {
 			return err
 		}
 
+		if err := is.AddAppImage(img); err != nil {
+			return err
+		}
+
 		imageMeta := &imageMeta{
 			layer:    l,
 			children: make(map[ID]struct{}),
 		}
 
 		is.images[IDFromDigest(dgst)] = imageMeta
-
 		return nil
 	})
 	if err != nil {
@@ -117,6 +130,14 @@ func (is *store) restore() error {
 	return nil
 }
 
+func (is *store) LockId(id string) {
+	is.locker.Lock(id)
+}
+
+func (is *store) UnlockId(id string) {
+	is.locker.Unlock(id)
+}
+
 func (is *store) Create(config []byte) (ID, error) {
 	var img Image
 	err := json.Unmarshal(config, &img)
@@ -146,6 +167,8 @@ func (is *store) Create(config []byte) (
 		return "", err
 	}
 	imageID := IDFromDigest(dgst)
+	is.locker.Lock(imageID.String())
+	defer is.locker.Unlock(imageID.String())
 
 	is.Lock()
 	defer is.Unlock()
@@ -222,7 +245,80 @@ func (is *store) Get(id ID) (*Image, err
 	return img, nil
 }
 
+func (is *store) AddAppImage(img *Image) error {
+	flag, err := img.GetAppImageflag()
+	if err != nil {
+		return err
+	}
+
+	if "true" != flag {
+		return nil
+	}
+
+	config, err := json.Marshal(NewImageWithoutCreated(img))
+	if err != nil {
+		return err
+	}
+	dgst := digest.FromBytes(config)
+	imageID := IDFromDigest(dgst)
+	is.applock.Lock()
+	defer is.applock.Unlock()
+	is.appimages[imageID] = struct{}{}
+
+	return nil
+}
+
+func (is *store) GetAppImage(img *Image) (bool, error) {
+	flag, err := img.GetAppImageflag()
+	if err != nil {
+		return false, err
+	}
+
+	if "true" != flag {
+		return false, err
+	}
+
+	config, err := json.Marshal(NewImageWithoutCreated(img))
+	if err != nil {
+		return false, err
+	}
+	dgst := digest.FromBytes(config)
+	imageID := IDFromDigest(dgst)
+	is.applock.RLock()
+	defer is.applock.RUnlock()
+	_, ok := is.appimages[imageID]
+	if ok {
+		return true, nil
+	}
+	return false, nil
+}
+
+func (is *store) DeleteAppImage(img *Image) error {
+	flag, err := img.GetAppImageflag()
+	if err != nil {
+		return err
+	}
+
+	if "true" != flag {
+		return nil
+	}
+
+	config, err := json.Marshal(NewImageWithoutCreated(img))
+	if err != nil {
+		return err
+	}
+	dgst := digest.FromBytes(config)
+	imageID := IDFromDigest(dgst)
+	is.applock.Lock()
+	defer is.applock.Unlock()
+	delete(is.appimages, imageID)
+	return nil
+}
+
 func (is *store) Delete(id ID) ([]layer.Metadata, error) {
+	is.locker.Lock(id.String())
+	defer is.locker.Unlock(id.String())
+
 	is.Lock()
 	defer is.Unlock()
 
@@ -250,6 +346,9 @@ func (is *store) Delete(id ID) ([]layer.
 	delete(is.images, id)
 	is.fs.Delete(id.Digest())
 
+	if err := is.DeleteAppImage(img); err != nil {
+		logrus.Errorf("error delete appimage id=%v: %q", id, err)
+	}
 	if imageMeta.layer != nil {
 		return is.lss[img.OperatingSystem()].Release(imageMeta.layer)
 	}
--- 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
@@ -15,6 +15,7 @@ import (
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/image"
+	"github.com/docker/docker/image/appcompose"
 	v1 "github.com/docker/docker/image/v1"
 	"github.com/docker/docker/layer"
 	"github.com/docker/docker/pkg/archive"
@@ -28,10 +29,14 @@ import (
 	"github.com/sirupsen/logrus"
 )
 
-func (l *tarexporter) checkifbaseInApp(appimg *image.Image, baseimg *image.Image) bool {
+func (l *tarexporter) checkifbaseInUpgrade(upgradeimg *image.Image, baseimg *image.Image) bool {
 	baseID := baseimg.RootFS.ChainID()
-	for i := range appimg.RootFS.DiffIDs {
-                rootFS := *appimg.RootFS
+	upgradeID := upgradeimg.RootFS.ChainID()
+	if baseID == upgradeID {
+		return false
+	}
+	for i := range upgradeimg.RootFS.DiffIDs {
+                rootFS := *upgradeimg.RootFS
                 rootFS.DiffIDs = rootFS.DiffIDs[:i+1]
                 if baseID == rootFS.ChainID() {
                         l.index = i
@@ -41,7 +46,27 @@ func (l *tarexporter) checkifbaseInApp(a
 	return false
 }
 
-func (l *tarexporter) LoadApp(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
+func (l *tarexporter) checkUpgradeLayer(upgradeimg *image.Image) (bool, error) {
+	if l.index == -1 {
+		return false, fmt.Errorf("index is not initialized")
+	}
+	diffids := upgradeimg.Diff()
+	for i, diffid := range diffids {
+		if i <= l.index {
+			continue;
+		}
+		flag, err := upgradeimg.GetLayerDiff(diffid)
+		if err != nil {
+			return false, err
+		}
+		if flag != "true" {
+			return false, nil
+		}
+	}
+	return true, nil
+}
+
+func (l *tarexporter) LoadUpgrade(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
 	var progressOutput progress.Output
 	if !quiet {
 		progressOutput = streamformatter.NewJSONProgressOutput(outStream, false)
@@ -117,8 +142,11 @@ func (l *tarexporter) LoadApp(inTar io.R
 		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")
+		if have := l.checkifbaseInUpgrade(img, baseimg);have == false {
+			return fmt.Errorf("baseimage is not included in upgradeimage, please check it")
+		}
+		if flag, _ := l.checkUpgradeLayer(img);flag == false {
+			return fmt.Errorf("loaded layer is not upgrade layer, please check it")
 		}
 		rootFS := *img.RootFS
 		rootFS.DiffIDs = nil
@@ -170,6 +198,8 @@ func (l *tarexporter) LoadApp(inTar io.R
 		if err != nil {
 			return err
 		}
+		ac := appcompose.NewAppComposer(l.is, l.lss, l.rs, l.as, l.loggerImgEvent)
+		ac.GenImgByImageID(imgID)
 		imageIDsStr += fmt.Sprintf("Loaded image ID: %s\n", imgID)
 
 		imageRefCount = 0
@@ -304,6 +334,8 @@ func (l *tarexporter) Load(inTar io.Read
 		if err != nil {
 			return err
 		}
+		ac := appcompose.NewAppComposer(l.is, l.lss, l.rs, l.as, l.loggerImgEvent)
+		ac.GenImgByImageID(imgID)
 		imageIDsStr += fmt.Sprintf("Loaded image ID: %s\n", imgID)
 
 		imageRefCount = 0
--- 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,30 +35,24 @@ 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 {
+type saveUpgradeSession struct {
 	*tarexporter
 	outDir      string
 	baseimgDescr *imageDescriptor
-	appimgDescr *imageDescriptor
+	upgradeimgDescr *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
+	upgradeID   image.ID
 	index       int
 }
 
-func (l *tarexporter) SaveApp(basename string, appname string, outStream io.Writer) error {
+func (l *tarexporter) SaveUpgrade(basename string, upgradename string, repo string, tag string, outStream io.Writer) error {
 	var pbase *imageDescriptor
-	var papp  *imageDescriptor
+	var pupgrade  *imageDescriptor
 	var baseID image.ID
-	var appID  image.ID
 
 	baseimages, err := l.parseNames([]string{basename})
 	if err != nil {
@@ -66,11 +60,11 @@ func (l *tarexporter) SaveApp(basename s
 	}
 
 	defer l.releaseLayerReferences(baseimages)
-	appimages, err := l.parseNames([]string{appname})
+	upgradeimages, err := l.parseNames([]string{upgradename})
 	if err != nil {
 		return err
 	}
-	defer l.releaseLayerReferences(appimages)
+	defer l.releaseLayerReferences(upgradeimages)
 
 	for k, v := range baseimages {
 		baseID = k
@@ -78,20 +72,19 @@ func (l *tarexporter) SaveApp(basename s
 		break
 	}
 
-	for k, v := range appimages {
-		appID = k
-		papp = v
+	for _, v := range upgradeimages {
+		pupgrade = v
 		break
 	}
-	session1 := &saveAppSession{tarexporter:l, baseimgDescr: pbase, appimgDescr: papp, appID:appID, baseID:baseID}
+	session1 := &saveUpgradeSession{tarexporter:l, baseimgDescr: pbase, upgradeimgDescr: pupgrade, baseID:baseID, index:-1}
 
-	have := session1.checkAppIncludebase(pbase, papp)
+	have := session1.checkUpgradeIncludebase(pbase, pupgrade)
 
 	if have == false {
-		return errors.Errorf("baseImage is not included in appImage")
+		return errors.Errorf("baseImage is not included in upgradeImage")
 	}
 
-	return session1.saveApp(outStream)
+	return session1.saveUpgrade(outStream, repo, tag)
 }
 
 func (l *tarexporter) Save(names []string, outStream io.Writer) error {
@@ -105,18 +98,17 @@ 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
+func (s *saveUpgradeSession) checkUpgradeIncludebase(pbase *imageDescriptor, pupgrade *imageDescriptor) bool {
+	img := pupgrade.image
 	baseimg := pbase.image
-	appChainID := appimg.RootFS.ChainID()
+	ChainID := img.RootFS.ChainID()
 	baseChainID := baseimg.RootFS.ChainID()
-	s.baseChainID = baseChainID
-	if  appChainID == baseChainID {
+	if ChainID == baseChainID {
 		return false
 	}
 
-	for i := range appimg.RootFS.DiffIDs {
-		rootFS := *appimg.RootFS
+	for i := range img.RootFS.DiffIDs {
+		rootFS := *img.RootFS
 		rootFS.DiffIDs = rootFS.DiffIDs[:i+1]
 		if baseChainID == rootFS.ChainID() {
 			s.index = i
@@ -126,7 +118,7 @@ func (s *saveAppSession) checkAppInclude
 	return false
 }
 
-func (s *saveAppSession) saveApp(outStream io.Writer) error {
+func (s *saveUpgradeSession) saveUpgrade(outStream io.Writer, repo string, tag string) error {
 	s.savedLayers = make(map[string]struct{})
 	s.diffIDPaths = make(map[layer.DiffID]string)
 
@@ -138,15 +130,13 @@ func (s *saveAppSession) saveApp(outStre
 	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
+	imageDescr := s.upgradeimgDescr
 
-	foreignSrcs, err := s.saveAppimage(id, s.baseChainID)
+	foreignSrcs, err := s.saveUpgradeimage()
 	if err != nil {
 		return err
 	}
@@ -154,14 +144,7 @@ func (s *saveAppSession) saveApp(outStre
 	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))
-	}
+	repoTags = append(repoTags, repo+":"+tag)
 
 	for _, l := range imageDescr.layers {
 		// IMPORTANT: We use path, not filepath here to ensure the layers
@@ -170,7 +153,7 @@ func (s *saveAppSession) saveApp(outStre
 		// LCOL.
 		layers = append(layers, path.Join(l, legacyLayerFileName))
 	}
-
+	id := s.upgradeID
 	manifest = append(manifest, manifestItem{
 		Config:       id.Digest().Hex() + ".json",
 		RepoTags:     repoTags,
@@ -188,25 +171,6 @@ func (s *saveAppSession) saveApp(outStre
 		}
 	}
 
-	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 {
@@ -244,17 +208,33 @@ func (s *saveAppSession) saveApp(outStre
 	return err
 }
 
-func (s *saveAppSession) saveAppimage(id image.ID, layerID layer.ChainID) (map[layer.DiffID]distribution.Descriptor, error) {
+func (s *saveUpgradeSession) saveUpgradeimage() (map[layer.DiffID]distribution.Descriptor, error) {
 
-	appimg := s.appimgDescr.image
-	if len(appimg.RootFS.DiffIDs) == 0 {
+	img := s.upgradeimgDescr.image
+	if len(img.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 {
+	diffs := []layer.DiffID{}
+
+	for i, diff := range img.RootFS.DiffIDs {
+		if i <= s.index  {
+			continue
+		}
+		diffs = append(diffs, diff)
+	}
+	upgradeimg := image.NewUpgradeImage(img, diffs)
+	config, err := json.Marshal(upgradeimg)
+	if err != nil {
+		return nil, err
+	}
+	dgst := digest.FromBytes(config)
+	id := image.IDFromDigest(dgst)
+	s.upgradeID = id
+	for i := range upgradeimg.RootFS.DiffIDs {
 		if i <= s.index  {
 			continue
 		}
@@ -263,10 +243,10 @@ func (s *saveAppSession) saveAppimage(id
 			// pre v1.9 docker.
 			Created: time.Unix(0, 0),
 		}
-		if i == len(appimg.RootFS.DiffIDs)-1 {
-			v1Img = appimg.V1Image
+		if i == len(upgradeimg.RootFS.DiffIDs)-1 {
+			v1Img = upgradeimg.V1Image
 		}
-		rootFS := *appimg.RootFS
+		rootFS := *upgradeimg.RootFS
 		rootFS.DiffIDs = rootFS.DiffIDs[:i+1]
 		v1ID, err := v1.CreateID(v1Img, rootFS.ChainID(), parent)
 		if err != nil {
@@ -278,8 +258,8 @@ func (s *saveAppSession) saveAppimage(id
 			v1Img.Parent = parent.Hex()
 		}
 
-		v1Img.OS = appimg.OS
-		src, err := s.saveLayer(rootFS.ChainID(), v1Img, appimg.Created)
+		v1Img.OS = upgradeimg.OS
+		src, err := s.saveLayer(rootFS.ChainID(), v1Img, upgradeimg.Created)
 		if err != nil {
 			return nil, err
 		}
@@ -289,18 +269,18 @@ func (s *saveAppSession) saveAppimage(id
 			if foreignSrcs == nil {
 				foreignSrcs = make(map[layer.DiffID]distribution.Descriptor)
 			}
-			foreignSrcs[appimg.RootFS.DiffIDs[i]] = src
+			foreignSrcs[upgradeimg.RootFS.DiffIDs[i]] = src
 		}
 	}
 
 	configFile := filepath.Join(s.outDir, id.Digest().Hex()+".json")
-	if err := ioutil.WriteFile(configFile, appimg.RawJSON(), 0644); err != nil {
+	if err := ioutil.WriteFile(configFile, config, 0644); err != nil {
 		return nil, err
 	}
-	if err := system.Chtimes(configFile, appimg.Created, appimg.Created); err != nil {
+	if err := system.Chtimes(configFile, upgradeimg.Created, upgradeimg.Created); err != nil {
 		return nil, err
 	}
-	s.appimgDescr.layers = layers
+	s.upgradeimgDescr.layers = layers
 	return foreignSrcs, nil
 }
 
@@ -560,6 +540,7 @@ func (s *saveSession) saveImage(id image
 		v1Img := image.V1Image{
 			// This is for backward compatibility used for
 			// pre v1.9 docker.
+			// when we export image to a tar file,  this tar file can be load to a docker which is pre v1.9 docker
 			Created: time.Unix(0, 0),
 		}
 		if i == len(img.RootFS.DiffIDs)-1 {
@@ -667,7 +648,6 @@ func (s *saveSession) saveLayer(id layer
 		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 {
@@ -675,6 +655,7 @@ func (s *saveSession) saveLayer(id layer
 			}
 		}
 
+
 		s.diffIDPaths[l.DiffID()] = layerPath
 	}
 	s.savedLayers[legacyImg.ID] = struct{}{}
@@ -686,7 +667,7 @@ func (s *saveSession) saveLayer(id layer
 	return src, nil
 }
 
-func (s *saveAppSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, createdTime time.Time) (distribution.Descriptor, error) {
+func (s *saveUpgradeSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, createdTime time.Time) (distribution.Descriptor, error) {
 	if _, exists := s.savedLayers[legacyImg.ID]; exists {
 		return distribution.Descriptor{}, 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
@@ -28,22 +28,18 @@ type tarexporter struct {
 	is             image.Store
 	lss            map[string]layer.Store
 	rs             refstore.Store
-	loggerImgEvent LogImageEvent
+	as	       image.ApplayerStore
+	loggerImgEvent image.LogImageEvent
 	index          int
 }
 
-// LogImageEvent defines interface for event generation related to image tar(load and save) operations
-type LogImageEvent interface {
-	// LogImageEvent generates an event related to an image operation
-	LogImageEvent(imageID, refName, action string)
-}
-
 // NewTarExporter returns new Exporter for tar packages
-func NewTarExporter(is image.Store, lss map[string]layer.Store, rs refstore.Store, loggerImgEvent LogImageEvent) image.Exporter {
+func NewTarExporter(is image.Store, lss map[string]layer.Store, rs refstore.Store, as image.ApplayerStore, loggerImgEvent image.LogImageEvent) image.Exporter {
 	return &tarexporter{
 		is:             is,
 		lss:            lss,
 		rs:             rs,
+		as:             as,
 		loggerImgEvent: loggerImgEvent,
 	}
 }
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/layer/layer.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/layer/layer.go
@@ -183,6 +183,7 @@ type CreateRWLayerOpts struct {
 // Store represents a backend for managing both
 // read-only and read-write layers.
 type Store interface {
+	RegisterDir(dir string, diffID DiffID, size int64, parent ChainID) (Layer, error)
 	Register(io.Reader, ChainID) (Layer, error)
 	Get(ChainID) (Layer, error)
 	Map() map[ChainID]Layer
--- lcf-utils-1.0.1/src/loongker-ce-20.10.3.orig/sources/engine/layer/layer_store.go
+++ lcf-utils-1.0.1/src/loongker-ce-20.10.3/sources/engine/layer/layer_store.go
@@ -20,6 +20,7 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/vbatts/tar-split/tar/asm"
 	"github.com/vbatts/tar-split/tar/storage"
+	"github.com/docker/docker/daemon/graphdriver/copy"
 )
 
 // maxLayerDepth represents the maximum number of
@@ -279,10 +280,125 @@ func (ls *layerStore) applyTar(tx *fileM
 	return nil
 }
 
+func (ls *layerStore) applydirByHardlink(fromDir string, layer *roLayer) error {
+	metadata, err := ls.driver.GetMetadata(layer.cacheID)
+	if err != nil {
+		return err
+	}
+	applyDir := metadata["UpperDir"]
+	err = copy.DirCopy(fromDir, applyDir, copy.Hardlink, true)
+	if err != nil {
+		return err
+	}
+	logrus.Debugf("Apply dir %s to %s, size: %d", layer.diffID, layer.cacheID, layer.size)
+
+	return nil
+}
+
 func (ls *layerStore) Register(ts io.Reader, parent ChainID) (Layer, error) {
 	return ls.registerWithDescriptor(ts, parent, distribution.Descriptor{})
 }
 
+func (ls *layerStore) RegisterDir(dir string, diffID DiffID, size int64, parent ChainID) (Layer, error) {
+	// err is used to hold the error which will always trigger
+	// cleanup of creates sources but may not be an error returned
+	// to the caller (already exists).
+	var err error
+	var pid string
+	var p *roLayer
+	var chainID ChainID
+
+	if string(parent) == "" {
+		chainID = ChainID(diffID)
+	} else {
+		chainID = createChainIDFromParent(parent, diffID)
+	}
+
+
+	if existingLayer := ls.get(chainID); existingLayer != nil {
+		return existingLayer.getReference(), nil
+	}
+
+	if string(parent) != "" {
+		p = ls.get(parent)
+		if p == nil {
+			return nil, ErrLayerDoesNotExist
+		}
+		pid = p.cacheID
+		// Release parent chain if error
+		defer func() {
+			if err != nil {
+				ls.layerL.Lock()
+				ls.releaseLayer(p)
+				ls.layerL.Unlock()
+			}
+		}()
+		if p.depth() >= maxLayerDepth {
+			err = ErrMaxDepthExceeded
+			return nil, err
+		}
+	}
+
+	// Create new roLayer
+	layer := &roLayer{
+		parent:         p,
+		cacheID:        stringid.GenerateRandomID(),
+		referenceCount: 1,
+		layerStore:     ls,
+		references:     map[Layer]struct{}{},
+		descriptor:     distribution.Descriptor{},
+		diffID:		diffID,
+		size:		size,
+		chainID:	chainID,
+	}
+
+	if err = ls.driver.Create(layer.cacheID, pid, nil); err != nil {
+		return nil, err
+	}
+
+	tx, err := ls.store.StartTransaction()
+	if err != nil {
+		return nil, err
+	}
+
+	defer func() {
+		if err != nil {
+			logrus.Debugf("Cleaning up layer %s: %v", layer.cacheID, err)
+			if err := ls.driver.Remove(layer.cacheID); err != nil {
+				logrus.Errorf("Error cleaning up cache layer %s: %v", layer.cacheID, err)
+			}
+			if err := tx.Cancel(); err != nil {
+				logrus.Errorf("Error canceling metadata transaction %q: %s", tx.String(), err)
+			}
+		}
+	}()
+
+	if err = ls.applydirByHardlink(dir, layer); err != nil {
+		return nil, err
+	}
+
+	if err = storeLayer(tx, layer); err != nil {
+		return nil, err
+	}
+
+	ls.layerL.Lock()
+	defer ls.layerL.Unlock()
+
+	if existingLayer := ls.getWithoutLock(layer.chainID); existingLayer != nil {
+		// Set error for cleanup, but do not return the error
+		err = errors.New("layer already exists")
+		return existingLayer.getReference(), err
+	}
+
+	if err = tx.Commit(layer.chainID); err != nil {
+		return nil, err
+	}
+
+	ls.layerMap[layer.chainID] = layer
+
+	return layer.getReference(), nil
+}
+
 func (ls *layerStore) registerWithDescriptor(ts io.Reader, parent ChainID, descriptor distribution.Descriptor) (Layer, error) {
 	// err is used to hold the error which will always trigger
 	// cleanup of creates sources but may not be an error returned
