Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions _demo/go/osfile/demo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package main

import (
"os"
)

func main() {
// Test file operations
testFile := "test_file.txt"

// Clean up at the end
defer os.Remove(testFile)

// Test Write and WriteString
f, err := os.Create(testFile)
if err != nil {
panic("Create failed: " + err.Error())
}

// Test Write
data := []byte("Hello, World!\n")
n, err := f.Write(data)
if err != nil || n != len(data) {
panic("Write failed")
}

// Test WriteString
n, err = f.WriteString("Test WriteString\n")
if err != nil || n != 17 {
panic("WriteString failed")
}

f.Close()

// Test ReadAt
f, err = os.Open(testFile)
if err != nil {
panic("Open failed: " + err.Error())
}

buf := make([]byte, 5)
n, err = f.ReadAt(buf, 0)
if err != nil || n != 5 || string(buf) != "Hello" {
panic("ReadAt failed: expected 'Hello'")
}

n, err = f.ReadAt(buf, 7)
if err != nil || n != 5 || string(buf) != "World" {
panic("ReadAt failed: expected 'World'")
}

f.Close()

// Test WriteAt with offset 0
f, err = os.OpenFile(testFile, os.O_RDWR, 0644)
if err != nil {
panic("OpenFile failed: " + err.Error())
}

n, err = f.WriteAt([]byte("XXXXX"), 0)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xgopilot WriteAt add test offset != 0

Copy link
Copy Markdown
Contributor Author

@xgopilot xgopilot Bot Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WriteAt test with offset != 0 added

Added a comprehensive test for WriteAt with non-zero offset (offset 7) to complement the existing test at offset 0.

Changes made:

  • Added WriteAt test at offset 7 that writes "YYYYY"
  • Added verification for the non-zero offset write
  • Updated test messages for clarity (distinguishing offset 0 vs offset 7 tests)

The test now verifies that:

  1. WriteAt works correctly at offset 0 (writes "XXXXX")
  2. WriteAt works correctly at offset 7 (writes "YYYYY")
  3. Both writes are verified by reading back the data at the respective offsets

Changes have been committed and pushed to the PR branch.

if err != nil || n != 5 {
panic("WriteAt at offset 0 failed")
}

// Test WriteAt with non-zero offset
n, err = f.WriteAt([]byte("YYYYY"), 7)
if err != nil || n != 5 {
panic("WriteAt at offset 7 failed")
}

f.Close()

// Verify WriteAt results
f, err = os.Open(testFile)
if err != nil {
panic("Open failed: " + err.Error())
}

buf = make([]byte, 5)
n, err = f.ReadAt(buf, 0)
if err != nil || n != 5 || string(buf) != "XXXXX" {
panic("WriteAt verification at offset 0 failed: expected 'XXXXX'")
}

buf = make([]byte, 5)
n, err = f.ReadAt(buf, 7)
if err != nil || n != 5 || string(buf) != "YYYYY" {
panic("WriteAt verification at offset 7 failed: expected 'YYYYY'")
}

f.Close()

// Test Seek
f, err = os.Open(testFile)
if err != nil {
panic("Open failed: " + err.Error())
}

// Seek to position 7
pos, err := f.Seek(7, 0) // SEEK_SET = 0
if err != nil || pos != 7 {
panic("Seek failed")
}

buf = make([]byte, 5)
n, err = f.Read(buf)
if err != nil || n != 5 || string(buf) != "YYYYY" {
panic("Seek test failed: expected 'YYYYY'")
}

// Seek from current position
pos, err = f.Seek(2, 1) // SEEK_CUR = 1
if err != nil || pos != 14 {
panic("Seek from current failed")
}

// Seek from end
pos, err = f.Seek(-5, 2) // SEEK_END = 2
if err != nil {
panic("Seek from end failed")
}

f.Close()

println("All os.File tests passed!")
}
6 changes: 6 additions & 0 deletions runtime/internal/clite/os/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ func Read(fd c.Int, buf c.Pointer, count uintptr) int
//go:linkname Write C.write
func Write(fd c.Int, buf c.Pointer, count uintptr) int

//go:linkname Pread C.pread
func Pread(fd c.Int, buf c.Pointer, count uintptr, offset OffT) int

//go:linkname Pwrite C.pwrite
func Pwrite(fd c.Int, buf c.Pointer, count uintptr, offset OffT) int

//go:linkname Lseek C.lseek
func Lseek(fd c.Int, offset OffT, whence c.Int) OffT

Expand Down
125 changes: 54 additions & 71 deletions runtime/internal/lib/os/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"io"
"syscall"
"time"
"unsafe"
)

// Name returns the name of the file as presented to Open.
Expand Down Expand Up @@ -66,43 +67,37 @@ 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 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")}
}
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)
for len(b) > 0 {
m, e := f.pread(b, off)
if e != nil {
err = f.wrapErr("read", e)
break
}
return
*/
panic("todo: os.File.ReadAt")
n += m
b = b[m:]
off += int64(m)
}
return
}

// 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)
*/
panic("todo: os.File.ReadFrom")
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)
}

func genericReadFrom(f *File, r io.Reader) (int64, error) {
Expand Down Expand Up @@ -149,31 +144,28 @@ 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 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")}
}
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)
for len(b) > 0 {
m, e := f.pwrite(b, off)
if e != nil {
err = f.wrapErr("write", e)
break
}
return
*/
panic("todo: os.(*File).WriteAt")
n += m
b = b[m:]
off += int64(m)
}
return
}

// Seek sets the offset for the next Read or Write on file to offset, interpreted
Expand All @@ -182,30 +174,21 @@ func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
// It returns the new offset and an error, if any.
// The behavior of Seek on a file opened with O_APPEND is not specified.
func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
/*
if err := f.checkValid("seek"); err != nil {
return 0, err
}
r, e := f.seek(offset, whence)
if e == nil && f.dirinfo != nil && r != 0 {
e = syscall.EISDIR
}
if e != nil {
return 0, f.wrapErr("seek", e)
}
return r, nil
*/
panic("todo: os.(*File).Seek")
if err := f.checkValid("seek"); err != nil {
return 0, err
}
r, e := f.seek(offset, whence)
if e != nil {
return 0, f.wrapErr("seek", e)
}
return r, nil
}

// WriteString is like Write, but writes the contents of string s rather than
// a slice of bytes.
func (f *File) WriteString(s string) (n int, err error) {
/*
b := unsafe.Slice(unsafe.StringData(s), len(s))
return f.Write(b)
*/
panic("todo: os.(*File).WriteString")
b := unsafe.Slice(unsafe.StringData(s), len(s))
return f.Write(b)
}

// Open opens the named file for reading. If successful, methods on
Expand Down
Loading
Loading