patch os: File.Write

This commit is contained in:
xushiwei
2024-06-25 18:07:58 +08:00
parent 207c41581c
commit d64d220b49
5 changed files with 804 additions and 57 deletions

View File

@@ -5,6 +5,8 @@
package os
import (
"errors"
"io"
"syscall"
)
@@ -47,7 +49,6 @@ const (
SEEK_END int = 2 // seek relative to the end
)
/*
// Read reads up to len(b) bytes from the File and stores them in b.
// It returns the number of bytes read and any error encountered.
// At end of file, Read returns 0, io.EOF.
@@ -64,37 +65,43 @@ func (f *File) Read(b []byte) (n int, err error) {
// ReadAt always returns a non-nil error when n < len(b).
// At end of file, that error is io.EOF.
func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
if err := f.checkValid("read"); err != nil {
return 0, err
}
if off < 0 {
return 0, &PathError{Op: "readat", Path: f.name, Err: errors.New("negative offset")}
}
for len(b) > 0 {
m, e := f.pread(b, off)
if e != nil {
err = f.wrapErr("read", e)
break
/*
if err := f.checkValid("read"); err != nil {
return 0, err
}
n += m
b = b[m:]
off += int64(m)
}
return
if off < 0 {
return 0, &PathError{Op: "readat", Path: f.name, Err: errors.New("negative offset")}
}
for len(b) > 0 {
m, e := f.pread(b, off)
if e != nil {
err = f.wrapErr("read", e)
break
}
n += m
b = b[m:]
off += int64(m)
}
return
*/
panic("todo")
}
// ReadFrom implements io.ReaderFrom.
func (f *File) ReadFrom(r io.Reader) (n int64, err error) {
if err := f.checkValid("write"); err != nil {
return 0, err
}
n, handled, e := f.readFrom(r)
if !handled {
return genericReadFrom(f, r) // without wrapping
}
return n, f.wrapErr("write", e)
/*
if err := f.checkValid("write"); err != nil {
return 0, err
}
n, handled, e := f.readFrom(r)
if !handled {
return genericReadFrom(f, r) // without wrapping
}
return n, f.wrapErr("write", e)
*/
panic("todo")
}
func genericReadFrom(f *File, r io.Reader) (int64, error) {
@@ -128,7 +135,8 @@ func (f *File) Write(b []byte) (n int, err error) {
err = io.ErrShortWrite
}
epipecheck(f, e)
// TODO(xsw):
// epipecheck(f, e)
if e != nil {
err = f.wrapErr("write", e)
@@ -145,30 +153,34 @@ var errWriteAtInAppendMode = errors.New("os: invalid use of WriteAt on file open
//
// If file was opened with the O_APPEND flag, WriteAt returns an error.
func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
if err := f.checkValid("write"); err != nil {
return 0, err
}
if f.appendMode {
return 0, errWriteAtInAppendMode
}
if off < 0 {
return 0, &PathError{Op: "writeat", Path: f.name, Err: errors.New("negative offset")}
}
for len(b) > 0 {
m, e := f.pwrite(b, off)
if e != nil {
err = f.wrapErr("write", e)
break
/*
if err := f.checkValid("write"); err != nil {
return 0, err
}
n += m
b = b[m:]
off += int64(m)
}
return
if f.appendMode {
return 0, errWriteAtInAppendMode
}
if off < 0 {
return 0, &PathError{Op: "writeat", Path: f.name, Err: errors.New("negative offset")}
}
for len(b) > 0 {
m, e := f.pwrite(b, off)
if e != nil {
err = f.wrapErr("write", e)
break
}
n += m
b = b[m:]
off += int64(m)
}
return
*/
panic("todo")
}
/*
// Seek sets the offset for the next Read or Write on file to offset, interpreted
// according to whence: 0 means relative to the origin of the file, 1 means
// relative to the current offset, and 2 means relative to the end.
@@ -249,10 +261,12 @@ func fixCount(n int, err error) (int, error) {
}
return n, err
}
*/
// TODO(xsw):
// checkWrapErr is the test hook to enable checking unexpected wrapped errors of poll.ErrFileClosing.
// It is set to true in the export_test.go for tests (including fuzz tests).
var checkWrapErr = false
// var checkWrapErr = false
// wrapErr wraps an error that occurred during an operation on an open file.
// It passes io.EOF through unchanged, otherwise converts
@@ -261,14 +275,17 @@ func (f *File) wrapErr(op string, err error) error {
if err == nil || err == io.EOF {
return err
}
/* TODO(xsw):
if err == poll.ErrFileClosing {
err = ErrClosed
} else if checkWrapErr && errors.Is(err, poll.ErrFileClosing) {
panic("unexpected error wrapping poll.ErrFileClosing: " + err.Error())
}
*/
return &PathError{Op: op, Path: f.name, Err: err}
}
/*
// TempDir returns the default directory to use for temporary files.
//
// On Unix systems, it returns $TMPDIR if non-empty, else /tmp.

View File

@@ -48,11 +48,11 @@ func (e *LinkError) Unwrap() error {
}
func toMode(mode FileMode) os.ModeT {
panic("todo")
panic("todo: toMode")
}
func toSyscallErr(errno c.Int) error {
panic("todo")
panic("todo: toSyscallErr")
}
func toPathErr(op, path string, errno c.Int) error {

View File

@@ -7,6 +7,10 @@ package os
import (
"io/fs"
"syscall"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/os"
)
// Getpagesize returns the underlying system's memory page size.
@@ -14,8 +18,9 @@ func Getpagesize() int { return syscall.Getpagesize() }
// File represents an open file descriptor.
type File struct {
fd uintptr
name string
fd uintptr
name string
appendMode bool
}
// NewFile returns a new File with the given file descriptor and
@@ -28,7 +33,27 @@ type File struct {
// conditions described in the comments of the Fd method, and the same
// constraints apply.
func NewFile(fd uintptr, name string) *File {
return &File{fd, name}
return &File{fd: fd, name: name}
}
// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
func (f *File) write(b []byte) (n int, err error) {
n = int(os.Write(c.Int(f.fd), unsafe.Pointer(unsafe.SliceData(b)), uintptr(len(b))))
if e := os.Errno; e != 0 {
err = toSyscallErr(e)
}
return
}
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
func (f *File) read(b []byte) (n int, err error) {
n = int(os.Read(c.Int(f.fd), unsafe.Pointer(unsafe.SliceData(b)), uintptr(len(b))))
if e := os.Errno; e != 0 {
err = toSyscallErr(e)
}
return
}
// checkValid checks whether f is valid for use.