[lxc-devel] [lxd/master] Make sure lxc file edit doesn't change target file's permissions

ctrlrsf on Github lxc-bot at linuxcontainers.org
Fri May 27 15:46:17 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 958 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160527/3f35ca03/attachment.bin>
-------------- next part --------------
From dcd4c9474ff01182fd16e90b333f902cd2dbd046 Mon Sep 17 00:00:00 2001
From: Rene Fragoso <ctrlrsf at gmail.com>
Date: Fri, 27 May 2016 10:26:15 -0400
Subject: [PATCH 1/3] Add push file method that does not send file owner and
 mode

This method is similar to PushFile, but it does not accept file owner
and mode parameters, and thus does not send any permissions to the lxd
server when pushing the file. By not sending the file permissions to lxd,
lxd will not change the file owner and permissions after file is copied.

This new method is required because PushFile could not be modified
without changing its API to accomplish the same thing. Although uid
and gid could be set to -1, mode is an os.FileMode (uint32) and
setting it to -1 would overflow it.

Signed-off-by: Rene Fragoso <ctrlrsf at gmail.com>
---
 client.go | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/client.go b/client.go
index d1e08cb..caa774a 100644
--- a/client.go
+++ b/client.go
@@ -1664,6 +1664,29 @@ func (c *Client) PushFile(container string, p string, gid int, uid int, mode os.
 	return err
 }
 
+func (c *Client) PushFileEdit(container string, p string, buf io.ReadSeeker) error {
+	if c.Remote.Public {
+		return fmt.Errorf("This function isn't supported by public remotes.")
+	}
+
+	query := url.Values{"path": []string{p}}
+	uri := c.url(shared.APIVersion, "containers", container, "files") + "?" + query.Encode()
+
+	req, err := http.NewRequest("POST", uri, buf)
+	if err != nil {
+		return err
+	}
+	req.Header.Set("User-Agent", shared.UserAgent)
+
+	raw, err := c.Http.Do(req)
+	if err != nil {
+		return err
+	}
+
+	_, err = HoistResponse(raw, Sync)
+	return err
+}
+
 func (c *Client) PullFile(container string, p string) (int, int, int, io.ReadCloser, error) {
 	if c.Remote.Public {
 		return 0, 0, 0, nil, fmt.Errorf("This function isn't supported by public remotes.")

From 1c2750eb7aa2f1b7627dc06079bd5c3d8581bdff Mon Sep 17 00:00:00 2001
From: Rene Fragoso <ctrlrsf at gmail.com>
Date: Fri, 27 May 2016 11:24:02 -0400
Subject: [PATCH 2/3] lxc file edit should use push method that doesn't send
 file owner and mode

The lxc file edit command needs to call a different/new method that pushes
a file without changing its owner and permissions.

Changes:

- Added pushEditedFile() which parses arguments and calls PushFileEdit()
  instead of normal PushFile().
- change edit() to call pushEditedFile() instead of push()

Signed-off-by: Rene Fragoso <ctrlrsf at gmail.com>
---
 lxc/file.go | 47 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/lxc/file.go b/lxc/file.go
index d96bc4c..7ced3a5 100644
--- a/lxc/file.go
+++ b/lxc/file.go
@@ -153,6 +153,49 @@ func (c *fileCmd) push(config *lxd.Config, args []string) error {
 	return nil
 }
 
+func (c *fileCmd) pushEditedFile(config *lxd.Config, args []string) error {
+	if len(args) < 2 {
+		return errArgs
+	}
+
+	target := args[len(args)-1]
+	pathSpec := strings.SplitN(target, "/", 2)
+
+	if len(pathSpec) != 2 {
+		return fmt.Errorf(i18n.G("Invalid target %s"), target)
+	}
+
+	targetPath := pathSpec[1]
+	remote, container := config.ParseRemoteAndContainer(pathSpec[0])
+
+	d, err := lxd.NewClient(config, remote)
+	if err != nil {
+		return err
+	}
+
+	sourcefilename := args[0]
+
+	/* Make sure file is accessible by us before trying to push */
+	var file *os.File
+	if sourcefilename == "-" {
+		file = os.Stdin
+	} else {
+		file, err = os.Open(sourcefilename)
+		if err != nil {
+			return err
+		}
+	}
+
+	defer file.Close()
+
+	err = d.PushFileEdit(container, targetPath, file)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 func (c *fileCmd) pull(config *lxd.Config, args []string) error {
 	if len(args) < 2 {
 		return errArgs
@@ -235,7 +278,7 @@ func (c *fileCmd) edit(config *lxd.Config, args []string) error {
 
 	// If stdin isn't a terminal, read text from it
 	if !termios.IsTerminal(int(syscall.Stdin)) {
-		return c.push(config, append([]string{os.Stdin.Name()}, args[0]))
+		return c.pushEditedFile(config, append([]string{os.Stdin.Name()}, args[0]))
 	}
 
 	// Create temp file
@@ -256,7 +299,7 @@ func (c *fileCmd) edit(config *lxd.Config, args []string) error {
 		return err
 	}
 
-	err = c.push(config, append([]string{fname}, args[0]))
+	err = c.pushEditedFile(config, append([]string{fname}, args[0]))
 	if err != nil {
 		return err
 	}

From fb639ebb29b69b19eb1a73b8f42a39306f10d05c Mon Sep 17 00:00:00 2001
From: Rene Fragoso <ctrlrsf at gmail.com>
Date: Fri, 27 May 2016 11:33:48 -0400
Subject: [PATCH 3/3] Add test for "lxc file edit" target file owner and
 permission

Signed-off-by: Rene Fragoso <ctrlrsf at gmail.com>
---
 test/suites/basic.sh | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/test/suites/basic.sh b/test/suites/basic.sh
index 3af6038..75d5435 100644
--- a/test/suites/basic.sh
+++ b/test/suites/basic.sh
@@ -218,6 +218,14 @@ test_basic_usage() {
   lxc exec foo /bin/cat /root/in1 | grep abc
   lxc exec foo -- /bin/rm -f root/in1
 
+  # test lxc file edit doesn't change target file's owner and permissions
+  echo "content" | lxc file push - foo/tmp/edit_test
+  lxc exec foo -- chown 55.55 /tmp/edit_test
+  lxc exec foo -- chmod 555 /tmp/edit_test
+  echo "new content" | lxc file edit foo/tmp/edit_test
+  [ "$(lxc exec foo -- cat /tmp/edit_test)" = "new content" ]
+  [ "$(lxc exec foo -- stat -c \"%u %g %a\" /tmp/edit_test)" = "55 55 555" ]
+
   # make sure stdin is chowned to our container root uid (Issue #590)
   [ -t 0 ] && [ -t 1 ] && lxc exec foo -- chown 1000:1000 /proc/self/fd/0
 


More information about the lxc-devel mailing list