github.com/dctrud/umoci@v0.4.3-0.20191016193643-05a1d37de015/pkg/unpriv/unpriv_test.go (about)

     1  /*
     2   * umoci: Umoci Modifies Open Containers' Images
     3   * Copyright (C) 2016, 2017, 2018 SUSE LLC.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *    http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package unpriv
    19  
    20  import (
    21  	"archive/tar"
    22  	"bytes"
    23  	"io/ioutil"
    24  	"os"
    25  	"path/filepath"
    26  	"reflect"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/pkg/errors"
    31  )
    32  
    33  func TestWrapNoTricks(t *testing.T) {
    34  	if os.Geteuid() == 0 {
    35  		t.Log("unpriv.* tests only work with non-root privileges")
    36  		t.Skip()
    37  	}
    38  
    39  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestWrapNoTricks")
    40  	if err != nil {
    41  		t.Fatal(err)
    42  	}
    43  	defer RemoveAll(dir)
    44  
    45  	// Make sure that no error is returned an no trickery is done if fn() works
    46  	// the first time. This is important to make sure that we're not doing
    47  	// dodgy stuff if unnecessary.
    48  	if err := Wrap(filepath.Join(dir, "nonexistant", "path"), func(path string) error {
    49  		return nil
    50  	}); err != nil {
    51  		t.Errorf("wrap returned error in the simple case: %s", err)
    52  	}
    53  
    54  	// Now make sure that Wrap doesn't mess with any directories in the same case.
    55  	if err := os.MkdirAll(filepath.Join(dir, "parent", "directory"), 0755); err != nil {
    56  		t.Fatal(err)
    57  	}
    58  	if err := os.Chmod(filepath.Join(dir, "parent"), 0); err != nil {
    59  		t.Fatal(err)
    60  	}
    61  	if err := Wrap(filepath.Join(dir, "parent", "directory"), func(path string) error {
    62  		return nil
    63  	}); err != nil {
    64  		t.Errorf("wrap returned error in the simple case: %s", err)
    65  	}
    66  }
    67  
    68  func TestLstat(t *testing.T) {
    69  	if os.Geteuid() == 0 {
    70  		t.Log("unpriv.* tests only work with non-root privileges")
    71  		t.Skip()
    72  	}
    73  
    74  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestLstat")
    75  	if err != nil {
    76  		t.Fatal(err)
    77  	}
    78  	defer RemoveAll(dir)
    79  
    80  	// Create some structure.
    81  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
    82  		t.Fatal(err)
    83  	}
    84  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "directories", "file"), []byte("some content"), 0555); err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "file"), 0); err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0); err != nil {
    91  		t.Fatal(err)
    92  	}
    93  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
    94  		t.Fatal(err)
    95  	}
    96  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
    97  		t.Fatal(err)
    98  	}
    99  
   100  	var fi os.FileInfo
   101  
   102  	// Check that the mode was unchanged.
   103  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   104  	if err != nil {
   105  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   106  	}
   107  	if fi.Mode()&os.ModePerm != 0 {
   108  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   109  	}
   110  
   111  	// Double check it was unchanged.
   112  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   113  	if err != nil {
   114  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   115  	}
   116  	if fi.Mode()&os.ModePerm != 0 {
   117  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   118  	}
   119  
   120  	// Check that the parents were unchanged.
   121  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
   122  	if err != nil {
   123  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   124  	}
   125  	if fi.Mode()&os.ModePerm != 0 {
   126  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   127  	}
   128  	fi, err = Lstat(filepath.Join(dir, "some", "parent"))
   129  	if err != nil {
   130  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   131  	}
   132  	if fi.Mode()&os.ModePerm != 0 {
   133  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   134  	}
   135  	fi, err = Lstat(filepath.Join(dir, "some"))
   136  	if err != nil {
   137  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   138  	}
   139  	if fi.Mode()&os.ModePerm != 0 {
   140  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   141  	}
   142  
   143  	// Make sure that os.Lstat still fails.
   144  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   145  	if err == nil {
   146  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   147  	} else if !os.IsPermission(errors.Cause(err)) {
   148  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   149  	}
   150  }
   151  
   152  func TestReadlink(t *testing.T) {
   153  	if os.Geteuid() == 0 {
   154  		t.Log("unpriv.* tests only work with non-root privileges")
   155  		t.Skip()
   156  	}
   157  
   158  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestReadlink")
   159  	if err != nil {
   160  		t.Fatal(err)
   161  	}
   162  	defer RemoveAll(dir)
   163  
   164  	// Create some structure.
   165  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
   166  		t.Fatal(err)
   167  	}
   168  	if err := os.Symlink("some path", filepath.Join(dir, "some", "parent", "directories", "link1")); err != nil {
   169  		t.Fatal(err)
   170  	}
   171  	if err := os.Symlink("..", filepath.Join(dir, "some", "parent", "directories", "link2")); err != nil {
   172  		t.Fatal(err)
   173  	}
   174  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0); err != nil {
   175  		t.Fatal(err)
   176  	}
   177  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
   178  		t.Fatal(err)
   179  	}
   180  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
   181  		t.Fatal(err)
   182  	}
   183  
   184  	var linkname string
   185  
   186  	// Check that the links can be read.
   187  	linkname, err = Readlink(filepath.Join(dir, "some", "parent", "directories", "link1"))
   188  	if err != nil {
   189  		t.Errorf("unexpected unpriv.readlink error: %s", err)
   190  	}
   191  	if linkname != "some path" {
   192  		t.Errorf("unexpected linkname for path %s: %s", "link1", linkname)
   193  	}
   194  	linkname, err = Readlink(filepath.Join(dir, "some", "parent", "directories", "link2"))
   195  	if err != nil {
   196  		t.Errorf("unexpected unpriv.readlink error: %s", err)
   197  	}
   198  	if linkname != ".." {
   199  		t.Errorf("unexpected linkname for path %s: %s", "link2", linkname)
   200  	}
   201  
   202  	var fi os.FileInfo
   203  
   204  	// Check that the parents were unchanged.
   205  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
   206  	if err != nil {
   207  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   208  	}
   209  	if fi.Mode()&os.ModePerm != 0 {
   210  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   211  	}
   212  	fi, err = Lstat(filepath.Join(dir, "some", "parent"))
   213  	if err != nil {
   214  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   215  	}
   216  	if fi.Mode()&os.ModePerm != 0 {
   217  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   218  	}
   219  	fi, err = Lstat(filepath.Join(dir, "some"))
   220  	if err != nil {
   221  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   222  	}
   223  	if fi.Mode()&os.ModePerm != 0 {
   224  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   225  	}
   226  
   227  	// Make sure that os.Lstat still fails.
   228  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "link1"))
   229  	if err == nil {
   230  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   231  	} else if !os.IsPermission(errors.Cause(err)) {
   232  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   233  	}
   234  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "link2"))
   235  	if err == nil {
   236  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   237  	} else if !os.IsPermission(errors.Cause(err)) {
   238  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   239  	}
   240  }
   241  
   242  func TestSymlink(t *testing.T) {
   243  	if os.Geteuid() == 0 {
   244  		t.Log("unpriv.* tests only work with non-root privileges")
   245  		t.Skip()
   246  	}
   247  
   248  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestSymlink")
   249  	if err != nil {
   250  		t.Fatal(err)
   251  	}
   252  	defer RemoveAll(dir)
   253  
   254  	// Create some structure.
   255  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
   256  		t.Fatal(err)
   257  	}
   258  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0); err != nil {
   259  		t.Fatal(err)
   260  	}
   261  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
   262  		t.Fatal(err)
   263  	}
   264  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
   265  		t.Fatal(err)
   266  	}
   267  
   268  	// unpriv.Symlink.
   269  	if err := Symlink("some path", filepath.Join(dir, "some", "parent", "directories", "link1")); err != nil {
   270  		t.Fatal(err)
   271  	}
   272  	if err := Symlink("..", filepath.Join(dir, "some", "parent", "directories", "link2")); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  
   276  	var linkname string
   277  
   278  	// Check that the links can be read.
   279  	linkname, err = Readlink(filepath.Join(dir, "some", "parent", "directories", "link1"))
   280  	if err != nil {
   281  		t.Errorf("unexpected unpriv.readlink error: %s", err)
   282  	}
   283  	if linkname != "some path" {
   284  		t.Errorf("unexpected linkname for path %s: %s", "link1", linkname)
   285  	}
   286  	linkname, err = Readlink(filepath.Join(dir, "some", "parent", "directories", "link2"))
   287  	if err != nil {
   288  		t.Errorf("unexpected unpriv.readlink error: %s", err)
   289  	}
   290  	if linkname != ".." {
   291  		t.Errorf("unexpected linkname for path %s: %s", "link2", linkname)
   292  	}
   293  
   294  	var fi os.FileInfo
   295  
   296  	// Check that the parents were unchanged.
   297  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
   298  	if err != nil {
   299  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   300  	}
   301  	if fi.Mode()&os.ModePerm != 0 {
   302  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   303  	}
   304  	fi, err = Lstat(filepath.Join(dir, "some", "parent"))
   305  	if err != nil {
   306  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   307  	}
   308  	if fi.Mode()&os.ModePerm != 0 {
   309  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   310  	}
   311  	fi, err = Lstat(filepath.Join(dir, "some"))
   312  	if err != nil {
   313  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   314  	}
   315  	if fi.Mode()&os.ModePerm != 0 {
   316  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   317  	}
   318  
   319  	// Make sure that os.Lstat still fails.
   320  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "link1"))
   321  	if err == nil {
   322  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   323  	} else if !os.IsPermission(errors.Cause(err)) {
   324  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   325  	}
   326  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "link2"))
   327  	if err == nil {
   328  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   329  	} else if !os.IsPermission(errors.Cause(err)) {
   330  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   331  	}
   332  }
   333  
   334  func TestOpen(t *testing.T) {
   335  	if os.Geteuid() == 0 {
   336  		t.Log("unpriv.* tests only work with non-root privileges")
   337  		t.Skip()
   338  	}
   339  
   340  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestOpen")
   341  	if err != nil {
   342  		t.Fatal(err)
   343  	}
   344  	defer RemoveAll(dir)
   345  
   346  	fileContent := []byte("some content")
   347  
   348  	// Create some structure.
   349  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
   350  		t.Fatal(err)
   351  	}
   352  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "directories", "file"), fileContent, 0555); err != nil {
   353  		t.Fatal(err)
   354  	}
   355  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "file"), []byte("parent"), 0555); err != nil {
   356  		t.Fatal(err)
   357  	}
   358  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "file"), []byte("some"), 0555); err != nil {
   359  		t.Fatal(err)
   360  	}
   361  	if err := ioutil.WriteFile(filepath.Join(dir, "file"), []byte("dir"), 0555); err != nil {
   362  		t.Fatal(err)
   363  	}
   364  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "file"), 0); err != nil {
   365  		t.Fatal(err)
   366  	}
   367  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0); err != nil {
   368  		t.Fatal(err)
   369  	}
   370  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
   371  		t.Fatal(err)
   372  	}
   373  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
   374  		t.Fatal(err)
   375  	}
   376  
   377  	fh, err := Open(filepath.Join(dir, "some", "parent", "directories", "file"))
   378  	if err != nil {
   379  		t.Errorf("unexpected unpriv.open error: %s", err)
   380  	}
   381  	defer fh.Close()
   382  
   383  	var fi os.FileInfo
   384  
   385  	// Check that the mode was unchanged.
   386  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   387  	if err != nil {
   388  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   389  	}
   390  	if fi.Mode()&os.ModePerm != 0 {
   391  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   392  	}
   393  
   394  	// Check using fh.Stat.
   395  	fi, err = fh.Stat()
   396  	if err != nil {
   397  		t.Errorf("unexpected unpriv.open.stat error: %s", err)
   398  	}
   399  	if fi.Mode()&os.ModePerm != 0 {
   400  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   401  	}
   402  
   403  	// Read the file contents.
   404  	gotContent, err := ioutil.ReadAll(fh)
   405  	if err != nil {
   406  		t.Errorf("unexpected error reading from unpriv.open: %s", err)
   407  	}
   408  	if !bytes.Equal(gotContent, fileContent) {
   409  		t.Errorf("unpriv.open content doesn't match actual content: expected=%s got=%s", fileContent, gotContent)
   410  	}
   411  
   412  	// Now change the mode using fh.Chmod.
   413  	if err := fh.Chmod(0755); err != nil {
   414  		t.Errorf("unexpected error doing fh.chown: %s", err)
   415  	}
   416  
   417  	// Double check it was changed.
   418  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   419  	if err != nil {
   420  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   421  	}
   422  	if fi.Mode()&os.ModePerm != 0755 {
   423  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   424  	}
   425  
   426  	// Change it back.
   427  	if err := fh.Chmod(0); err != nil {
   428  		t.Errorf("unexpected error doing fh.chown: %s", err)
   429  	}
   430  
   431  	// Double check it was changed.
   432  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   433  	if err != nil {
   434  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   435  	}
   436  	if fi.Mode()&os.ModePerm != 0 {
   437  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   438  	}
   439  
   440  	// Check that the parents were unchanged.
   441  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
   442  	if err != nil {
   443  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   444  	}
   445  	if fi.Mode()&os.ModePerm != 0 {
   446  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   447  	}
   448  	fi, err = Lstat(filepath.Join(dir, "some", "parent"))
   449  	if err != nil {
   450  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   451  	}
   452  	if fi.Mode()&os.ModePerm != 0 {
   453  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   454  	}
   455  	fi, err = Lstat(filepath.Join(dir, "some"))
   456  	if err != nil {
   457  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   458  	}
   459  	if fi.Mode()&os.ModePerm != 0 {
   460  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   461  	}
   462  
   463  	// Make sure that os.Lstat still fails.
   464  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   465  	if err == nil {
   466  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   467  	} else if !os.IsPermission(errors.Cause(err)) {
   468  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   469  	}
   470  }
   471  
   472  func TestReaddir(t *testing.T) {
   473  	if os.Geteuid() == 0 {
   474  		t.Log("unpriv.* tests only work with non-root privileges")
   475  		t.Skip()
   476  	}
   477  
   478  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestReaddir")
   479  	if err != nil {
   480  		t.Fatal(err)
   481  	}
   482  	defer RemoveAll(dir)
   483  
   484  	fileContent := []byte("some content")
   485  
   486  	// Create some structure.
   487  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
   488  		t.Fatal(err)
   489  	}
   490  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "directories", "file1"), fileContent, 0555); err != nil {
   491  		t.Fatal(err)
   492  	}
   493  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "directories", "file2"), fileContent, 0555); err != nil {
   494  		t.Fatal(err)
   495  	}
   496  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "directories", "file3"), fileContent, 0555); err != nil {
   497  		t.Fatal(err)
   498  	}
   499  	if err := os.Mkdir(filepath.Join(dir, "some", "parent", "directories", "dir"), 0755); err != nil {
   500  		t.Fatal(err)
   501  	}
   502  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "file1"), 0); err != nil {
   503  		t.Fatal(err)
   504  	}
   505  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "file2"), 0); err != nil {
   506  		t.Fatal(err)
   507  	}
   508  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "file3"), 0); err != nil {
   509  		t.Fatal(err)
   510  	}
   511  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "dir"), 0); err != nil {
   512  		t.Fatal(err)
   513  	}
   514  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0); err != nil {
   515  		t.Fatal(err)
   516  	}
   517  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
   518  		t.Fatal(err)
   519  	}
   520  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
   521  		t.Fatal(err)
   522  	}
   523  
   524  	// Make sure that the naive Open.Readdir will fail.
   525  	fh, err := Open(filepath.Join(dir, "some", "parent", "directories"))
   526  	if err != nil {
   527  		t.Errorf("unexpected unpriv.open error: %s", err)
   528  	}
   529  	defer fh.Close()
   530  
   531  	_, err = fh.Readdir(-1)
   532  	if err == nil {
   533  		t.Errorf("unexpected unpriv.open.readdir success (unwrapped readdir)!")
   534  	}
   535  
   536  	// Check that Readdir() only returns the relevant results.
   537  	infos, err := Readdir(filepath.Join(dir, "some", "parent", "directories"))
   538  	if err != nil {
   539  		t.Errorf("unexpected unpriv.readdir error: %s", err)
   540  	}
   541  	if len(infos) != 4 {
   542  		t.Errorf("expected unpriv.readdir to give %d results, got %d", 4, len(infos))
   543  	}
   544  	for _, info := range infos {
   545  		if info.Mode()&os.ModePerm != 0 {
   546  			t.Errorf("unexpected modeperm for path %s: %o", info.Name(), info.Mode()&os.ModePerm)
   547  		}
   548  	}
   549  
   550  	var fi os.FileInfo
   551  
   552  	// Check that the parents were unchanged.
   553  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
   554  	if err != nil {
   555  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   556  	}
   557  	if fi.Mode()&os.ModePerm != 0 {
   558  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   559  	}
   560  	fi, err = Lstat(filepath.Join(dir, "some", "parent"))
   561  	if err != nil {
   562  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   563  	}
   564  	if fi.Mode()&os.ModePerm != 0 {
   565  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   566  	}
   567  	fi, err = Lstat(filepath.Join(dir, "some"))
   568  	if err != nil {
   569  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   570  	}
   571  	if fi.Mode()&os.ModePerm != 0 {
   572  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   573  	}
   574  
   575  	// Make sure that os.Lstat still fails.
   576  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   577  	if err == nil {
   578  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   579  	} else if !os.IsPermission(errors.Cause(err)) {
   580  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   581  	}
   582  
   583  	// Make sure that the naive Open.Readdir will still fail.
   584  	fh, err = Open(filepath.Join(dir, "some", "parent", "directories"))
   585  	if err != nil {
   586  		t.Errorf("unexpected unpriv.open error: %s", err)
   587  	}
   588  	defer fh.Close()
   589  
   590  	_, err = fh.Readdir(-1)
   591  	if err == nil {
   592  		t.Errorf("unexpected unpriv.open.readdir success (unwrapped readdir)!")
   593  	}
   594  }
   595  
   596  func TestWrapWrite(t *testing.T) {
   597  	if os.Geteuid() == 0 {
   598  		t.Log("unpriv.* tests only work with non-root privileges")
   599  		t.Skip()
   600  	}
   601  
   602  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestWrapWrite")
   603  	if err != nil {
   604  		t.Fatal(err)
   605  	}
   606  	defer RemoveAll(dir)
   607  
   608  	fileContent := []byte("some content")
   609  
   610  	// Create some structure.
   611  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
   612  		t.Fatal(err)
   613  	}
   614  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0); err != nil {
   615  		t.Fatal(err)
   616  	}
   617  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
   618  		t.Fatal(err)
   619  	}
   620  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
   621  		t.Fatal(err)
   622  	}
   623  
   624  	if err := Wrap(filepath.Join(dir, "some", "parent", "directories", "lolpath"), func(path string) error {
   625  		return ioutil.WriteFile(path, fileContent, 0755)
   626  	}); err != nil {
   627  		t.Errorf("unpexected unpriv.wrap writing error: %s", err)
   628  	}
   629  
   630  	fh, err := Open(filepath.Join(dir, "some", "parent", "directories", "lolpath"))
   631  	if err != nil {
   632  		t.Errorf("unexpected unpriv.open error: %s", err)
   633  	}
   634  	defer fh.Close()
   635  
   636  	// Read the file contents.
   637  	gotContent, err := ioutil.ReadAll(fh)
   638  	if err != nil {
   639  		t.Errorf("unexpected error reading from unpriv.open: %s", err)
   640  	}
   641  	if !bytes.Equal(gotContent, fileContent) {
   642  		t.Errorf("unpriv.open content doesn't match actual content: expected=%s got=%s", fileContent, gotContent)
   643  	}
   644  
   645  	var fi os.FileInfo
   646  
   647  	// Check that the parents were unchanged.
   648  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
   649  	if err != nil {
   650  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   651  	}
   652  	if fi.Mode()&os.ModePerm != 0 {
   653  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   654  	}
   655  	fi, err = Lstat(filepath.Join(dir, "some", "parent"))
   656  	if err != nil {
   657  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   658  	}
   659  	if fi.Mode()&os.ModePerm != 0 {
   660  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   661  	}
   662  	fi, err = Lstat(filepath.Join(dir, "some"))
   663  	if err != nil {
   664  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   665  	}
   666  	if fi.Mode()&os.ModePerm != 0 {
   667  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   668  	}
   669  
   670  	// Make sure that os.Lstat still fails.
   671  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   672  	if err == nil {
   673  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   674  	} else if !os.IsPermission(errors.Cause(err)) {
   675  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   676  	}
   677  }
   678  
   679  func TestLink(t *testing.T) {
   680  	if os.Geteuid() == 0 {
   681  		t.Log("unpriv.* tests only work with non-root privileges")
   682  		t.Skip()
   683  	}
   684  
   685  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestLink")
   686  	if err != nil {
   687  		t.Fatal(err)
   688  	}
   689  	defer RemoveAll(dir)
   690  
   691  	fileContent := []byte("some content")
   692  
   693  	// Create some structure.
   694  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
   695  		t.Fatal(err)
   696  	}
   697  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "directories", "file"), fileContent, 0555); err != nil {
   698  		t.Fatal(err)
   699  	}
   700  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "file"), 0); err != nil {
   701  		t.Fatal(err)
   702  	}
   703  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0); err != nil {
   704  		t.Fatal(err)
   705  	}
   706  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
   707  		t.Fatal(err)
   708  	}
   709  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
   710  		t.Fatal(err)
   711  	}
   712  
   713  	fh, err := Open(filepath.Join(dir, "some", "parent", "directories", "file"))
   714  	if err != nil {
   715  		t.Errorf("unexpected unpriv.open error: %s", err)
   716  	}
   717  	defer fh.Close()
   718  
   719  	var fi os.FileInfo
   720  
   721  	// Read the file contents.
   722  	gotContent, err := ioutil.ReadAll(fh)
   723  	if err != nil {
   724  		t.Errorf("unexpected error reading from unpriv.open: %s", err)
   725  	}
   726  	if !bytes.Equal(gotContent, fileContent) {
   727  		t.Errorf("unpriv.open content doesn't match actual content: expected=%s got=%s", fileContent, gotContent)
   728  	}
   729  
   730  	// Make new links.
   731  	if err := Link(filepath.Join(dir, "some", "parent", "directories", "file"), filepath.Join(dir, "some", "parent", "directories", "file2")); err != nil {
   732  		t.Errorf("unexpected unpriv.link error: %s", err)
   733  	}
   734  	if err := Link(filepath.Join(dir, "some", "parent", "directories", "file"), filepath.Join(dir, "some", "parent", "file2")); err != nil {
   735  		t.Errorf("unexpected unpriv.link error: %s", err)
   736  	}
   737  
   738  	// Check the contents.
   739  	fh1, err := Open(filepath.Join(dir, "some", "parent", "directories", "file2"))
   740  	if err != nil {
   741  		t.Errorf("unexpected unpriv.open error: %s", err)
   742  	}
   743  	defer fh1.Close()
   744  	gotContent1, err := ioutil.ReadAll(fh1)
   745  	if err != nil {
   746  		t.Errorf("unexpected error reading from unpriv.open: %s", err)
   747  	}
   748  	if !bytes.Equal(gotContent1, fileContent) {
   749  		t.Errorf("unpriv.open content doesn't match actual content: expected=%s got=%s", fileContent, gotContent1)
   750  	}
   751  
   752  	// And the other link.
   753  	fh2, err := Open(filepath.Join(dir, "some", "parent", "file2"))
   754  	if err != nil {
   755  		t.Errorf("unexpected unpriv.open error: %s", err)
   756  	}
   757  	defer fh2.Close()
   758  	gotContent2, err := ioutil.ReadAll(fh2)
   759  	if err != nil {
   760  		t.Errorf("unexpected error reading from unpriv.open: %s", err)
   761  	}
   762  	if !bytes.Equal(gotContent2, fileContent) {
   763  		t.Errorf("unpriv.open content doesn't match actual content: expected=%s got=%s", fileContent, gotContent2)
   764  	}
   765  
   766  	// Double check it was unchanged.
   767  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   768  	if err != nil {
   769  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   770  	}
   771  	if fi.Mode()&os.ModePerm != 0 {
   772  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   773  	}
   774  	fi1, err := Lstat(filepath.Join(dir, "some", "parent", "directories", "file2"))
   775  	if err != nil {
   776  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   777  	}
   778  	if fi.Mode()&os.ModePerm != 0 {
   779  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   780  	}
   781  	fi2, err := Lstat(filepath.Join(dir, "some", "parent", "file2"))
   782  	if err != nil {
   783  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   784  	}
   785  	if fi.Mode()&os.ModePerm != 0 {
   786  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   787  	}
   788  
   789  	// Check that the files are the same.
   790  	if !os.SameFile(fi, fi1) {
   791  		t.Errorf("link1 and original file not the same!")
   792  	}
   793  	if !os.SameFile(fi, fi2) {
   794  		t.Errorf("link2 and original file not the same!")
   795  	}
   796  	if !os.SameFile(fi1, fi2) {
   797  		t.Errorf("link1 and link2 not the same!")
   798  	}
   799  
   800  	// Check that the parents were unchanged.
   801  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
   802  	if err != nil {
   803  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   804  	}
   805  	if fi.Mode()&os.ModePerm != 0 {
   806  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   807  	}
   808  	fi, err = Lstat(filepath.Join(dir, "some", "parent"))
   809  	if err != nil {
   810  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   811  	}
   812  	if fi.Mode()&os.ModePerm != 0 {
   813  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   814  	}
   815  	fi, err = Lstat(filepath.Join(dir, "some"))
   816  	if err != nil {
   817  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   818  	}
   819  	if fi.Mode()&os.ModePerm != 0 {
   820  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   821  	}
   822  
   823  	// Make sure that os.Lstat still fails.
   824  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   825  	if err == nil {
   826  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   827  	} else if !os.IsPermission(errors.Cause(err)) {
   828  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   829  	}
   830  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "file2"))
   831  	if err == nil {
   832  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   833  	} else if !os.IsPermission(errors.Cause(err)) {
   834  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   835  	}
   836  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "file2"))
   837  	if err == nil {
   838  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   839  	} else if !os.IsPermission(errors.Cause(err)) {
   840  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   841  	}
   842  }
   843  
   844  func TestLchownRemove(t *testing.T) {
   845  	// FIXME: We probably should remove Lchown.
   846  	t.Log("unpriv.Lchown cannot really be tested")
   847  	t.Skip()
   848  }
   849  
   850  func TestChtimes(t *testing.T) {
   851  	if os.Geteuid() == 0 {
   852  		t.Log("unpriv.* tests only work with non-root privileges")
   853  		t.Skip()
   854  	}
   855  
   856  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestChtimes")
   857  	if err != nil {
   858  		t.Fatal(err)
   859  	}
   860  	defer RemoveAll(dir)
   861  
   862  	fileContent := []byte("some content")
   863  
   864  	// Create some structure.
   865  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
   866  		t.Fatal(err)
   867  	}
   868  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "directories", "file"), fileContent, 0555); err != nil {
   869  		t.Fatal(err)
   870  	}
   871  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "file"), 0); err != nil {
   872  		t.Fatal(err)
   873  	}
   874  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0); err != nil {
   875  		t.Fatal(err)
   876  	}
   877  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
   878  		t.Fatal(err)
   879  	}
   880  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
   881  		t.Fatal(err)
   882  	}
   883  
   884  	var fi os.FileInfo
   885  
   886  	// Get the atime and mtime of one of the paths.
   887  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
   888  	if err != nil {
   889  		t.Errorf("unexpected error from unpriv.lstat: %s", err)
   890  	}
   891  	hdrOld, _ := tar.FileInfoHeader(fi, "")
   892  
   893  	// Modify the times.
   894  	atime := time.Unix(12345678, 12421512)
   895  	mtime := time.Unix(11245631, 13373321)
   896  	if err := Chtimes(filepath.Join(dir, "some", "parent", "directories"), atime, mtime); err != nil {
   897  		t.Errorf("unexpected error from unpriv.chtimes: %s", err)
   898  	}
   899  
   900  	// Get the new atime and mtime.
   901  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
   902  	if err != nil {
   903  		t.Errorf("unexpected error from unpriv.lstat: %s", err)
   904  	}
   905  	hdrNew, _ := tar.FileInfoHeader(fi, "")
   906  
   907  	if hdrNew.AccessTime.Equal(hdrOld.AccessTime) {
   908  		t.Errorf("atime was unchanged! %s", hdrNew.AccessTime)
   909  	}
   910  	if hdrNew.ModTime.Equal(hdrOld.ModTime) {
   911  		t.Errorf("mtime was unchanged! %s", hdrNew.ModTime)
   912  	}
   913  	if !hdrNew.ModTime.Equal(mtime) {
   914  		t.Errorf("mtime was not change to correct value. expected='%s' got='%s'", mtime, hdrNew.ModTime)
   915  	}
   916  	if !hdrNew.AccessTime.Equal(atime) {
   917  		t.Errorf("atime was not change to correct value. expected='%s' got='%s'", atime, hdrNew.AccessTime)
   918  	}
   919  
   920  	// Check that the parents were unchanged.
   921  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
   922  	if err != nil {
   923  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   924  	}
   925  	if fi.Mode()&os.ModePerm != 0 {
   926  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   927  	}
   928  	fi, err = Lstat(filepath.Join(dir, "some", "parent"))
   929  	if err != nil {
   930  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   931  	}
   932  	if fi.Mode()&os.ModePerm != 0 {
   933  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   934  	}
   935  	fi, err = Lstat(filepath.Join(dir, "some"))
   936  	if err != nil {
   937  		t.Errorf("unexpected unpriv.lstat error: %s", err)
   938  	}
   939  	if fi.Mode()&os.ModePerm != 0 {
   940  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
   941  	}
   942  
   943  	// Make sure that os.Lstat still fails.
   944  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
   945  	if err == nil {
   946  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   947  	} else if !os.IsPermission(errors.Cause(err)) {
   948  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   949  	}
   950  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "file2"))
   951  	if err == nil {
   952  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   953  	} else if !os.IsPermission(errors.Cause(err)) {
   954  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   955  	}
   956  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "file2"))
   957  	if err == nil {
   958  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
   959  	} else if !os.IsPermission(errors.Cause(err)) {
   960  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
   961  	}
   962  }
   963  
   964  func TestLutimes(t *testing.T) {
   965  	if os.Geteuid() == 0 {
   966  		t.Log("unpriv.* tests only work with non-root privileges")
   967  		t.Skip()
   968  	}
   969  
   970  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestLutimes")
   971  	if err != nil {
   972  		t.Fatal(err)
   973  	}
   974  	defer RemoveAll(dir)
   975  
   976  	fileContent := []byte("some content")
   977  
   978  	// Create some structure.
   979  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
   980  		t.Fatal(err)
   981  	}
   982  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "directories", "file"), fileContent, 0555); err != nil {
   983  		t.Fatal(err)
   984  	}
   985  	if err := os.Symlink(".", filepath.Join(dir, "some", "parent", "directories", "link2")); err != nil {
   986  		t.Fatal(err)
   987  	}
   988  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "file"), 0); err != nil {
   989  		t.Fatal(err)
   990  	}
   991  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0); err != nil {
   992  		t.Fatal(err)
   993  	}
   994  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
   995  		t.Fatal(err)
   996  	}
   997  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
   998  		t.Fatal(err)
   999  	}
  1000  
  1001  	var fi os.FileInfo
  1002  
  1003  	// Get the atime and mtime of one of the paths.
  1004  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
  1005  	if err != nil {
  1006  		t.Errorf("unexpected error from unpriv.lstat: %s", err)
  1007  	}
  1008  	hdrDirOld, _ := tar.FileInfoHeader(fi, "")
  1009  
  1010  	// Modify the times.
  1011  	atime := time.Unix(12345678, 12421512)
  1012  	mtime := time.Unix(11245631, 13373321)
  1013  	if err := Lutimes(filepath.Join(dir, "some", "parent", "directories"), atime, mtime); err != nil {
  1014  		t.Errorf("unexpected error from unpriv.lutimes: %s", err)
  1015  	}
  1016  
  1017  	// Get the new atime and mtime.
  1018  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
  1019  	if err != nil {
  1020  		t.Errorf("unexpected error from unpriv.lstat: %s", err)
  1021  	}
  1022  	hdrDirNew, _ := tar.FileInfoHeader(fi, "")
  1023  
  1024  	if hdrDirNew.AccessTime.Equal(hdrDirOld.AccessTime) {
  1025  		t.Errorf("atime was unchanged! %s", hdrDirNew.AccessTime)
  1026  	}
  1027  	if hdrDirNew.ModTime.Equal(hdrDirOld.ModTime) {
  1028  		t.Errorf("mtime was unchanged! %s", hdrDirNew.ModTime)
  1029  	}
  1030  	if !hdrDirNew.ModTime.Equal(mtime) {
  1031  		t.Errorf("mtime was not change to correct value. expected='%s' got='%s'", mtime, hdrDirNew.ModTime)
  1032  	}
  1033  	if !hdrDirNew.AccessTime.Equal(atime) {
  1034  		t.Errorf("atime was not change to correct value. expected='%s' got='%s'", atime, hdrDirNew.AccessTime)
  1035  	}
  1036  
  1037  	// Do the same for a symlink.
  1038  	atime = time.Unix(18127518, 12421122)
  1039  	mtime = time.Unix(15245123, 19912991)
  1040  
  1041  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories", "link2"))
  1042  	if err != nil {
  1043  		t.Errorf("unexpected error from unpriv.lstat: %s", err)
  1044  	}
  1045  	hdrOld, _ := tar.FileInfoHeader(fi, "")
  1046  	if err := Lutimes(filepath.Join(dir, "some", "parent", "directories", "link2"), atime, mtime); err != nil {
  1047  		t.Errorf("unexpected error from unpriv.lutimes: %s", err)
  1048  	}
  1049  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories", "link2"))
  1050  	if err != nil {
  1051  		t.Errorf("unexpected error from unpriv.lstat: %s", err)
  1052  	}
  1053  	hdrNew, _ := tar.FileInfoHeader(fi, "")
  1054  
  1055  	if hdrNew.AccessTime.Equal(hdrOld.AccessTime) {
  1056  		t.Errorf("atime was unchanged! %s", hdrNew.AccessTime)
  1057  	}
  1058  	if hdrNew.ModTime.Equal(hdrOld.ModTime) {
  1059  		t.Errorf("mtime was unchanged! %s", hdrNew.ModTime)
  1060  	}
  1061  	if !hdrNew.ModTime.Equal(mtime) {
  1062  		t.Errorf("mtime was not change to correct value. expected='%s' got='%s'", mtime, hdrNew.ModTime)
  1063  	}
  1064  	if !hdrNew.AccessTime.Equal(atime) {
  1065  		t.Errorf("atime was not change to correct value. expected='%s' got='%s'", atime, hdrNew.AccessTime)
  1066  	}
  1067  
  1068  	// Make sure that the parent was not changed by Lutimes.
  1069  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
  1070  	if err != nil {
  1071  		t.Errorf("unexpected error from unpriv.lstat: %s", err)
  1072  	}
  1073  	hdrDirNew2, _ := tar.FileInfoHeader(fi, "")
  1074  
  1075  	if !hdrDirNew2.AccessTime.Equal(hdrDirNew.AccessTime) {
  1076  		t.Errorf("atime was changed! expected='%s' got='%s'", hdrDirNew.AccessTime, hdrDirNew2.AccessTime)
  1077  	}
  1078  	if !hdrDirNew2.ModTime.Equal(hdrDirNew.ModTime) {
  1079  		t.Errorf("mtime was changed! expected='%s' got='%s'", hdrDirNew.ModTime, hdrDirNew2.ModTime)
  1080  	}
  1081  
  1082  	// Check that the parents were unchanged.
  1083  	fi, err = Lstat(filepath.Join(dir, "some", "parent", "directories"))
  1084  	if err != nil {
  1085  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1086  	}
  1087  	if fi.Mode()&os.ModePerm != 0 {
  1088  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1089  	}
  1090  	fi, err = Lstat(filepath.Join(dir, "some", "parent"))
  1091  	if err != nil {
  1092  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1093  	}
  1094  	if fi.Mode()&os.ModePerm != 0 {
  1095  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1096  	}
  1097  	fi, err = Lstat(filepath.Join(dir, "some"))
  1098  	if err != nil {
  1099  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1100  	}
  1101  	if fi.Mode()&os.ModePerm != 0 {
  1102  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1103  	}
  1104  
  1105  	// Make sure that os.Lstat still fails.
  1106  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "file"))
  1107  	if err == nil {
  1108  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
  1109  	} else if !os.IsPermission(errors.Cause(err)) {
  1110  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
  1111  	}
  1112  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "directories", "file2"))
  1113  	if err == nil {
  1114  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
  1115  	} else if !os.IsPermission(errors.Cause(err)) {
  1116  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
  1117  	}
  1118  	fi, err = os.Lstat(filepath.Join(dir, "some", "parent", "file2"))
  1119  	if err == nil {
  1120  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
  1121  	} else if !os.IsPermission(errors.Cause(err)) {
  1122  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
  1123  	}
  1124  }
  1125  
  1126  func TestRemove(t *testing.T) {
  1127  	if os.Geteuid() == 0 {
  1128  		t.Log("unpriv.* tests only work with non-root privileges")
  1129  		t.Skip()
  1130  	}
  1131  
  1132  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestRemove")
  1133  	if err != nil {
  1134  		t.Fatal(err)
  1135  	}
  1136  	defer RemoveAll(dir)
  1137  
  1138  	fileContent := []byte("some content")
  1139  
  1140  	// Create some structure.
  1141  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
  1142  		t.Fatal(err)
  1143  	}
  1144  	if err := os.MkdirAll(filepath.Join(dir, "some", "cousin", "directories"), 0755); err != nil {
  1145  		t.Fatal(err)
  1146  	}
  1147  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "directories", "file"), fileContent, 0555); err != nil {
  1148  		t.Fatal(err)
  1149  	}
  1150  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "file2"), fileContent, 0555); err != nil {
  1151  		t.Fatal(err)
  1152  	}
  1153  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "file"), 0); err != nil {
  1154  		t.Fatal(err)
  1155  	}
  1156  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0); err != nil {
  1157  		t.Fatal(err)
  1158  	}
  1159  	if err := os.Chmod(filepath.Join(dir, "some", "cousin", "directories"), 0); err != nil {
  1160  		t.Fatal(err)
  1161  	}
  1162  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "file2"), 0); err != nil {
  1163  		t.Fatal(err)
  1164  	}
  1165  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
  1166  		t.Fatal(err)
  1167  	}
  1168  	if err := os.Chmod(filepath.Join(dir, "some", "cousin"), 0); err != nil {
  1169  		t.Fatal(err)
  1170  	}
  1171  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
  1172  		t.Fatal(err)
  1173  	}
  1174  
  1175  	// Make sure that os.Remove fails.
  1176  	if err := os.Remove(filepath.Join(dir, "some", "parent", "directories", "file")); err == nil {
  1177  		t.Errorf("os.remove did not fail!")
  1178  	}
  1179  
  1180  	// Now try removing all of the things.
  1181  	if err := Remove(filepath.Join(dir, "some", "parent", "directories", "file")); err != nil {
  1182  		t.Errorf("unexpected failure in unpriv.remove: %s", err)
  1183  	}
  1184  	if err := Remove(filepath.Join(dir, "some", "parent", "directories")); err != nil {
  1185  		t.Errorf("unexpected failure in unpriv.remove: %s", err)
  1186  	}
  1187  	if err := Remove(filepath.Join(dir, "some", "parent", "file2")); err != nil {
  1188  		t.Errorf("unexpected failure in unpriv.remove: %s", err)
  1189  	}
  1190  	if err := Remove(filepath.Join(dir, "some", "cousin", "directories")); err != nil {
  1191  		t.Errorf("unexpected failure in unpriv.remove: %s", err)
  1192  	}
  1193  
  1194  	// Check that they are gone.
  1195  	if _, err := Lstat(filepath.Join(dir, "some", "parent", "directories")); !os.IsNotExist(errors.Cause(err)) {
  1196  		t.Errorf("expected deleted directory to give ENOENT: %s", err)
  1197  	}
  1198  	if _, err := Lstat(filepath.Join(dir, "some", "cousin", "directories")); !os.IsNotExist(errors.Cause(err)) {
  1199  		t.Errorf("expected deleted directory to give ENOENT: %s", err)
  1200  	}
  1201  	if _, err := Lstat(filepath.Join(dir, "some", "cousin", "directories")); !os.IsNotExist(errors.Cause(err)) {
  1202  		t.Errorf("expected deleted file to give ENOENT: %s", err)
  1203  	}
  1204  	if _, err := Lstat(filepath.Join(dir, "some", "parent", "file2")); !os.IsNotExist(errors.Cause(err)) {
  1205  		t.Errorf("expected deleted file to give ENOENT: %s", err)
  1206  	}
  1207  }
  1208  
  1209  func TestRemoveAll(t *testing.T) {
  1210  	if os.Geteuid() == 0 {
  1211  		t.Log("unpriv.* tests only work with non-root privileges")
  1212  		t.Skip()
  1213  	}
  1214  
  1215  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestRemoveAll")
  1216  	if err != nil {
  1217  		t.Fatal(err)
  1218  	}
  1219  	defer RemoveAll(dir)
  1220  
  1221  	fileContent := []byte("some content")
  1222  
  1223  	// Create some structure.
  1224  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
  1225  		t.Fatal(err)
  1226  	}
  1227  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "cousin", "directories"), 0755); err != nil {
  1228  		t.Fatal(err)
  1229  	}
  1230  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "directories", "file"), fileContent, 0555); err != nil {
  1231  		t.Fatal(err)
  1232  	}
  1233  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "file2"), fileContent, 0555); err != nil {
  1234  		t.Fatal(err)
  1235  	}
  1236  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "file"), 0); err != nil {
  1237  		t.Fatal(err)
  1238  	}
  1239  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0); err != nil {
  1240  		t.Fatal(err)
  1241  	}
  1242  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "cousin", "directories"), 0); err != nil {
  1243  		t.Fatal(err)
  1244  	}
  1245  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "cousin"), 0); err != nil {
  1246  		t.Fatal(err)
  1247  	}
  1248  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "file2"), 0); err != nil {
  1249  		t.Fatal(err)
  1250  	}
  1251  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
  1252  		t.Fatal(err)
  1253  	}
  1254  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
  1255  		t.Fatal(err)
  1256  	}
  1257  
  1258  	// Make sure that os.RemoveAll fails.
  1259  	if err := os.RemoveAll(filepath.Join(dir, "some", "parent")); err == nil {
  1260  		t.Errorf("os.removeall did not fail!")
  1261  	}
  1262  
  1263  	// Now try to removeall the entire tree.
  1264  	if err := RemoveAll(filepath.Join(dir, "some", "parent")); err != nil {
  1265  		t.Errorf("unexpected failure in unpriv.removeall: %s", err)
  1266  	}
  1267  
  1268  	// Check that they are gone.
  1269  	if _, err := Lstat(filepath.Join(dir, "some", "parent")); !os.IsNotExist(errors.Cause(err)) {
  1270  		t.Errorf("expected deleted directory to give ENOENT: %s", err)
  1271  	}
  1272  	if _, err := Lstat(filepath.Join(dir, "some")); err != nil {
  1273  		t.Errorf("expected parent of deleted directory to not have error: %s", err)
  1274  	}
  1275  
  1276  	// Make sure that trying to remove the directory after it's gone still won't fail.
  1277  	if err := RemoveAll(filepath.Join(dir, "some", "parent")); err != nil {
  1278  		t.Errorf("unexpected failure in unpriv.removeall (after deletion): %s", err)
  1279  	}
  1280  }
  1281  
  1282  func TestMkdir(t *testing.T) {
  1283  	if os.Geteuid() == 0 {
  1284  		t.Log("unpriv.* tests only work with non-root privileges")
  1285  		t.Skip()
  1286  	}
  1287  
  1288  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestMkdir")
  1289  	if err != nil {
  1290  		t.Fatal(err)
  1291  	}
  1292  	defer RemoveAll(dir)
  1293  
  1294  	// Create no structure.
  1295  	if err := os.MkdirAll(filepath.Join(dir, "some"), 0755); err != nil {
  1296  		t.Fatal(err)
  1297  	}
  1298  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
  1299  		t.Fatal(err)
  1300  	}
  1301  
  1302  	// Make some subdirectories.
  1303  	if err := Mkdir(filepath.Join(dir, "some", "child"), 0); err != nil {
  1304  		t.Fatal(err)
  1305  	}
  1306  	if err := Mkdir(filepath.Join(dir, "some", "other-child"), 0); err != nil {
  1307  		t.Fatal(err)
  1308  	}
  1309  	if err := Mkdir(filepath.Join(dir, "some", "child", "dir"), 0); err != nil {
  1310  		t.Fatal(err)
  1311  	}
  1312  
  1313  	// Check that they all have chmod(0).
  1314  	var fi os.FileInfo
  1315  
  1316  	// Double check it was unchanged.
  1317  	fi, err = Lstat(filepath.Join(dir, "some", "child"))
  1318  	if err != nil {
  1319  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1320  	}
  1321  	if fi.Mode()&os.ModePerm != 0 {
  1322  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1323  	}
  1324  	fi, err = Lstat(filepath.Join(dir, "some", "other-child"))
  1325  	if err != nil {
  1326  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1327  	}
  1328  	if fi.Mode()&os.ModePerm != 0 {
  1329  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1330  	}
  1331  	fi, err = Lstat(filepath.Join(dir, "some", "child", "dir"))
  1332  	if err != nil {
  1333  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1334  	}
  1335  	if fi.Mode()&os.ModePerm != 0 {
  1336  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1337  	}
  1338  	fi, err = Lstat(filepath.Join(dir, "some"))
  1339  	if err != nil {
  1340  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1341  	}
  1342  	if fi.Mode()&os.ModePerm != 0 {
  1343  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1344  	}
  1345  
  1346  	// Make sure that os.Lstat still fails.
  1347  	fi, err = os.Lstat(filepath.Join(dir, "some", "child"))
  1348  	if err == nil {
  1349  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
  1350  	} else if !os.IsPermission(errors.Cause(err)) {
  1351  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
  1352  	}
  1353  	fi, err = os.Lstat(filepath.Join(dir, "some", "other-child"))
  1354  	if err == nil {
  1355  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
  1356  	} else if !os.IsPermission(errors.Cause(err)) {
  1357  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
  1358  	}
  1359  	fi, err = os.Lstat(filepath.Join(dir, "some", "child", "dir"))
  1360  	if err == nil {
  1361  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
  1362  	} else if !os.IsPermission(errors.Cause(err)) {
  1363  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
  1364  	}
  1365  }
  1366  
  1367  func TestMkdirAll(t *testing.T) {
  1368  	if os.Geteuid() == 0 {
  1369  		t.Log("unpriv.* tests only work with non-root privileges")
  1370  		t.Skip()
  1371  	}
  1372  
  1373  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestMkdirAll")
  1374  	if err != nil {
  1375  		t.Fatal(err)
  1376  	}
  1377  	defer RemoveAll(dir)
  1378  
  1379  	// Create no structure.
  1380  	if err := os.MkdirAll(filepath.Join(dir, "some"), 0755); err != nil {
  1381  		t.Fatal(err)
  1382  	}
  1383  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
  1384  		t.Fatal(err)
  1385  	}
  1386  
  1387  	// Make some subdirectories.
  1388  	if err := MkdirAll(filepath.Join(dir, "some", "child"), 0); err != nil {
  1389  		t.Fatal(err)
  1390  	}
  1391  	if err := MkdirAll(filepath.Join(dir, "some", "other-child", "with", "more", "children"), 0); err != nil {
  1392  		t.Fatal(err)
  1393  	}
  1394  	if err := MkdirAll(filepath.Join(dir, "some", "child", "with", "more", "children"), 0); err != nil {
  1395  		t.Fatal(err)
  1396  	}
  1397  
  1398  	// Check that they all have chmod(0).
  1399  	var fi os.FileInfo
  1400  
  1401  	// Double check it was unchanged.
  1402  	fi, err = Lstat(filepath.Join(dir, "some", "child"))
  1403  	if err != nil {
  1404  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1405  	}
  1406  	if fi.Mode()&os.ModePerm != 0 {
  1407  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1408  	}
  1409  	fi, err = Lstat(filepath.Join(dir, "some", "child", "with"))
  1410  	if err != nil {
  1411  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1412  	}
  1413  	if fi.Mode()&os.ModePerm != 0 {
  1414  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1415  	}
  1416  	fi, err = Lstat(filepath.Join(dir, "some", "child", "with", "more"))
  1417  	if err != nil {
  1418  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1419  	}
  1420  	if fi.Mode()&os.ModePerm != 0 {
  1421  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1422  	}
  1423  	fi, err = Lstat(filepath.Join(dir, "some", "child", "with", "more", "children"))
  1424  	if err != nil {
  1425  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1426  	}
  1427  	if fi.Mode()&os.ModePerm != 0 {
  1428  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1429  	}
  1430  	fi, err = Lstat(filepath.Join(dir, "some", "other-child"))
  1431  	if err != nil {
  1432  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1433  	}
  1434  	if fi.Mode()&os.ModePerm != 0 {
  1435  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1436  	}
  1437  	fi, err = Lstat(filepath.Join(dir, "some", "other-child", "with"))
  1438  	if err != nil {
  1439  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1440  	}
  1441  	if fi.Mode()&os.ModePerm != 0 {
  1442  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1443  	}
  1444  	fi, err = Lstat(filepath.Join(dir, "some", "other-child", "with", "more"))
  1445  	if err != nil {
  1446  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1447  	}
  1448  	if fi.Mode()&os.ModePerm != 0 {
  1449  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1450  	}
  1451  	fi, err = Lstat(filepath.Join(dir, "some", "other-child", "with", "more", "children"))
  1452  	if err != nil {
  1453  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1454  	}
  1455  	if fi.Mode()&os.ModePerm != 0 {
  1456  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1457  	}
  1458  	fi, err = Lstat(filepath.Join(dir, "some"))
  1459  	if err != nil {
  1460  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1461  	}
  1462  	if fi.Mode()&os.ModePerm != 0 {
  1463  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1464  	}
  1465  
  1466  	// Make sure that os.Lstat still fails.
  1467  	fi, err = os.Lstat(filepath.Join(dir, "some", "child"))
  1468  	if err == nil {
  1469  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
  1470  	} else if !os.IsPermission(errors.Cause(err)) {
  1471  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
  1472  	}
  1473  	fi, err = os.Lstat(filepath.Join(dir, "some", "other-child"))
  1474  	if err == nil {
  1475  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
  1476  	} else if !os.IsPermission(errors.Cause(err)) {
  1477  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
  1478  	}
  1479  	fi, err = os.Lstat(filepath.Join(dir, "some", "child", "dir"))
  1480  	if err == nil {
  1481  		t.Errorf("expected os.Lstat to give EPERM -- got no error!")
  1482  	} else if !os.IsPermission(errors.Cause(err)) {
  1483  		t.Errorf("expected os.Lstat to give EPERM -- got %s", err)
  1484  	}
  1485  }
  1486  
  1487  func TestMkdirAllMissing(t *testing.T) {
  1488  	if os.Geteuid() == 0 {
  1489  		t.Log("unpriv.* tests only work with non-root privileges")
  1490  		t.Skip()
  1491  	}
  1492  
  1493  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestMkdirAllMissing")
  1494  	if err != nil {
  1495  		t.Fatal(err)
  1496  	}
  1497  	defer RemoveAll(dir)
  1498  
  1499  	// Create no structure, but with read access.
  1500  	if err := os.MkdirAll(filepath.Join(dir, "some"), 0755); err != nil {
  1501  		t.Fatal(err)
  1502  	}
  1503  
  1504  	// Make some subdirectories.
  1505  	if err := MkdirAll(filepath.Join(dir, "some", "a", "b", "c", "child"), 0); err != nil {
  1506  		t.Fatal(err)
  1507  	}
  1508  	if err := MkdirAll(filepath.Join(dir, "some", "x", "y", "z", "other-child", "with", "more", "children"), 0); err != nil {
  1509  		t.Fatal(err)
  1510  	}
  1511  	if err := MkdirAll(filepath.Join(dir, "some", "a", "b", "c", "child", "with", "more", "children"), 0); err != nil {
  1512  		t.Fatal(err)
  1513  	}
  1514  	// Make sure that os.MkdirAll fails.
  1515  	if err := os.MkdirAll(filepath.Join(dir, "some", "serious", "hacks"), 0); err == nil {
  1516  		t.Fatalf("expected MkdirAll to error out")
  1517  	}
  1518  
  1519  	// Check that they all have chmod(0).
  1520  	var fi os.FileInfo
  1521  
  1522  	// Double check it was unchanged.
  1523  	fi, err = Lstat(filepath.Join(dir, "some", "a", "b", "c", "child"))
  1524  	if err != nil {
  1525  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1526  	}
  1527  	if fi.Mode()&os.ModePerm != 0 {
  1528  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1529  	}
  1530  	fi, err = Lstat(filepath.Join(dir, "some", "a", "b", "c", "child", "with"))
  1531  	if err != nil {
  1532  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1533  	}
  1534  	if fi.Mode()&os.ModePerm != 0 {
  1535  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1536  	}
  1537  	fi, err = Lstat(filepath.Join(dir, "some", "a", "b", "c", "child", "with", "more"))
  1538  	if err != nil {
  1539  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1540  	}
  1541  	if fi.Mode()&os.ModePerm != 0 {
  1542  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1543  	}
  1544  	fi, err = Lstat(filepath.Join(dir, "some", "a", "b", "c", "child", "with", "more", "children"))
  1545  	if err != nil {
  1546  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1547  	}
  1548  	if fi.Mode()&os.ModePerm != 0 {
  1549  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1550  	}
  1551  	fi, err = Lstat(filepath.Join(dir, "some", "x", "y", "z", "other-child"))
  1552  	if err != nil {
  1553  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1554  	}
  1555  	if fi.Mode()&os.ModePerm != 0 {
  1556  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1557  	}
  1558  	fi, err = Lstat(filepath.Join(dir, "some", "x", "y", "z", "other-child", "with"))
  1559  	if err != nil {
  1560  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1561  	}
  1562  	if fi.Mode()&os.ModePerm != 0 {
  1563  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1564  	}
  1565  	fi, err = Lstat(filepath.Join(dir, "some", "x", "y", "z", "other-child", "with", "more"))
  1566  	if err != nil {
  1567  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1568  	}
  1569  	if fi.Mode()&os.ModePerm != 0 {
  1570  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1571  	}
  1572  	fi, err = Lstat(filepath.Join(dir, "some", "x", "y", "z", "other-child", "with", "more", "children"))
  1573  	if err != nil {
  1574  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1575  	}
  1576  	if fi.Mode()&os.ModePerm != 0 {
  1577  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1578  	}
  1579  }
  1580  
  1581  // Makes sure that if a parent directory only has +rw (-x) permissions, things
  1582  // are handled correctly. This is modelled after fedora's root filesystem
  1583  // (specifically /var/log/anaconda/pre-anaconda-logs/lvmdump).
  1584  func TestMkdirRWPerm(t *testing.T) {
  1585  	if os.Geteuid() == 0 {
  1586  		t.Log("unpriv.* tests only work with non-root privileges")
  1587  		t.Skip()
  1588  	}
  1589  
  1590  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestMkdirRWPerm")
  1591  	if err != nil {
  1592  		t.Fatal(err)
  1593  	}
  1594  	defer RemoveAll(dir)
  1595  
  1596  	fileContent := []byte("some content")
  1597  
  1598  	// Create some small structure. This is modelled after /var/log/anaconda/pre-anaconda-logs/lvmdump.
  1599  	if err := os.MkdirAll(filepath.Join(dir, "var", "log", "anaconda", "pre-anaconda-logs", "lvmdump"), 0755); err != nil {
  1600  		t.Fatal(err)
  1601  	}
  1602  	if err := os.Chmod(filepath.Join(dir, "var", "log", "anaconda", "pre-anaconda-logs"), 0600); err != nil {
  1603  		t.Fatal(err)
  1604  	}
  1605  
  1606  	// Now we have to try to create /var/log/anaconda/pre-anaconda-logs/lvmdump/config_diff.
  1607  	if fh, err := os.Create(filepath.Join(dir, "var", "log", "anaconda", "pre-anaconda-logs", "lvmdump", "config_diff")); err == nil {
  1608  		fh.Close()
  1609  		t.Fatalf("expected error when using os.create for lvmdump/config_diff!")
  1610  	}
  1611  
  1612  	// Try to do it with unpriv.
  1613  	fh, err := Create(filepath.Join(dir, "var", "log", "anaconda", "pre-anaconda-logs", "lvmdump", "config_diff"))
  1614  	if err != nil {
  1615  		t.Fatalf("unexpected unpriv.create error: %s", err)
  1616  	}
  1617  	defer fh.Close()
  1618  
  1619  	if n, err := fh.Write(fileContent); err != nil {
  1620  		t.Fatal(err)
  1621  	} else if n != len(fileContent) {
  1622  		t.Fatalf("incomplete write to config_diff")
  1623  	}
  1624  
  1625  	// Make some subdirectories.
  1626  	if err := MkdirAll(filepath.Join(dir, "some", "a", "b", "c", "child"), 0); err != nil {
  1627  		t.Fatal(err)
  1628  	}
  1629  	if err := MkdirAll(filepath.Join(dir, "some", "x", "y", "z", "other-child", "with", "more", "children"), 0); err != nil {
  1630  		t.Fatal(err)
  1631  	}
  1632  	if err := MkdirAll(filepath.Join(dir, "some", "a", "b", "c", "child", "with", "more", "children"), 0); err != nil {
  1633  		t.Fatal(err)
  1634  	}
  1635  	// Make sure that os.MkdirAll fails.
  1636  	if err := os.MkdirAll(filepath.Join(dir, "some", "serious", "hacks"), 0); err == nil {
  1637  		t.Fatalf("expected MkdirAll to error out")
  1638  	}
  1639  
  1640  	// Check that they all have chmod(0).
  1641  	var fi os.FileInfo
  1642  
  1643  	// Double check it was unchanged.
  1644  	fi, err = Lstat(filepath.Join(dir, "some", "a", "b", "c", "child"))
  1645  	if err != nil {
  1646  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1647  	}
  1648  	if fi.Mode()&os.ModePerm != 0 {
  1649  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1650  	}
  1651  	fi, err = Lstat(filepath.Join(dir, "some", "a", "b", "c", "child", "with"))
  1652  	if err != nil {
  1653  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1654  	}
  1655  	if fi.Mode()&os.ModePerm != 0 {
  1656  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1657  	}
  1658  	fi, err = Lstat(filepath.Join(dir, "some", "a", "b", "c", "child", "with", "more"))
  1659  	if err != nil {
  1660  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1661  	}
  1662  	if fi.Mode()&os.ModePerm != 0 {
  1663  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1664  	}
  1665  	fi, err = Lstat(filepath.Join(dir, "some", "a", "b", "c", "child", "with", "more", "children"))
  1666  	if err != nil {
  1667  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1668  	}
  1669  	if fi.Mode()&os.ModePerm != 0 {
  1670  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1671  	}
  1672  	fi, err = Lstat(filepath.Join(dir, "some", "x", "y", "z", "other-child"))
  1673  	if err != nil {
  1674  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1675  	}
  1676  	if fi.Mode()&os.ModePerm != 0 {
  1677  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1678  	}
  1679  	fi, err = Lstat(filepath.Join(dir, "some", "x", "y", "z", "other-child", "with"))
  1680  	if err != nil {
  1681  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1682  	}
  1683  	if fi.Mode()&os.ModePerm != 0 {
  1684  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1685  	}
  1686  	fi, err = Lstat(filepath.Join(dir, "some", "x", "y", "z", "other-child", "with", "more"))
  1687  	if err != nil {
  1688  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1689  	}
  1690  	if fi.Mode()&os.ModePerm != 0 {
  1691  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1692  	}
  1693  	fi, err = Lstat(filepath.Join(dir, "some", "x", "y", "z", "other-child", "with", "more", "children"))
  1694  	if err != nil {
  1695  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1696  	}
  1697  	if fi.Mode()&os.ModePerm != 0 {
  1698  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1699  	}
  1700  }
  1701  
  1702  // Makes sure that if a parent directory only has +rx (-w) permissions, things
  1703  // are handled correctly with Mkdir or Create.
  1704  func TestMkdirRPerm(t *testing.T) {
  1705  	if os.Geteuid() == 0 {
  1706  		t.Log("unpriv.* tests only work with non-root privileges")
  1707  		t.Skip()
  1708  	}
  1709  
  1710  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestMkdirRPerm")
  1711  	if err != nil {
  1712  		t.Fatal(err)
  1713  	}
  1714  	defer RemoveAll(dir)
  1715  
  1716  	fileContent := []byte("some content")
  1717  
  1718  	// Create some small structure.
  1719  	if err := os.MkdirAll(filepath.Join(dir, "var", "log"), 0755); err != nil {
  1720  		t.Fatal(err)
  1721  	}
  1722  	if err := os.Chmod(filepath.Join(dir, "var", "log"), 0555); err != nil {
  1723  		t.Fatal(err)
  1724  	}
  1725  	if err := os.Chmod(filepath.Join(dir, "var"), 0555); err != nil {
  1726  		t.Fatal(err)
  1727  	}
  1728  
  1729  	if fh, err := os.Create(filepath.Join(dir, "var", "log", "anaconda")); err == nil {
  1730  		fh.Close()
  1731  		t.Fatalf("expected error when using os.create for lvmdump/config_diff!")
  1732  	}
  1733  
  1734  	// Try to do it with unpriv.
  1735  	fh, err := Create(filepath.Join(dir, "var", "log", "anaconda"))
  1736  	if err != nil {
  1737  		t.Fatalf("unexpected unpriv.create error: %s", err)
  1738  	}
  1739  	if err := fh.Chmod(0); err != nil {
  1740  		t.Fatalf("unexpected unpriv.create.chmod error: %s", err)
  1741  	}
  1742  	defer fh.Close()
  1743  
  1744  	if n, err := fh.Write(fileContent); err != nil {
  1745  		t.Fatal(err)
  1746  	} else if n != len(fileContent) {
  1747  		t.Fatalf("incomplete write to config_diff")
  1748  	}
  1749  
  1750  	// Make some subdirectories.
  1751  	if err := MkdirAll(filepath.Join(dir, "var", "log", "anaconda2", "childdir"), 0); err != nil {
  1752  		t.Fatal(err)
  1753  	}
  1754  
  1755  	// Check that they all have chmod(0).
  1756  	var fi os.FileInfo
  1757  
  1758  	// Double check it was unchanged.
  1759  	fi, err = Lstat(filepath.Join(dir, "var", "log", "anaconda"))
  1760  	if err != nil {
  1761  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1762  	}
  1763  	if fi.Mode()&os.ModePerm != 0 {
  1764  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1765  	}
  1766  	fi, err = Lstat(filepath.Join(dir, "var", "log", "anaconda2", "childdir"))
  1767  	if err != nil {
  1768  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1769  	}
  1770  	if fi.Mode()&os.ModePerm != 0 {
  1771  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1772  	}
  1773  	fi, err = Lstat(filepath.Join(dir, "var", "log", "anaconda2"))
  1774  	if err != nil {
  1775  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1776  	}
  1777  	if fi.Mode()&os.ModePerm != 0 {
  1778  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1779  	}
  1780  	fi, err = Lstat(filepath.Join(dir, "var", "log"))
  1781  	if err != nil {
  1782  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1783  	}
  1784  	if fi.Mode()&os.ModePerm != 0555 {
  1785  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1786  	}
  1787  	fi, err = Lstat(filepath.Join(dir, "var"))
  1788  	if err != nil {
  1789  		t.Errorf("unexpected unpriv.lstat error: %s", err)
  1790  	}
  1791  	if fi.Mode()&os.ModePerm != 0555 {
  1792  		t.Errorf("unexpected modeperm for path %s: %o", fi.Name(), fi.Mode()&os.ModePerm)
  1793  	}
  1794  }
  1795  
  1796  func TestWalk(t *testing.T) {
  1797  	// There are two important things to make sure of here. That we actually
  1798  	// hit all of the paths (once), and that the fileinfo we get is the one we
  1799  	// expected.
  1800  
  1801  	if os.Geteuid() == 0 {
  1802  		t.Log("unpriv.* tests only work with non-root privileges")
  1803  		t.Skip()
  1804  	}
  1805  
  1806  	dir, err := ioutil.TempDir("", "umoci-unpriv.TestWalk")
  1807  	if err != nil {
  1808  		t.Fatal(err)
  1809  	}
  1810  	defer RemoveAll(dir)
  1811  
  1812  	// Create some structure.
  1813  	if err := os.MkdirAll(filepath.Join(dir, "some", "parent", "directories"), 0755); err != nil {
  1814  		t.Fatal(err)
  1815  	}
  1816  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parent", "directories", "file"), []byte("some content"), 0555); err != nil {
  1817  		t.Fatal(err)
  1818  	}
  1819  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories", "file"), 0); err != nil {
  1820  		t.Fatal(err)
  1821  	}
  1822  	if err := os.Chmod(filepath.Join(dir, "some", "parent", "directories"), 0123); err != nil {
  1823  		t.Fatal(err)
  1824  	}
  1825  	if err := os.Chmod(filepath.Join(dir, "some", "parent"), 0); err != nil {
  1826  		t.Fatal(err)
  1827  	}
  1828  	if err := os.Chmod(filepath.Join(dir, "some"), 0); err != nil {
  1829  		t.Fatal(err)
  1830  	}
  1831  	if err := os.Chmod(dir, 0755); err != nil {
  1832  		t.Fatal(err)
  1833  	}
  1834  
  1835  	// Walk over it.
  1836  	seen := map[string]int{}
  1837  	err = Walk(dir, func(path string, info os.FileInfo, err error) error {
  1838  		// Don't expect errors.
  1839  		if err != nil {
  1840  			t.Errorf("unexpected error in walkfunc(%s): %v", path, err)
  1841  			return err
  1842  		}
  1843  
  1844  		// Run Lstat first, and return an error if it would fail so Wrap "works".
  1845  		newFi, err := os.Lstat(path)
  1846  		if err != nil {
  1847  			return err
  1848  		}
  1849  
  1850  		// Figure out the expected mode.
  1851  		expectedMode := os.FileMode(0xFFFFFFFF)
  1852  		switch path {
  1853  		case dir:
  1854  			expectedMode = 0755 | os.ModeDir
  1855  		case filepath.Join(dir, "some"),
  1856  			filepath.Join(dir, "some", "parent"):
  1857  			expectedMode = os.ModeDir
  1858  		case filepath.Join(dir, "some", "parent", "directories"):
  1859  			expectedMode = 0123 | os.ModeDir
  1860  		case filepath.Join(dir, "some", "parent", "directories", "file"):
  1861  			expectedMode = 0
  1862  		default:
  1863  			t.Errorf("saw unexpected path %s", path)
  1864  			return nil
  1865  		}
  1866  
  1867  		// Check the mode.
  1868  		if info.Mode() != expectedMode {
  1869  			t.Errorf("got unexpected mode on %s: expected %o got %o", path, info.Mode(), expectedMode)
  1870  		}
  1871  		if !reflect.DeepEqual(info, newFi) {
  1872  			t.Errorf("got different info after lstat: before=%#v after=%#v", info, newFi)
  1873  		}
  1874  
  1875  		// Update seen map.
  1876  		seen[path]++
  1877  		return nil
  1878  	})
  1879  	if err != nil {
  1880  		t.Errorf("unexpected walk error: %v", err)
  1881  	}
  1882  
  1883  	// Check the seen map.
  1884  	for path, num := range seen {
  1885  		if num != 1 {
  1886  			t.Errorf("path %s seen an unexpected number of times %d (expected %d)", path, num, 1)
  1887  		}
  1888  	}
  1889  	if len(seen) != 5 {
  1890  		t.Errorf("saw an unexpected number of paths: len(%v) != %v", seen, 5)
  1891  	}
  1892  }