Skip to content

Commit

Permalink
image/layout/tar: Add a CreateTarFile helper
Browse files Browse the repository at this point in the history
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-init image-layout PATH

where 'image-layout' is a separate level 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 <wking@tremily.us>
  • Loading branch information
wking committed Sep 16, 2016
1 parent b7893a4 commit c649de3
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/oci-cas
/oci-create-runtime-bundle
/oci-image-init
/oci-image-validate
/oci-refs
/oci-unpack
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ EPOCH_TEST_COMMIT ?= v0.2.0
TOOLS := \
oci-cas \
oci-create-runtime-bundle \
oci-image-init \
oci-image-validate \
oci-refs \
oci-unpack
Expand Down
57 changes: 57 additions & 0 deletions cmd/oci-image-init/image_layout.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2016 The Linux Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"fmt"
"os"

"github.com/opencontainers/image-tools/image/layout"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

type imageLayout struct{}

func newImageLayoutCmd() *cobra.Command {
state := &imageLayout{}

return &cobra.Command{
Use: "image-layout PATH",
Short: "Initialize an OCI image-layout repository",
Run: state.Run,
}
}

func (state *imageLayout) Run(cmd *cobra.Command, args []string) {
if len(args) != 1 {
if err := cmd.Usage(); err != nil {
fmt.Fprintln(os.Stderr, err)
}
os.Exit(1)
}

path := args[0]

ctx := context.Background()

err := layout.CreateTarFile(ctx, path)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}

os.Exit(0)
}
37 changes: 37 additions & 0 deletions cmd/oci-image-init/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2016 The Linux Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

func main() {
cmd := &cobra.Command{
Use: "oci-image-init",
Short: "Initialize an OCI image",
}

cmd.AddCommand(newImageLayoutCmd())

err := cmd.Execute()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
47 changes: 47 additions & 0 deletions image/layout/tar.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,50 @@ func CheckTarVersion(ctx context.Context, reader io.ReadSeeker) (err error) {

return nil
}

// CreateTarFile creates a new image-layout tar file at the given path.
func CreateTarFile(ctx context.Context, path string) (err error) {
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
if err != nil {
return err
}
defer file.Close()

tarWriter := tar.NewWriter(file)
defer tarWriter.Close()

now := time.Now()
for _, name := range []string{"./blobs/", "./refs/"} {
header := &tar.Header{
Name: name,
Mode: 0777,
ModTime: now,
Typeflag: tar.TypeDir,
}
err = tarWriter.WriteHeader(header)
if err != nil {
return err
}
}

imageLayoutVersion := ImageLayoutVersion{
Version: "1.0.0",
}
imageLayoutVersionBytes, err := json.Marshal(imageLayoutVersion)
if err != nil {
return err
}
header := &tar.Header{
Name: "./oci-layout",
Mode: 0666,
Size: int64(len(imageLayoutVersionBytes)),
ModTime: now,
Typeflag: tar.TypeReg,
}
err = tarWriter.WriteHeader(header)
if err != nil {
return err
}
_, err = tarWriter.Write(imageLayoutVersionBytes)
return err
}

0 comments on commit c649de3

Please sign in to comment.