@@ -10,39 +10,14 @@ import (
1010 "strings"
1111
1212 "github.com/Microsoft/go-winio"
13- "github.com/Microsoft/hcsshim/internal/oc"
1413 "github.com/Microsoft/hcsshim/internal/wclayer"
1514 "github.com/Microsoft/hcsshim/pkg/cimfs"
16- "go.opencensus.io/trace"
1715)
1816
19- // A CimLayerWriter implements the wclayer.LayerWriter interface to allow writing container
20- // image layers in the cim format.
21- // A cim layer consist of cim files (which are usually stored in the `cim-layers` directory and
22- // some other files which are stored in the directory of that layer (i.e the `path` directory).
23- type CimLayerWriter struct {
24- ctx context.Context
25- s * trace.Span
26- // path to the layer (i.e layer's directory) as provided by the caller.
27- // Even if a layer is stored as a cim in the cim directory, some files associated
28- // with a layer are still stored in this path.
29- layerPath string
30- // parent layer paths
31- parentLayerPaths []string
32- // Handle to the layer cim - writes to the cim file
33- cimWriter * cimfs.CimFsWriter
34- // Handle to the writer for writing files in the local filesystem
35- stdFileWriter * stdFileWriter
36- // reference to currently active writer either cimWriter or stdFileWriter
37- activeWriter io.Writer
38- // denotes if this layer has the UtilityVM directory
39- hasUtilityVM bool
40- // some files are written outside the cim during initial import (via stdFileWriter) because we need to
41- // make some modifications to these files before writing them to the cim. The pendingOps slice
42- // maintains a list of such delayed modifications to the layer cim. These modifications are applied at
43- // the very end of layer import process.
44- pendingOps []pendingCimOp
45- }
17+ var (
18+ ErrBlockCIMWriterNotSupported = fmt .Errorf ("writing block device CIM isn't supported" )
19+ ErrBlockCIMParentTypeMismatch = fmt .Errorf ("parent layer block CIM type doesn't match with extraction layer" )
20+ )
4621
4722type hive struct {
4823 name string
6035 }
6136)
6237
38+ // CIMLayerWriter is an interface that supports writing a new container image layer to the
39+ // CIM format
40+ type CIMLayerWriter interface {
41+ // Add adds a file to the layer with given metadata.
42+ Add (string , * winio.FileBasicInfo , int64 , []byte , []byte , []byte ) error
43+ // AddLink adds a hard link to the layer. The target must already have been added.
44+ AddLink (string , string ) error
45+ // AddAlternateStream adds an alternate stream to a file
46+ AddAlternateStream (string , uint64 ) error
47+ // Remove removes a file that was present in a parent layer from the layer.
48+ Remove (string ) error
49+ // Write writes data to the current file. The data must be in the format of a Win32
50+ // backup stream.
51+ Write ([]byte ) (int , error )
52+ // Close finishes the layer writing process and releases any resources.
53+ Close (context.Context ) error
54+ }
55+
6356func isDeltaOrBaseHive (path string ) bool {
6457 for _ , hv := range hives {
6558 if strings .EqualFold (path , filepath .Join (wclayer .HivesPath , hv .delta )) ||
@@ -79,8 +72,33 @@ func isStdFile(path string) bool {
7972 path == wclayer .BcdFilePath || path == wclayer .BootMgrFilePath )
8073}
8174
75+ // cimLayerWriter is a base struct that is further extended by forked cim writer & blocked
76+ // cim writer to provide full functionality of writing layers.
77+ type cimLayerWriter struct {
78+ ctx context.Context
79+ // Handle to the layer cim - writes to the cim file
80+ cimWriter * cimfs.CimFsWriter
81+ // Handle to the writer for writing files in the local filesystem
82+ stdFileWriter * stdFileWriter
83+ // reference to currently active writer either cimWriter or stdFileWriter
84+ activeWriter io.Writer
85+ // denotes if this layer has the UtilityVM directory
86+ hasUtilityVM bool
87+ // path to the layer (i.e layer's directory) as provided by the caller.
88+ // Even if a layer is stored as a cim in the cim directory, some files associated
89+ // with a layer are still stored in this path.
90+ layerPath string
91+ // parent layer paths
92+ parentLayerPaths []string
93+ // some files are written outside the cim during initial import (via stdFileWriter) because we need to
94+ // make some modifications to these files before writing them to the cim. The pendingOps slice
95+ // maintains a list of such delayed modifications to the layer cim. These modifications are applied at
96+ // the very end of layer import process.
97+ pendingOps []pendingCimOp
98+ }
99+
82100// Add adds a file to the layer with given metadata.
83- func (cw * CimLayerWriter ) Add (name string , fileInfo * winio.FileBasicInfo , fileSize int64 , securityDescriptor []byte , extendedAttributes []byte , reparseData []byte ) error {
101+ func (cw * cimLayerWriter ) Add (name string , fileInfo * winio.FileBasicInfo , fileSize int64 , securityDescriptor []byte , extendedAttributes []byte , reparseData []byte ) error {
84102 if name == wclayer .UtilityVMPath {
85103 cw .hasUtilityVM = true
86104 }
@@ -108,7 +126,7 @@ func (cw *CimLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo, fileSi
108126}
109127
110128// AddLink adds a hard link to the layer. The target must already have been added.
111- func (cw * CimLayerWriter ) AddLink (name string , target string ) error {
129+ func (cw * cimLayerWriter ) AddLink (name string , target string ) error {
112130 // set active write to nil so that we panic if layer tar is incorrectly formatted.
113131 cw .activeWriter = nil
114132 if isStdFile (target ) {
@@ -130,7 +148,7 @@ func (cw *CimLayerWriter) AddLink(name string, target string) error {
130148
131149// AddAlternateStream creates another alternate stream at the given
132150// path. Any writes made after this call will go to that stream.
133- func (cw * CimLayerWriter ) AddAlternateStream (name string , size uint64 ) error {
151+ func (cw * cimLayerWriter ) AddAlternateStream (name string , size uint64 ) error {
134152 if isStdFile (name ) {
135153 // As of now there is no known case of std file having multiple data streams.
136154 // If such a file is encountered our assumptions are wrong. Error out.
@@ -144,21 +162,14 @@ func (cw *CimLayerWriter) AddAlternateStream(name string, size uint64) error {
144162 return nil
145163}
146164
147- // Remove removes a file that was present in a parent layer from the layer.
148- func (cw * CimLayerWriter ) Remove (name string ) error {
149- // set active write to nil so that we panic if layer tar is incorrectly formatted.
150- cw .activeWriter = nil
151- return cw .cimWriter .Unlink (name )
152- }
153-
154165// Write writes data to the current file. The data must be in the format of a Win32
155166// backup stream.
156- func (cw * CimLayerWriter ) Write (b []byte ) (int , error ) {
167+ func (cw * cimLayerWriter ) Write (b []byte ) (int , error ) {
157168 return cw .activeWriter .Write (b )
158169}
159170
160171// Close finishes the layer writing process and releases any resources.
161- func (cw * CimLayerWriter ) Close (ctx context.Context ) (retErr error ) {
172+ func (cw * cimLayerWriter ) Close (ctx context.Context ) (retErr error ) {
162173 if err := cw .stdFileWriter .Close (ctx ); err != nil {
163174 return err
164175 }
@@ -170,7 +181,7 @@ func (cw *CimLayerWriter) Close(ctx context.Context) (retErr error) {
170181 }
171182 }()
172183
173- // UVM based containers aren 't supported with CimFS, don't process the UVM layer
184+ // We don 't support running UtilityVM with CIM layers yet.
174185 processUtilityVM := false
175186
176187 if len (cw .parentLayerPaths ) == 0 {
@@ -190,50 +201,3 @@ func (cw *CimLayerWriter) Close(ctx context.Context) (retErr error) {
190201 }
191202 return nil
192203}
193-
194- func NewCimLayerWriter (ctx context.Context , layerPath , cimPath string , parentLayerPaths , parentLayerCimPaths []string ) (_ * CimLayerWriter , err error ) {
195- if ! cimfs .IsCimFSSupported () {
196- return nil , fmt .Errorf ("CimFs not supported on this build" )
197- }
198-
199- ctx , span := trace .StartSpan (ctx , "hcsshim::NewCimLayerWriter" )
200- defer func () {
201- if err != nil {
202- oc .SetSpanStatus (span , err )
203- span .End ()
204- }
205- }()
206- span .AddAttributes (
207- trace .StringAttribute ("path" , layerPath ),
208- trace .StringAttribute ("cimPath" , cimPath ),
209- trace .StringAttribute ("parentLayerPaths" , strings .Join (parentLayerCimPaths , ", " )),
210- trace .StringAttribute ("parentLayerPaths" , strings .Join (parentLayerPaths , ", " )))
211-
212- parentCim := ""
213- if len (parentLayerPaths ) > 0 {
214- if filepath .Dir (cimPath ) != filepath .Dir (parentLayerCimPaths [0 ]) {
215- return nil , fmt .Errorf ("parent cim can not be stored in different directory" )
216- }
217- // We only need to provide parent CIM name, it is assumed that both parent CIM
218- // and newly created CIM are present in the same directory.
219- parentCim = filepath .Base (parentLayerCimPaths [0 ])
220- }
221-
222- cim , err := cimfs .Create (filepath .Dir (cimPath ), parentCim , filepath .Base (cimPath ))
223- if err != nil {
224- return nil , fmt .Errorf ("error in creating a new cim: %w" , err )
225- }
226-
227- sfw , err := newStdFileWriter (layerPath , parentLayerPaths )
228- if err != nil {
229- return nil , fmt .Errorf ("error in creating new standard file writer: %w" , err )
230- }
231- return & CimLayerWriter {
232- ctx : ctx ,
233- s : span ,
234- layerPath : layerPath ,
235- parentLayerPaths : parentLayerPaths ,
236- cimWriter : cim ,
237- stdFileWriter : sfw ,
238- }, nil
239- }
0 commit comments