Home | History | Annotate | Download | only in os
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // +build darwin dragonfly freebsd linux netbsd openbsd solaris
      6 
      7 package os_test
      8 
      9 import (
     10 	. "os"
     11 	"runtime"
     12 	"syscall"
     13 	"testing"
     14 )
     15 
     16 func init() {
     17 	isReadonlyError = func(err error) bool { return err == syscall.EROFS }
     18 }
     19 
     20 func checkUidGid(t *testing.T, path string, uid, gid int) {
     21 	dir, err := Stat(path)
     22 	if err != nil {
     23 		t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
     24 	}
     25 	sys := dir.Sys().(*syscall.Stat_t)
     26 	if int(sys.Uid) != uid {
     27 		t.Errorf("Stat %q: uid %d want %d", path, sys.Uid, uid)
     28 	}
     29 	if int(sys.Gid) != gid {
     30 		t.Errorf("Stat %q: gid %d want %d", path, sys.Gid, gid)
     31 	}
     32 }
     33 
     34 func TestChown(t *testing.T) {
     35 	// Chown is not supported under windows or Plan 9.
     36 	// Plan9 provides a native ChownPlan9 version instead.
     37 	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
     38 		t.Skipf("%s does not support syscall.Chown", runtime.GOOS)
     39 	}
     40 	// Use TempDir() to make sure we're on a local file system,
     41 	// so that the group ids returned by Getgroups will be allowed
     42 	// on the file.  On NFS, the Getgroups groups are
     43 	// basically useless.
     44 	f := newFile("TestChown", t)
     45 	defer Remove(f.Name())
     46 	defer f.Close()
     47 	dir, err := f.Stat()
     48 	if err != nil {
     49 		t.Fatalf("stat %s: %s", f.Name(), err)
     50 	}
     51 
     52 	// Can't change uid unless root, but can try
     53 	// changing the group id.  First try our current group.
     54 	gid := Getgid()
     55 	t.Log("gid:", gid)
     56 	if err = Chown(f.Name(), -1, gid); err != nil {
     57 		t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
     58 	}
     59 	sys := dir.Sys().(*syscall.Stat_t)
     60 	checkUidGid(t, f.Name(), int(sys.Uid), gid)
     61 
     62 	// Then try all the auxiliary groups.
     63 	groups, err := Getgroups()
     64 	if err != nil {
     65 		t.Fatalf("getgroups: %s", err)
     66 	}
     67 	t.Log("groups: ", groups)
     68 	for _, g := range groups {
     69 		if err = Chown(f.Name(), -1, g); err != nil {
     70 			t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err)
     71 		}
     72 		checkUidGid(t, f.Name(), int(sys.Uid), g)
     73 
     74 		// change back to gid to test fd.Chown
     75 		if err = f.Chown(-1, gid); err != nil {
     76 			t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
     77 		}
     78 		checkUidGid(t, f.Name(), int(sys.Uid), gid)
     79 	}
     80 }
     81 
     82 func TestFileChown(t *testing.T) {
     83 	// Fchown is not supported under windows or Plan 9.
     84 	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
     85 		t.Skipf("%s does not support syscall.Fchown", runtime.GOOS)
     86 	}
     87 	// Use TempDir() to make sure we're on a local file system,
     88 	// so that the group ids returned by Getgroups will be allowed
     89 	// on the file.  On NFS, the Getgroups groups are
     90 	// basically useless.
     91 	f := newFile("TestFileChown", t)
     92 	defer Remove(f.Name())
     93 	defer f.Close()
     94 	dir, err := f.Stat()
     95 	if err != nil {
     96 		t.Fatalf("stat %s: %s", f.Name(), err)
     97 	}
     98 
     99 	// Can't change uid unless root, but can try
    100 	// changing the group id.  First try our current group.
    101 	gid := Getgid()
    102 	t.Log("gid:", gid)
    103 	if err = f.Chown(-1, gid); err != nil {
    104 		t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
    105 	}
    106 	sys := dir.Sys().(*syscall.Stat_t)
    107 	checkUidGid(t, f.Name(), int(sys.Uid), gid)
    108 
    109 	// Then try all the auxiliary groups.
    110 	groups, err := Getgroups()
    111 	if err != nil {
    112 		t.Fatalf("getgroups: %s", err)
    113 	}
    114 	t.Log("groups: ", groups)
    115 	for _, g := range groups {
    116 		if err = f.Chown(-1, g); err != nil {
    117 			t.Fatalf("fchown %s -1 %d: %s", f.Name(), g, err)
    118 		}
    119 		checkUidGid(t, f.Name(), int(sys.Uid), g)
    120 
    121 		// change back to gid to test fd.Chown
    122 		if err = f.Chown(-1, gid); err != nil {
    123 			t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
    124 		}
    125 		checkUidGid(t, f.Name(), int(sys.Uid), gid)
    126 	}
    127 }
    128 
    129 func TestLchown(t *testing.T) {
    130 	// Lchown is not supported under windows or Plan 9.
    131 	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
    132 		t.Skipf("%s does not support syscall.Lchown", runtime.GOOS)
    133 	}
    134 	// Use TempDir() to make sure we're on a local file system,
    135 	// so that the group ids returned by Getgroups will be allowed
    136 	// on the file.  On NFS, the Getgroups groups are
    137 	// basically useless.
    138 	f := newFile("TestLchown", t)
    139 	defer Remove(f.Name())
    140 	defer f.Close()
    141 	dir, err := f.Stat()
    142 	if err != nil {
    143 		t.Fatalf("stat %s: %s", f.Name(), err)
    144 	}
    145 
    146 	linkname := f.Name() + "2"
    147 	if err := Link(f.Name(), linkname); err != nil {
    148 		t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err)
    149 	}
    150 	defer Remove(linkname)
    151 
    152 	f2, err := Open(linkname)
    153 	if err != nil {
    154 		t.Fatalf("open %s: %v", linkname, err)
    155 	}
    156 	defer f2.Close()
    157 
    158 	// Can't change uid unless root, but can try
    159 	// changing the group id.  First try our current group.
    160 	gid := Getgid()
    161 	t.Log("gid:", gid)
    162 	if err = Lchown(linkname, -1, gid); err != nil {
    163 		t.Fatalf("lchown %s -1 %d: %s", linkname, gid, err)
    164 	}
    165 	sys := dir.Sys().(*syscall.Stat_t)
    166 	checkUidGid(t, linkname, int(sys.Uid), gid)
    167 
    168 	// Then try all the auxiliary groups.
    169 	groups, err := Getgroups()
    170 	if err != nil {
    171 		t.Fatalf("getgroups: %s", err)
    172 	}
    173 	t.Log("groups: ", groups)
    174 	for _, g := range groups {
    175 		if err = Lchown(linkname, -1, g); err != nil {
    176 			t.Fatalf("lchown %s -1 %d: %s", linkname, g, err)
    177 		}
    178 		checkUidGid(t, linkname, int(sys.Uid), g)
    179 
    180 		// change back to gid to test fd.Chown
    181 		if err = f2.Chown(-1, gid); err != nil {
    182 			t.Fatalf("fchown %s -1 %d: %s", linkname, gid, err)
    183 		}
    184 		checkUidGid(t, linkname, int(sys.Uid), gid)
    185 	}
    186 }
    187