Skip to content

Commit b345be7

Browse files
committed
add file.Truncate
Signed-off-by: leongross <[email protected]>
1 parent a5ceb79 commit b345be7

File tree

4 files changed

+92
-10
lines changed

4 files changed

+92
-10
lines changed

src/os/file.go

-10
Original file line numberDiff line numberDiff line change
@@ -283,16 +283,6 @@ func (f *File) Sync() (err error) {
283283
return
284284
}
285285

286-
// Truncate is a stub, not yet implemented
287-
func (f *File) Truncate(size int64) (err error) {
288-
if f.handle == nil {
289-
err = ErrClosed
290-
} else {
291-
err = ErrNotImplemented
292-
}
293-
return &PathError{Op: "truncate", Path: f.name, Err: err}
294-
}
295-
296286
// LinkError records an error during a link or symlink or rename system call and
297287
// the paths that caused it.
298288
type LinkError struct {

src/os/file_unix.go

+20
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,26 @@ func Readlink(name string) (string, error) {
112112
}
113113
}
114114

115+
// Truncate changes the size of the file.
116+
// It does not change the I/O offset.
117+
// If there is an error, it will be of type *PathError.
118+
119+
// Alternatively just use 'raw' syscall by file name
120+
func (f *File) Truncate(size int64) (err error) {
121+
if f.handle == nil {
122+
return ErrClosed
123+
}
124+
125+
e := ignoringEINTR(func() error {
126+
return syscall.Truncate(f.name, size)
127+
})
128+
129+
if e != nil {
130+
return &PathError{Op: "truncate", Path: f.name, Err: e}
131+
}
132+
return
133+
}
134+
115135
// ReadAt reads up to len(b) bytes from the File starting at the given absolute offset.
116136
// It returns the number of bytes read and any error encountered, possibly io.EOF.
117137
// At end of file, Pread returns 0, io.EOF.

src/os/truncate_test.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//go:build darwin || (linux && !baremetal && !js && !wasi)
2+
3+
// Copyright 2024 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package os_test
8+
9+
import (
10+
"os"
11+
. "os"
12+
"path/filepath"
13+
"testing"
14+
)
15+
16+
func TestTruncate(t *testing.T) {
17+
tmpDir, _ := os.MkdirTemp("", "TestTruncate")
18+
if err := RemoveAll(""); err != nil {
19+
t.Errorf("Truncate(\"\"): %v; want nil", err)
20+
}
21+
22+
file := filepath.Join(tmpDir, "truncate_0x100")
23+
24+
fd, err := Create(file)
25+
if err != nil {
26+
t.Fatalf("create %q: %s", file, err)
27+
}
28+
29+
// truncate up to 0x100
30+
if err := fd.Truncate(0x100); err != nil {
31+
t.Fatalf("truncate %q: %s", file, err)
32+
}
33+
34+
// check if size is 0x100
35+
fi, err := Stat(file)
36+
if err != nil {
37+
t.Fatalf("stat %q: %s", file, err)
38+
}
39+
40+
if fi.Size() != 0x100 {
41+
t.Fatalf("size of %q is %d; want 0x100", file, fi.Size())
42+
}
43+
44+
// truncate down to 0x80
45+
if err := fd.Truncate(0x80); err != nil {
46+
t.Fatalf("truncate %q: %s", file, err)
47+
}
48+
49+
// check if size is 0x80
50+
fi, err = Stat(file)
51+
if err != nil {
52+
t.Fatalf("stat %q: %s", file, err)
53+
}
54+
55+
if fi.Size() != 0x80 {
56+
t.Fatalf("size of %q is %d; want 0x80", file, fi.Size())
57+
}
58+
}

src/syscall/syscall_libc.go

+14
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,15 @@ func Unlink(path string) (err error) {
153153
return
154154
}
155155

156+
func Truncate(path string, length int64) (err error) {
157+
data := cstring(path)
158+
fail := int(libc_truncate(&data[0], length))
159+
if fail < 0 {
160+
err = getErrno()
161+
}
162+
return
163+
}
164+
156165
func Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
157166

158167
func Kill(pid int, sig Signal) (err error) {
@@ -431,5 +440,10 @@ func libc_readlink(path *byte, buf *byte, count uint) int
431440
//export unlink
432441
func libc_unlink(pathname *byte) int32
433442

443+
// int truncate(const char *path, off_t length);
444+
//
445+
//export truncate
446+
func libc_truncate(path *byte, length int64) int32
447+
434448
//go:extern environ
435449
var libc_environ *unsafe.Pointer

0 commit comments

Comments
 (0)