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 | ||||||
|  |  | ||||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 Dan Kegel
						Dan Kegel