diff options
author | leongross <[email protected]> | 2024-03-26 13:21:50 +0100 |
---|---|---|
committer | Ron Evans <[email protected]> | 2024-04-14 16:56:53 +0200 |
commit | dcee228c4e29af5c06112f0ccc093c8f6483d64f (patch) | |
tree | feaa50819ed9032ed31ab45bd693afd332f21596 | |
parent | 9d6e30701b98f856125e55ba3fd26fa6b8f4a280 (diff) | |
download | tinygo-dcee228c4e29af5c06112f0ccc093c8f6483d64f.tar.gz tinygo-dcee228c4e29af5c06112f0ccc093c8f6483d64f.zip |
add os.Link
Signed-off-by: leongross <[email protected]>
-rw-r--r-- | src/os/file_unix.go | 13 | ||||
-rw-r--r-- | src/os/os_hardlink_test.go | 53 | ||||
-rw-r--r-- | src/syscall/syscall_libc.go | 15 |
3 files changed, 81 insertions, 0 deletions
diff --git a/src/os/file_unix.go b/src/os/file_unix.go index 665fb0937..25f0266a6 100644 --- a/src/os/file_unix.go +++ b/src/os/file_unix.go @@ -74,6 +74,19 @@ func tempDir() string { return dir } +// Link creates newname as a hard link to the oldname file. +// If there is an error, it will be of type *LinkError. +func Link(oldname, newname string) error { + e := ignoringEINTR(func() error { + return syscall.Link(oldname, newname) + }) + + if e != nil { + return &LinkError{"link", oldname, newname, e} + } + return nil +} + // Symlink creates newname as a symbolic link to oldname. // On Windows, a symlink to a non-existent oldname creates a file symlink; // if oldname is later created as a directory the symlink will not work. diff --git a/src/os/os_hardlink_test.go b/src/os/os_hardlink_test.go new file mode 100644 index 000000000..96f1c9bbb --- /dev/null +++ b/src/os/os_hardlink_test.go @@ -0,0 +1,53 @@ +//go:build !windows && !baremetal && !js && !wasi && !wasip1 && !wasm_unknown + +// 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" + "syscall" + "testing" +) + +func TestHardlink(t *testing.T) { + defer chtmpdir(t)() + from, to := "hardlinktestfrom", "hardlinktestto" + + file, err := Create(to) + if err != nil { + t.Fatalf("Create(%q) failed: %v", to, err) + } + if err = file.Close(); err != nil { + t.Errorf("Close(%q) failed: %v", to, err) + } + err = Link(to, from) + if err != nil { + t.Fatalf("Link(%q, %q) failed: %v", to, from, err) + } + + tostat, err := Lstat(to) + if err != nil { + t.Fatalf("Lstat(%q) failed: %v", to, err) + } + fromstat, err := Stat(from) + if err != nil { + t.Fatalf("Stat(%q) failed: %v", from, err) + } + if !SameFile(tostat, fromstat) { + t.Errorf("Symlink(%q, %q) did not create symlink", to, from) + } + + fromstat, err = Lstat(from) + if err != nil { + t.Fatalf("Lstat(%q) failed: %v", from, err) + } + // if they have the same inode, they are hard links + if fromstat.Sys().(*syscall.Stat_t).Ino != tostat.Sys().(*syscall.Stat_t).Ino { + t.Fatalf("Lstat(%q).Sys().Ino = %v, Lstat(%q).Sys().Ino = %v, want the same", to, tostat.Sys().(*syscall.Stat_t).Ino, from, fromstat.Sys().(*syscall.Stat_t).Ino) + } + + file.Close() +} diff --git a/src/syscall/syscall_libc.go b/src/syscall/syscall_libc.go index 7a13245b6..fb2e23968 100644 --- a/src/syscall/syscall_libc.go +++ b/src/syscall/syscall_libc.go @@ -134,6 +134,16 @@ func Rename(from, to string) (err error) { return } +func Link(oldname, newname string) (err error) { + fromdata := cstring(oldname) + todata := cstring(newname) + fail := int(libc_link(&fromdata[0], &todata[0])) + if fail < 0 { + err = getErrno() + } + return +} + func Symlink(from, to string) (err error) { fromdata := cstring(from) todata := cstring(to) @@ -416,6 +426,11 @@ func libc_rename(from, to *byte) int32 //export symlink func libc_symlink(from, to *byte) int32 +// int link(const char *oldname, *newname); +// +//export link +func libc_link(oldname, newname *byte) int32 + // int fsync(int fd); // //export fsync |