Skip to content

Commit

Permalink
os: add file.Truncate
Browse files Browse the repository at this point in the history
  • Loading branch information
leongross authored Aug 2, 2024
1 parent 417a26d commit a8a532f
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 12 deletions.
10 changes: 0 additions & 10 deletions src/os/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,16 +290,6 @@ func (f *File) Sync() (err error) {
return
}

// Truncate is a stub, not yet implemented
func (f *File) Truncate(size int64) (err error) {
if f.handle == nil {
err = ErrClosed
} else {
err = ErrNotImplemented
}
return &PathError{Op: "truncate", Path: f.name, Err: err}
}

// LinkError records an error during a link or symlink or rename system call and
// the paths that caused it.
type LinkError struct {
Expand Down
19 changes: 19 additions & 0 deletions src/os/file_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,25 @@ func Readlink(name string) (string, error) {
}
}

// Truncate changes the size of the file.
// It does not change the I/O offset.
// If there is an error, it will be of type *PathError.
// Alternatively just use 'raw' syscall by file name
func (f *File) Truncate(size int64) (err error) {
if f.handle == nil {
return ErrClosed
}

e := ignoringEINTR(func() error {
return syscall.Truncate(f.name, size)
})

if e != nil {
return &PathError{Op: "truncate", Path: f.name, Err: e}
}
return
}

// ReadAt reads up to len(b) bytes from the File starting at the given absolute offset.
// It returns the number of bytes read and any error encountered, possibly io.EOF.
// At end of file, Pread returns 0, io.EOF.
Expand Down
14 changes: 14 additions & 0 deletions src/os/file_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ func Pipe() (r *File, w *File, err error) {
return
}

func (f *unixFileHandle) Truncate(size int64) error {
return ErrNotImplemented
}

func tempDir() string {
n := uint32(syscall.MAX_PATH)
for {
Expand Down Expand Up @@ -106,6 +110,16 @@ func (f unixFileHandle) Sync() error {
return ErrNotImplemented
}

func (f *File) Truncate(size int64) error {
var err error
if f.handle == nil {
err = ErrClosed
} else {
err = ErrNotImplemented
}
return &PathError{Op: "truncate", Path: f.name, Err: err}
}

// isWindowsNulName reports whether name is os.DevNull ('NUL') on Windows.
// True is returned if name is 'NUL' whatever the case.
func isWindowsNulName(name string) bool {
Expand Down
61 changes: 61 additions & 0 deletions src/os/truncate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//go:build darwin || (linux && !baremetal && !js && !wasi)

// Copyright 2024 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_test

import (
. "os"
"path/filepath"
"runtime"
"testing"
)

func TestTruncate(t *testing.T) {
// Truncate is not supported on Windows or wasi at the moment
if runtime.GOOS == "windows" || runtime.GOOS == "wasip1" || runtime.GOOS == "wasip2" {
t.Logf("skipping test on %s", runtime.GOOS)
return
}

tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "truncate_test")

fd, err := Create(file)
if err != nil {
t.Fatalf("create %q: got %v, want nil", file, err)
}
defer fd.Close()

// truncate up to 0x100
if err := fd.Truncate(0x100); err != nil {
t.Fatalf("truncate %q: got %v, want nil", file, err)
}

// check if size is 0x100
fi, err := Stat(file)
if err != nil {
t.Fatalf("stat %q: got %v, want nil", file, err)
}

if fi.Size() != 0x100 {
t.Fatalf("size of %q is %d; want 0x100", file, fi.Size())
}

// truncate down to 0x80
if err := fd.Truncate(0x80); err != nil {
t.Fatalf("truncate %q: got %v, want nil", file, err)
}

// check if size is 0x80
fi, err = Stat(file)
if err != nil {
t.Fatalf("stat %q: got %v, want nil", file, err)
}

if fi.Size() != 0x80 {
t.Fatalf("size of %q is %d; want 0x80", file, fi.Size())
}
}
10 changes: 8 additions & 2 deletions src/syscall/libc_wasip2.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,6 @@ func chmod(pathname *byte, mode uint32) int32 {
//
//export mkdir
func mkdir(pathname *byte, mode uint32) int32 {

path := goString(pathname)
dir, relPath := findPreopenForPath(path)
if dir.d == cm.ResourceNone {
Expand Down Expand Up @@ -773,7 +772,6 @@ var libcCWD wasiDir
var wasiPreopens map[string]types.Descriptor

func populatePreopens() {

var cwd string

// find CWD
Expand Down Expand Up @@ -1354,3 +1352,11 @@ func getcwd(buf *byte, size uint) *byte {
copy(s, cwd)
return buf
}

// int truncate(const char *path, off_t length);
//
//export truncate
func truncate(path *byte, length int64) int32 {
libcErrno = ENOSYS
return -1
}
14 changes: 14 additions & 0 deletions src/syscall/syscall_libc.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,15 @@ func Execve(pathname string, argv []string, envv []string) (err error) {
return
}

func Truncate(path string, length int64) (err error) {
data := cstring(path)
fail := int(libc_truncate(&data[0], length))
if fail < 0 {
err = getErrno()
}
return
}

func Faccessat(dirfd int, path string, mode uint32, flags int) (err error)

func Kill(pid int, sig Signal) (err error) {
Expand Down Expand Up @@ -451,3 +460,8 @@ func libc_fork() int32
//
//export execve
func libc_execve(filename *byte, argv **byte, envp **byte) int

// int truncate(const char *path, off_t length);
//
//export truncate
func libc_truncate(path *byte, length int64) int32

0 comments on commit a8a532f

Please sign in to comment.