os: implement and smoketest os.Chmod
Этот коммит содержится в:
родитель
e668c8c1a7
коммит
be7bbba4ca
4 изменённых файлов: 106 добавлений и 16 удалений
|
@ -1,5 +1,9 @@
|
|||
// +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
|
||||
|
||||
import (
|
||||
|
@ -133,6 +137,48 @@ func (f unixFileHandle) Close() error {
|
|||
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.
|
||||
// The err parameter must be either nil or of type syscall.Errno.
|
||||
func handleSyscallError(err error) error {
|
||||
|
@ -148,3 +194,19 @@ func handleSyscallError(err error) error {
|
|||
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
|
||||
|
||||
// fixLongPath is a noop on non-Windows platforms.
|
||||
func fixLongPath(path string) string {
|
||||
return path
|
||||
}
|
||||
|
||||
func Pipe() (r *File, w *File, err error) {
|
||||
var p [2]int
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Log("TODO: implement Pread for Windows")
|
||||
|
|
|
@ -68,6 +68,15 @@ func Chdir(path string) (err error) {
|
|||
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) {
|
||||
data := cstring(path)
|
||||
fail := int(libc_mkdir(&data[0], mode))
|
||||
|
@ -211,6 +220,10 @@ func libc_mprotect(addr unsafe.Pointer, len uintptr, prot int32) int32
|
|||
//export chdir
|
||||
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);
|
||||
//export mkdir
|
||||
func libc_mkdir(pathname *byte, mode uint32) int32
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче