os: implement and smoketest os.Chmod
Этот коммит содержится в:
родитель
e668c8c1a7
коммит
be7bbba4ca
4 изменённых файлов: 106 добавлений и 16 удалений
|
@ -1,5 +1,9 @@
|
||||||
// +build !baremetal,!js
|
// +build !baremetal,!js
|
||||||
|
|
||||||
|
// Portions copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -133,6 +137,48 @@ func (f unixFileHandle) Close() error {
|
||||||
return handleSyscallError(syscall.Close(syscallFd(f)))
|
return handleSyscallError(syscall.Close(syscallFd(f)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Chmod changes the mode of the named file to mode.
|
||||||
|
// If the file is a symbolic link, it changes the mode of the link's target.
|
||||||
|
// If there is an error, it will be of type *PathError.
|
||||||
|
//
|
||||||
|
// A different subset of the mode bits are used, depending on the
|
||||||
|
// operating system.
|
||||||
|
//
|
||||||
|
// On Unix, the mode's permission bits, ModeSetuid, ModeSetgid, and
|
||||||
|
// ModeSticky are used.
|
||||||
|
//
|
||||||
|
// On Windows, only the 0200 bit (owner writable) of mode is used; it
|
||||||
|
// controls whether the file's read-only attribute is set or cleared.
|
||||||
|
// The other bits are currently unused. For compatibility with Go 1.12
|
||||||
|
// and earlier, use a non-zero mode. Use mode 0400 for a read-only
|
||||||
|
// file and 0600 for a readable+writable file.
|
||||||
|
func Chmod(name string, mode FileMode) error {
|
||||||
|
longName := fixLongPath(name)
|
||||||
|
e := ignoringEINTR(func() error {
|
||||||
|
return syscall.Chmod(longName, syscallMode(mode))
|
||||||
|
})
|
||||||
|
if e != nil {
|
||||||
|
return &PathError{Op: "chmod", Path: name, Err: e}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignoringEINTR makes a function call and repeats it if it returns an
|
||||||
|
// EINTR error. This appears to be required even though we install all
|
||||||
|
// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
|
||||||
|
// Also #20400 and #36644 are issues in which a signal handler is
|
||||||
|
// installed without setting SA_RESTART. None of these are the common case,
|
||||||
|
// but there are enough of them that it seems that we can't avoid
|
||||||
|
// an EINTR loop.
|
||||||
|
func ignoringEINTR(fn func() error) error {
|
||||||
|
for {
|
||||||
|
err := fn()
|
||||||
|
if err != syscall.EINTR {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// handleSyscallError converts syscall errors into regular os package errors.
|
// handleSyscallError converts syscall errors into regular os package errors.
|
||||||
// The err parameter must be either nil or of type syscall.Errno.
|
// The err parameter must be either nil or of type syscall.Errno.
|
||||||
func handleSyscallError(err error) error {
|
func handleSyscallError(err error) error {
|
||||||
|
@ -148,3 +194,19 @@ func handleSyscallError(err error) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
|
||||||
|
func syscallMode(i FileMode) (o uint32) {
|
||||||
|
o |= uint32(i.Perm())
|
||||||
|
if i&ModeSetuid != 0 {
|
||||||
|
o |= syscall.S_ISUID
|
||||||
|
}
|
||||||
|
if i&ModeSetgid != 0 {
|
||||||
|
o |= syscall.S_ISGID
|
||||||
|
}
|
||||||
|
if i&ModeSticky != 0 {
|
||||||
|
o |= syscall.S_ISVTX
|
||||||
|
}
|
||||||
|
// No mapping for Go's ModeTemporary (plan9 only).
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,11 @@ import (
|
||||||
|
|
||||||
type syscallFd = int
|
type syscallFd = int
|
||||||
|
|
||||||
|
// fixLongPath is a noop on non-Windows platforms.
|
||||||
|
func fixLongPath(path string) string {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
func Pipe() (r *File, w *File, err error) {
|
func Pipe() (r *File, w *File, err error) {
|
||||||
var p [2]int
|
var p [2]int
|
||||||
err = handleSyscallError(syscall.Pipe2(p[:], syscall.O_CLOEXEC))
|
err = handleSyscallError(syscall.Pipe2(p[:], syscall.O_CLOEXEC))
|
||||||
|
@ -50,19 +55,3 @@ func (f unixFileHandle) ReadAt(b []byte, offset int64) (n int, err error) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignoringEINTR makes a function call and repeats it if it returns an
|
|
||||||
// EINTR error. This appears to be required even though we install all
|
|
||||||
// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
|
|
||||||
// Also #20400 and #36644 are issues in which a signal handler is
|
|
||||||
// installed without setting SA_RESTART. None of these are the common case,
|
|
||||||
// but there are enough of them that it seems that we can't avoid
|
|
||||||
// an EINTR loop.
|
|
||||||
func ignoringEINTR(fn func() error) error {
|
|
||||||
for {
|
|
||||||
err := fn()
|
|
||||||
if err != syscall.EINTR {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,6 +25,32 @@ func newFile(testName string, t *testing.T) (f *File) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkMode(t *testing.T, path string, mode FileMode) {
|
||||||
|
dir, err := Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
|
||||||
|
}
|
||||||
|
if dir.Mode()&ModePerm != mode {
|
||||||
|
t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChmod(t *testing.T) {
|
||||||
|
f := newFile("TestChmod", t)
|
||||||
|
defer Remove(f.Name())
|
||||||
|
defer f.Close()
|
||||||
|
// Creation mode is read write
|
||||||
|
|
||||||
|
fm := FileMode(0456)
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
fm = FileMode(0444) // read-only file
|
||||||
|
}
|
||||||
|
if err := Chmod(f.Name(), fm); err != nil {
|
||||||
|
t.Fatalf("chmod %s %#o: %s", f.Name(), fm, err)
|
||||||
|
}
|
||||||
|
checkMode(t, f.Name(), fm)
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadAt(t *testing.T) {
|
func TestReadAt(t *testing.T) {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
t.Log("TODO: implement Pread for Windows")
|
t.Log("TODO: implement Pread for Windows")
|
||||||
|
|
|
@ -68,6 +68,15 @@ func Chdir(path string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Chmod(path string, mode uint32) (err error) {
|
||||||
|
data := cstring(path)
|
||||||
|
fail := int(libc_chmod(&data[0], mode))
|
||||||
|
if fail < 0 {
|
||||||
|
err = getErrno()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func Mkdir(path string, mode uint32) (err error) {
|
func Mkdir(path string, mode uint32) (err error) {
|
||||||
data := cstring(path)
|
data := cstring(path)
|
||||||
fail := int(libc_mkdir(&data[0], mode))
|
fail := int(libc_mkdir(&data[0], mode))
|
||||||
|
@ -211,6 +220,10 @@ func libc_mprotect(addr unsafe.Pointer, len uintptr, prot int32) int32
|
||||||
//export chdir
|
//export chdir
|
||||||
func libc_chdir(pathname *byte) int32
|
func libc_chdir(pathname *byte) int32
|
||||||
|
|
||||||
|
// int chmod(const char *pathname, mode_t mode);
|
||||||
|
//export chmod
|
||||||
|
func libc_chmod(pathname *byte, mode uint32) int32
|
||||||
|
|
||||||
// int mkdir(const char *pathname, mode_t mode);
|
// int mkdir(const char *pathname, mode_t mode);
|
||||||
//export mkdir
|
//export mkdir
|
||||||
func libc_mkdir(pathname *byte, mode uint32) int32
|
func libc_mkdir(pathname *byte, mode uint32) int32
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче