github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/snap/squashfs/stat_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2017-2018 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package squashfs_test
    21  
    22  import (
    23  	"fmt"
    24  	"math"
    25  	"os"
    26  	"time"
    27  
    28  	. "gopkg.in/check.v1"
    29  
    30  	"github.com/snapcore/snapd/snap/squashfs"
    31  )
    32  
    33  func (s *SquashfsTestSuite) TestStatBadNodes(c *C) {
    34  	badlines := map[string][]string{
    35  		"node": {
    36  			// size, but device
    37  			"brwxrwxr-x u/u             53595 2017-12-08 11:19 .",
    38  			"crwxrwxr-x u/u             53595 2017-12-08 11:19 .",
    39  			// node info is noise
    40  			"brwxrwxr-x u/u             noise 2017-12-08 11:19 .",
    41  			"crwxrwxr-x u/u             noise 2017-12-08 11:19 .",
    42  			// major is noise
    43  			"brwxrwxr-x u/u             noise, 1 2017-12-08 11:19 .",
    44  			"crwxrwxr-x u/u             noise, 1 2017-12-08 11:19 .",
    45  			// minor is noise
    46  			"brwxrwxr-x u/u             1, noise 2017-12-08 11:19 .",
    47  			"crwxrwxr-x u/u             1, noise 2017-12-08 11:19 .",
    48  		},
    49  		"size": {
    50  			// size is noise
    51  			"drwxrwxr-x u/g             noise 2017-12-08 11:19 .",
    52  			"drwxrwxr-x u/g             1noise 2017-12-08 11:19 .",
    53  			// size too big
    54  			"drwxrwxr-x u/g             36893488147419103232 2017-12-08 11:19 .",
    55  		},
    56  		"line": {
    57  			// shorter than the minimum:
    58  			"-rw-r--r-- too/short 20 2017-12-08 11:19 ./",
    59  			// truncated:
    60  			"drwxrwxr-x",
    61  			"drwxrwxr-x ",
    62  			"drwxrwxr-x u/u",
    63  			"drwxrwxr-x u/g ",
    64  			"drwxrwxr-x u/g             53595",
    65  			"drwxrwxr-x u/g             53595 ",
    66  			"drwxrwxr-x u/g             53595 2017-12-08 11:19",
    67  			"drwxrwxr-x u/g             53595 2017-12-08 11:19 ",
    68  
    69  			// mode keeps on going
    70  			"drwxrwxr-xr-x u/g             53595 2017-12-08 11:19 .",
    71  
    72  			// spurious padding:
    73  			"drwxrwxr-x  u/u             53595 2017-12-08 11:19 .",
    74  
    75  			// missing size
    76  			"drwxrwxr-x u/u                    2017-12-08 11:19 ",
    77  			// everything is size
    78  			"drwxrwxr-x u/u 111111111111111111111111111111111111",
    79  		},
    80  		"mode": {
    81  			// zombie file type?
    82  			"zrwxrwxr-x u/g             53595 2017-12-08 11:19 .",
    83  			// strange permissions
    84  			"dbwxrwxr-x u/g             53595 2017-12-08 11:19 .",
    85  			"drbxrwxr-x u/g             53595 2017-12-08 11:19 .",
    86  			"drwbrwxr-x u/g             53595 2017-12-08 11:19 .",
    87  			"drwxbwxr-x u/g             53595 2017-12-08 11:19 .",
    88  			"drwxrbxr-x u/g             53595 2017-12-08 11:19 .",
    89  			"drwxrwbr-x u/g             53595 2017-12-08 11:19 .",
    90  			"drwxrwxb-x u/g             53595 2017-12-08 11:19 .",
    91  			"drwxrwxrbx u/g             53595 2017-12-08 11:19 .",
    92  			"drwxrwxr-b u/g             53595 2017-12-08 11:19 .",
    93  		},
    94  		"owner": {
    95  			"-rw-r--r-- some.user.with.a.much.too.long.name/some.group.with.a.much.too.long.name               20 2017-12-08 11:19 ./foo",
    96  			"-rw-r--r-- nogroup/               20 2017-12-08 11:19 ./foo",
    97  			"-rw-r--r-- noslash               20 2017-12-08 11:19 ./foo",
    98  			"-rw-r--r-- this.line.finishes.before.finishing.owner",
    99  		},
   100  		"time": {
   101  			// time is bonkers:
   102  			"drwxrwxr-x u/u             53595 2017-bonkers-what .",
   103  		},
   104  		"path": {
   105  			// path doesn't start with "."
   106  			"drwxrwxr-x u/g             53595 2017-12-08 11:19 foo",
   107  		},
   108  	}
   109  	for kind, lines := range badlines {
   110  		for _, line := range lines {
   111  			com := Commentf("%q (expected bad %s)", line, kind)
   112  			st, err := squashfs.FromRaw([]byte(line))
   113  			c.Assert(err, NotNil, com)
   114  			c.Check(st, IsNil, com)
   115  			c.Check(err, ErrorMatches, fmt.Sprintf("cannot parse %s: .*", kind))
   116  		}
   117  	}
   118  }
   119  
   120  func (s *SquashfsTestSuite) TestStatUserGroup(c *C) {
   121  	usergroups := [][2]string{
   122  		{"u", "g"},
   123  		{"user", "group"},
   124  		{"some.user.with.a.veery.long.name", "group"},
   125  		{"user", "some.group.with.a.very.long.name"},
   126  		{"some.user.with.a.veery.long.name", "some.group.with.a.very.long.name"},
   127  	}
   128  	for _, ug := range usergroups {
   129  		user, group := ug[0], ug[1]
   130  		raw := []byte(fmt.Sprintf("-rw-r--r-- %s/%s               20 2017-12-08 11:19 ./foo", user, group))
   131  
   132  		com := Commentf("%q", raw)
   133  		c.Assert(len(user) <= 32, Equals, true, com)
   134  		c.Assert(len(group) <= 32, Equals, true, com)
   135  
   136  		st, err := squashfs.FromRaw(raw)
   137  		c.Assert(err, IsNil, com)
   138  		c.Check(st.Mode(), Equals, os.FileMode(0644), com)
   139  		c.Check(st.Path(), Equals, "/foo", com)
   140  		c.Check(st.User(), Equals, user, com)
   141  		c.Check(st.Group(), Equals, group, com)
   142  		c.Check(st.Size(), Equals, int64(20), com)
   143  		c.Check(st.ModTime(), Equals, time.Date(2017, 12, 8, 11, 19, 0, 0, time.UTC), com)
   144  	}
   145  }
   146  
   147  func (s *SquashfsTestSuite) TestStatPath(c *C) {
   148  	paths := [][]byte{
   149  		[]byte("hello"),
   150  		[]byte(" this is/ a path/(somehow)"),
   151  		{239, 191, 190},
   152  		{0355, 0240, 0200, 0355, 0260, 0200},
   153  	}
   154  	for _, path := range paths {
   155  		raw := []byte(fmt.Sprintf("-rw-r--r-- user/group               20 2017-12-08 11:19 ./%s", path))
   156  
   157  		com := Commentf("%q", raw)
   158  		st, err := squashfs.FromRaw(raw)
   159  		c.Assert(err, IsNil, com)
   160  		c.Check(st.Mode(), Equals, os.FileMode(0644), com)
   161  		c.Check(st.Path(), Equals, fmt.Sprintf("/%s", path), com)
   162  		c.Check(st.User(), Equals, "user", com)
   163  		c.Check(st.Group(), Equals, "group", com)
   164  		c.Check(st.Size(), Equals, int64(20), com)
   165  		c.Check(st.ModTime(), Equals, time.Date(2017, 12, 8, 11, 19, 0, 0, time.UTC), com)
   166  	}
   167  }
   168  
   169  func (s *SquashfsTestSuite) TestStatBlock(c *C) {
   170  	line := "brw-rw---- root/disk             7,  0 2017-12-05 10:29 ./dev/loop0"
   171  	st, err := squashfs.FromRaw([]byte(line))
   172  	c.Assert(err, IsNil)
   173  	c.Check(st.Mode(), Equals, os.FileMode(0660|os.ModeDevice))
   174  	c.Check(st.Path(), Equals, "/dev/loop0")
   175  	c.Check(st.User(), Equals, "root")
   176  	c.Check(st.Group(), Equals, "disk")
   177  	c.Check(st.Size(), Equals, int64(0))
   178  	c.Check(st.ModTime(), Equals, time.Date(2017, 12, 5, 10, 29, 0, 0, time.UTC))
   179  	// note the major and minor numbers are ignored (for now)
   180  }
   181  
   182  func (s *SquashfsTestSuite) TestStatCharacter(c *C) {
   183  	line := "crw-rw---- root/audio           14,  3 2017-12-05 10:29 ./dev/dsp"
   184  	st, err := squashfs.FromRaw([]byte(line))
   185  	c.Assert(err, IsNil)
   186  	c.Check(st.Mode(), Equals, os.FileMode(0660|os.ModeCharDevice))
   187  	c.Check(st.Path(), Equals, "/dev/dsp")
   188  	c.Check(st.User(), Equals, "root")
   189  	c.Check(st.Group(), Equals, "audio")
   190  	c.Check(st.Size(), Equals, int64(0))
   191  	c.Check(st.ModTime(), Equals, time.Date(2017, 12, 5, 10, 29, 0, 0, time.UTC))
   192  	// note the major and minor numbers are ignored (for now)
   193  }
   194  
   195  func (s *SquashfsTestSuite) TestStatSymlink(c *C) {
   196  	line := "lrwxrwxrwx root/root                 4 2017-12-05 10:29 ./var/run -> /run"
   197  	st, err := squashfs.FromRaw([]byte(line))
   198  	c.Assert(err, IsNil)
   199  	c.Check(st.Mode(), Equals, os.FileMode(0777|os.ModeSymlink))
   200  	c.Check(st.Path(), Equals, "/var/run")
   201  	c.Check(st.User(), Equals, "root")
   202  	c.Check(st.Group(), Equals, "root")
   203  	c.Check(st.Size(), Equals, int64(4))
   204  	c.Check(st.ModTime(), Equals, time.Date(2017, 12, 5, 10, 29, 0, 0, time.UTC))
   205  }
   206  
   207  func (s *SquashfsTestSuite) TestStatNamedPipe(c *C) {
   208  	line := "prw-rw-r-- john/john                 0 2018-01-09 10:24 ./afifo"
   209  	st, err := squashfs.FromRaw([]byte(line))
   210  	c.Assert(err, IsNil)
   211  	c.Check(st.Mode(), Equals, os.FileMode(0664|os.ModeNamedPipe))
   212  	c.Check(st.Path(), Equals, "/afifo")
   213  	c.Check(st.User(), Equals, "john")
   214  	c.Check(st.Group(), Equals, "john")
   215  	c.Check(st.Size(), Equals, int64(0))
   216  	c.Check(st.ModTime(), Equals, time.Date(2018, 1, 9, 10, 24, 0, 0, time.UTC))
   217  }
   218  
   219  func (s *SquashfsTestSuite) TestStatSocket(c *C) {
   220  	line := "srwxrwxr-x john/john                 0 2018-01-09 10:24 ./asock"
   221  	st, err := squashfs.FromRaw([]byte(line))
   222  	c.Assert(err, IsNil)
   223  	c.Check(st.Mode(), Equals, os.FileMode(0775|os.ModeSocket))
   224  	c.Check(st.Path(), Equals, "/asock")
   225  	c.Check(st.User(), Equals, "john")
   226  	c.Check(st.Group(), Equals, "john")
   227  	c.Check(st.Size(), Equals, int64(0))
   228  	c.Check(st.ModTime(), Equals, time.Date(2018, 1, 9, 10, 24, 0, 0, time.UTC))
   229  }
   230  
   231  func (s *SquashfsTestSuite) TestStatLength(c *C) {
   232  	ns := []int64{
   233  		0,
   234  		1024,
   235  		math.MaxInt32,
   236  		math.MaxInt64,
   237  	}
   238  	for _, n := range ns {
   239  		raw := []byte(fmt.Sprintf("-rw-r--r-- user/group %16d 2017-12-08 11:19 ./some filename", n))
   240  
   241  		com := Commentf("%q", raw)
   242  		st, err := squashfs.FromRaw(raw)
   243  		c.Assert(err, IsNil, com)
   244  		c.Check(st.Mode(), Equals, os.FileMode(0644), com)
   245  		c.Check(st.Path(), Equals, "/some filename", com)
   246  		c.Check(st.User(), Equals, "user", com)
   247  		c.Check(st.Group(), Equals, "group", com)
   248  		c.Check(st.Size(), Equals, n, com)
   249  		c.Check(st.ModTime(), Equals, time.Date(2017, 12, 8, 11, 19, 0, 0, time.UTC), com)
   250  	}
   251  }
   252  
   253  func (s *SquashfsTestSuite) TestStatModeBits(c *C) {
   254  	for i := os.FileMode(0); i <= 0777; i++ {
   255  		raw := []byte(fmt.Sprintf("%s user/group            53595 2017-12-08 11:19 ./yadda", i))
   256  
   257  		com := Commentf("%q vs %o", raw, i)
   258  		st, err := squashfs.FromRaw(raw)
   259  		c.Assert(err, IsNil, com)
   260  		c.Check(st.Mode(), Equals, i, com)
   261  		c.Check(st.Path(), Equals, "/yadda", com)
   262  		c.Check(st.User(), Equals, "user", com)
   263  		c.Check(st.Group(), Equals, "group", com)
   264  		c.Check(st.Size(), Equals, int64(53595), com)
   265  		c.Check(st.ModTime(), Equals, time.Date(2017, 12, 8, 11, 19, 0, 0, time.UTC), com)
   266  
   267  		jRaw := make([]byte, len(raw))
   268  
   269  		for j := 01000 + i; j <= 07777; j += 01000 {
   270  			// this silliness only needed because os.FileMode's String() throws away sticky/setuid/setgid bits
   271  			copy(jRaw, raw)
   272  			if j&01000 != 0 {
   273  				if j&0001 != 0 {
   274  					jRaw[9] = 't'
   275  				} else {
   276  					jRaw[9] = 'T'
   277  				}
   278  			}
   279  			if j&02000 != 0 {
   280  				if j&0010 != 0 {
   281  					jRaw[6] = 's'
   282  				} else {
   283  					jRaw[6] = 'S'
   284  				}
   285  			}
   286  			if j&04000 != 0 {
   287  				if j&0100 != 0 {
   288  					jRaw[3] = 's'
   289  				} else {
   290  					jRaw[3] = 'S'
   291  				}
   292  			}
   293  			com := Commentf("%q vs %o", jRaw, j)
   294  			st, err := squashfs.FromRaw(jRaw)
   295  			c.Assert(err, IsNil, com)
   296  			c.Check(st.Mode(), Equals, j, com)
   297  		}
   298  	}
   299  }