Skip to content

Commit 00f13ac

Browse files
committed
Add preserve ownership option for copy to container
Signed-off-by: Derek McGowan <derek@mcg.dev>
1 parent a15ccf7 commit 00f13ac

5 files changed

Lines changed: 97 additions & 20 deletions

File tree

api/next.txtpb

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,13 @@ file: {
965965
type: TYPE_BOOL
966966
json_name: "noWalk"
967967
}
968+
field: {
969+
name: "preserve_ownership"
970+
number: 4
971+
label: LABEL_OPTIONAL
972+
type: TYPE_BOOL
973+
json_name: "preserveOwnership"
974+
}
968975
}
969976
options: {
970977
go_package: "github.com/containerd/nerdbox/api/types/transfer/v1;transfer"
@@ -973,7 +980,7 @@ file: {
973980
location: {
974981
span: 16
975982
span: 0
976-
span: 33
983+
span: 38
977984
span: 1
978985
}
979986
location: {
@@ -1007,7 +1014,7 @@ file: {
10071014
path: 0
10081015
span: 25
10091016
span: 0
1010-
span: 33
1017+
span: 38
10111018
span: 1
10121019
leading_comments: " ContainerFilesystem represents a path within a running container's\n filesystem. It acts as either a source or destination in a transfer\n operation, identifying the container and path for archive operations.\n"
10131020
}
@@ -1137,6 +1144,46 @@ file: {
11371144
span: 23
11381145
span: 24
11391146
}
1147+
location: {
1148+
path: 4
1149+
path: 0
1150+
path: 2
1151+
path: 3
1152+
span: 37
1153+
span: 8
1154+
span: 36
1155+
leading_comments: " When true, preserve the UID/GID from tar headers when extracting\n files. When false, extracted files are owned by the extracting\n process.\n"
1156+
}
1157+
location: {
1158+
path: 4
1159+
path: 0
1160+
path: 2
1161+
path: 3
1162+
path: 5
1163+
span: 37
1164+
span: 8
1165+
span: 12
1166+
}
1167+
location: {
1168+
path: 4
1169+
path: 0
1170+
path: 2
1171+
path: 3
1172+
path: 1
1173+
span: 37
1174+
span: 13
1175+
span: 31
1176+
}
1177+
location: {
1178+
path: 4
1179+
path: 0
1180+
path: 2
1181+
path: 3
1182+
path: 3
1183+
span: 37
1184+
span: 34
1185+
span: 35
1186+
}
11401187
}
11411188
syntax: "proto3"
11421189
buf_extension: {

api/proto/nerdbox/types/transfer/v1/filesystem.proto

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,9 @@ message ContainerFilesystem {
3131
// itself without walking into its contents. This is useful for
3232
// stat-like operations where only the directory's metadata is needed.
3333
bool no_walk = 3;
34+
35+
// When true, preserve the UID/GID from tar headers when extracting
36+
// files. When false, extracted files are owned by the extracting
37+
// process.
38+
bool preserve_ownership = 4;
3439
}

api/types/transfer/v1/filesystem.pb.go

Lines changed: 21 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/transfer/containerfs.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (t *containerFSTransferrer) Transfer(ctx context.Context, src, dst any, opt
6363
}
6464
rootfs := filepath.Join(t.bundleDir, d.ContainerID, "rootfs")
6565
r := s.Reader(ctx)
66-
return readPath(r, rootfs, d.Path, s.MediaType)
66+
return readPath(r, rootfs, d.Path, s.MediaType, d.PreserveOwnership)
6767
}
6868

6969
return errdefs.ErrNotImplemented
@@ -150,8 +150,9 @@ func writeTarEntry(tw *tar.Writer, filePath string, fi os.FileInfo, name string)
150150
}
151151

152152
// readPath reads a tar archive from r and extracts it to the given path
153-
// within rootfs.
154-
func readPath(r io.Reader, rootfs, path, mediaType string) error {
153+
// within rootfs. When preserveOwnership is true, extracted files have
154+
// their UID/GID set from the tar headers.
155+
func readPath(r io.Reader, rootfs, path, mediaType string, preserveOwnership bool) error {
155156
if mediaType != mediaTypeTar {
156157
return fmt.Errorf("unsupported media type %q: %w", mediaType, errdefs.ErrNotImplemented)
157158
}
@@ -175,13 +176,13 @@ func readPath(r io.Reader, rootfs, path, mediaType string) error {
175176
return fmt.Errorf("tar entry %q would escape destination", header.Name)
176177
}
177178

178-
if err := extractTarEntry(target, header, tr); err != nil {
179+
if err := extractTarEntry(target, header, tr, preserveOwnership); err != nil {
179180
return err
180181
}
181182
}
182183
}
183184

184-
func extractTarEntry(target string, header *tar.Header, r io.Reader) error {
185+
func extractTarEntry(target string, header *tar.Header, r io.Reader, preserveOwnership bool) error {
185186
switch header.Typeflag {
186187
case tar.TypeDir:
187188
if err := os.MkdirAll(target, os.FileMode(header.Mode)); err != nil {
@@ -217,5 +218,12 @@ func extractTarEntry(target string, header *tar.Header, r io.Reader) error {
217218
return err
218219
}
219220
}
221+
222+
if preserveOwnership {
223+
if err := os.Lchown(target, header.Uid, header.Gid); err != nil {
224+
return fmt.Errorf("failed to chown %s: %w", target, err)
225+
}
226+
}
227+
220228
return nil
221229
}

internal/transfer/types.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,19 @@ func init() {
3939
// filesystem. It acts as either a source or destination in a transfer
4040
// operation, identifying the container and path for archive operations.
4141
type ContainerFilesystem struct {
42-
ContainerID string
43-
Path string
44-
NoWalk bool
42+
ContainerID string
43+
Path string
44+
NoWalk bool
45+
PreserveOwnership bool
4546
}
4647

4748
// MarshalAny marshals the ContainerFilesystem to a typeurl.Any.
4849
func (cf *ContainerFilesystem) MarshalAny(ctx context.Context, sm streaming.StreamCreator) (typeurl.Any, error) {
4950
return typeurl.MarshalAny(&transferpb.ContainerFilesystem{
50-
ContainerID: cf.ContainerID,
51-
Path: cf.Path,
52-
NoWalk: cf.NoWalk,
51+
ContainerID: cf.ContainerID,
52+
Path: cf.Path,
53+
NoWalk: cf.NoWalk,
54+
PreserveOwnership: cf.PreserveOwnership,
5355
})
5456
}
5557

@@ -62,6 +64,7 @@ func (cf *ContainerFilesystem) UnmarshalAny(ctx context.Context, sg streaming.St
6264
cf.ContainerID = p.ContainerID
6365
cf.Path = p.Path
6466
cf.NoWalk = p.NoWalk
67+
cf.PreserveOwnership = p.PreserveOwnership
6568
return nil
6669
}
6770

0 commit comments

Comments
 (0)