aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorleongross <[email protected]>2024-08-02 08:22:46 -0700
committerGitHub <[email protected]>2024-08-02 17:22:46 +0200
commita8a532f9d6201d76f7177e30b9abd367c37c1000 (patch)
tree010eb69b94357a0e752ce9bc5aadd732803f8bbc
parent417a26d20c23ea0aaa8f95325bb30172b3e3e9e9 (diff)
downloadtinygo-a8a532f9d6201d76f7177e30b9abd367c37c1000.tar.gz
tinygo-a8a532f9d6201d76f7177e30b9abd367c37c1000.zip
os: add file.Truncate
-rw-r--r--src/os/file.go10
-rw-r--r--src/os/file_unix.go19
-rw-r--r--src/os/file_windows.go14
-rw-r--r--src/os/truncate_test.go61
-rw-r--r--src/syscall/libc_wasip2.go10
-rw-r--r--src/syscall/syscall_libc.go14
6 files changed, 116 insertions, 12 deletions
diff --git a/src/os/file.go b/src/os/file.go
index acf33f850..7c3c0db12 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -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 {
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index badfc71ff..ef7abcbac 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -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.
diff --git a/src/os/file_windows.go b/src/os/file_windows.go
index 70f3a3dd0..5860c76b0 100644
--- a/src/os/file_windows.go
+++ b/src/os/file_windows.go
@@ -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 {
@@ -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 {
diff --git a/src/os/truncate_test.go b/src/os/truncate_test.go
new file mode 100644
index 000000000..2b1d982ba
--- /dev/null
+++ b/src/os/truncate_test.go
@@ -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())
+ }
+}
diff --git a/src/syscall/libc_wasip2.go b/src/syscall/libc_wasip2.go
index 1e985c1da..3aadf877f 100644
--- a/src/syscall/libc_wasip2.go
+++ b/src/syscall/libc_wasip2.go
@@ -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 {
@@ -773,7 +772,6 @@ var libcCWD wasiDir
var wasiPreopens map[string]types.Descriptor
func populatePreopens() {
-
var cwd string
// find CWD
@@ -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
+}
diff --git a/src/syscall/syscall_libc.go b/src/syscall/syscall_libc.go
index 0dec4c74d..2321292d9 100644
--- a/src/syscall/syscall_libc.go
+++ b/src/syscall/syscall_libc.go
@@ -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) {
@@ -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