library os: openFileNolog

This commit is contained in:
xushiwei
2024-07-19 23:19:59 +08:00
parent ea6b397526
commit 6f82b36962
15 changed files with 283 additions and 18 deletions

View File

@@ -532,7 +532,7 @@ func ignoreName(name string) bool {
func supportedInternal(name string) bool { func supportedInternal(name string) bool {
return strings.HasPrefix(name, "abi.") || strings.HasPrefix(name, "bytealg.") || return strings.HasPrefix(name, "abi.") || strings.HasPrefix(name, "bytealg.") ||
strings.HasPrefix(name, "oserror.") || strings.HasPrefix(name, "reflectlite.") || strings.HasPrefix(name, "oserror.") || strings.HasPrefix(name, "reflectlite.") ||
strings.HasPrefix(name, "syscall/execenv.") strings.HasPrefix(name, "syscall/unix.") || strings.HasPrefix(name, "syscall/execenv.")
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -753,6 +753,7 @@ var hasAltPkg = map[string]none{
"internal/oserror": {}, "internal/oserror": {},
"internal/reflectlite": {}, "internal/reflectlite": {},
"internal/syscall/execenv": {}, "internal/syscall/execenv": {},
"internal/syscall/unix": {},
"math": {}, "math": {},
"math/cmplx": {}, "math/cmplx": {},
"reflect": {}, "reflect": {},

View File

@@ -0,0 +1,15 @@
// Copyright 2018 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.
//go:build js && wasm
package unix
func IsNonblock(fd int) (nonblocking bool, err error) {
return false, nil
}
func HasNonblockFlag(flag int) bool {
return false
}

View File

@@ -0,0 +1,23 @@
// Copyright 2018 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.
//go:build unix
package unix
import "github.com/goplus/llgo/c/syscall"
/* TODO(xsw):
func IsNonblock(fd int) (nonblocking bool, err error) {
flag, e1 := Fcntl(fd, syscall.F_GETFL, 0)
if e1 != nil {
return false, e1
}
return flag&syscall.O_NONBLOCK != 0, nil
}
*/
func HasNonblockFlag(flag int) bool {
return flag&syscall.O_NONBLOCK != 0
}

View File

@@ -0,0 +1,37 @@
// Copyright 2023 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.
//go:build wasip1
package unix
import "github.com/goplus/llgo/c/syscall"
/* TODO(xsw):
import (
"syscall"
_ "unsafe" // for go:linkname
)
func IsNonblock(fd int) (nonblocking bool, err error) {
flags, e1 := fd_fdstat_get_flags(fd)
if e1 != nil {
return false, e1
}
return flags&syscall.FDFLAG_NONBLOCK != 0, nil
}
*/
func HasNonblockFlag(flag int) bool {
return flag&syscall.FDFLAG_NONBLOCK != 0
}
/* TODO(xsw):
// This helper is implemented in the syscall package. It means we don't have
// to redefine the fd_fdstat_get host import or the fdstat struct it
// populates.
//
//-go:linkname fd_fdstat_get_flags syscall.fd_fdstat_get_flags
func fd_fdstat_get_flags(fd int) (uint32, error)
*/

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package unix
// llgo:skipall
import (
_ "unsafe"
)

View File

@@ -208,7 +208,6 @@ func (f *File) WriteString(s string) (n int, err error) {
panic("todo: os.(*File).WriteString") panic("todo: os.(*File).WriteString")
} }
/*
// setStickyBit adds ModeSticky to the permission bits of path, non atomic. // setStickyBit adds ModeSticky to the permission bits of path, non atomic.
func setStickyBit(name string) error { func setStickyBit(name string) error {
fi, err := Stat(name) fi, err := Stat(name)
@@ -217,7 +216,6 @@ func setStickyBit(name string) error {
} }
return Chmod(name, fi.Mode()|ModeSticky) return Chmod(name, fi.Mode()|ModeSticky)
} }
*/
// Open opens the named file for reading. If successful, methods on // Open opens the named file for reading. If successful, methods on
// the returned file can be used for reading; the associated file // the returned file can be used for reading; the associated file

View File

@@ -48,7 +48,6 @@ func (f *File) pwrite(b []byte, off int64) (n int, err error) {
panic("todo: os.(*File).pwrite") panic("todo: os.(*File).pwrite")
} }
/*
// syscallMode returns the syscall-specific mode bits from Go's portable mode bits. // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
func syscallMode(i FileMode) (o uint32) { func syscallMode(i FileMode) (o uint32) {
o |= uint32(i.Perm()) o |= uint32(i.Perm())
@@ -65,6 +64,7 @@ func syscallMode(i FileMode) (o uint32) {
return return
} }
/* TODO(xsw):
// See docs in file.go:Chmod. // See docs in file.go:Chmod.
func chmod(name string, mode FileMode) error { func chmod(name string, mode FileMode) error {
longName := fixLongPath(name) longName := fixLongPath(name)

View File

@@ -8,6 +8,9 @@ package os
import ( import (
"runtime" "runtime"
"syscall"
"github.com/goplus/llgo/internal/lib/internal/syscall/unix"
) )
// Fd returns the integer Unix file descriptor referencing the open file. // Fd returns the integer Unix file descriptor referencing the open file.
@@ -30,15 +33,6 @@ func (f *File) Fd() uintptr {
return f.fd return f.fd
} }
// NewFile returns a new File with the given file descriptor and
// name. The returned value will be nil if fd is not a valid file
// descriptor. On Unix systems, if the file descriptor is in
// non-blocking mode, NewFile will attempt to return a pollable File
// (one for which the SetDeadline methods work).
//
// After passing it to NewFile, fd may become invalid under the same
// conditions described in the comments of the Fd method, and the same
// constraints apply.
func NewFile(fd uintptr, name string) *File { func NewFile(fd uintptr, name string) *File {
return &File{fd: fd, name: name} return &File{fd: fd, name: name}
} }
@@ -113,6 +107,83 @@ const (
kindNoPoll kindNoPoll
) )
// newFile is like NewFile, but if called from OpenFile or Pipe
// (as passed in the kind parameter) it tries to add the file to
// the runtime poller.
func newFile(fd int, name string, kind newFileKind) *File {
f := &File{
fd: uintptr(fd),
name: name,
stdoutOrErr: fd == 1 || fd == 2,
}
/* TODO(xsw):
pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock
// If the caller passed a non-blocking filedes (kindNonBlock),
// we assume they know what they are doing so we allow it to be
// used with kqueue.
if kind == kindOpenFile {
switch runtime.GOOS {
case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd":
var st syscall.Stat_t
err := ignoringEINTR(func() error {
return syscall.Fstat(fd, &st)
})
typ := st.Mode & syscall.S_IFMT
// Don't try to use kqueue with regular files on *BSDs.
// On FreeBSD a regular file is always
// reported as ready for writing.
// On Dragonfly, NetBSD and OpenBSD the fd is signaled
// only once as ready (both read and write).
// Issue 19093.
// Also don't add directories to the netpoller.
if err == nil && (typ == syscall.S_IFREG || typ == syscall.S_IFDIR) {
pollable = false
}
// In addition to the behavior described above for regular files,
// on Darwin, kqueue does not work properly with fifos:
// closing the last writer does not cause a kqueue event
// for any readers. See issue #24164.
if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && typ == syscall.S_IFIFO {
pollable = false
}
}
}
clearNonBlock := false
if pollable {
if kind == kindNonBlock {
// The descriptor is already in non-blocking mode.
// We only set f.nonblock if we put the file into
// non-blocking mode.
} else if err := syscall.SetNonblock(fd, true); err == nil {
f.nonblock = true
clearNonBlock = true
} else {
pollable = false
}
}
// An error here indicates a failure to register
// with the netpoll system. That can happen for
// a file descriptor that is not supported by
// epoll/kqueue; for example, disk files on
// Linux systems. We assume that any real error
// will show up in later I/O.
// We do restore the blocking behavior if it was set by us.
if pollErr := f.pfd.Init("file", pollable); pollErr != nil && clearNonBlock {
if err := syscall.SetNonblock(fd, false); err == nil {
f.nonblock = false
}
}
runtime.SetFinalizer(f.file, (*file).close)
*/
return f
}
// TODO(xsw): // TODO(xsw):
// func sigpipe() // implemented in package runtime // func sigpipe() // implemented in package runtime
@@ -135,7 +206,48 @@ const DevNull = "/dev/null"
// openFileNolog is the Unix implementation of OpenFile. // openFileNolog is the Unix implementation of OpenFile.
// Changes here should be reflected in openFdAt, if relevant. // Changes here should be reflected in openFdAt, if relevant.
func openFileNolog(name string, flag int, perm FileMode) (*File, error) { func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
panic("todo: os.openFileNolog") setSticky := false
if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 {
if _, err := Stat(name); IsNotExist(err) {
setSticky = true
}
}
var r int
for {
var e error
r, e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
if e == nil {
break
}
// We have to check EINTR here, per issues 11180 and 39237.
if e == syscall.EINTR {
continue
}
return nil, &PathError{Op: "open", Path: name, Err: e}
}
// open(2) itself won't handle the sticky bit on *BSD and Solaris
if setSticky {
setStickyBit(name)
}
// There's a race here with fork/exec, which we are
// content to live with. See ../syscall/exec_unix.go.
if !supportsCloseOnExec {
syscall.CloseOnExec(r)
}
kind := kindOpenFile
if unix.HasNonblockFlag(flag) {
kind = kindNonBlock
panic("todo: os.openFileNolog: unix.HasNonblockFlag")
}
f := newFile(r, name, kind)
return f, nil
} }
func tempDir() string { func tempDir() string {

View File

@@ -0,0 +1,11 @@
// Copyright 2014 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.
//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || netbsd || openbsd || solaris || wasip1
package os
// According to sticky(8), neither open(2) nor mkdir(2) will create
// a file with the sticky bit set.
const supportsCreateWithStickyBit = false

View File

@@ -0,0 +1,9 @@
// Copyright 2014 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.
//go:build !aix && !darwin && !dragonfly && !freebsd && !js && !netbsd && !openbsd && !solaris && !wasip1
package os
const supportsCreateWithStickyBit = true

11
internal/lib/os/sys_js.go Normal file
View File

@@ -0,0 +1,11 @@
// Copyright 2018 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.
//go:build js && wasm
package os
// supportsCloseOnExec reports whether the platform supports the
// O_CLOEXEC flag.
const supportsCloseOnExec = false

View File

@@ -0,0 +1,14 @@
// Copyright 2014 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.
//go:build unix
package os
// supportsCloseOnExec reports whether the platform supports the
// O_CLOEXEC flag.
// On Darwin, the O_CLOEXEC flag was introduced in OS X 10.7 (Darwin 11.0.0).
// See https://support.apple.com/kb/HT1633.
// On FreeBSD, the O_CLOEXEC flag was introduced in version 8.3.
const supportsCloseOnExec = true

View File

@@ -0,0 +1,11 @@
// Copyright 2023 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.
//go:build wasip1
package os
// supportsCloseOnExec reports whether the platform supports the
// O_CLOEXEC flag.
const supportsCloseOnExec = false

View File

@@ -19,10 +19,11 @@ func Getpagesize() int { return syscall.Getpagesize() }
// File represents an open file descriptor. // File represents an open file descriptor.
type File struct { type File struct {
fd uintptr fd uintptr
name string name string
appendMode bool appendMode bool
nonblock bool nonblock bool
stdoutOrErr bool
} }
// write writes len(b) bytes to the File. // write writes len(b) bytes to the File.