Skip to content

Commit 87d6a53

Browse files
committed
image/layout/tar: Add a CreateTarFile helper
The NewEngine commands for the tar-backed image-layout engines (both the CAS and refs engines) open files O_RDWR and expect image-layout compatible content in the tarball. That makes sense, but for folks who *don't* have such a tarball, a helper like CreateTarFile makes it easy to explicitly create an empty one. The 0666 file modes and 0777 directory modes rely on the caller's umask to appropriately limit user/group/other permissions for the tarball itself and any content extracted to the filesystem from the tarball. The trailing slashes are based on part of libarchive's description of old-style archives [1]: name Pathname, stored as a null-terminated string. Early tar implementations only stored regular files (including hardlinks to those files). One common early convention used a trailing "/" character to indicate a directory name, allowing directory permissions and owner information to be archived and restored. and POSIX ustar archives [2]: name, prefix ... The standard does not require a trailing / character on directory names, though most implementations still include this for compatibility reasons. Expose this new functionality on the command line as: $ oci-image-tool init image-layout PATH where 'init' and 'image-layout' are two separate levels in case we support initializing additional types of repositories in the future. [1]: https://github.com/libarchive/libarchive/wiki/ManPageTar5#old-style-archive-format [2]: https://github.com/libarchive/libarchive/wiki/ManPageTar5#posix-ustar-archives Signed-off-by: W. Trevor King <[email protected]>
1 parent be239fd commit 87d6a53

File tree

4 files changed

+143
-0
lines changed

4 files changed

+143
-0
lines changed

cmd/oci-image-tool/init.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2016 The Linux Foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"io"
19+
"log"
20+
21+
"github.com/spf13/cobra"
22+
)
23+
24+
func newInitCmd(stdout io.Writer, stderr *log.Logger) *cobra.Command {
25+
cmd := &cobra.Command{
26+
Use: "init",
27+
Short: "Initialize an OCI image",
28+
}
29+
30+
cmd.AddCommand(newInitImageLayoutCmd(stdout, stderr))
31+
32+
return cmd
33+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2016 The Linux Foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"io"
19+
"log"
20+
"os"
21+
22+
"github.com/opencontainers/image-spec/image/layout"
23+
"github.com/spf13/cobra"
24+
"golang.org/x/net/context"
25+
)
26+
27+
type initImageLayout struct {
28+
stderr *log.Logger
29+
}
30+
31+
func newInitImageLayoutCmd(stdout io.Writer, stderr *log.Logger) *cobra.Command {
32+
state := &initImageLayout{
33+
stderr: stderr,
34+
}
35+
36+
return &cobra.Command{
37+
Use: "image-layout PATH",
38+
Short: "Initialize an OCI image-layout repository",
39+
Run: state.Run,
40+
}
41+
}
42+
43+
func (state *initImageLayout) Run(cmd *cobra.Command, args []string) {
44+
if len(args) != 1 {
45+
if err := cmd.Usage(); err != nil {
46+
state.stderr.Println(err)
47+
}
48+
os.Exit(1)
49+
}
50+
51+
path := args[0]
52+
53+
ctx := context.Background()
54+
55+
err := layout.CreateTarFile(ctx, path)
56+
if err != nil {
57+
state.stderr.Println(err)
58+
os.Exit(1)
59+
}
60+
61+
os.Exit(0)
62+
}

cmd/oci-image-tool/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func main() {
3030
stdout := log.New(os.Stdout, "", 0)
3131
stderr := log.New(os.Stderr, "", 0)
3232

33+
cmd.AddCommand(newInitCmd(os.Stdout, stderr))
3334
cmd.AddCommand(newValidateCmd(stdout, stderr))
3435
cmd.AddCommand(newUnpackCmd(stdout, stderr))
3536
cmd.AddCommand(newBundleCmd(stdout, stderr))

image/layout/tar.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,50 @@ func CheckTarVersion(ctx context.Context, reader io.ReadSeeker) (err error) {
219219

220220
return nil
221221
}
222+
223+
// CreateTarFile creates a new image-layout tar file at the given path.
224+
func CreateTarFile(ctx context.Context, path string) (err error) {
225+
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
226+
if err != nil {
227+
return err
228+
}
229+
defer file.Close()
230+
231+
tarWriter := tar.NewWriter(file)
232+
defer tarWriter.Close()
233+
234+
now := time.Now()
235+
for _, name := range []string{"./blobs/", "./refs/"} {
236+
header := &tar.Header{
237+
Name: name,
238+
Mode: 0777,
239+
ModTime: now,
240+
Typeflag: tar.TypeDir,
241+
}
242+
err = tarWriter.WriteHeader(header)
243+
if err != nil {
244+
return err
245+
}
246+
}
247+
248+
imageLayoutVersion := specs.ImageLayoutVersion{
249+
Version: "1.0.0",
250+
}
251+
imageLayoutVersionBytes, err := json.Marshal(imageLayoutVersion)
252+
if err != nil {
253+
return err
254+
}
255+
header := &tar.Header{
256+
Name: "./oci-layout",
257+
Mode: 0666,
258+
Size: int64(len(imageLayoutVersionBytes)),
259+
ModTime: now,
260+
Typeflag: tar.TypeReg,
261+
}
262+
err = tarWriter.WriteHeader(header)
263+
if err != nil {
264+
return err
265+
}
266+
_, err = tarWriter.Write(imageLayoutVersionBytes)
267+
return err
268+
}

0 commit comments

Comments
 (0)